Here's some sample output from ex1.c:
Repetition value 14 x x x x x x L*l%!]!mveQ_>OL*l%!]!mveQ_>OL*l%!]!mveQ_>OL*l%!]!mveQ_>OL*l%!]!mveQ_>OL*l%!]!mve u$)lH%sP`<mGd<u$)lH%sP`<mGd<u$)lH%sP`<mGd<u$)lH%sP`<mGd<u$)lH%sP`<mGd<u$)lH%sP`< ?yC9CyK@?5C7by?yC9CyK@?5C7by?yC9CyK@?5C7byyC9CyK@?5C77byyC9CyK@?5C77byyC9CyK@?5C f$THP@)ckf[HIsf$THP@)ckf[HIsf$THP@)ckf[Isf$THP@)ckf[Isf$$THP@)ckf[Isf$$THP@)ckf[ (J@nWG5Wl&OH:S(J@nWG5Wl&OH:S(J@nWG5WlOH:S(J@nWG5WlOH:S(J@nnWG5WlOH:S(J@nnWG5WlOH ixl6Y$5}1x(QEXixl6Y$5}1x(QEXixl6Y$51x(QEXixl6Y$51x(QEXixl6Y$$51x(QEXixl6Y$$51x(Q 3"Dag6CSGn1(*`3"Dag6CSGn1(*`3"DagCSGn1(*`3"DagCSGn1(*`3"DagCSGGn1(*`3"DagCSGGn1( s$*4RQ+8@jqB!#s$*4RQ+8@jqB!#s$*4Q+8@jqB!#s$*4Q+8@jqB!#s$*4Q+8@jjqB!#s$*4Q+8@jjqB D1HZHI\nAI=d:YD1HZHI\nAI=d:YD1HHI\nAI=d:YD1HI\nAI=@d:YD1HI\nAI=@@d:YD1HI\nAI=@@d T+JO(!PT32SRrTT+JO(!PT32SRrTT+O(!PT32SRrT+O(!PT32SRrTT+O(!PT32SRrrTT+O(!PT32SRrr co#802+u~,Y&&#co#802+u~,Y&&#c#802+u~,Y&#c#802+u~,Y&#c#8Y02+u~,Y&#cc#8Y02+u~,Y&#c Zfr9Jrd;N@@=bAZfr9Jrd;N@@=bAfr9Jrd;N@=bAfr9Jrd;N@=bAfr9JrXd;N@=bAfrr9JrXd;N@=bAf _=G>h>*R&&7D1K_=G>h>*R&&7D1K=G>h>*R&7D1K=G>h>*R&7D1K=G>h>*)R&7D1K=GG>h>*)R&7D1K= #KICd&eMMu:9fW#KICd&eMMu:9f#KICd&eMu:9f#KICd&eMu:9f#KICd&eMpu:9f#KICCd&eMpu:9f#K M~<\H7[[5TCk$yM~<\H7[[5TCk$M~<\H7[5TCk$M~<\H7[5TCk$M~<\H7[5TWCk$M~<\\H7[5TWCk$M~ 1;$.FJJ8oQyKUh1;$.FJJ8oQyKh1;$.FJ8oQyKh1;$.FJ8oQyKh1;$.FJ8oQy7Kh1;$.FFJ8oQy7Kh1; 9B=TT==t7F-:zY9B=TT==t7F-:Y9B=TT=t7F-:Y9B=TT=t7F-:Y9B=TT=t7F-?:Y9B=TTT=t7F-?:Y9B FIJbIIN<WnzEa_FIJbIIN<Wnza_FIJbIN<Wnza_FIJbIN<Wnza_FIJbIN<WnzaO_FIJbINN<WnzaO_FI <G?_##nY9iyG>P<G?_##nY9iy>P<G?_#nY9iy>P<G?_#nY9iy>P<G?_#nY9iy>_P<G?_#nnY9iy>_P<G MCZ@@OZ0;\AvoZMCZ@@OZ0;\AoZMCZ@OZ0;\AoZMCZ@OZ0;\AoZMCZ@OZ0;\AoZuMCZ@OZZ0;\AoZuMC LcDKKO&0O$^`9GLcDKKO&0O$`9GLcDKO&0O$`9GLcDKO&0O$`9GLcDKO&0O$`9G%LcDKO&00O$`9G%Lc K%\AA}LF!^i=-1K%\AA}LF!^=-1K%\A}LF!^=-1K%\A}LF!^=-1K%\A}LF!^=-1-K%\A}LFF!^=-1-K% dz''KCWXv?]X@@dz''KCWXv?X@@dz'KCWXv?X@@dz'KCWXv?X@@dz'KCWXv?X@@d)z'KCWXXv?X@@d)z 2oII{p)_qL@^\L2oII{p)_qL^\L2oI{p)_qL^\L2oI{p)_qL^\L2oI{p)_qL^\L2UoI{p)__qL^\L2Uo K\RR-_l$!cm8Y>K\RR-_l$!c8Y>K\R-_l$!c8Y>K\R-_l$!c8Y>K\R-_l$!c8Y>K&\R-_l$$!c8Y>K&\ dF**'[8E9\(zb,dF**'[8E9\zb,dF*'[8E9\zb,dF*'[8E9\zb,dF*'[8E9\zb,dcF*'[8EE9\zb,dcF M*44sPW]Z>}S~_M*44sPW]Z>S~_M*4sPW]Z>S~_M*4sPW]Z>S~_M*4sPW]Z>S~_MC*4sPW]]Z>S~_MC* o[JJ?UY5o]Ak+_o[JJ?UY5o]k+_o[J?UY5o]k+_o[J?UY5o]k+_o[J?UY5o]k+_oM[J?UY55o]k+_oM[ E,uu.;;"^*^e`uE,uu.;;"^*e`uE,u.;;"^*e`uE,u.;;"^*e`uE,u.;;"^*e`uE),u.;;""^*e`uE), b(VLL!bz@~V?[gb(VLL!bz@~?[gb(VL!bz@~?[gb(VL!bz@~?[gb(VL!bz@~?[g+b(VL!bzz@~?[g+b( ASOvv-("M04\'+ASOvv-("M0\'+ASOv-("M0\'+ASOv-("M0\'+ASOv-("M0\'+CASOv-(""M0\'+CAS J&G~~*uZ(b_Ey<J&G~~*uZ(b_y<J&G~*uZ(b_y<J&G~*uZ(b_y<J&G~*uZ(b_y<OJ&G~*uuZ(b_y<OJ& "E=EssII>Tk,FS"E=EssII>TkFS"E=EsII>TkFS"E=EsII>TkFS"E=EsII>TkF?S"E=EsIII>TkF?S"E 2O0`dd=D<Mv*J,2O0`dd=D<MvJ,2O0`d=D<MvJ,2O0`d=D<MvJ,2O0`d=D<MvJl,2O0`d==D<MvJl,2O ~M>=2BB)0A]&>O~M>=2BB)0A]&O~M>=2B)0A]&O~M>=2B)0A]&O~M>=2B)0A]Q&O~M>=22B)0A]Q&O~M I%O_}EE.l@8%W7I%O_}EE.l@8%7I%O_}E.l@8%7I%O_}E.l@8%7I%O_}E.l@8M%7I%O_}}E.l@8M%7I% 7%6^%)))[#PNd;7%6^%)))[#PNd7%6^%))[#PNd7%6^%))[#PNd7%6^%))[#PPNd7%6^^%))[#PPNd7% yE13sH!**WE`!DyE13sH!**WE`!yE13sH!*WE`!yE13sH!*WE`!yE13sH!*ZWE`!yE133sH!*ZWE`!yE aJG'[Y45PP)LDWaJG'[Y45PP)LDWJG'[Y45P)LDWJG'[Y45P)LDWJG'[Y4Z5P)LDWJGG'[Y4Z5P)LDWJ c0at^0\&`jj'5<c0at^0\&`jj'5<0at^0\&`j'5<0at^0\&`j'5<0at^0.\&`j'5<0aat^0.\&`j'5<0 x6\6TOU%/X"@@1x6\6TOU%/X"@@1x\6TOU%/X"@1x\6TOU%/X"@1x\6(TOU%/X"@1xx\6(TOU%/X"@1x !#<(z6'E%;?'%!!#<(z6'E%;?'%!!#(z6'E%;?'%!#(z6'E%;?'%!|#(z6'E%;?'%%!|#(z6'E%;?'%% 3v7+78bg]tXTZK3v7+78bg]tXTZK3v778bg]tXTZK3v78bg]tXcTZK3v78bg]tXccTZK3v78bg]tXccT W:&^"_Ra1eHssyW:&^"_Ra1eHssyW:&^_Ra1eHssyW:&^_Ra1eHssyW:&^_Ra1eeHssyW:&^_Ra1eeHs W#\|wg1_k_yrzAW#\|wg1_k_yrzAW#\|w1_k_yrzAW#\|w1_k_yrzAW#\|w1_kk_yrzAW#\|w1_kk_yr ^_Fg,X+aAg/-Vy^_Fg,X+aAg/-Vy^_Fg,X+Ag/-Vy^_Fg,X+Ag/-Vy^_Fg,XX+Ag/-Vy^_Fg,XX+Ag/- S`9%>>E]7(492AS`9%>>E]7(492AS`9%>>E]7492AS`9%>>E]7492AS`9%%>>E]7492AS`9%%>>E]749 /J:@3-vDU;.%=3/J:@3-vDU;.%=3/J:@3-vDU;.=3/J:@3-vDU;.=3/JJ:@3-vDU;.=3/JJ:@3-vDU;. '\n/-DhREKk{E#'\n/-DhREKk{E#'\n/-DhREKk{E#\n/-DhREKk{{E#\n/-DhREKk{{E#\n/-DhREKk ^:$J=wp1<w<+p1^:$J=wp1<w<+p1^:$J=wp1<w<+p1^:$J=wp1<w<+p1^:$J=wp1<w<+p1^:$J=wp1<w
/* * Example C code 1, for simple SIRDS scheme * * (C) Copyright 1994 By Peter Chang <Peter.Chang at nottingham.ac.uk> * * The output is a SIRTS (single image random text stereogram) * of a sphere, though the aspect ratio of text characters * will make this look like an ellipsoid. * * Due to the limited resolution of using text characters, the result * will be very layered. * It looks like a pile of discs of decreasing size. * * To compile under UNIX, use something like this: * cc -ansi -O ex1.c -lm * * Things to be done by you, the reader, include putting in * the graphics stuff, some error checking and a user interface -- * whether it be a straightforward command line interface or * a fancy GUI. * * It is assumed that the graphics library uses the following * coordinate system: upper left is the origin (0,0) and x,y increase * in the rightward and downward direction, respectively. * * Possible problems include the restrictive memory architecture * of personal computers and their operating systems. * For example, the IBM PC and its clones running {MS,DR,PC}-DOS * only allow a program to access 640K of memory directly. * */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #define VD (300.0*pmm) /* Viewing distance from screen (in pixels) */ #define ES (65.0*pmm) /* Eye separation */ #define OS (150.0*pmm) /* Offset into screen */ #define MYLOW -32000 #define MYHIGH 32000 /* * This define statement controls the number of different text * characters used by the program to make the SIRTS * If you want to use just two characters ('!' and '"') * then comment it out. */ #define MANYCHARS typedef struct { int t; int f; } Llist; /* Link list structure, contains 'to' and 'from' indices */ int width, height; /* dimensions of final picture, in pixels */ /* * this is set for ASCII text output with a fixed width of 6 pixels * (ie. an xterm with 'fixed' font) on a monitor with 100dpi resolution */ float pmm = 0.656; /* resolution in pixels per mm */ unsigned int *dtos = NULL; /* pointer to lookup table for depth to separation */ int density = 127; /* density of dots, out of 255 */ int main() { int **ztop = NULL; /* z-buffer */ void zfillall(int **zbuf); void drawsirds(int **zbuf); int **zmema(void); void zmemf(int **zbuf); width = 80; /* set these two values to whatever you want */ height = 50; ztop = zmema(); zfillall(ztop); drawsirds(ztop); zmemf(ztop); exit(EXIT_SUCCESS); } /* * Defines z-values for all objects using discretised height fields */ void zfillall(int **zbuf) { int x, y; int *zll; int bv, iv; void drawobj(int **zbuf); iv = MYLOW; for (y=0; y<height; y++) { /* set background to const initially */ zll = zbuf[y]; for (x=0; x<width; x++) { *zll++ = iv; } } drawobj(zbuf); bv = 0; for (y=0; y<height; y++) { /* reset background to 0 */ zll = zbuf[y]; for (x=0; x<width; x++, zll++) { if (*zll == iv) *zll = bv; } } } /* * as an example, let's fill in the z-values of hemisphere of radius * height/2 */ void drawobj(int **zbuf) { int ox, x, y, z, t; register int oy, tx, ty; int *zline; int hemisphere(register int tx, register int ty, register int oy); ox = width/2; oy = height/2; ty = oy; for (y=0; y<height; y++, ty--) { zline = zbuf[y]; tx = -ox; for (x=0; x<width; x++, tx++, zline++) { z = *zline; t = hemisphere(tx, ty, oy); /* this line is all important, it's the essence of a z buffer */ if (t > z) *zline = t; } } } /* * a hemisphere function, * you can try one of your own instead */ int hemisphere(register int tx, register int ty, register int oy) { float tt; tt = oy*oy - tx*tx - ty*ty; return (tt > 0.0) ? (int) sqrt(tt) : 0; } /* * generate and output SIRDS */ void drawsirds(int **zbuf) { int x, y, pixpos; int *zline; Llist *same; /* doubly-linked list of matching points */ unsigned char *pixarray; /* holds the colours of a row */ unsigned int *nowdtos = NULL; /* pointer of somewhere in lookup table */ unsigned int colour; unsigned int *lookup (void ); void sirdssimp(int *zline, Llist *same, unsigned int *nowdtos); /* generic graphics routine */ void DrawPoint(int x, int y, unsigned int colour); srand(time(NULL)); same = (Llist *) malloc(width*sizeof(Llist)); pixarray = (unsigned char *) malloc(width*sizeof(char)); nowdtos = lookup(); /* this is to show the repetition of the background */ y = *nowdtos; printf("Repetition value %d\n", y); for (x=0; x<width; x++) { printf(((x%y) == 0) ? "x" : " "); } printf("\n"); for (y=0; y<height; y++) { zline = zbuf[y]; for (x=0; x<width; x++) { /* initialise matching list */ same[x].t = x; same[x].f = x; } sirdssimp(zline, same, nowdtos); for (x=0; x<width; x++) { pixpos = same[x].f; colour = (pixpos != x) ? pixarray[pixpos] : #ifdef MANYCHARS /* get a random value from 0 to 255 */ (rand() & 0xff); #else /* use this for two colours, at a set density */ ((rand() & 0xff) > density); #endif pixarray[x] = colour; DrawPoint(x, y, colour); } } free(same); free(pixarray); free(dtos); } /* * a lookup table for calculating the depth to shift info */ unsigned int *lookup (void ) { int i, range; unsigned int *look; float qfac, oss, vd; oss = 2.0*OS; qfac = ES; range = (int) (oss+0.5); vd = VD + oss; if (dtos != NULL) free(dtos); dtos = (unsigned int *) malloc (range*sizeof(int)); look = dtos; for (i=0; i<range; i++, look++) { *look = (unsigned int) (qfac*(oss-i)/(vd-i)+0.5); } return dtos+(range/2); /* return pointer to lookup table */ } /* * simple SIRDS scheme, no hidden surface removal * * the algorithm derives from the Thimbleby paper */ void sirdssimp(int *zline, Llist *same, unsigned int *nowdtos) { register int x, z0, s; register short left, right; register short st, sl, sr; for (x=0; x<width; x++) { z0 = *zline++; /* works out separation from depth using lookup table */ s = *(nowdtos+z0); left = x - s/2; right = left + s; if (left >= 0 && right < width) { /* now we put in to & from pointers for matching points */ sl = left; sr = right; for (st=same[sr].f; st!=sl && st!=sr; st=same[sr].f) { if (st > sl) { sr = st; } else { same[sl].t = sr; same[sr].f = sl; sr = sl; sl = st; } } same[sl].t = sr; same[sr].f = sl; } } } /* memory (de)allocation for zbuffer */ int **zmema(void) { int i; int **zbuf; zbuf = (int **) malloc(height*sizeof(int *)); for (i=0; i<height; i++) zbuf[i] = (int *) malloc(width*sizeof(int)); return zbuf; } void zmemf(int **zbuf) { int i; if (zbuf != NULL) { for(i=0; i<height; i++) free(zbuf[i]); free(zbuf); } } /* * Draw a point of a given colour * * This is just ASCII output at the moment, ie. a SIRTS output */ void DrawPoint(int x, int y, unsigned int colour) { int c; /* there are 94 printable ASCII characters from '!' to '~' inclusive */ c = (colour % 94) + '!'; printf("%c", c); if (x==width-1) printf("\n"); /* fudge to go to next line */ }
/* * Example C code 2, for correct-geometry SIRDS scheme * * (C) Copyright 1994 By Peter Chang <Peter.Chang at nottingham.ac.uk> * * This is incomplete code showing a sketch of the ideas * introduced in the text. * * Only the elements that differ from ex1.c are given. * More importantly, filltriangle() is also missing. * * The main deviation from the text is that the two buffers store * values of s, which decrease with increasing z. * So the buffer fills done by filltriangle() must update each slot * only if the new s is less than the old value. */ /* sets the tolerance for the comparison of s values */ #define TOLERANCE 1 #include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #define VD (300.0*pmm) /* Viewing distance from screen (in pixels) */ #define ES (65.0*pmm) /* Eye separation */ #define OS (150.0*pmm) /* Offset into screen */ #define MYLOW -32000 #define MYHIGH 32000 #define MANYCHARS typedef struct { int t; int f; } Llist; /* Link list structure, contains 'to' and 'from' indices */ int width, height; /* dimensions of final picture, in pixels */ float pmm = 0.656; /* resolution in pixels per mm */ int density = 127; /* density of dots, out of 255 */ int main() { int **ztopl = NULL, **ztopr = NULL; /* s-buffers */ void sfillall(int **zbufl, int **zbufr); void drawsirds(int **zbufl, int **zbufr); int **zmema(void); void zmemf(int **zbuf); width = 80; /* set these two values to whatever you want */ height = 50; ztopl = zmema(); ztopr = zmema(); sfillall(ztopl, ztopr); drawsirds(ztopl, ztopr); zmemf(ztopl); zmemf(ztopr); exit(EXIT_SUCCESS); } /* * fills s-values for all objects */ void sfillall(int **zbufl, int **zbufr) { int x, y; int *zll, *zlr; int bv, iv; void sdrawobj(int **zbufl, int **zbufr); iv = MYHIGH; for (y=0; y<height; y++) { /* set background to const initially */ zll = zbufl[y]; zlr = zbufr[y]; for (x=0; x<width; x++) { *zll++ = iv; *zlr++ = iv; } } sdrawobj(zbufl, zbufr); /* z-buffer now contains values of s */ bv = (int) ES*(OS+height/2.0)/(VD+OS+height/2.0); /* z = 0 */ for (y=0; y<height; y++) { /* reset background */ zll = zbufl[y]; zlr = zbufr[y]; for (x=0; x<width; x++, zll++, zlr++) { if (*zll == iv) *zll = bv; if (*zlr == iv) *zlr = bv; } } } /* * this time let's do a triangle * notice that we have two buffers */ void sdrawobj(int **zbufl, int **zbufr) { int xa, ya, xb, yb, xc, yc; float sa, sb, sc, za, zb, zc; float es, oy, vd, vdos; float ax, ay, az; float bx, by, bz; float cx, cy, cz; /* * The interpolated z-buffer fill is done by this function. * Its inputs are the coordinates of the vertices of a triangle * and the z-buffer. */ int filltriangle(int x1, int y1, float z1, int x2, int y2, float z2, int x3, int y3, float z3, int **zbuffer); es = ES; vd = VD; vdos = vd + OS; oy = height/2.0; /* let's do an isoceles triangle */ ax = 0.8*oy; ay = 0.0*oy; az = 0.0*oy; bx = -0.7*oy; by = 0.6*oy; bz = 0.3*oy; cx = -0.7*oy; cy = -0.6*oy; cz = -0.3*oy; za = vd/(vdos - az); /* z' */ xa = za*ax; /* x' */ ya = za*ay; /* y' */ sa = es*(1 - za); /* s */ xa -= sa/2; /* xL */ zb = vd/(vdos - bz); xb = zb*bx; yb = zb*by; sb = es*(1 - zb); xb -= sb/2; zc = vd/(vdos - cz); xc = zc*cx; yc = zc*cy; sc = es*(1 - zc); xc -= sc/2; /* fill left buffer then right */ filltriangle(xa, ya, sa, xb, yb, sb, xc, yc, sc, zbufl); filltriangle((xa+sa), ya, sa, (xb+sb), yb, sb, (xc+sc), yc, sc, zbufr); } /* * generate and output SIRDS */ void drawsirds(int **zbufl, int **zbufr) { int x, y, pixpos; int *zll, *zlr; Llist *same; /* doubly-linked list of matching points */ unsigned char *pixarray; /* holds the colours of a row */ unsigned int colour; void sirdsnew(int *zll, int *zlr, Llist *same); /* generic graphics routine */ void DrawPoint(int x, int y, unsigned int colour); srand(time(NULL)); same = (Llist *) malloc(width*sizeof(Llist)); pixarray = (unsigned char *) malloc(width*sizeof(char)); /* no need for lookup table */ for (y=0; y<height; y++) { zll = zbufl[y]; zlr = zbufr[y]; for (x=0; x<width; x++) { /* initialise matching list */ same[x].t = x; same[x].f = x; } sirdsnew(zll, zlr, same); for (x=0; x<width; x++) { pixpos = same[x].f; colour = (pixpos != x) ? pixarray[pixpos] : #ifdef MANYCHARS /* get a random value from 0 to 255 */ (rand() & 0xff); #else /* use this for two colours, at a set density */ ((rand() & 0xff) > density); #endif pixarray[x] = colour; DrawPoint(x, y, colour); } } free(same); free(pixarray); } /* * new SIRDS scheme, with hidden surface removal * * the new algorithm discussed in the paper */ void sirdsnew(int *zll, int *zlr, Llist *same) { register int s; register short left, right; register short st, sl, sr; for (left=0; left<width; left++) { s = *zll++; right = left + s; if (right < width) { s -= zlr[right]; /* check that both eyes can see the point */ if (s <= TOLERANCE && s >= -TOLERANCE) { /* now we put in to & from pointers for matching points */ sl = left; sr = right; for (st=same[sr].f; st!=sl && st!=sr; st=same[sr].f) { if (st > sl) { sr = st; } else { same[sl].t = sr; same[sr].f = sl; sr = sl; sl = st; } } same[sl].t = sr; same[sr].f = sl; } } } }