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