/* 23jul2K ... this skel has getnumber working ! */ /* also hasnumberbump stuff is installed */ /* getbutton is working again */ /* and we have IFCLICK back ... after what? 5 years */ /* doesn't have slevy stars nor hanrahan arguments */ /* middle button substitute for 2mouse wintels */ /* needs odometer/speedometer */ /* doesn't have slevy char2wall */ /* and we Stuart's real frustum */ /****************************************************************/ /**** 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**********************************/ /****************************************************************/ #include #include #include #include /* for the speedometer */ #include #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 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 IFCLICK(K,a){static flag=1;if(getbutton(K))flag=1-flag;if(flag){a} } /* global variables */ float gap, gap0=1.; /* kludge so that arguments() can set a default gap0 */ float lux[3]={1.,2.,3.}; /*world light direction vector */ float luxx[3]; /* object space direction vector*/ float amb, pwr ; /* ambient fraction, pseudo-specular power */ float mysiz,speed, torq, focal, far; /*console navigation variables */ int win = 1; /* 2 full screen, use 0 for demand sized */ unsigned int CLAW,PAW,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 */ /**********************************************************************/ 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=.1; torq=.02; focal = 2.; far =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 cpack(long hexad){ float red, green, blue; red = (hexad & 255)/255.; green = ((hexad >> 8) & 255)/255.; blue = ((hexad >> 16)& 255)/255.; glColor3f(red,green,blue); } /**********************************************************************/ void drawvert(int th, int ta){ int hexad, bb,gg,rr; 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); /* cpack */ rr = (int)(255.* MAX(spec, lmb*dog)); gg = (int)(255.*MAX(spec, lmb*(.25 + ABS(cat -.5)))); bb = (int)(255.*MAX(spec, lmb*(1 - cat))); hexad = (bb<<16) + (gg<<8) + rr ; /* hexad = ((int)(bb*255))<<16 + ((int)(gg*255))<<8 + (int)(rr*255); */ cpack(hexad); #if 0 glColor3f(rr,gg,bb); 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 */ #endif 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){ /* transfer from skel.c as an exercise */ } /**********************************************************************/ 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){ 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]); } /**********************************************************************/ int number, hasnumber, decimal, sign; float getnumber(float dflt){ float v = (sign ? -number : number); if(!hasnumber) return dflt; return decimal>0 ? v/(float)decimal : v; } void bump(float *val, float incr){ /* slevy 98 */ float by = fabs(incr); 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); } /**********************************************************************/ int getbutton(unsigned char key){ /* returns that keybit was set */ if(CLAW & (1<M?M:f)) #define SLIDF(K,f,m,M,d) PRESS(K,((f -= d)M?M:f)) /* Only ASCII characters can be processes by this GLUT callback function */ IF(27) { exit(0); } /* ESC exit */ TOGGLE('v',binoc); /* cross-eyed STEREO */ TOGGLE(' ',mode); TOGGLE('h',morph); /* autotymer on/off */ TOGGLE('W',msg); /* writing on/off */ PRESS('n', nose -= .001 , nose += .001 ); /* for binoculars */ PRESS('s', bump(&speed,.02), bump(&speed,-.02)); /* flying speed */ PRESS('q',torq /= 1.02, torq *= 1.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', far *= 1.01 , far /= 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 */ if(key >= '0' && key <= '9') { hasnumber = 1; number = number*10+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 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); } /**********************************************************************/ 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, U Illinois, 1995..1997 %s",""); LABEL2(80,2770,"(N)ose %0.3f",nose); LABEL2(80,2700,"(S)peed %0.4f",speed); LABEL2(80,2630," tor(Q) %0.4f",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 %.2g",mysiz); LABEL2(80,2350,"far cli(P)er= %.2g",far); LABEL2(80,2280,"(Z)ap %s",""); LABEL2(80,2210,"(G)ap %.2g",gap); LABEL2(80,2140,"(A)mb %.2g",amb); LABEL2(80,2070,"pw(R) %.2g",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); /* the following 5 aren't needed for a picture */ glutKeyboardFunc(keyboard); glutSpecialFunc(special_keybo); glutMouseFunc(mousepushed); glutMotionFunc(mousemoved); glutPassiveMotionFunc(mousemoved); /* beyond here you do need them */ glutReshapeFunc(reshaped); glutIdleFunc(idle); glutMainLoop(); }