1/*
2 * 3-D gear wheels.  This program is in the public domain.
3 *
4 * Command line options:
5 *    -info      print GL implementation information
6 *    -exit      automatically exit after 30 seconds
7 *    -noanim    turn off animation
8 *
9 *
10 * Brian Paul
11 */
12
13/* Conversion to GLUT by Mark J. Kilgard */
14
15
16
17#include <math.h>
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include "glut_wrap.h"
22
23#ifndef M_PI
24#define M_PI 3.14159265
25#endif
26
27static GLint T0 = 0;
28static GLint Frames = 0;
29static GLint autoexit = 0;
30static GLint win = 0;
31static GLboolean Visible = GL_TRUE;
32static GLboolean Animate = GL_TRUE;
33static GLfloat viewDist = 40.0;
34
35
36/**
37
38  Draw a gear wheel.  You'll probably want to call this function when
39  building a display list since we do a lot of trig here.
40
41  Input:  inner_radius - radius of hole at center
42          outer_radius - radius at center of teeth
43          width - width of gear
44          teeth - number of teeth
45          tooth_depth - depth of tooth
46
47 **/
48
49static void
50gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
51  GLint teeth, GLfloat tooth_depth)
52{
53  GLint i;
54  GLfloat r0, r1, r2;
55  GLfloat angle, da;
56  GLfloat u, v, len;
57
58  r0 = inner_radius;
59  r1 = outer_radius - tooth_depth / 2.0;
60  r2 = outer_radius + tooth_depth / 2.0;
61
62  da = 2.0 * M_PI / teeth / 4.0;
63
64  glShadeModel(GL_FLAT);
65
66  glNormal3f(0.0, 0.0, 1.0);
67
68  /* draw front face */
69  glBegin(GL_QUAD_STRIP);
70  for (i = 0; i <= teeth; i++) {
71    angle = i * 2.0 * M_PI / teeth;
72    glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
73    glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
74    if (i < teeth) {
75      glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
76      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
77    }
78  }
79  glEnd();
80
81  /* draw front sides of teeth */
82  glBegin(GL_QUADS);
83  da = 2.0 * M_PI / teeth / 4.0;
84  for (i = 0; i < teeth; i++) {
85    angle = i * 2.0 * M_PI / teeth;
86
87    glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
88    glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
89    glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
90    glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
91  }
92  glEnd();
93
94  glNormal3f(0.0, 0.0, -1.0);
95
96  /* draw back face */
97  glBegin(GL_QUAD_STRIP);
98  for (i = 0; i <= teeth; i++) {
99    angle = i * 2.0 * M_PI / teeth;
100    glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
101    glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
102    if (i < teeth) {
103      glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
104      glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
105    }
106  }
107  glEnd();
108
109  /* draw back sides of teeth */
110  glBegin(GL_QUADS);
111  da = 2.0 * M_PI / teeth / 4.0;
112  for (i = 0; i < teeth; i++) {
113    angle = i * 2.0 * M_PI / teeth;
114
115    glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
116    glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
117    glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
118    glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
119  }
120  glEnd();
121
122  /* draw outward faces of teeth */
123  glBegin(GL_QUAD_STRIP);
124  for (i = 0; i < teeth; i++) {
125    angle = i * 2.0 * M_PI / teeth;
126
127    glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
128    glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
129    u = r2 * cos(angle + da) - r1 * cos(angle);
130    v = r2 * sin(angle + da) - r1 * sin(angle);
131    len = sqrt(u * u + v * v);
132    u /= len;
133    v /= len;
134    glNormal3f(v, -u, 0.0);
135    glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
136    glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
137    glNormal3f(cos(angle), sin(angle), 0.0);
138    glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
139    glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
140    u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
141    v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
142    glNormal3f(v, -u, 0.0);
143    glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
144    glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
145    glNormal3f(cos(angle), sin(angle), 0.0);
146  }
147
148  glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
149  glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
150
151  glEnd();
152
153  glShadeModel(GL_SMOOTH);
154
155  /* draw inside radius cylinder */
156  glBegin(GL_QUAD_STRIP);
157  for (i = 0; i <= teeth; i++) {
158    angle = i * 2.0 * M_PI / teeth;
159    glNormal3f(-cos(angle), -sin(angle), 0.0);
160    glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
161    glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
162  }
163  glEnd();
164
165}
166
167static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
168static GLint gear1, gear2, gear3;
169static GLfloat angle = 0.0;
170
171static void
172cleanup(void)
173{
174   glDeleteLists(gear1, 1);
175   glDeleteLists(gear2, 1);
176   glDeleteLists(gear3, 1);
177   glutDestroyWindow(win);
178}
179
180static void
181draw(void)
182{
183  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
184
185  glPushMatrix();
186
187    glTranslatef(0.0, 0.0, -viewDist);
188
189    glRotatef(view_rotx, 1.0, 0.0, 0.0);
190    glRotatef(view_roty, 0.0, 1.0, 0.0);
191    glRotatef(view_rotz, 0.0, 0.0, 1.0);
192
193    glPushMatrix();
194      glTranslatef(-3.0, -2.0, 0.0);
195      glRotatef(angle, 0.0, 0.0, 1.0);
196      glCallList(gear1);
197    glPopMatrix();
198
199    glPushMatrix();
200      glTranslatef(3.1, -2.0, 0.0);
201      glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
202      glCallList(gear2);
203    glPopMatrix();
204
205    glPushMatrix();
206      glTranslatef(-3.1, 4.2, 0.0);
207      glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
208      glCallList(gear3);
209    glPopMatrix();
210
211  glPopMatrix();
212
213  glutSwapBuffers();
214
215  Frames++;
216
217  {
218    GLint t = glutGet(GLUT_ELAPSED_TIME);
219    if (t - T0 >= 5000) {
220      GLfloat seconds = (t - T0) / 1000.0;
221      GLfloat fps = Frames / seconds;
222      printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps);
223      fflush(stdout);
224      T0 = t;
225      Frames = 0;
226      if ((t >= 999.0 * autoexit) && (autoexit)) {
227        cleanup();
228        exit(0);
229      }
230    }
231  }
232}
233
234
235static void
236idle(void)
237{
238  static double t0 = -1.;
239  double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
240  if (t0 < 0.0)
241    t0 = t;
242  dt = t - t0;
243  t0 = t;
244
245  angle += 70.0 * dt;  /* 70 degrees per second */
246  angle = fmod(angle, 360.0); /* prevents eventual overflow */
247
248  glutPostRedisplay();
249}
250
251static void
252update_idle_func(void)
253{
254  if (Visible && Animate)
255    glutIdleFunc(idle);
256  else
257    glutIdleFunc(NULL);
258}
259
260/* change view angle, exit upon ESC */
261/* ARGSUSED1 */
262static void
263key(unsigned char k, int x, int y)
264{
265  switch (k) {
266  case 'z':
267    view_rotz += 5.0;
268    break;
269  case 'Z':
270    view_rotz -= 5.0;
271    break;
272  case 'd':
273     viewDist += 1.0;
274     break;
275  case 'D':
276     viewDist -= 1.0;
277     break;
278  case 'a':
279     Animate = !Animate;
280     update_idle_func();
281     break;
282  case 27:  /* Escape */
283    cleanup();
284    exit(0);
285    break;
286  default:
287    return;
288  }
289  glutPostRedisplay();
290}
291
292/* change view angle */
293/* ARGSUSED1 */
294static void
295special(int k, int x, int y)
296{
297  switch (k) {
298  case GLUT_KEY_UP:
299    view_rotx += 5.0;
300    break;
301  case GLUT_KEY_DOWN:
302    view_rotx -= 5.0;
303    break;
304  case GLUT_KEY_LEFT:
305    view_roty += 5.0;
306    break;
307  case GLUT_KEY_RIGHT:
308    view_roty -= 5.0;
309    break;
310  default:
311    return;
312  }
313  glutPostRedisplay();
314}
315
316/* new window size or exposure */
317static void
318reshape(int width, int height)
319{
320  GLfloat h = (GLfloat) height / (GLfloat) width;
321
322  glViewport(0, 0, (GLint) width, (GLint) height);
323  glMatrixMode(GL_PROJECTION);
324  glLoadIdentity();
325  glFrustum(-1.0, 1.0, -h, h, 5.0, 200.0);
326  glMatrixMode(GL_MODELVIEW);
327}
328
329static void
330init(int argc, char *argv[])
331{
332  static GLfloat pos[4] = {5.0, 5.0, 10.0, 0.0};
333  static GLfloat red[4] = {0.8, 0.1, 0.0, 1.0};
334  static GLfloat green[4] = {0.0, 0.8, 0.2, 1.0};
335  static GLfloat blue[4] = {0.2, 0.2, 1.0, 1.0};
336  GLint i;
337
338  glLightfv(GL_LIGHT0, GL_POSITION, pos);
339  glEnable(GL_CULL_FACE);
340  glEnable(GL_LIGHTING);
341  glEnable(GL_LIGHT0);
342  glEnable(GL_DEPTH_TEST);
343
344  /* make the gears */
345  gear1 = glGenLists(1);
346  glNewList(gear1, GL_COMPILE);
347  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
348  gear(1.0, 4.0, 1.0, 20, 0.7);
349  glEndList();
350
351  gear2 = glGenLists(1);
352  glNewList(gear2, GL_COMPILE);
353  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
354  gear(0.5, 2.0, 2.0, 10, 0.7);
355  glEndList();
356
357  gear3 = glGenLists(1);
358  glNewList(gear3, GL_COMPILE);
359  glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
360  gear(1.3, 2.0, 0.5, 10, 0.7);
361  glEndList();
362
363  glEnable(GL_NORMALIZE);
364
365  for ( i=1; i<argc; i++ ) {
366    if (strcmp(argv[i], "-info")==0) {
367      printf("GL_RENDERER   = %s\n", (char *) glGetString(GL_RENDERER));
368      printf("GL_VERSION    = %s\n", (char *) glGetString(GL_VERSION));
369      printf("GL_VENDOR     = %s\n", (char *) glGetString(GL_VENDOR));
370      printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
371      fflush(stdout);
372    }
373    else if ( strcmp(argv[i], "-exit")==0) {
374      autoexit = 30;
375      printf("Auto Exit after %i seconds.\n", autoexit );
376      fflush(stdout);
377    }
378    else if (strcmp(argv[i], "-noanim") == 0) {
379      Animate = GL_FALSE;
380    }
381  }
382}
383
384
385static void
386visible(int vis)
387{
388   Visible = vis;
389   update_idle_func();
390}
391
392int main(int argc, char *argv[])
393{
394  glutInitWindowSize(300, 300);
395  glutInit(&argc, argv);
396  glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
397  win = glutCreateWindow("Gears");
398  init(argc, argv);
399
400  glutDisplayFunc(draw);
401  glutReshapeFunc(reshape);
402  glutKeyboardFunc(key);
403  glutSpecialFunc(special);
404  glutVisibilityFunc(visible);
405  update_idle_func();
406
407  glutMainLoop();
408  return 0;             /* ANSI C requires main to return int. */
409}
410