/* tree.c : SGI: three-dimensional fractal trees */ static const char *Version[] = { "@(#) tree.c Copyright (c) 1994 C. Alex. North-Keys", "$Grueppe: Talisman $", "$Anfang: Mon Sep 19 04:07:33 GMT 1994 $", "$Compiliert: "__DATE__" " __TIME__ " $", "$Source: /usr/people/erlkonig/zoo/sgi/fractals/tree.c $", "$State: $", "$Revision: $", "$Date: Mon Sep 19 04:07:33 GMT 1994 $", "$Author: erlkonig $", (const char*)0 }; /* NOTE: this API (GL) is obsolete - use OpenGL instead */ #include #include #include #include #include "tree.h" enum { X = 0, Y = 1, Z = 2, XYZ = 3, }; /* global */ int PrettyFlag = 0; void NV(const float point[XYZ]) { v3f(point); if(PrettyFlag) n3f(point); return; } /* base - 3d-coord, scale - magnitude of xyz components outward */ void Plain(const float base[XYZ], float scale) { static const float Blue[] = { 0.0, 0.0, 1.0 }; static float ground[] = { AMBIENT, 0, 0, 0, DIFFUSE, 0, .01, .3, SPECULAR, .1, .1, .3, LMNULL, }; static int initialized = 0; if( ! initialized) { lmdef(DEFMATERIAL, 1004, 0, ground); ++initialized; } if(PrettyFlag) lmbind(MATERIAL, 1004); else lmbind(MATERIAL, 0); c3f(Blue); bgnpolygon(); { float trg[3] = { base[X] + scale, base[Y], base[Z] + scale }; NV(trg); } { float trg[3] = { base[X] - scale, base[Y], base[Z] + scale }; NV(trg); } { float trg[3] = { base[X] - scale, base[Y], base[Z] - scale }; NV(trg); } { float trg[3] = { base[X] + scale, base[Y], base[Z] - scale }; NV(trg); } endpolygon(); return; } /* base - 3d-coord, scale - magnitude of xyz components */ void Leaf(const float base[XYZ], float scale) { static const float Inner[] = { 0.0, 0.8, 0.4 }; static const float Outer[] = { 0.0, 0.4, 0.0 }; bgnpolygon(); c3f(Outer); { float trg[3] = { base[X] + scale, base[Y], base[Z] }; NV(trg); } { float trg[3] = { base[X], base[Y], base[Z] + scale }; NV(trg); } c3f(Inner); NV(base); endpolygon(); bgnpolygon(); c3f(Outer); { float trg[3] = { base[X], base[Y], base[Z] + scale }; NV(trg); } { float trg[3] = { base[X] - scale, base[Y], base[Z] }; NV(trg); } c3f(Inner); NV(base); endpolygon(); bgnpolygon(); c3f(Outer); { float trg[3] = { base[X] - scale, base[Y], base[Z] }; NV(trg); } { float trg[3] = { base[X], base[Y], base[Z] - scale }; NV(trg); } c3f(Inner); NV(base); endpolygon(); bgnpolygon(); c3f(Outer); { float trg[3] = { base[X], base[Y], base[Z] - scale }; NV(trg); } { float trg[3] = { base[X] + scale, base[Y], base[Z] }; NV(trg); } c3f(Inner); NV(base); endpolygon(); return; } /* src, trg - 3d-coords, rad - radius (to side of sqr Xsection) of branch */ void Branch(const float src[XYZ], const float trg[XYZ], float rad) { /* 8 vertices, 4 faces */ float fl[3] = { src[X] - rad, src[Y], src[Z] - rad }; float fr[3] = { src[X] + rad, src[Y], src[Z] - rad }; float br[3] = { src[X] + rad, src[Y], src[Z] + rad }; float bl[3] = { src[X] - rad, src[Y], src[Z] + rad }; float FL[3] = { trg[X] - rad, trg[Y], trg[Z] - rad }; float FR[3] = { trg[X] + rad, trg[Y], trg[Z] - rad }; float BR[3] = { trg[X] + rad, trg[Y], trg[Z] + rad }; float BL[3] = { trg[X] - rad, trg[Y], trg[Z] + rad }; static const float Brown[] = { 0.3, 0.2, 0.0 }; static const float DarkBrown[] = { 0.1, 0.16666, 0.0 }; static float wood[] = { AMBIENT, 0, 0, 0, DIFFUSE, .2, .1, 0, SPECULAR, .0, .0, .0, LMNULL, }; static int initialized = 0; if( ! initialized) { lmdef(DEFMATERIAL, 1002, 0, wood); ++initialized; } if(PrettyFlag) lmbind(MATERIAL, 1002); else lmbind(MATERIAL, 0); bgntmesh(); c3f(Brown); NV(fl); NV(FL); c3f(DarkBrown); NV(fr); NV(FR); c3f(Brown); NV(br); NV(BR); c3f(DarkBrown); NV(bl); NV(BL); c3f(Brown); NV(fl); endtmesh(); return; } /* base - 3d-coord, scale - magnitude of xyz components, depth - ends at 0 */ void Tree(const float base[XYZ], float scale, int depth) { int lift = 30 + scale; float rad = scale / 10; if(depth > 0) { float trg[3]; int i; for(i = 0 ; i <= 2 ; ++i) trg[i] = base[i]; trg[Y] += lift; /* [Y] holds this value */ trg[X] = base[X] + scale; trg[Z] = base[Z] + scale; Branch(base, trg, rad); Tree(trg, scale/2, depth - 1); trg[X] = base[X] - scale; trg[Z] = base[Z] + scale; Branch(base, trg, rad); Tree(trg, scale/2, depth - 1); trg[X] = base[X] - scale; trg[Z] = base[Z] - scale; Branch(base, trg, rad); Tree(trg, scale/2, depth - 1); trg[X] = base[X] + scale; trg[Z] = base[Z] - scale; Branch(base, trg, rad); Tree(trg, scale/2, depth - 1); } { static float chlorphyll[] = { AMBIENT, .1, .1, .1, DIFFUSE, 0, .369, 0, SPECULAR, .0, .6, .0, LMNULL, }; static int initialized = 0; if( ! initialized) { lmdef(DEFMATERIAL, 1003, 0, chlorphyll); ++initialized; } } if((int)(base[Y] / 100)) { if(PrettyFlag) lmbind(MATERIAL, 1003); else lmbind(MATERIAL, 0); Leaf(base, 4 + scale); } return; } void GetCenteredMouse(long *xp, long *yp) { static Screencoord left, right, bottom, top; long originx, originy, mx, my; int initialized = 0; if( ! initialized) { getviewport(&left, &right, &bottom, &top); getorigin(&originx, &originy); ++initialized; } /* origin at bottom left */ mx = (getvaluator(MOUSEX) - originx); my = (getvaluator(MOUSEY) - originy); /* now in reference to origin at center of window */ mx = mx - ((left + right) / 2); my = my - ((top + bottom) / 2); *xp = mx, *yp = my; return; } void Pretty(void) { PrettyFlag = ! PrettyFlag; if(PrettyFlag) { subpixel(TRUE); blendfunction(BF_SA, BF_MSA); pntsmooth(TRUE); linesmooth(SML_ON | SML_SMOOTHER | SML_END_CORRECT); polysmooth(PYSM_ON); } else { subpixel(FALSE); blendfunction(BF_ONE, BF_ZERO); pntsmooth(SMP_OFF); linesmooth(SML_OFF); polysmooth(PYSM_OFF); } { static float lm[] = { AMBIENT, 0, 0, 0, LOCALVIEWER, 1, LMNULL, }; static float lt[] = { LCOLOR, 1, 1, 1, POSITION, 200, 500, -200, 1, /* 1:point source */ LMNULL, }; static float mat[] = { AMBIENT, .1, .1, .1, DIFFUSE, 0, .369, 0, SPECULAR, .0, .6, .0, LMNULL, }; if(PrettyFlag) { lmdef(DEFLMODEL, 1001, 0, lm); lmbind(LMODEL, 1001); lmdef(DEFLIGHT, 1001, 0, lt); lmbind(LIGHT0, 1001); lmdef(DEFMATERIAL, 1001, 0, mat); lmbind(MATERIAL, 1001); lmbind(BACKMATERIAL, 1001); } else { lmbind(LMODEL, 0); lmbind(LIGHT0, 0); lmbind(MATERIAL, 0); lmbind(BACKMATERIAL, 0); } } return; } int main(int ac, char **av) { int size = 800; float here[XYZ] = { 0, 500, -1200 }; float there[XYZ] = { 0, 0, 400 }; float twist = 0; int depth = 0; /* initialize graphics */ prefsize(1200, 900); winopen("tree"); stereobuffer(); doublebuffer(); mmode(MVIEWING); { long xsize, ysize; float aspect; getsize(&xsize, &ysize); aspect = (float)xsize / (float)ysize; fprintf(stderr, "xsize %ld, ysize %ld, aspect %f\n", xsize, ysize, aspect); perspective(100, aspect, -500, 500); } RGBmode(); lsetdepth(getgdesc(GD_ZMAX), getgdesc(GD_ZMIN)); { float parms[] = { 400, 10000, 0.0, 0.0, 0.25 }; fogvertex(FG_VTX_LIN, parms); fogvertex(FG_ON, 0); /* the zero is ignored */ } zbuffer(TRUE); gconfig(); qdevice(KEYBD); qdevice(LEFTMOUSE); qdevice(MIDDLEMOUSE); for(;;) { static int left = 0; static int panning = 0, zooming = 0; int bail = 0; short val; Device dev; /* clear everything to dark blue */ czclear(0x00440000, getgdesc(GD_ZMAX)); leftbuffer(left), rightbuffer(!left); pushmatrix(); { static const float zero[XYZ] = { 0, 0, 0 }; static const float b1[XYZ] = { 300, 0, 100 }; static const float b2[XYZ] = { -375, 0, 375 }; static const float b3[XYZ] = { -300, 0, -200 }; /* choose viewpoint */ lookat( here[X], here[Y], here[Z], there[X], there[Y], there[Z], twist); /* make plain and tree */ Plain(zero, 400); Tree(b1, 50, depth - 1); Tree(b2, 40, depth - 3); Tree(b3, 70, depth - 2); Tree(zero, 100, depth); } popmatrix(); swapbuffers(); gflush(); if(panning) { long mx, my; GetCenteredMouse(&mx, &my); here[X] += -mx; here[Y] += my; } if(zooming) { long mx, my; GetCenteredMouse(&mx, &my); here[Z] += (my - mx) / 2; } switch((panning || zooming) ? (qtest() ? qread(&val) : TIMER0) : qread(&val)) { default: break; case TIMER0: break; case LEFTMOUSE: panning = val; break; case MIDDLEMOUSE: zooming = val; break; case KEYBD: switch(val) { default: ringbell(); break; case 'a': ++depth; break; case 'z': --depth; break; case 'u': here[Y] += 10; break; case 'd': here[Y] -= 10; break; case 'l': here[X] += 10; break; case 'r': here[X] -= 10; break; case 'n': here[Z] += 10; break; case 'f': here[Z] -= 10; break; case 'U': here[Y] += 100; break; case 'D': here[Y] -= 100; break; case 'L': here[X] += 100; break; case 'R': here[X] -= 100; break; case 'N': here[Z] += 100; break; case 'F': here[Z] -= 100; break; case 'p': Pretty(); break; case 'q': gexit(); return 0; } case REDRAW: break; /* will happen without effort from here */ case INPUTCHANGE: break; case WINQUIT: gexit(); return 0; } } /* for(;;) */ gexit(); /* shouldn`t ever actually get here*/ return 0; }