/****************************************************************/ /* Draft, 25nov00 annotated skel2001.c*/ /****************************************************************/ /**** skel.c = OpenSkelGlut.c = Noosh97 with CAVE removed ****/ /**** (C) 1994 Board of Trustees University of Illinois ****/ /**** A Model Real-Time Interactive OpenGL Application ****/ /**** George Francis, Glenn Chappell, Chris Hartman ****/ /**** e-mail gfrancis@math.uiuc.edu ****/ /******* revised 16jan2K by gkf**********************************/ /******* Exercise one solved and Stuart's gadgets too ************/ /****************************************************************/ /*>>> <<<*/ #pragma warning (disable:4305) /* double-to-float */ #pragma warning (disable:4101) /* unreferenced local variable */ #pragma warning (disable:4056) /* overflow in fp constant arithmetic */ /*>>> <<<*/ #include #include #include #include /* for the speedometer */ #include /*>>> <<<*/ #define random rand /* for Windows */ #define MAX(x,y) (((x)<(y))?(y):(x)) #define MIN(x,y) (((x)<(y))?(x):(y)) #define ABS(u) ((u)<0 ? -(u): (u)) #define FOR(a,b,c) for((a)=(b);(a)<(c);(a)++) #define DOT(p,q) ((p)[0]*(q)[0]+(p)[1]*(q)[1]+(p)[2]*(q)[2]) #define NRM(p) sqrt(DOT((p),(p))) #define M_PI (355./113.) #define DG M_PI/180 #define S(u) sin(u*DG) #define C(u) cos(u*DG) #define CLAMP(x,u,v) (xv ? v: x)) /*>>> global variables <<<*/ float gap, gap0=1.; /* kludge so that arguments() can set a default gap0 */ float lux[3]={.3,.5,.7}; /*world light direction vector */ float luxx[3]; /* object space direction vector*/ float amb, pwr ; /* ambient fraction, pseudo-specular power */ float mysiz,speed, torq, focal, wfar; /*console navigation variables */ int win = 1; /* 2 full screen, use 0 for demand sized */ unsigned int BUT, XX, YY,SHIF; /* used in chaptrack gluttery */ int xt,yt; /* once was xt,yt,xm,ym for viewportery */ int mode,morph,msg,binoc; /* pretty global */ int th0, th1, dth, ta0, ta1, dta; /* torus parameters */ #define FLYMODE (0) #define TURNMODE (1) int ii, jj, kk; float tmp, temp; /* saves gray hairs later */ float aff[16], starmat[16], mat[16]; int binoc; /* flag */ float nose; /* to eye distance in console */ int hasnumber, number, decimal, sign ; /* for Stuart's number parser */ /**********************************************************************/ /*>>> <<<*/ kommrusch(int fr, int to){ /* Self-initializing function draws a cube.*/ static int virgin=1; /* Steve Kommrusch, Math 198, 1984 */ static float cc,ss; static float hcube[16][4]; static int ep[]={ 0, 1, 3, 2, 0, /* Eulerian path */ 4, 5, 7, 6, 4, 12,13,15,14,12, 8, 9,13, 5, 1, 9, 11, 15, 7, 3, 11, 10, 14, 6, 2, 10, 8, 0}; if(virgin){ virgin=0; /* corners of a body-centered cube */ FOR(ii,0,16)FOR(jj,0,4)hcube[ii][jj]=(ii&(1<>> <<<*/ void autotymer(int reset){ /* cheap animations */ #define TYME(cnt,max,act) {static cnt; if(first)cnt=max; else\ if(cnt?cnt--:0){ act ; goto Break;}} static first = 1; /* the first time autymer is called */ if(reset)first=1; /* or if it is reset to start over */ TYME( shrink , 150,th0++;th1--;ta0++;ta1--) TYME( pause , 20, ) TYME( grow , 150,th0--;th1++;ta0--;ta1++) TYME( dwell , 30, ) TYME(finish , 1 , first = 1 ) first = 0; Break: ; /* yes Virginia, C has gotos */ } /**********************************************************************/ /*>>> <<<*/ void deFault(void){ th0=5; th1=355; ta0=5; ta1=355; gap = gap0; msg=1; binoc=0; nose=.06; mode=TURNMODE; speed=.01; torq=.005; focal = 2.; wfar =13.; mysiz=.01; morph=0; FOR(ii,0,16) starmat[ii]=aff[ii] = (ii/4==ii%4); /* identities */ FOR(ii,0,3)lux[ii]/=NRM(lux); amb = .3; pwr = 10. ; aff[12]=0; aff[13]= 0; aff[14]= -4.2; /* place where we can see it */ autotymer(1); /* reset autotymer to start at the beginning */ } /**********************************************************************/ /*>>> <<<*/ void drawvert(int th, int ta){ float lmb,spec,nn[3], dog, cat; nn[0] = C(th)*C(ta); /* unit sphere radius vector */ nn[1] = S(th)*C(ta); nn[2] = S(ta); lmb = DOT(nn,luxx);lmb =(lmb<0 ? .2 : lmb); lmb = MAX(amb, lmb); spec = CLAMP((1.1 - pwr+pwr*lmb), 0., 1.); dog = (ta-ta0)/(float)(ta1-ta0); cat = (th-th0)/(float)(th1-th0); glColor3f( MAX(spec, lmb*dog), /* map R^2(dog,cat)->R^3(RGBspace */ MAX(spec, lmb*(.25 + ABS(cat -.5))), /* dog cat model of Hartman */ MAX(spec, lmb*(1 - cat))); /* illiLight by Ray Idaszak 1989 */ glVertex3f( C(th) + .5*nn[0], S(th) + .5*nn[1], .5*nn[2]); } /* end drawvert */ /**********************************************************************/ /*>>> <<<*/ void drawtor(void){ int th, ta; dth = (int)((th1-th0)/24); /* 24 meridian strips */ dta = (int)((ta1-ta0)/24); /* 24 triangle pairs per strip */ for(th=th0; th < th1; th += dth){ glBegin(GL_TRIANGLE_STRIP); for(ta=ta0; ta < ta1; ta += dta){ drawvert(th,ta); drawvert(th+gap*dth,ta); } glEnd(); } /* end for.theta loop */ } /* end drawtor */ /**********************************************************************/ void drawcube(void){ kommrusch(1,3);} /**********************************************************************/ void drawall(void){ drawtor(); drawcube(); } /**********************************************************************/ /*>>> <<<*/ void drawstars(void){ static float star[1000][3]; static int virgin=1; if(virgin){ /* first time set up the stars */ FOR(ii,0,1000)FOR(jj,0,3)star[ii][jj]=random()/(float)0x40000000-1.; virgin=0; /* never again */ } glMatrixMode(GL_MODELVIEW); glPushMatrix(); /* insurance of superstition */ glMultMatrixf(starmat); glColor3f(1.0,1.0,0.0); glBegin(GL_POINTS); FOR(ii,0,1000)glVertex3fv(star[ii]); glEnd(); glPopMatrix(); glClear(GL_DEPTH_BUFFER_BIT); /* so the stars are behind everything */ } /**********************************************************************/ /*>>> <<<*/ void arguments(int argc,char **argv){ /* Pat Hanrahan 1989 */ while(--argc){++argv; if(argv[0][0]=='-')switch(argv[0][1]){ case 'w': win =atoi(argv[1]); argv++; argc--; break; case 'g': gap0=atof(argv[1]); argv++; argc--; break; }}} /**********************************************************************/ #if 0 void arguments(int argc,char **argv){ extern char *optarg; extern int optind; int chi; /* w: needs ONE number after -w, c means NO number follows*/ while ((chi = getopt(argc,argv,"w:d:g:")) != -1) switch(chi) { case 'w': win=atoi(optarg); break; case 'g': gap0=atof(optarg); break; } if (optind!=argc) fprintf(stderr,"%s: Incorrect usage\n",argv[0]); } #endif /*>>> <<<*/ /**********************************************************************/ /* Stuart Levy 1998 improved gadgets getnumber, bump */ /**********************************************************************/ float getnumber(float dflt){ /* dflt is an action or a constant */ if(!hasnumber)return dflt; /* in case no number to put in */ tmp = sign ? -number : number; return decimal>0 ? tmp/(float)decimal : tmp ; } /**********************************************************************/ void bump(float *val, float incr){ /* use bump(&nose, .01) for example */ float abs = fabs(incr); char frmt[8], code[32]; int digits = 1; if(hasnumber){ *val = getnumber(0); return; } if(abs <= .003) digits=3; else if(abs <= .03) digits=2; sprintf(frmt, "%%.%de" , digits); sprintf(code, frmt, incr >0 ? (*val)*(1+abs):(*val)/(1+abs)); sscanf(code, "%f", val); } /**********************************************************************/ void keyboard(unsigned char key, int x, int y){ #define IF(K) if(key==K) #define PRESS(K,A,b) IF(K){b;}IF((K-32)){A;} /*was backwards in previous versions */ #define TOGGLE(K,flg) IF(K){(flg) = getnumber(1-(flg));} #define CYCLE(K,f,m) PRESS((K), \ getnumber((f)=(((f)+(m)-1)%(m))), getnumber((f)=(++(f)%(m)))) /* Only ASCII characters can be processes by this GLUT callback function */ IF(27)exit(0); /* ESC exit */ TOGGLE('v',binoc); /* cross-eyed STEREO */ CYCLE(' ', mode,TURNMODE+1); /* fly/turn modes */ TOGGLE('h',morph); /* autotymer on/off */ TOGGLE('w',msg); /* writing on/off */ PRESS('n', bump(&nose, -.001), bump(&nose,.001)) /* for binoculars */ PRESS('s', bump(&speed,-.02), bump(&speed,.02)) /* flying speed */ PRESS('q', bump(&torq, -.02), bump(&torq,.02)) /* turning speed */ PRESS('o', bump(&focal,-.1) , bump(&focal,.1)) /* telephoto */ PRESS('i', bump(&mysiz,-.1) , bump(&mysiz, .1)) /* rescale the world */ PRESS('p', bump(&wfar, -.01) , bump(&wfar, .01)) /* rear clipping plane */ PRESS('z', deFault(), deFault()) /* zap changes */ PRESS('g',bump(&gap, -.1), bump(&gap,.1)) /* gap parameter */ PRESS('a',bump(&amb, -.1), bump(&amb,.1)) /* ambient fraction */ PRESS('r',bump(&pwr, -.1), bump(&pwr,.1)) /* pseudo-spec power */ /* Stuart Levy's gadget parser from avn.c */ if(key >= '0' && key <= '9'){ hasnumber = 1; number = 10*number + (key - '0'); decimal *= 10;} else if(key == '.'){ decimal = 1;} else if(key == '-'){ sign = -1;} else {hasnumber = number = decimal = sign = 0;} glutPostRedisplay(); } /**********************************************************************/ void special_keybo(int key, int x, int y){ /*non-ASCII keypresses go here, if you're lucky enough to know their names */ fprintf(stderr," non-ASCII character was pressed.\n"); fprintf(stderr," use special_keybo() to process it\n"); } /**********************************************************************/ float speedometer(void){ double dbl; static double rate; static int ii=0; static struct _timeb lnow, lthen; if(++ii % 8 == 0){ /* 8 times around measure time */ _ftime(&lnow); dbl = (double)(lnow.time - lthen.time) +(double)(lnow.millitm - lthen.millitm)/1000; lthen = lnow; rate = 8/dbl; } return((float)rate); } #if 0 float speedometer(void){ double dbl; static double rate; static int ii=0; static struct timezone notused; static struct timeval now, then; if(++ii % 8 == 0){ /* 8 times around measure time */ gettimeofday(&now, ¬used); /* elapsed time */ dbl = (double)(now.tv_sec - then.tv_sec) +(double)(now.tv_usec - then.tv_usec)/1000000; then = now; rate = 8/dbl; } return((float)rate); } #endif /**********************************************************************/ void char2wall(float x,float y,float z, char buf[]){ char *p; glRasterPos3f(x,y,z); for(p = buf;*p;p++) glutBitmapCharacter(GLUT_BITMAP_9_BY_15,*p); } /**********************************************************************/ void messages(void){ char buf[256]; /* console messages are done differently from cave */ #define LABEL2(x,y,W,u) {sprintf(buf,(W),(u));char2wall(x,y,0.,buf);} glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); gluOrtho2D(0,3000,0,3000); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); /*bull's eye*/ if(mode==TURNMODE) glColor3f(0x22/255.,0x88/255.,0xdd/255.); else glColor3f(.8,.8,.8); LABEL2(1500,1500,"%s","o"); /* writings */ if(mode==TURNMODE) glColor3f(1.,0.,1.); else glColor3f(1.,1.,0.); LABEL2(80,80,"%4.1f fps",speedometer()); LABEL2(80,2840,\ "(ESC)ape (V)Binoc (MAUS2)Fore (BAR)Flymode %s (H)omotopy (W)riting", mode?"FLYING":"CONTROL"); LABEL2(10,10,"illiOpenSkelGLUT \ by Francis, Bourd, Hartman & Chappell, UIllinois, 1995..2000 %s",""); LABEL2(80,2770,"(N)ose %0.3f",nose); LABEL2(80,2700,"(S)peed %0.3f",speed); LABEL2(80,2630," tor(Q) %0.3f",torq); LABEL2(80,2560,"near clipper %g", mysiz*focal); LABEL2(80,2490,"f(O)cal factor %g",focal); LABEL2(80,2420,"my s(I)ze %0.3f",mysiz); LABEL2(80,2350,"wfar cli(P)er= %0.3f",wfar); LABEL2(80,2280,"(Z)ap %s",""); LABEL2(80,2210,"(G)ap %0.3f",gap); LABEL2(80,2140,"(A)mb %0.3f",amb); LABEL2(80,2070,"pw(R) %0.3f",pwr); glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); } /**********************************************************************/ void chaptrack(int but,int xx,int yy,int shif){ long dx,dy; dx = xx -.5*xt; dx = abs(dx)>5?dx:0; dy = yy -.5*yt; dy = abs(dy)>5?dy:0; glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); if(mode==TURNMODE) glTranslatef(aff[12],aff[13],aff[14]); glRotatef(dx*torq,0.,1.,0.); glRotatef(dy*torq,1.,0.,0.); if(but&(1<"); if(win==2) glutFullScreen(); glEnable(GL_DEPTH_TEST); glutDisplayFunc(drawcons); glutKeyboardFunc(keyboard); glutSpecialFunc(special_keybo); glutMouseFunc(mousepushed); glutMotionFunc(mousemoved); glutPassiveMotionFunc(mousemoved); glutReshapeFunc(reshaped); glutIdleFunc(idle); glutMainLoop(); }