/* gkf: 11/30/04 */ /* gkf: 3/27/02 articulation with torus and teapot */ /* gkf: autotymer has frustum experiments */ /*****************************2002*************************************/ /**** skel.c = OpenSkelGlut.c = Noosh97 with CAVE removed ****/ /**** (C) 1994--2002 Board of Trustees University of Illinois ****/ /**** A Model Real-Time Interactive C/OpenGL/GLUT Animator ****/ /**** George Francis, Stuart Levy, Glenn Chappell, Chris Hartman****/ /**** e-mail gfrancis@math.uiuc.edu : revised 2jan02 by gkf ****/ /**********************************************************************/ #include #include #include /* sgi */ #include /* sgi */ #include // #pragma warning (disable:4305) /* constant double-to-float */ #define MAX(x,y) (((x)<(y))?(y):(x)) #define MIN(x,y) (((x)<(y))?(x):(y)) #define CLAMP(x,u,v) (xv ? v: x)) #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) /* Tsu Ch'ung Chi 430 AD */ #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)) #define random rand /* library dependent name */ #define IFCLICK(K,a){static ff=1; if(getbutton(K))ff=1-ff; if(ff){a} } #define MERIDIANS 32 #define LATITUDES 32 #define MANYSTARS 10000 /************************** global variables **************************/ int win=1; /* used once to choose window size */ int chapmat=1; int vumat=1; float gap, gap0=1.; /* deFault() uses gap0 set by arguments() */ float lux[3]={1.,2.,3.}; /* world light non unit vector */ float luxx[3]; /* object space direction vector */ float amb, pwr; /*ambient fraction, pseudo-specular power */ float mysiz,speed, torq, focal, wfar; /* navigation control variables */ unsigned int PAW,XX,YY,SHIF; /* used in chaptrack gluttery */ int xwide,yhigh; /* viewportery width and height */ int mode,morph,msg,binoc; /* viewing globals */ int th0, th1, dth, ta0, ta1, dta; /* torus parameters */ #define FLYMODE (0) /* yellow: turns around head as center */ #define TURNMODE (1) /* purple: turns around object center */ int ii, jj, kk; float tmp, temp; /* saves gray hairs later */ float aff[16], starmat[16], mat[16]; /* OpenGL placement matrices */ float camat[16], tormat[16], teamat[16]; int binoc; /* flag for binocular stereo */ float nose; /* to eye distance in console */ char clefs[128]; /* which keys were pressed last */ /*********************** steering *************************************/ void autotymer(int reset){ /* cheap animator */ #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 , focal *= 1.01; aff[14] *= 1.01; ) TYME( pause , 20, 0 ) TYME( grow , 150, focal /= 1.01; aff[14] /= 1.01; ) TYME( dwell , 30, 0 ) TYME(finish , 1 , first = 1 ) /* this TYME must be the last one */ first = 0; Break: ; /* yes Virginia, C has gotos */ } /**********************************************************************/ void deFault(void){ /* (Z)ap also restores these assignments */ vumat=chapmat=1; th0=5; th1=355; ta0=5; ta1=355; gap = gap0; /* torus parameters */ msg=1; binoc=0; nose=.06; mode=TURNMODE; /* gadget parameters */ speed=.02; torq=.02; focal = 2.; wfar=100; mysiz=.01; morph=0; FOR(ii,0,16) camat[ii]=tormat[ii]=teamat[ii]=starmat[ii]=aff[ii] = (ii/4==ii%4); amb = .3; pwr = 10; /* lighting params */ tmp=NRM(lux); FOR(ii,0,3)lux[ii] /= tmp; /* normalize light vector */ 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 */ } /*************************** scenery **********************************/ void drawvert(int th, int ta){ /* make one properly lighted vertex */ float bb,gg,rr; float lmb,spec,nn[3], dog, cat; /* radius of unit sphere is also unit normal to the torus */ nn[0] = C(th)*C(ta); nn[1] = S(th)*C(ta); nn[2] = S(ta); /* illiLight by Ray Idaszak 1989 uses max{amb*lmb, rgb*lmb, spec} */ lmb = DOT(nn,luxx); lmb =(lmb<0 ? .2 : lmb); lmb = MAX(amb, lmb); spec = CLAMP((1.1 - pwr+pwr*lmb), 0., 1.); /* illiPaint by Chris Hartman 1993 maps R2(cat,dog)->R3(r,g,b) */ dog = (ta-ta0)/(float)(ta1-ta0); cat = (th-th0)/(float)(th1-th0); rr = MAX(spec, lmb*dog); gg = MAX(spec, lmb*(.25 + ABS(cat -.5))); bb = MAX(spec, lmb*(1 - cat)); glColor3f(rr,gg,bb); /* torus has unit small diameter and unit big radius */ glVertex3f( C(th) + .5*nn[0], S(th) + .5*nn[1], 0 + .5*nn[2]); } /* end drawvert */ /**********************************************************************/ void drawtor(void){ /* illiTorus with gaps */ int th, ta; dth = (int)((th1-th0)/MERIDIANS); /* this many meridian strips */ dta = (int)((ta1-ta0)/LATITUDES); /* and 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){ /* transfer from skel.c as an exercise */ } /**********************************************************************/ void drawpot(void){ glPushMatrix(); glScalef(.5,.5,.5); glutWireTeapot(.5); glPopMatrix(); } /**********************************************************************/ void drawall(void){ glPushMatrix(); glMultMatrixf(tormat); drawtor(); glPopMatrix(); glPushMatrix(); glMultMatrixf(teamat); glutWireTeapot(.5); glPopMatrix(); } /**********************************************************************/ void drawstars(void){ /* replace with SLevy's much prettier stars */ static float star[MANYSTARS][3]; static int virgin=1; if(virgin){ /* first time through set up the stars */ FOR(ii,0,MANYSTARS){ /* in a unit cube then on unit sphere */ FOR(jj,0,3)star[ii][jj] =(float)random()/RAND_MAX - 0.5; tmp=NRM(star[ii]); FOR(jj,0,3)star[ii][jj]/=tmp; } virgin=0; /* never again */ } glMatrixMode(GL_MODELVIEW); glPushMatrix(); /* optional insurance or superstition */ glMultMatrixf(starmat); glColor3f(0.8,0.9,1.0); glBegin(GL_POINTS); FOR(ii,0,MANYSTARS)glVertex3fv(star[ii]); glEnd(); /* glutWireTeapot(1); if you prefer one on the firmament instead */ glPopMatrix(); /* optional insurance or superstition */ glClear(GL_DEPTH_BUFFER_BIT); /* put the stars at infinity */ } /************************ steering ***********************************/ 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; case 'L': lux[0]=atof(argv[1]); lux[1]=atof(argv[2]); lux[2]=atof(argv[3]); argv +=3; argc -=3; break; }}} /**********************************************************************/ int number, hasnumber, decimal, sign; /* globals for SLevy's gadgets */ /* these are assigned in keyboard() but used by these factor fcns */ float getnumber(float dflt){ /* from keyboard, factor of bump() */ float v = (sign ? -number : number); /* positive or negative nr */ if(!hasnumber) return dflt; /* if no new nr use old on */ return decimal>0 ? v/(float)decimal : v; } void bump(float *val, float incr){ /* SLevy 98 */ float by = fabs(incr); /* wizard speak ... best not mess with it */ char fmt[8], code[32]; int digits = 1; if(hasnumber) { *val = getnumber(0); return; } if(by <= .003) digits = 3; else if(by <= .03) digits = 2; sprintf(fmt, "%%.%de", digits); sprintf(code, fmt, *val * (1 + incr)); sscanf(code, "%f", val); } /********************from SLevy 2jan02 ********************************/ int getbutton(char key) { int uu = clefs[key & 127]; clefs[key & 127]=0; return uu; } /**********************************************************************/ void keyboard(unsigned char key, int x, int y){ clefs[key&127]=1; /* globalize the keys that were pressed */ #define IF(K) if(key==K) #define PRESS(K,A,b) IF(K){b;} IF(K-32){A;} /* catch upper case */ #define TOGGLE(K,flg) IF(K){(flg) = 1-(flg); } #define CYCLE(K,f,m) PRESS((K),(f)=(((f)+(m)-1)%(m)),(f)=(++(f)%(m))) #define SLIDI(K,f,m,M) PRESS(K,(--fM?M:f)) #define SLIDF(K,f,m,M,d) PRESS(K,((f -= d)M?M:f)) /* Only 127 ASCII chars are processed in this GLUT callback function */ /* Use the specialkeybo function for the special keys */ IF(27) { exit(0); } /* ESC exit */ TOGGLE('v',binoc); /* cross-eyed STEREO */ TOGGLE(' ',mode); /* space key */ TOGGLE('h',morph); /* autotymer on/off */ CYCLE('w',msg,3); /* writing on/off/speedometer+bullseye */ CYCLE('c',chapmat,4); CYCLE('u',vumat,4); PRESS('n', nose -= .001 , 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', focal *= 1.1 , focal /= 1.1) /* telephoto */ PRESS('i', mysiz /= 1.1, mysiz *= 1.1) /* rescale the world */ PRESS('p', wfar *= 1.01 , wfar /= 1.01) /* rear clipping plane */ PRESS('z', deFault(), deFault()); /* zap changes */ PRESS('g',gap /= .9, gap *= .9); /* gap parameter */ PRESS('a',amb /= .9, amb *= .9); /* ambient fraction */ PRESS('r',pwr /= .9, pwr *= .9); /* pseudo-spec power */ /********** SLevy's parser creates the input decimal ******************/ if(key >= '0' && key <= '9'){ /* if key is a digit numeral */ hasnumber = 1; number = number*10+key-'0'; decimal *= 10; } else if(key == '.') { decimal = 1; } /* it's a decimal ! */ else if(key == '-') { sign = -1; } /* it's negative ! */ else { hasnumber = number = decimal = sign = 0;} /* erase mess */ glutPostRedisplay(); /* in case window was resized */ } /**********************************************************************/ void specialkeybo(int key, int x, int y){ clefs[0]= key ; switch(key){ /* HOME END PAGE_DOWN RIGHT F1 etc see glut.h */ case GLUT_KEY_F1: th0++; th1--; break; case GLUT_KEY_F2: th0--; th1++; break; /* default: fprintf(stderr,"non-ASCII char [%d] pressed.\n", key); */ } hasnumber=number=decimal=0; glutPostRedisplay(); } //printf("keyboard CLAW= %d " ,CLAW); /**********************************************************************/ /**********************************************************************/ float speedometer(void){ /* this one is for unix */ 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); } /**********************************************************************/ #if 0 float speedometer(void){ /* this one is for win32*/ 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); } #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 LABEL(x,y,W,u) {sprintf(buf,(W),(u));char2wall(x,y,0.,buf);} glMatrixMode(GL_PROJECTION); glPushMatrix(); /* new projection matrix */ glLoadIdentity(); gluOrtho2D(0,3000,0,3000); /* new 2D coordinates */ glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); if(mode==TURNMODE) glColor3f(1.,0.,1.); else glColor3f(1.,1.,0.); LABEL(1500,1500,"%s","o"); /* place a bullseye dead center */ LABEL(80,80,"%4.1f fps",speedometer()); if(msg!=2){ /* bypass the distracting graffiti */ LABEL(80,2840,\ "(ESC)ape (V)Binoc (MAUS2)Fore (BAR)%s (H)omotopy (W)riting", mode?"TURNMODE":"FLYMODE"); LABEL(10,10,"illiSkel-2002 by Francis, Levy, Bourd, Hartman,\ & Chappell, U Illinois, 1995..2002 %s","14jan02"); LABEL(80,2770,"(N)ose %0.3f",nose); LABEL(80,2700,"[S]peed %0.4f",speed); LABEL(80,2630," tor[Q] %0.4f",torq); LABEL(80,2560,"near clipper %g", mysiz*focal); LABEL(80,2490,"f(O)cal factor %g",focal); LABEL(80,2420,"my s(I)ze %.2g",mysiz); LABEL(80,2350,"far cli(P)per= %.2g",wfar); LABEL(80,2280,"(Z)ap %s",""); LABEL(80,2210,"(G)ap %.2g",gap); LABEL(80,2140,"(A)mb %.2g",amb); LABEL(80,2070,"pw(R) %.2g",pwr); LABEL(80,1930,"dist %g",aff[14]); LABEL(80,1860,"f(O)cal factor %g",focal); LABEL(80,1780,"(C)hapmat %d",chapmat); LABEL(80,1710,"v(U)mat %d",vumat); } /* but clean up the stack pushes */ glPopMatrix(); glMatrixMode(GL_PROJECTION); glPopMatrix(); } /************************ navigation **********************************/ void chaptrack(float *aff, int paw,int xx,int yy,int shif){ long dx,dy; dx = xx -.5*xwide; dx = abs(dx)>5?dx:0; /* 5 pixel latency */ dy = yy -.5*yhigh; 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(paw&(1<"); if(win==2) glutFullScreen(); glEnable(GL_DEPTH_TEST); /* enable z-buffer */ glutDisplayFunc(drawcons); /* the following are optional for interactive control */ glutKeyboardFunc(keyboard); glutSpecialFunc(specialkeybo); glutMouseFunc(mousepushed); glutMotionFunc(mousemoved); glutPassiveMotionFunc(mousemoved); /* beyond here all are needed */ glutReshapeFunc(reshaped); glutIdleFunc(idle); glutMainLoop(); } /**********************************************************************/