http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[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 DEFAULTS       "*count:                1000000 \n"                     \
39                                         "*cycles:               2       \n"                     \
40                                         "*delay:                20000   \n"                     \
41                                         "*showFPS:      False   \n"                     \
42                                         "*wireframe:    False   \n"
43 # include "xlockmore.h"                         /* from the xscreensaver distribution */
44 # define refresh_gears 0
45 #else  /* !STANDALONE */
46 # include "xlock.h"                                     /* from the xlockmore distribution */
47 #endif /* !STANDALONE */
48
49 #ifdef USE_GL
50
51 #include "rotator.h"
52 #include "gltrackball.h"
53
54 #undef countof
55 #define countof(x) (sizeof((x))/sizeof((*x)))
56
57 #define DEF_MODE "random"
58 #define DEF_SPIN "True"
59
60 static char *mode_str;
61 static int spin;
62
63 static XrmOptionDescRec opts[] = {
64   {"-mode",      ".gears.mode", XrmoptionSepArg, 0 },
65   {"-planetary", ".gears.mode", XrmoptionNoArg, "planetary" },
66   {"-simple",    ".gears.mode", XrmoptionNoArg, "simple" },
67   {"-spin", ".gears.spin", XrmoptionNoArg, "true" },
68   {"+spin", ".gears.spin", XrmoptionNoArg, "false" },
69 };
70
71 static argtype vars[] = {
72   {&mode_str, "mode", "Mode", DEF_MODE, t_String},
73   {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
74 };
75
76 ENTRYPOINT 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   int             planetary_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     if (spin)
540           {
541                 double x, y, z;
542                 get_rotation (gp->rot, &x, &y, &z, !gp->button_down_p);
543                 glRotatef (x * 360, 1.0, 0.0, 0.0);
544                 glRotatef (y * 360, 0.0, 1.0, 0.0);
545                 glRotatef (z * 360, 0.0, 0.0, 1.0);
546           }
547
548     if (!gp->planetary_p) {
549       glPushMatrix();
550       glTranslatef(-3.0, -2.0, 0.0);
551       glRotatef(gp->angle, 0.0, 0.0, 1.0);
552 /* PURIFY 4.0.1 reports an unitialized memory read on the next line when using
553    * MesaGL 2.2 and -mono.  This has been fixed in MesaGL 2.3 and later. */
554       glCallList(gp->gear1);
555       glPopMatrix();
556
557       glPushMatrix();
558       glTranslatef(3.1, -2.0, 0.0);
559       glRotatef(-2.0 * gp->angle - 9.0, 0.0, 0.0, 1.0);
560       glCallList(gp->gear2);
561       glPopMatrix();
562
563       glPushMatrix();
564       glTranslatef(-3.1, 4.2, 0.0);
565       glRotatef(-2.0 * gp->angle - 25.0, 0.0, 0.0, 1.0);
566       glCallList(gp->gear3);
567       glPopMatrix();
568
569     } else { /* gp->planetary_p */
570
571       glScalef(0.8, 0.8, 0.8);
572
573       glPushMatrix();
574       glTranslatef(0.0, 4.2, 0.0);
575       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
576       glCallList(gp->gear1);
577       glPopMatrix();
578
579       glPushMatrix();
580       glRotatef(120, 0.0, 0.0, 1.0);
581       glTranslatef(0.0, 4.2, 0.0);
582       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
583       glCallList(gp->gear2);
584       glPopMatrix();
585
586       glPushMatrix();
587       glRotatef(240, 0.0, 0.0, 1.0);
588       glTranslatef(0.0, 4.2, 0.0);
589       glRotatef(gp->angle - 7.0, 0.0, 0.0, 1.0);
590       glCallList(gp->gear3);
591       glPopMatrix();
592
593       glPushMatrix();
594       glTranslatef(0.0, 0.0, 0.0);
595       glRotatef(-gp->angle, 0.0, 0.0, 1.0);
596       glCallList(gp->gear_inner);
597       glPopMatrix();
598
599       glPushMatrix();
600       glTranslatef(0.0, 0.0, 0.0);
601       glRotatef((gp->angle / 3.0) - 7.5, 0.0, 0.0, 1.0);
602       glCallList(gp->gear_outer);
603       glPopMatrix();
604
605       glPushMatrix();
606       glTranslatef(0.0, 0.0, 0.0);
607       glCallList(gp->armature);
608       glPopMatrix();
609     }
610
611         glPopMatrix();
612 }
613
614
615
616 /* new window size or exposure */
617 ENTRYPOINT void
618 reshape_gears (ModeInfo *mi, int width, int height)
619 {
620         GLfloat     h = (GLfloat) height / (GLfloat) width;
621
622         glViewport(0, 0, (GLint) width, (GLint) height);
623         glMatrixMode(GL_PROJECTION);
624         glLoadIdentity();
625         glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
626         glMatrixMode(GL_MODELVIEW);
627         glLoadIdentity();
628         glTranslatef(0.0, 0.0, -40.0);
629
630         /* The depth buffer will be cleared, if needed, before the
631          * next frame.  Right now we just want to black the screen.
632          */
633         glClear(GL_COLOR_BUFFER_BIT);
634
635 }
636
637
638 static void
639 pinit(ModeInfo * mi)
640 {
641         gearsstruct *gp = &gears[MI_SCREEN(mi)];
642         static const GLfloat pos[4]   = {5.0, 5.0, 10.0, 1.0};
643         static const GLfloat red[4]   = {0.8, 0.1, 0.0, 1.0};
644         static const GLfloat green[4] = {0.0, 0.8, 0.2, 1.0};
645         static const GLfloat blue[4]  = {0.2, 0.2, 1.0, 1.0};
646         static const GLfloat gray[4]  = {0.5, 0.5, 0.5, 1.0};
647         static const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
648         int         wire = MI_IS_WIREFRAME(mi);
649         int         mono = MI_IS_MONO(mi);
650
651         if (!wire) {
652                 glLightfv(GL_LIGHT0, GL_POSITION, pos);
653                 glEnable(GL_CULL_FACE);
654                 glEnable(GL_LIGHTING);
655                 glEnable(GL_LIGHT0);
656                 glEnable(GL_DEPTH_TEST);
657         }
658 #if 0
659 /*-
660  * Messes up on multiscreen Pseudocolor:0 StaticGray(monochrome):1
661  * 2nd time mode is run it is Grayscale on PseudoColor.
662  * The code below forces monochrome on TrueColor.
663  */
664         if (MI_IS_MONO(mi)) {
665                 red[0] = red[1] = red[2] = 1.0;
666                 green[0] = green[1] = green[2] = 1.0;
667                 blue[0] = blue[1] = blue[2] = 1.0;
668         }
669 #endif
670
671         /* make the gears */
672
673     if (! gp->planetary_p) {
674
675       gp->gear1 = glGenLists(1);
676       glNewList(gp->gear1, GL_COMPILE);
677       if (wire) {
678                 if (mono)
679           glColor4fv(white);
680                 else
681           glColor4fv(red);
682       } else {
683                 if (mono)
684           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
685                 else
686           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
687       }
688
689       gear(1.0, 4.0, 1.0, 20, 0.7, wire, False);
690       glEndList();
691
692       gp->gear2 = glGenLists(1);
693       glNewList(gp->gear2, GL_COMPILE);
694       if (wire) {
695                 if (mono)
696           glColor4fv(white);
697                 else
698           glColor4fv(green);
699       } else {
700                 if (mono)
701           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
702                 else
703           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
704       }
705       gear(0.5, 2.0, 2.0, 10, 0.7, wire, False);
706       glEndList();
707
708       gp->gear3 = glGenLists(1);
709       glNewList(gp->gear3, GL_COMPILE);
710       if (wire) {
711                 if (mono)
712           glColor4fv(white);
713                 else
714           glColor4fv(blue);
715       } else {
716                 if (mono)
717           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
718                 else
719           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
720       }
721       gear(1.3, 2.0, 0.5, 10, 0.7, wire, False);
722       glEndList();
723       if (!wire)
724                 glEnable(GL_NORMALIZE);
725
726     } else { /* gp->planetary_p */
727
728       gp->gear1 = glGenLists(1);
729       glNewList(gp->gear1, GL_COMPILE);
730       if (wire) {
731                 if (mono)
732           glColor4fv(white);
733                 else
734           glColor4fv(red);
735       } else {
736                 if (mono)
737           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
738                 else
739           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
740       }
741       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
742       glEndList();
743
744       gp->gear2 = glGenLists(1);
745       glNewList(gp->gear2, GL_COMPILE);
746       if (wire) {
747                 if (mono)
748           glColor4fv(white);
749                 else
750           glColor4fv(green);
751       } else {
752                 if (mono)
753           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
754                 else
755           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
756       }
757       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
758       glEndList();
759
760       gp->gear3 = glGenLists(1);
761       glNewList(gp->gear3, GL_COMPILE);
762       if (wire) {
763                 if (mono)
764           glColor4fv(white);
765                 else
766           glColor4fv(blue);
767       } else {
768                 if (mono)
769           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
770                 else
771           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
772       }
773       gear(1.3, 2.0, 2.0, 12, 0.7, wire, False);
774       glEndList();
775       if (!wire)
776                 glEnable(GL_NORMALIZE);
777
778
779       gp->gear_inner = glGenLists(1);
780       glNewList(gp->gear_inner, GL_COMPILE);
781       if (wire) {
782                 if (mono)
783           glColor4fv(white);
784                 else
785           glColor4fv(blue);
786       } else {
787                 if (mono)
788           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
789                 else
790           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
791       }
792       gear(1.0, 2.0, 2.0, 12, 0.7, wire, False);
793       glEndList();
794       if (!wire)
795                 glEnable(GL_NORMALIZE);
796
797
798       gp->gear_outer = glGenLists(1);
799       glNewList(gp->gear_outer, GL_COMPILE);
800       if (wire) {
801                 if (mono)
802           glColor4fv(white);
803                 else
804           glColor4fv(blue);
805       } else {
806                 if (mono)
807           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
808                 else
809           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
810       }
811       gear(5.7, 7.0, 2.0, 36, 0.7, wire, True);
812
813       /* put some nubs on the outer ring, so we can tell how it's moving */
814       glPushMatrix();
815       glTranslatef(7.0, 0, 0);
816       glRotatef(90, 0, 1, 0);
817
818       ctube(0.5, 0.5, wire);   /* nub 1 */
819       glPopMatrix();
820
821       glPushMatrix();
822       glRotatef(120, 0, 0, 1);
823       glTranslatef(7.0, 0, 0);
824       glRotatef(90, 0, 1, 0);
825       ctube(0.5, 0.5, wire);   /* nub 2 */
826       glPopMatrix();
827
828       glPushMatrix();
829       glRotatef(240, 0, 0, 1);
830       glTranslatef(7.0, 0, 0);
831       glRotatef(90, 0, 1, 0);
832       ctube(0.5, 0.5, wire);   /* nub 3 */
833       glPopMatrix();
834
835
836       glEndList();
837       if (!wire)
838                 glEnable(GL_NORMALIZE);
839
840       gp->armature = glGenLists(1);
841       glNewList(gp->armature, GL_COMPILE);
842       if (wire) {
843         if (mono)
844           glColor4fv(white);
845         else
846           glColor4fv(blue);
847       } else {
848         if (mono)
849           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
850         else
851           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, gray);
852       }
853
854       glTranslatef(0, 0, 1.5);
855       ctube(0.5, 10, wire);       /* center axle */
856
857       glPushMatrix();
858       glTranslatef(0.0, 4.2, -1);
859       ctube(0.5, 3, wire);       /* axle 1 */
860       glTranslatef(0, 0, 1.8);
861       ctube(0.7, 0.7, wire);
862       glPopMatrix();
863
864       glPushMatrix();
865       glRotatef(120, 0.0, 0.0, 1.0);
866       glTranslatef(0.0, 4.2, -1);
867       ctube(0.5, 3, wire);       /* axle 2 */
868       glTranslatef(0, 0, 1.8);
869       ctube(0.7, 0.7, wire);
870       glPopMatrix();
871
872       glPushMatrix();
873       glRotatef(240, 0.0, 0.0, 1.0);
874       glTranslatef(0.0, 4.2, -1);
875       ctube(0.5, 3, wire);       /* axle 3 */
876       glTranslatef(0, 0, 1.8);
877       ctube(0.7, 0.7, wire);
878       glPopMatrix();
879
880       glTranslatef(0, 0, 1.5);      /* center disk */
881       ctube(1.5, 2, wire);
882
883       glPushMatrix();
884       glRotatef(270, 0, 0, 1);
885       glRotatef(-10, 0, 1, 0);
886       glTranslatef(-2.2, 0, 0);
887       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 1 */
888       glPopMatrix();
889
890       glPushMatrix();
891       glRotatef(30, 0, 0, 1);
892       glRotatef(-10, 0, 1, 0);
893       glTranslatef(-2.2, 0, 0);
894       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 2 */
895       glPopMatrix();
896
897       glPushMatrix();
898       glRotatef(150, 0, 0, 1);
899       glRotatef(-10, 0, 1, 0);
900       glTranslatef(-2.2, 0, 0);
901       arm(4.0, 1.0, 0.5, 2.0, 1.0, wire);               /* arm 3 */
902       glPopMatrix();
903
904       glEndList();
905       if (!wire)
906         glEnable(GL_NORMALIZE);
907     }
908 }
909
910
911 ENTRYPOINT Bool
912 gears_handle_event (ModeInfo *mi, XEvent *event)
913 {
914   gearsstruct *gp = &gears[MI_SCREEN(mi)];
915
916   if (event->xany.type == ButtonPress &&
917       event->xbutton.button == Button1)
918     {
919       gp->button_down_p = True;
920       gltrackball_start (gp->trackball,
921                          event->xbutton.x, event->xbutton.y,
922                          MI_WIDTH (mi), MI_HEIGHT (mi));
923       return True;
924     }
925   else if (event->xany.type == ButtonRelease &&
926            event->xbutton.button == Button1)
927     {
928       gp->button_down_p = False;
929       return True;
930     }
931   else if (event->xany.type == ButtonPress &&
932            (event->xbutton.button == Button4 ||
933             event->xbutton.button == Button5))
934     {
935       gltrackball_mousewheel (gp->trackball, event->xbutton.button, 10,
936                               !!event->xbutton.state);
937       return True;
938     }
939   else if (event->xany.type == MotionNotify &&
940            gp->button_down_p)
941     {
942       gltrackball_track (gp->trackball,
943                          event->xmotion.x, event->xmotion.y,
944                          MI_WIDTH (mi), MI_HEIGHT (mi));
945       return True;
946     }
947
948   return False;
949 }
950
951
952 ENTRYPOINT void
953 init_gears (ModeInfo * mi)
954 {
955         int         screen = MI_SCREEN(mi);
956
957         /*Colormap    cmap; */
958         /* Boolean     rgba, doublebuffer, cmap_installed; */
959         gearsstruct *gp;
960
961         if (gears == NULL) {
962                 if ((gears = (gearsstruct *) calloc(MI_NUM_SCREENS(mi),
963                                               sizeof (gearsstruct))) == NULL)
964                         return;
965         }
966         gp = &gears[screen];
967
968     if (mode_str && !strcasecmp (mode_str, "planetary"))
969       gp->planetary_p = True;
970     else if (mode_str && !strcasecmp (mode_str, "simple"))
971       gp->planetary_p = False;
972     else if (!mode_str || !*mode_str || !strcasecmp (mode_str, "random"))
973       gp->planetary_p = !(random() % 2);
974     else
975       fprintf (stderr, "%s: mode must be planetary, simple, or random", 
976                progname);
977
978         gp->window = MI_WINDOW(mi);
979
980     gp->rot = make_rotator (1, 1, 1, 1, 0, True);
981     gp->trackball = gltrackball_init ();
982
983         if ((gp->glx_context = init_GL(mi)) != NULL) {
984                 reshape_gears(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
985                 pinit(mi);
986         } else {
987                 MI_CLEARWINDOW(mi);
988         }
989 }
990
991 ENTRYPOINT void
992 draw_gears (ModeInfo * mi)
993 {
994         gearsstruct *gp = &gears[MI_SCREEN(mi)];
995         Display    *display = MI_DISPLAY(mi);
996         Window      window = MI_WINDOW(mi);
997         int         angle_incr = MI_CYCLES(mi) ? MI_CYCLES(mi) : 2;
998
999     if (gp->planetary_p)
1000       angle_incr *= 3;
1001
1002         if (!gp->glx_context)
1003                 return;
1004
1005         glDrawBuffer(GL_BACK);
1006
1007         glXMakeCurrent(display, window, *(gp->glx_context));
1008         draw(mi);
1009
1010         /* let's do something so we don't get bored */
1011         gp->angle = (int) (gp->angle + angle_incr) % 360;
1012
1013     if (mi->fps_p) do_fps (mi);
1014         glFinish();
1015         glXSwapBuffers(display, window);
1016 }
1017
1018 ENTRYPOINT void
1019 release_gears (ModeInfo * mi)
1020 {
1021         if (gears != NULL) {
1022                 int         screen;
1023
1024                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1025                         gearsstruct *gp = &gears[screen];
1026
1027                         if (gp->glx_context) {
1028                                 /* Display lists MUST be freed while their glXContext is current. */
1029                                 glXMakeCurrent(MI_DISPLAY(mi), gp->window, *(gp->glx_context));
1030
1031                                 if (glIsList(gp->gear1))
1032                                         glDeleteLists(gp->gear1, 1);
1033                                 if (glIsList(gp->gear2))
1034                                         glDeleteLists(gp->gear2, 1);
1035                                 if (glIsList(gp->gear3))
1036                                         glDeleteLists(gp->gear3, 1);
1037                                 if (glIsList(gp->gear_inner))
1038                                         glDeleteLists(gp->gear_inner, 1);
1039                                 if (glIsList(gp->gear_outer))
1040                                         glDeleteLists(gp->gear_outer, 1);
1041
1042                         }
1043                 }
1044                 (void) free((void *) gears);
1045                 gears = NULL;
1046         }
1047         FreeAllGL(mi);
1048 }
1049
1050
1051 XSCREENSAVER_MODULE ("Gears", gears)
1052
1053 /*********************************************************/
1054
1055 #endif