2f27ba0c3fcc5e98a5201b418801313c33d6769d
[xscreensaver] / hacks / glx / gears.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* gears --- 3D gear wheels */
3
4 #if 0
5 static const char sccsid[] = "@(#)gears.c       4.07 97/11/24 xlockmore";
6 #endif
7
8 /*-
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and that
12  * both that copyright notice and this permission notice appear in
13  * supporting documentation.
14  *
15  * This file is provided AS IS with no warranties of any kind.  The author
16  * shall have no liability with respect to the infringement of copyrights,
17  * trade secrets or any patents by this file or any part thereof.  In no
18  * event will the author be liable for any lost revenue or profits or
19  * other special, indirect and consequential damages.
20  *
21  * Revision History:
22  * 09-Feb-01: "Planetary" gear system added by jwz@jwz.org.
23  * 10-May-97: Compatible with xscreensaver
24  * 22-Mar-97: Added support for -mono mode, and monochrome X servers.
25  *              Ed Mackey, emackey@netaxs.com
26  * 13-Mar-97: Memory leak fix by Tom Schmidt <tschmidt@micron.com>
27  * 1996: "written" by Danny Sung <dannys@ucla.edu>
28  *       Based on 3-D gear wheels by Brian Paul which is in the public domain.
29  */
30
31 /*-
32  * PURIFY 3.0a on SunOS4 reports an unitialized memory read on each of
33  * the glCallList() functions below when using MesaGL 2.1.  This has
34  * been fixed in MesaGL 2.2 and later releases.
35  */
36
37 #ifdef STANDALONE
38 # define PROGCLASS                                      "Gears"
39 # define HACK_INIT                                      init_gears
40 # define HACK_DRAW                                      draw_gears
41 # define HACK_RESHAPE                           reshape_gears
42 # define HACK_HANDLE_EVENT                      gears_handle_event
43 # define EVENT_MASK                                     PointerMotionMask
44 # define gears_opts                                     xlockmore_opts
45 # define DEFAULTS       "*count:                1       \n"                     \
46                                         "*cycles:               2       \n"                     \
47                                         "*delay:                20000   \n"                     \
48                                         "*showFPS:      False   \n"                     \
49                                         "*wireframe:    False   \n"
50 # include "xlockmore.h"                         /* from the xscreensaver distribution */
51 #else  /* !STANDALONE */
52 # include "xlock.h"                                     /* from the xlockmore distribution */
53 #endif /* !STANDALONE */
54
55 #ifdef USE_GL
56
57 #include "rotator.h"
58 #include "gltrackball.h"
59
60 #undef countof
61 #define countof(x) (sizeof((x))/sizeof((*x)))
62
63 #define DEF_PLANETARY "False"
64
65 static int planetary;
66
67 static XrmOptionDescRec opts[] = {
68   {"-planetary", ".gears.planetary", XrmoptionNoArg, "true" },
69   {"+planetary", ".gears.planetary", XrmoptionNoArg, "false" },
70 };
71
72 static argtype vars[] = {
73   {&planetary, "planetary", "Planetary", DEF_PLANETARY, t_Bool},
74 };
75
76 ModeSpecOpt gears_opts = {countof(opts), opts, countof(vars), vars, NULL};
77
78 #ifdef USE_MODULES
79 ModStruct   gears_description =
80 {"gears", "init_gears", "draw_gears", "release_gears",
81  "draw_gears", "init_gears", NULL, &gears_opts,
82  1000, 1, 2, 1, 4, 1.0, "",
83  "Shows GL's gears", 0, NULL};
84
85 #endif
86
87 #define SMOOTH_TUBE       /* whether to have smooth or faceted tubes */
88
89 #ifdef SMOOTH_TUBE
90 # define TUBE_FACES  20   /* how densely to render tubes */
91 #else
92 # define TUBE_FACES  6
93 #endif
94
95
96 typedef struct {
97   GLuint      gear1, gear2, gear3;
98   GLuint      gear_inner, gear_outer;
99   GLuint      armature;
100   GLfloat     angle;
101   GLXContext *glx_context;
102   Window      window;
103   rotator    *rot;
104   trackball_state *trackball;
105   Bool            button_down_p;
106 } gearsstruct;
107
108 static gearsstruct *gears = NULL;
109
110 /*-
111  * Draw a gear wheel.  You'll probably want to call this function when
112  * building a display list since we do a lot of trig here.
113  *
114  * Input:  inner_radius - radius of hole at center
115  *         outer_radius - radius at center of teeth
116  *         width - width of gear
117  *         teeth - number of teeth
118  *         tooth_depth - depth of tooth
119  *         wire - true for wireframe mode
120  */
121 static void
122 gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
123      GLint teeth, GLfloat tooth_depth, Bool wire, Bool invert)
124 {
125         GLint       i;
126         GLfloat     r0, r1, r2;
127         GLfloat     angle, da;
128         GLfloat     u, v, len;
129
130     if (!invert)
131       {
132         r0 = inner_radius;
133         r1 = outer_radius - tooth_depth / 2.0;
134         r2 = outer_radius + tooth_depth / 2.0;
135         glFrontFace(GL_CCW);
136       }
137     else
138       {
139         r0 = outer_radius;
140         r2 = inner_radius + tooth_depth / 2.0;
141         r1 = outer_radius - tooth_depth / 2.0;
142         glFrontFace(GL_CW);
143       }
144
145         da = 2.0 * M_PI / teeth / 4.0;
146
147         glShadeModel(GL_FLAT);
148
149         /* This subroutine got kind of messy when I added all the checks
150          * for wireframe mode.  A much cleaner solution that I sometimes
151          * use is to have a variable hold the value GL_LINE_LOOP when
152          * in wireframe mode, or hold the value GL_POLYGON otherwise.
153          * Then I just call glBegin(that_variable), give my polygon
154          * coordinates, and glEnd().  Pretty neat eh?  Too bad I couldn't
155          * integrate that trick here.
156          *                                  --Ed.
157          */
158
159         if (!wire)
160                 glNormal3f(0.0, 0.0, 1.0);
161
162         /* draw front face */
163         if (!wire)
164                 glBegin(GL_QUAD_STRIP);
165         for (i = 0; i <= teeth; i++) {
166                 if (wire)
167                         glBegin(GL_LINES);
168                 angle = i * 2.0 * M_PI / teeth;
169                 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
170                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
171                 if (!wire) {
172                         glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
173                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
174                 } else {
175                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
176                         glVertex3f(r1 * cos(angle + 4 * da), r1 * sin(angle + 4 * da), width * 0.5);
177                         glEnd();
178                 }
179         }
180         if (!wire)
181                 glEnd();
182
183         /* draw front sides of teeth */
184         if (!wire)
185                 glBegin(GL_QUADS);
186         da = 2.0 * M_PI / teeth / 4.0;
187         for (i = 0; i < teeth; i++) {
188                 angle = i * 2.0 * M_PI / teeth;
189
190                 if (wire)
191                         glBegin(GL_LINE_LOOP);
192                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
193                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
194                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
195                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
196                 if (wire)
197                         glEnd();
198         }
199         if (!wire)
200                 glEnd();
201
202
203         if (!wire)
204                 glNormal3f(0.0, 0.0, -1.0);
205
206         /* draw back face */
207         if (!wire)
208                 glBegin(GL_QUAD_STRIP);
209         for (i = 0; i <= teeth; i++) {
210                 angle = i * 2.0 * M_PI / teeth;
211                 if (wire)
212                         glBegin(GL_LINES);
213                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
214                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
215                 if (!wire) {
216                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
217                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
218                 } else {
219                         glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
220                         glVertex3f(r1 * cos(angle + 4 * da), r1 * sin(angle + 4 * da), -width * 0.5);
221                         glEnd();
222                 }
223         }
224         if (!wire)
225                 glEnd();
226
227         /* draw back sides of teeth */
228         if (!wire)
229                 glBegin(GL_QUADS);
230         da = 2.0 * M_PI / teeth / 4.0;
231         for (i = 0; i < teeth; i++) {
232                 angle = i * 2.0 * M_PI / teeth;
233
234                 if (wire)
235                         glBegin(GL_LINE_LOOP);
236                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
237                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
238                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
239                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
240                 if (wire)
241                         glEnd();
242         }
243         if (!wire)
244                 glEnd();
245
246
247         /* draw outward faces of teeth */
248         if (!wire)
249                 glBegin(GL_QUAD_STRIP);
250         for (i = 0; i <= teeth; i++) {
251                 angle = i * 2.0 * M_PI / teeth;
252
253         if(!invert) {
254           u = r2 * cos(angle + da) - r1 * cos(angle);
255           v = r2 * sin(angle + da) - r1 * sin(angle);
256         } else {
257           u = r2 * cos(angle + da + M_PI/2) - r1 * cos(angle + M_PI/2);
258           v = r2 * sin(angle + da + M_PI/2) - r1 * sin(angle + M_PI/2);
259         }
260
261                 len = sqrt(u * u + v * v);
262                 u /= len;
263                 v /= len;
264                 glNormal3f(v, -u, 0.0);
265
266                 if (wire)
267                         glBegin(GL_LINES);
268                 glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
269                 glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
270
271                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
272                 glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
273
274         if(!invert)
275           glNormal3f(cos(angle), sin(angle), 0.0);
276         else
277           glNormal3f(cos(angle + M_PI/2), sin(angle + M_PI/2), 0.0);
278
279                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5);
280                 glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5);
281
282         if(!invert) {
283           u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
284           v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
285         } else {
286           u = r1 * cos(angle + 3 * da + M_PI/2) - r2 * cos(angle + 2 * da + M_PI/2);
287           v = r1 * sin(angle + 3 * da + M_PI/2) - r2 * sin(angle + 2 * da + M_PI/2);
288         }
289
290                 glNormal3f(v, -u, 0.0);
291
292                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5);
293                 glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5);
294
295         if (!invert)
296           glNormal3f(cos(angle), sin(angle), 0.0);
297         else
298           glNormal3f(cos(angle + M_PI/2), sin(angle + M_PI/2), 0.0);
299
300                 if (wire)
301                         glEnd();
302         }
303
304         if (!wire) {
305                 glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
306                 glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
307                 glEnd();
308         }
309         if (!wire)
310                 glShadeModel(GL_SMOOTH);
311
312         /* draw inside radius cylinder */
313         if (!wire)
314                 glBegin(GL_QUAD_STRIP);
315         for (i = 0; i <= teeth; i++) {
316                 angle = i * 2.0 * M_PI / teeth;
317                 if (wire)
318                         glBegin(GL_LINES);
319
320         if (!invert)
321           glNormal3f(-cos(angle), -sin(angle), 0.0);
322         else
323           glNormal3f(cos(angle), sin(angle), 0.0);
324
325                 glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
326                 glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
327                 if (wire) {
328                         glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
329                         glVertex3f(r0 * cos(angle + 4 * da), r0 * sin(angle + 4 * da), -width * 0.5);
330                         glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
331                         glVertex3f(r0 * cos(angle + 4 * da), r0 * sin(angle + 4 * da), width * 0.5);
332                         glEnd();
333                 }
334         }
335         if (!wire)
336                 glEnd();
337
338 }
339
340
341 static void
342 unit_tube (Bool wire)
343 {
344   int i;
345   int faces = TUBE_FACES;
346   GLfloat step = M_PI * 2 / faces;
347   GLfloat th;
348   int z = 0;
349
350   /* side walls
351    */
352   glFrontFace(GL_CCW);
353
354 # ifdef SMOOTH_TUBE
355   glBegin(wire ? GL_LINES : GL_QUAD_STRIP);
356 # else
357   glBegin(wire ? GL_LINES : GL_QUADS);
358 # endif
359
360   for (i = 0, th = 0; i <= faces; i++)
361     {
362       GLfloat x = cos (th);
363       GLfloat y = sin (th);
364       glNormal3f(x, 0, y);
365       glVertex3f(x, 0.0, y);
366       glVertex3f(x, 1.0, y);
367       th += step;
368
369 # ifndef SMOOTH_TUBE
370       x = cos (th);
371       y = sin (th);
372       glVertex3f(x, 1.0, y);
373       glVertex3f(x, 0.0, y);
374 # endif
375     }
376   glEnd();
377
378   /* End caps
379    */
380   for (z = 0; z <= 1; z++)
381     {
382       glFrontFace(z == 0 ? GL_CCW : GL_CW);
383       glNormal3f(0, (z == 0 ? -1 : 1), 0);
384       glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
385       if (! wire) glVertex3f(0, z, 0);
386       for (i = 0, th = 0; i <= faces; i++)
387         {
388           GLfloat x = cos (th);
389           GLfloat y = sin (th);
390           glVertex3f(x, z, y);
391           th += step;
392         }
393       glEnd();
394     }
395 }
396
397
398 static void
399 tube (GLfloat x1, GLfloat y1, GLfloat z1,
400       GLfloat x2, GLfloat y2, GLfloat z2,
401       GLfloat diameter, GLfloat cap_size,
402       Bool wire)
403 {
404   GLfloat length, angle, a, b, c;
405
406   if (diameter <= 0) abort();
407
408   a = (x2 - x1);
409   b = (y2 - y1);
410   c = (z2 - z1);
411
412   length = sqrt (a*a + b*b + c*c);
413   angle = acos (a / length);
414
415   glPushMatrix();
416   glTranslatef(x1, y1, z1);
417   glScalef (length, length, length);
418
419   if (c == 0 && b == 0)
420     glRotatef (angle / (M_PI / 180), 0, 1, 0);
421   else
422     glRotatef (angle / (M_PI / 180), 0, -c, b);
423
424   glRotatef (-90, 0, 0, 1);
425   glScalef (diameter/length, 1, diameter/length);
426
427   /* extend the endpoints of the tube by the cap size in both directions */
428   if (cap_size != 0)
429     {
430       GLfloat c = cap_size/length;
431       glTranslatef (0, -c, 0);
432       glScalef (1, 1+c+c, 1);
433     }
434
435   unit_tube (wire);
436   glPopMatrix();
437 }
438
439
440 static void
441 ctube (GLfloat diameter, GLfloat width, Bool wire)
442 {
443   tube (0, 0,  width/2,
444         0, 0, -width/2,
445         diameter, 0, wire);
446 }
447
448 static void
449 arm(GLfloat length,
450     GLfloat width1, GLfloat height1,
451     GLfloat width2, GLfloat height2,
452     Bool wire)
453 {
454   glShadeModel(GL_FLAT);
455
456 #if 0  /* don't need these - they're embedded in other objects */
457   /* draw end 1 */
458   glFrontFace(GL_CW);
459   glNormal3f(-1, 0, 0);
460   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
461   glVertex3f(-length/2, -width1/2, -height1/2);
462   glVertex3f(-length/2,  width1/2, -height1/2);
463   glVertex3f(-length/2,  width1/2,  height1/2);
464   glVertex3f(-length/2, -width1/2,  height1/2);
465   glEnd();
466
467   /* draw end 2 */
468   glFrontFace(GL_CCW);
469   glNormal3f(1, 0, 0);
470   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
471   glVertex3f(length/2, -width2/2, -height2/2);
472   glVertex3f(length/2,  width2/2, -height2/2);
473   glVertex3f(length/2,  width2/2,  height2/2);
474   glVertex3f(length/2, -width2/2,  height2/2);
475   glEnd();
476 #endif
477
478   /* draw top */
479   glFrontFace(GL_CCW);
480   glNormal3f(0, 0, -1);
481   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
482   glVertex3f(-length/2, -width1/2, -height1/2);
483   glVertex3f(-length/2,  width1/2, -height1/2);
484   glVertex3f( length/2,  width2/2, -height2/2);
485   glVertex3f( length/2, -width2/2, -height2/2);
486   glEnd();
487
488   /* draw bottom */
489   glFrontFace(GL_CW);
490   glNormal3f(0, 0, 1);
491   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
492   glVertex3f(-length/2, -width1/2, height1/2);
493   glVertex3f(-length/2,  width1/2, height1/2);
494   glVertex3f( length/2,  width2/2, height2/2);
495   glVertex3f( length/2, -width2/2, height2/2);
496   glEnd();
497
498   /* draw left */
499   glFrontFace(GL_CW);
500   glNormal3f(0, -1, 0);
501   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
502   glVertex3f(-length/2, -width1/2, -height1/2);
503   glVertex3f(-length/2, -width1/2,  height1/2);
504   glVertex3f( length/2, -width2/2,  height2/2);
505   glVertex3f( length/2, -width2/2, -height2/2);
506   glEnd();
507
508   /* draw right */
509   glFrontFace(GL_CCW);
510   glNormal3f(0, 1, 0);
511   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
512   glVertex3f(-length/2,  width1/2, -height1/2);
513   glVertex3f(-length/2,  width1/2,  height1/2);
514   glVertex3f( length/2,  width2/2,  height2/2);
515   glVertex3f( length/2,  width2/2, -height2/2);
516   glEnd();
517
518   glFrontFace(GL_CCW);
519 }
520
521
522 static void
523 draw(ModeInfo * mi)
524 {
525         gearsstruct *gp = &gears[MI_SCREEN(mi)];
526         int         wire = MI_IS_WIREFRAME(mi);
527
528         if (!wire) {
529                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
530         } else {
531                 glClear(GL_COLOR_BUFFER_BIT);
532         }
533
534         glPushMatrix();
535
536     gltrackball_rotate (gp->trackball);
537
538     {
539       double x, y, z;
540       get_rotation (gp->rot, &x, &y, &z, !gp->button_down_p);
541       glRotatef (x * 360, 1.0, 0.0, 0.0);
542       glRotatef (y * 360, 0.0, 1.0, 0.0);
543       glRotatef (z * 360, 0.0, 0.0, 1.0);
544     }
545
546     if (!planetary) {
547       glPushMatrix();
548       glTranslatef(-3.0, -2.0, 0.0);
549       glRotatef(gp->angle, 0.0, 0.0, 1.0);
550 /* PURIFY 4.0.1 reports an unitialized memory read on the next line when using
551    * MesaGL 2.2 and -mono.  This has been fixed in MesaGL 2.3 and later. */
552       glCallList(gp->gear1);
553       glPopMatrix();
554
555       glPushMatrix();
556       glTranslatef(3.1, -2.0, 0.0);
557       glRotatef(-2.0 * gp->angle - 9.0, 0.0, 0.0, 1.0);
558       glCallList(gp->gear2);
559       glPopMatrix();
560
561       glPushMatrix();
562       glTranslatef(-3.1, 4.2, 0.0);
563       glRotatef(-2.0 * gp->angle - 25.0, 0.0, 0.0, 1.0);
564       glCallList(gp->gear3);
565       glPopMatrix();
566
567     } else { /* planetary */
568
569       glScalef(0.8, 0.8, 0.8);
570
571       glPushMatrix();
572       glTranslatef(0.0, 4.2, 0.0);
573       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
574       glCallList(gp->gear1);
575       glPopMatrix();
576
577       glPushMatrix();
578       glRotatef(120, 0.0, 0.0, 1.0);
579       glTranslatef(0.0, 4.2, 0.0);
580       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
581       glCallList(gp->gear2);
582       glPopMatrix();
583
584       glPushMatrix();
585       glRotatef(240, 0.0, 0.0, 1.0);
586       glTranslatef(0.0, 4.2, 0.0);
587       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
588       glCallList(gp->gear3);
589       glPopMatrix();
590
591       glPushMatrix();
592       glTranslatef(0.0, 0.0, 0.0);
593       glRotatef(-gp->angle, 0.0, 0.0, 1.0);
594       glCallList(gp->gear_inner);
595       glPopMatrix();
596
597       glPushMatrix();
598       glTranslatef(0.0, 0.0, 0.0);
599       glRotatef((gp->angle / 3.0) - 7.5, 0.0, 0.0, 1.0);
600       glCallList(gp->gear_outer);
601       glPopMatrix();
602
603       glPushMatrix();
604       glTranslatef(0.0, 0.0, 0.0);
605       glCallList(gp->armature);
606       glPopMatrix();
607     }
608
609         glPopMatrix();
610 }
611
612
613
614 /* new window size or exposure */
615 void
616 reshape_gears(ModeInfo *mi, int width, int height)
617 {
618         GLfloat     h = (GLfloat) height / (GLfloat) width;
619
620         glViewport(0, 0, (GLint) width, (GLint) height);
621         glMatrixMode(GL_PROJECTION);
622         glLoadIdentity();
623         glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
624         glMatrixMode(GL_MODELVIEW);
625         glLoadIdentity();
626         glTranslatef(0.0, 0.0, -40.0);
627
628         /* The depth buffer will be cleared, if needed, before the
629          * next frame.  Right now we just want to black the screen.
630          */
631         glClear(GL_COLOR_BUFFER_BIT);
632
633 }
634
635
636 static void
637 pinit(ModeInfo * mi)
638 {
639         gearsstruct *gp = &gears[MI_SCREEN(mi)];
640         static GLfloat pos[4] =
641         {5.0, 5.0, 10.0, 1.0};
642         static GLfloat red[4] =
643         {0.8, 0.1, 0.0, 1.0};
644         static GLfloat green[4] =
645         {0.0, 0.8, 0.2, 1.0};
646         static GLfloat blue[4] =
647         {0.2, 0.2, 1.0, 1.0};
648         static GLfloat gray[4] =
649         {0.5, 0.5, 0.5, 1.0};
650         static GLfloat white[4] =
651         {1.0, 1.0, 1.0, 1.0};
652         int         wire = MI_IS_WIREFRAME(mi);
653         int         mono = MI_IS_MONO(mi);
654
655         if (!wire) {
656                 glLightfv(GL_LIGHT0, GL_POSITION, pos);
657                 glEnable(GL_CULL_FACE);
658                 glEnable(GL_LIGHTING);
659                 glEnable(GL_LIGHT0);
660                 glEnable(GL_DEPTH_TEST);
661         }
662 #if 0
663 /*-
664  * Messes up on multiscreen Pseudocolor:0 StaticGray(monochrome):1
665  * 2nd time mode is run it is Grayscale on PseudoColor.
666  * The code below forces monochrome on TrueColor.
667  */
668         if (MI_IS_MONO(mi)) {
669                 red[0] = red[1] = red[2] = 1.0;
670                 green[0] = green[1] = green[2] = 1.0;
671                 blue[0] = blue[1] = blue[2] = 1.0;
672         }
673 #endif
674
675         /* make the gears */
676
677     if (! planetary) {
678
679       gp->gear1 = glGenLists(1);
680       glNewList(gp->gear1, GL_COMPILE);
681       if (wire) {
682                 if (mono)
683           glColor4fv(white);
684                 else
685           glColor4fv(red);
686       } else {
687                 if (mono)
688           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
689                 else
690           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
691       }
692
693       gear(1.0, 4.0, 1.0, 20, 0.7, wire, False);
694       glEndList();
695
696       gp->gear2 = glGenLists(1);
697       glNewList(gp->gear2, GL_COMPILE);
698       if (wire) {
699                 if (mono)
700           glColor4fv(white);
701                 else
702           glColor4fv(green);
703       } else {
704                 if (mono)
705           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
706                 else
707           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
708       }
709       gear(0.5, 2.0, 2.0, 10, 0.7, wire, False);
710       glEndList();
711
712       gp->gear3 = glGenLists(1);
713       glNewList(gp->gear3, GL_COMPILE);
714       if (wire) {
715                 if (mono)
716           glColor4fv(white);
717                 else
718           glColor4fv(blue);
719       } else {
720                 if (mono)
721           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
722                 else
723           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
724       }
725       gear(1.3, 2.0, 0.5, 10, 0.7, wire, False);
726       glEndList();
727       if (!wire)
728                 glEnable(GL_NORMALIZE);
729
730     } else { /* planetary */
731
732       gp->gear1 = glGenLists(1);
733       glNewList(gp->gear1, GL_COMPILE);
734       if (wire) {
735                 if (mono)
736           glColor4fv(white);
737                 else
738           glColor4fv(red);
739       } else {
740                 if (mono)
741           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
742                 else
743           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
744       }
745       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
746       glEndList();
747
748       gp->gear2 = glGenLists(1);
749       glNewList(gp->gear2, GL_COMPILE);
750       if (wire) {
751                 if (mono)
752           glColor4fv(white);
753                 else
754           glColor4fv(green);
755       } else {
756                 if (mono)
757           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
758                 else
759           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
760       }
761       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
762       glEndList();
763
764       gp->gear3 = glGenLists(1);
765       glNewList(gp->gear3, GL_COMPILE);
766       if (wire) {
767                 if (mono)
768           glColor4fv(white);
769                 else
770           glColor4fv(blue);
771       } else {
772                 if (mono)
773           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
774                 else
775           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
776       }
777       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
778       glEndList();
779       if (!wire)
780                 glEnable(GL_NORMALIZE);
781
782
783       gp->gear_inner = glGenLists(1);
784       glNewList(gp->gear_inner, GL_COMPILE);
785       if (wire) {
786                 if (mono)
787           glColor4fv(white);
788                 else
789           glColor4fv(blue);
790       } else {
791                 if (mono)
792           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
793                 else
794           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
795       }
796       gear(1.0, 2.0, 2.0, 12, 0.7, wire, False);
797       glEndList();
798       if (!wire)
799                 glEnable(GL_NORMALIZE);
800
801
802       gp->gear_outer = glGenLists(1);
803       glNewList(gp->gear_outer, GL_COMPILE);
804       if (wire) {
805                 if (mono)
806           glColor4fv(white);
807                 else
808           glColor4fv(blue);
809       } else {
810                 if (mono)
811           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
812                 else
813           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
814       }
815       gear(5.7, 7.0, 2.0, 36, 0.7, wire, True);
816
817       /* put some nubs on the outer ring, so we can tell how it's moving */
818       glPushMatrix();
819       glTranslatef(7.0, 0, 0);
820       glRotatef(90, 0, 1, 0);
821
822       ctube(0.5, 0.5, wire);   /* nub 1 */
823       glPopMatrix();
824
825       glPushMatrix();
826       glRotatef(120, 0, 0, 1);
827       glTranslatef(7.0, 0, 0);
828       glRotatef(90, 0, 1, 0);
829       ctube(0.5, 0.5, wire);   /* nub 2 */
830       glPopMatrix();
831
832       glPushMatrix();
833       glRotatef(240, 0, 0, 1);
834       glTranslatef(7.0, 0, 0);
835       glRotatef(90, 0, 1, 0);
836       ctube(0.5, 0.5, wire);   /* nub 3 */
837       glPopMatrix();
838
839
840       glEndList();
841       if (!wire)
842                 glEnable(GL_NORMALIZE);
843
844       gp->armature = glGenLists(1);
845       glNewList(gp->armature, GL_COMPILE);
846       if (wire) {
847         if (mono)
848           glColor4fv(white);
849         else
850           glColor4fv(blue);
851       } else {
852         if (mono)
853           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
854         else
855           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
856       }
857
858       glTranslatef(0, 0, 1.5);
859       ctube(0.5, 10, wire);       /* center axle */
860
861       glPushMatrix();
862       glTranslatef(0.0, 4.2, -1);
863       ctube(0.5, 3, wire);       /* axle 1 */
864       glTranslatef(0, 0, 1.8);
865       ctube(0.7, 0.7, wire);
866       glPopMatrix();
867
868       glPushMatrix();
869       glRotatef(120, 0.0, 0.0, 1.0);
870       glTranslatef(0.0, 4.2, -1);
871       ctube(0.5, 3, wire);       /* axle 2 */
872       glTranslatef(0, 0, 1.8);
873       ctube(0.7, 0.7, wire);
874       glPopMatrix();
875
876       glPushMatrix();
877       glRotatef(240, 0.0, 0.0, 1.0);
878       glTranslatef(0.0, 4.2, -1);
879       ctube(0.5, 3, wire);       /* axle 3 */
880       glTranslatef(0, 0, 1.8);
881       ctube(0.7, 0.7, wire);
882       glPopMatrix();
883
884       glTranslatef(0, 0, 1.5);      /* center disk */
885       ctube(1.5, 2, wire);
886
887       glPushMatrix();
888       glRotatef(270, 0, 0, 1);
889       glRotatef(-10, 0, 1, 0);
890       glTranslatef(-2.2, 0, 0);
891       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 1 */
892       glPopMatrix();
893
894       glPushMatrix();
895       glRotatef(30, 0, 0, 1);
896       glRotatef(-10, 0, 1, 0);
897       glTranslatef(-2.2, 0, 0);
898       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 2 */
899       glPopMatrix();
900
901       glPushMatrix();
902       glRotatef(150, 0, 0, 1);
903       glRotatef(-10, 0, 1, 0);
904       glTranslatef(-2.2, 0, 0);
905       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 3 */
906       glPopMatrix();
907
908       glEndList();
909       if (!wire)
910         glEnable(GL_NORMALIZE);
911     }
912 }
913
914
915 Bool
916 gears_handle_event (ModeInfo *mi, XEvent *event)
917 {
918   gearsstruct *gp = &gears[MI_SCREEN(mi)];
919
920   if (event->xany.type == ButtonPress &&
921       event->xbutton.button == Button1)
922     {
923       gp->button_down_p = True;
924       gltrackball_start (gp->trackball,
925                          event->xbutton.x, event->xbutton.y,
926                          MI_WIDTH (mi), MI_HEIGHT (mi));
927       return True;
928     }
929   else if (event->xany.type == ButtonRelease &&
930            event->xbutton.button == Button1)
931     {
932       gp->button_down_p = False;
933       return True;
934     }
935   else if (event->xany.type == ButtonPress &&
936            (event->xbutton.button == Button4 ||
937             event->xbutton.button == Button5))
938     {
939       gltrackball_mousewheel (gp->trackball, event->xbutton.button, 10,
940                               !!event->xbutton.state);
941       return True;
942     }
943   else if (event->xany.type == MotionNotify &&
944            gp->button_down_p)
945     {
946       gltrackball_track (gp->trackball,
947                          event->xmotion.x, event->xmotion.y,
948                          MI_WIDTH (mi), MI_HEIGHT (mi));
949       return True;
950     }
951
952   return False;
953 }
954
955
956 void
957 init_gears(ModeInfo * mi)
958 {
959         int         screen = MI_SCREEN(mi);
960
961         /*Colormap    cmap; */
962         /* Boolean     rgba, doublebuffer, cmap_installed; */
963         gearsstruct *gp;
964
965         if (gears == NULL) {
966                 if ((gears = (gearsstruct *) calloc(MI_NUM_SCREENS(mi),
967                                               sizeof (gearsstruct))) == NULL)
968                         return;
969         }
970         gp = &gears[screen];
971
972         gp->window = MI_WINDOW(mi);
973
974     gp->rot = make_rotator (1, 1, 1, 1, 0, True);
975     gp->trackball = gltrackball_init ();
976
977         if ((gp->glx_context = init_GL(mi)) != NULL) {
978                 reshape_gears(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
979                 pinit(mi);
980         } else {
981                 MI_CLEARWINDOW(mi);
982         }
983 }
984
985 void
986 draw_gears(ModeInfo * mi)
987 {
988         gearsstruct *gp = &gears[MI_SCREEN(mi)];
989         Display    *display = MI_DISPLAY(mi);
990         Window      window = MI_WINDOW(mi);
991         int         angle_incr = MI_CYCLES(mi) ? MI_CYCLES(mi) : 2;
992
993     if (planetary)
994       angle_incr *= 3;
995
996         if (!gp->glx_context)
997                 return;
998
999         glDrawBuffer(GL_BACK);
1000
1001         glXMakeCurrent(display, window, *(gp->glx_context));
1002         draw(mi);
1003
1004         /* let's do something so we don't get bored */
1005         gp->angle = (int) (gp->angle + angle_incr) % 360;
1006
1007     if (mi->fps_p) do_fps (mi);
1008         glFinish();
1009         glXSwapBuffers(display, window);
1010 }
1011
1012 void
1013 release_gears(ModeInfo * mi)
1014 {
1015         if (gears != NULL) {
1016                 int         screen;
1017
1018                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1019                         gearsstruct *gp = &gears[screen];
1020
1021                         if (gp->glx_context) {
1022                                 /* Display lists MUST be freed while their glXContext is current. */
1023                                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1024
1025                                 if (glIsList(gp->gear1))
1026                                         glDeleteLists(gp->gear1, 1);
1027                                 if (glIsList(gp->gear2))
1028                                         glDeleteLists(gp->gear2, 1);
1029                                 if (glIsList(gp->gear3))
1030                                         glDeleteLists(gp->gear3, 1);
1031                                 if (glIsList(gp->gear_inner))
1032                                         glDeleteLists(gp->gear_inner, 1);
1033                                 if (glIsList(gp->gear_outer))
1034                                         glDeleteLists(gp->gear_outer, 1);
1035
1036                         }
1037                 }
1038                 (void) free((void *) gears);
1039                 gears = NULL;
1040         }
1041         FreeAllGL(mi);
1042 }
1043
1044
1045 /*********************************************************/
1046
1047 #endif