/* * 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. */ #ifdef HAVE_ARGP #include #endif #include #include #include #include #ifdef HAVE_FREEGLUT #include #elif defined __APPLE__ #include #else #include #endif #ifndef GLAPIENTRY #define GLAPIENTRY #endif 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 __attribute__((noreturn)) cleanup(void) { glDeleteLists(gear1, 1); glDeleteLists(gear2, 1); glDeleteLists(gear3, 1); glutDestroyWindow(win); exit(EXIT_SUCCESS); } 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(); } } static GLfloat rotation_speed = 70.0; 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 += rotation_speed * 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 '\e': cleanup(); 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 GLboolean print_glinfo = GL_FALSE; 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); if (print_glinfo) { 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); } } static void visible(int vis) { Visible = vis; update_idle_func(); } static char *window_title = "Gears"; #ifdef HAVE_ARGP static const struct argp_option options[] = { {"version", 'V', 0, 0, "print program version"}, {"info", 256, 0, 0, "display OpenGL renderer information"}, {"exit", 257, 0, 0, "automatically exit after 30 seconds"}, {"noanim", 258, 0, 0, "don't start animation"}, {"spin", 259, "speed", 0, "set rotational speed in RPM (defaults to 11.666666667)"}, {"title", 260, "title", 0, "set window title (defaults to \"Gears\")"}, {0}}; static error_t parse_opt(int key, char *val, struct argp_state *) { switch (key) { case 'V': printf("glxgears 9.0.1\n"); exit(EXIT_SUCCESS); case 256: print_glinfo = GL_TRUE; break; case 257: autoexit = 30; break; case 258: Animate = GL_FALSE; break; case 259: rotation_speed = atof(val) * 6; break; case 260: window_title = val; break; } return 0; } static const struct argp argp = { options, parse_opt, 0, "The glxgears program is a port of the `gears` demo to GLX. It displays a " "set of rotating gears and prints out the frame rate at regular intervals. " "It has become quite popular as basic benchmarking tool."}; #else static void parse_args(int argc, char *argv[]) { for (GLint i = 1; i < argc; i++) if (strcmp(argv[i], "-exit") == 0) { autoexit = 30; printf("Auto exiting after %i seconds.\n", autoexit); fflush(stdout); } else if (strcmp(argv[i], "-info") == 0) print_glinfo = GL_TRUE; else if (strcmp(argv[i], "-noanim") == 0) Animate = GL_FALSE; } #endif int main(int argc, char *argv[]) { #ifdef HAVE_ARGP argp_parse(&argp, argc, argv, ARGP_LONG_ONLY, 0, 0); #else parse_args(argc, argv); #endif glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); win = glutCreateWindow(window_title); init_scene(); glutDisplayFunc(draw); glutReshapeFunc(reshape); glutKeyboardFunc(key); glutSpecialFunc(special); glutVisibilityFunc(visible); update_idle_func(); glutMainLoop(); return EXIT_SUCCESS; }