/* hourgl.c hour glass */ /* Mouse buttons control axis of rotation */ /* "B" and "b" make various blends */ /* "C" and "c" make color distinct or same */ /* "F" and "f" make rotation faster or slower */ /* "S" and "s" scale larger or smaller */ #include #include #include #include #include #ifndef M_PI #define M_PI 3.14159265 #endif typedef GLfloat point[3]; /* x,y,z */ static GLfloat rs[11] = {0.10, 0.11, 0.13, 0.16, 0.20, 0.26, 0.36, 0.45, 0.53, 0.58, 0.60}; static GLfloat zs[11] = {0.00, 0.10, 0.20, 0.30, 0.40, 0.50, 0.60, 0.70, 0.80, 0.90, 1.00}; static GLfloat xs, ys; /* points on hour glass */ static GLfloat throat = 0.05; static GLfloat theta[] = {90.0,0.0,0.0}; static GLint axis = 2; static int lineset = 7; /* 'C' or 'c' */ static double rotation = 1.0; /* 'F' or 'f' */ static GLfloat myScale = 1.0; /* 'S' or 's' */ static GLfloat centroid[3]= { 0.0, 0.0, 0.0}; /* 'O' or 'o' */ static int winWidth = 500; static int winHeight = 500; static iblend = 0; /* internal functions */ static void normal(point n, point p, point q, point r); static void draw_patch(point p1, point p2, point p3, point p4); static void myInit(void); static void draw_sand(); static void draw_surface(void); static void draw_hour(void); static void display(void); static void drawText(void); static void spin_hour(void); static void mouse(int btn, int state, int x, int y); static void keyboard(unsigned char key, int x, int y); static void myReshape(int w, int h); static void normal(point n, point p, point q, point r) { n[0]=(q[1]-p[1])*(r[2]-p[2])-(q[2]-p[2])*(r[1]-p[1]); n[1]=(q[2]-p[2])*(r[0]-p[0])-(q[0]-p[0])*(r[2]-p[2]); n[2]=(q[0]-p[0])*(r[2]-p[2])-(q[2]-p[2])*(r[0]-p[0]); } static void draw_patch(point p1, point p2, point p3, point p4) { point n; normal(n, p1, p2, p3); glBegin(GL_QUADS); glNormal3fv(n); glVertex3fv(p1); glVertex3fv(p2); glVertex3fv(p3); glVertex3fv(p4); glEnd(); } static void myInit(void) { glClearColor(1.0, 1.0, 1.0, 0.0); } static void draw_sand() { /* glBlendFunc(GL_ONE, GL_ZERO); */ glColor4f(1.0, 0.0, 0.0, 0.33); glTranslatef(0.0, 0.0, -0.7); glutSolidSphere(0.2, 12, 12); glTranslatef(0.0, 0.0, 0.7); /* reset for future drawers */ } static void draw_surface(void) { int i, j; double r, r1, r2, a, a1, a2, da; point p1, p2, p3, p4; /* glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); */ glColor4f(0.25, 0.6, 0.25, 0.33); da = M_PI/12.0; for(i=0; i<10; i++) /* patches */ { r1 = rs[i]-throat; r2 = rs[i+1]-throat; a1 = 0.0; a2 = a1+da; for(j=0; j<24; j++) { p1[0] = r1*cos(a1); p1[1] = r1*sin(a1); p1[2] = zs[i]; p2[0] = r1*cos(a2); p2[1] = r1*sin(a2); p2[2] = zs[i]; p3[0] = r2*cos(a2); p3[1] = r2*sin(a2); p3[2] = zs[i+1]; p4[0] = r2*cos(a1); p4[1] = r2*sin(a1); p4[2] = zs[i+1]; draw_patch(p1, p2, p3, p4); p1[2] = -p1[2]; p2[2] = -p2[2]; p3[2] = -p3[2]; p4[2] = -p4[2]; draw_patch(p1, p2, p3, p4); a1 = a2; a2 = a1+da; } } /* end patches */ i = 10; /* ends */ r = rs[i]-throat; a = 0.0; glEnable(GL_POLYGON_SMOOTH); glBegin(GL_POLYGON); for(j=0; j<24; j++) { xs = r*cos(a); ys = r*sin(a); glVertex3f(xs, ys, zs[i]); a = a+da; } glEnd(); i = 10; /* ends */ r = rs[i]-throat; a = 0.0; glEnable(GL_POLYGON_SMOOTH); glBegin(GL_POLYGON); for(j=0; j<24; j++) { xs = r*cos(a); ys = r*sin(a); glVertex3f(xs, ys, -zs[i]); a = a+da; } glEnd(); } static void draw_hour(void) { int i, j; double r, a, da; glEnable(GL_LINE_SMOOTH); /* glBlendFunc(GL_ONE, GL_ONE); */ glColor4f(0.25, 0.25, 0.6, 0.33); da = M_PI/12.0; for(i=0; i<11; i++) /* circles */ { r = rs[i]-throat; a = 0.0; glBegin(GL_LINE_LOOP); for(j=0; j<24; j++) { xs = r*cos(a); ys = r*sin(a); glVertex3f(xs, ys, zs[i]); a = a+da; } glEnd(); if(i!=0) { a = 0.0; glBegin(GL_LINE_LOOP); for(j=0; j<24; j++) { xs = r*cos(a); ys = r*sin(a); glVertex3f(xs, ys, -zs[i]); a = a+da; } glEnd(); } } /* end circles */ a = 0.0; for(j=0; j<24; j++) /* sides */ { glBegin(GL_LINE_STRIP); for(i=10; i>=0; i--) { r = rs[i]-throat; xs = r*cos(a); ys = r*sin(a); glVertex3f(xs, ys, zs[i]); } for(i=1; i<11; i++) { r = rs[i]-throat; xs = r*cos(a); ys = r*sin(a); glVertex3f(xs, ys, -zs[i]); } glEnd(); a = a+da; } /* end sides */ } static void display(void) { /* display callback, clear frame buffer and z buffer, */ /* rotate hour and draw, swap buffers */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glRotatef(theta[0], 1.0, 0.0, 0.0); glRotatef(theta[1], 0.0, 1.0, 0.0); glRotatef(theta[2], 0.0, 0.0, 1.0); if(lineset==1 || lineset==3 || lineset==5 || lineset==7) draw_hour(); if(lineset==2 || lineset==3 || lineset==6 || lineset==7) draw_sand(); if(lineset==4 || lineset==5 || lineset==6 || lineset==7) draw_surface(); drawText(); glFlush(); glutSwapBuffers(); } static void drawText(void) { char msg1[] = "'S' or 's' for size, 'B' or 'b' for blend function 1,3,5,7 draw hour"; char msg2[] = "'F' or 'f' for speed, 'C' or 'c' for configuration 2,3,6,7 draw sand"; char msg3[] = "mouse button for rotation axis change 4,5,6,7 draw surf"; int i, len; /* Draw text */ glEnable(GL_LINE_SMOOTH); /* glBlendFunc(GL_ONE, GL_ONE); */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glLoadIdentity(); glOrtho(0, winWidth, 0, winHeight, -1, 1); glMatrixMode(GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); glColor4f(0.0, 0.0, 1.0, 1.0); glRasterPos2i(10, 10); len = strlen(msg1); sprintf(&msg1[57], "%d", iblend); for (i=0; i 360.0) theta[axis] = theta[axis] - 360.0; /* display(); */ glutPostRedisplay(); } static void mouse(int btn, int state, int x, int y) { /* mouse callback, selects an axis about which to rotate */ if(btn==GLUT_LEFT_BUTTON && state == GLUT_DOWN) axis = 0; if(btn==GLUT_MIDDLE_BUTTON && state == GLUT_DOWN) axis = 1; if(btn==GLUT_RIGHT_BUTTON && state == GLUT_DOWN) axis = 2; } static void keyboard(unsigned char key, int x, int y) { switch (key) { case 'B': glEnable(GL_BLEND); iblend++; if(iblend>3) iblend = 1; switch (iblend) { case 1: glBlendFunc(GL_SRC_ALPHA, GL_DST_ALPHA); break; case 2: glBlendFunc(GL_ONE, GL_ZERO); break; case 3: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); break; } break; case 'b': glDisable(GL_BLEND); iblend = 0; break; case 'C': lineset++; if(lineset>7) lineset=0; break; case 'c': lineset--; if(lineset<0) lineset=7; break; case 'F': rotation=rotation+0.25; if(rotation>5.0) rotation=5.0; break; case 'f': rotation=rotation-0.25; if(rotation<0.0) rotation=0.0; break; case 's': myScale *= 1.25; /* decrease size by 25% */ myReshape(winWidth, winHeight); break; case 'S': myScale /= 1.25; /* increase size by 25% */ myReshape(winWidth, winHeight); break; } } static void myReshape(int w, int h) { winWidth = w; winHeight = h; glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(w <= h) glOrtho(-2.0*myScale, 2.0*myScale, -2.0*myScale * (GLfloat)h / (GLfloat)w, 2.0*myScale * (GLfloat)h / (GLfloat)w, -10.0*myScale, 10.0*myScale); else glOrtho(-2.0*myScale * (GLfloat)w / (GLfloat)h, 2.0*myScale * (GLfloat)w / (GLfloat)h, -2.0*myScale, 2.0*myScale, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); } int main(int argc, char *argv[]) { glutInit(&argc, argv); /* need both double buffering and z buffer */ glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(winWidth, winHeight); glutCreateWindow("hourGL"); glutReshapeFunc(myReshape); glutDisplayFunc(display); /* draws screen */ glutIdleFunc(spin_hour); /* "spin_hour" setup */ glutMouseFunc(mouse); /* "mouse" setup */ glutKeyboardFunc(keyboard); /* "keyboard" setup */ glEnable(GL_DEPTH_TEST); /* Enable hidden--surface--removal */ myInit(); glutMainLoop(); return 0; }