/* * 3-D gear wheels. This program is in the public domain. * * Command line options: * -info print GL implementation information * -exit automatically exit after 30 seconds * -noanim turn off animation * * * Brian Paul * Conversion to GLUT by Mark J. Kilgard * Other modifications by Lexxy Fox. */ #include #include #include #include #include "glut_wrap.h" static GLint T0 = 0; static GLint Frames = 0; static GLint autoexit = 0; static GLint win = 0; static GLboolean Visible = GL_TRUE; static GLboolean Animate = GL_TRUE; static GLfloat viewDist = 40.0; /** Draw a gear wheel. You'll probably want to call this function when building a display list since we do a lot of trig here. Input: inner_radius - radius of hole at center outer_radius - radius at center of teeth width - width of gear teeth - number of teeth tooth_depth - depth of tooth **/ static void gear( GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth ) { GLint i; GLfloat r0, r1, r2; GLfloat angle, da; GLfloat u, v, len; r0 = inner_radius; r1 = outer_radius - tooth_depth / 2.0; r2 = outer_radius + tooth_depth / 2.0; da = 2.0 * M_PI / teeth / 4.0; glShadeModel(GL_FLAT); glNormal3f(0.0, 0.0, 1.0); /* draw front face */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); if (i < teeth) { glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); glVertex3f( r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5 ); } } glEnd(); /* draw front sides of teeth */ glBegin(GL_QUADS); da = 2.0 * M_PI / teeth / 4.0; for (i = 0; i < teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); } glEnd(); glNormal3f(0.0, 0.0, -1.0); /* draw back face */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); if (i < teeth) { glVertex3f( r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5 ); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); } } glEnd(); /* draw back sides of teeth */ glBegin(GL_QUADS); da = 2.0 * M_PI / teeth / 4.0; for (i = 0; i < teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f( r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5 ); glVertex3f( r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5 ); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); } glEnd(); /* draw outward faces of teeth */ glBegin(GL_QUAD_STRIP); for (i = 0; i < teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); u = r2 * cos(angle + da) - r1 * cos(angle); v = r2 * sin(angle + da) - r1 * sin(angle); len = sqrt(u * u + v * v); u /= len; v /= len; glNormal3f(v, -u, 0.0); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); glNormal3f(cos(angle), sin(angle), 0.0); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); glVertex3f( r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5 ); u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); glNormal3f(v, -u, 0.0); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); glVertex3f( r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5 ); glNormal3f(cos(angle), sin(angle), 0.0); } glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); glEnd(); glShadeModel(GL_SMOOTH); /* draw inside radius cylinder */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0 * M_PI / teeth; glNormal3f(-cos(angle), -sin(angle), 0.0); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); } glEnd(); } static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; static GLint gear1, gear2, gear3; static GLfloat angle = 0.0; static void cleanup(void) { glDeleteLists(gear1, 1); glDeleteLists(gear2, 1); glDeleteLists(gear3, 1); glutDestroyWindow(win); } static void draw(void) { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glPushMatrix(); glTranslatef(0.0, 0.0, -viewDist); glRotatef(view_rotx, 1.0, 0.0, 0.0); glRotatef(view_roty, 0.0, 1.0, 0.0); glRotatef(view_rotz, 0.0, 0.0, 1.0); glPushMatrix(); glTranslatef(-3.0, -2.0, 0.0); glRotatef(angle, 0.0, 0.0, 1.0); glCallList(gear1); glPopMatrix(); glPushMatrix(); glTranslatef(3.1, -2.0, 0.0); glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0); glCallList(gear2); glPopMatrix(); glPushMatrix(); glTranslatef(-3.1, 4.2, 0.0); glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0); glCallList(gear3); glPopMatrix(); glPopMatrix(); glutSwapBuffers(); Frames++; GLint t = glutGet(GLUT_ELAPSED_TIME); if (t - T0 >= 5000) { GLfloat seconds = (t - T0) / 1000.0; GLfloat fps = Frames / seconds; printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps); fflush(stdout); T0 = t; Frames = 0; if ((t >= 999.0 * autoexit) && (autoexit)) { cleanup(); exit(EXIT_SUCCESS); } } } static void idle(void) { static double t0 = -1.; double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; if (t0 < 0.0) t0 = t; dt = t - t0; t0 = t; angle += 70.0 * dt; /* 70 degrees per second */ angle = fmod(angle, 360.0); /* prevents eventual overflow */ glutPostRedisplay(); } static void update_idle_func(void) { if (Visible && Animate) glutIdleFunc(idle); else glutIdleFunc(NULL); } /* change view angle, exit upon ESC */ static void key(unsigned char k, int, int) { switch (k) { case 'z': view_rotz += 5.0; break; case 'Z': view_rotz -= 5.0; break; case 'd': viewDist += 1.0; break; case 'D': viewDist -= 1.0; break; case 'a': Animate = !Animate; update_idle_func(); break; case 27: /* Escape */ cleanup(); exit(EXIT_SUCCESS); break; default: return; } glutPostRedisplay(); } /* change view angle */ static void special(int k, int, int) { switch (k) { case GLUT_KEY_UP: view_rotx += 5.0; break; case GLUT_KEY_DOWN: view_rotx -= 5.0; break; case GLUT_KEY_LEFT: view_roty += 5.0; break; case GLUT_KEY_RIGHT: view_roty -= 5.0; break; default: return; } glutPostRedisplay(); } /* new window size or exposure */ static void reshape(int width, int height) { GLfloat h = (GLfloat)height / (GLfloat)width; glViewport(0, 0, (GLint)width, (GLint)height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -h, h, 5.0, 200.0); glMatrixMode(GL_MODELVIEW); } static void init_scene(void) { glLightfv(GL_LIGHT0, GL_POSITION, (const GLfloat[]){5.0, 5.0, 10.0, 0.0}); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); /* make the gears */ gear1 = glGenLists(1); glNewList(gear1, GL_COMPILE); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (const GLfloat[]){245.0 / 255, 169.0 / 255, 184.0 / 255, 1} ); gear(1.0, 4.0, 1.0, 20, 0.7); glEndList(); gear2 = glGenLists(1); glNewList(gear2, GL_COMPILE); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (const GLfloat[]){1, 1, 1, 1}); gear(0.5, 2.0, 2.0, 10, 0.7); glEndList(); gear3 = glGenLists(1); glNewList(gear3, GL_COMPILE); glMaterialfv( GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (const GLfloat[]){91.0 / 255, 206.0 / 255, 250.0 / 255, 1} ); gear(1.3, 2.0, 0.5, 10, 0.7); glEndList(); glEnable(GL_NORMALIZE); } static void visible(int vis) { Visible = vis; update_idle_func(); } void parse_args(int argc, char *argv[]) { for (GLint i = 1; i < argc; i++) { if (strcmp(argv[i], "-info") == 0) { printf("GL_VENDOR = %s\n", (char *)glGetString(GL_VENDOR)); printf("GL_RENDERER = %s\n", (char *)glGetString(GL_RENDERER)); printf("GL_VERSION = %s\n", (char *)glGetString(GL_VERSION)); printf("GL_EXTENSIONS = %s\n", (char *)glGetString(GL_EXTENSIONS)); fflush(stdout); } else if (strcmp(argv[i], "-exit") == 0) { autoexit = 30; printf("Auto Exit after %i seconds.\n", autoexit); fflush(stdout); } else if (strcmp(argv[i], "-noanim") == 0) { Animate = GL_FALSE; } } } int main(int argc, char *argv[]) { parse_args(argc, argv); glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); win = glutCreateWindow("Gears"); init_scene(); glutDisplayFunc(draw); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutSpecialFunc(special); glutVisibilityFunc(visible); update_idle_func(); glutMainLoop(); return EXIT_SUCCESS; }