http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.06.tar.gz
[xscreensaver] / hacks / glx / dnalogo.c
1 /* DNA Logo, Copyright (c) 2001, 2002, 2003 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 #define DEFAULTS        __extension__ \
13                         "*delay:            25000   \n" \
14                         "*showFPS:          False   \n" \
15                         "*wireframe:        False   \n" \
16                         "*doGasket:         True    \n" \
17                         "*doHelix:          True    \n" \
18                         "*doLadder:         True    \n" \
19                         "*doFrame:          True    \n" \
20                         "*wallFacets:       360     \n" \
21                         "*barFacets:        90      \n" \
22                         "*clockwise:        False   \n" \
23                         "*turns:            0.69    \n" \
24                         "*turnSpacing:      2.2     \n" \
25                         "*barSpacing:       0.24    \n" \
26                         "*wallHeight:       0.45    \n" \
27                         "*wallThickness:    0.12    \n" \
28                         "*barThickness:     0.058   \n" \
29                         "*wallTaper:        0.95    \n" \
30                         "*gasketSize:       1.88    \n" \
31                         "*gasketDepth:      0.15    \n" \
32                         "*gasketThickness:  0.4     \n" \
33                         "*frameSize:        1.20    \n" \
34                         "*frameDepth:       0.01    \n" \
35                         "*frameThickness:   0.03    \n" \
36                         "*triangleSize:     0.045   \n" \
37                         "*speed:            1.0     \n" \
38                         ".foreground:       #00AA00 \n" \
39                         "*geometry:         =640x640\n" \
40
41 # define refresh_logo 0
42 # define release_logo 0
43 #undef countof
44 #define countof(x) (sizeof((x))/sizeof((*x)))
45
46 #include "xlockmore.h"
47 #include "normals.h"
48 #include "tube.h"
49 #include "rotator.h"
50 #include "gltrackball.h"
51
52 #ifdef USE_GL /* whole file */
53
54 typedef struct {
55   Bool spinning_p;
56   GLfloat position;     /* 0.0 - 1.0 */
57   GLfloat speed;        /* how far along the path (may be negative) */
58   GLfloat probability;  /* relative likelyhood to start spinning */
59 } spinner;
60
61 typedef struct {
62   GLXContext *glx_context;
63
64   GLuint helix_list,  helix_list_wire,  helix_list_facetted;
65   GLuint gasket_list, gasket_list_wire;
66   GLuint frame_list,  frame_list_wire;
67
68   int wall_facets;
69   int bar_facets;
70   Bool clockwise;
71   GLfloat color[4];
72
73   GLfloat turns;
74   GLfloat turn_spacing;
75   GLfloat bar_spacing;
76   GLfloat wall_height;
77   GLfloat wall_thickness;
78   GLfloat bar_thickness;
79   GLfloat wall_taper;
80
81   GLfloat gasket_size;
82   GLfloat gasket_depth;
83   GLfloat gasket_thickness;
84
85   GLfloat frame_size;
86   GLfloat frame_depth;
87   GLfloat frame_thickness;
88   GLfloat triangle_size;
89
90   GLfloat speed;
91
92   spinner gasket_spinnerx, gasket_spinnery, gasket_spinnerz;
93   spinner scene_spinnerx,  scene_spinnery;
94   spinner helix_spinnerz;
95   spinner frame_spinner;
96
97   trackball_state *trackball;
98   Bool button_down_p;
99
100   int wire_overlay;  /* frame countdown */
101
102 } logo_configuration;
103
104 static logo_configuration *dcs = NULL;
105
106 static XrmOptionDescRec opts[] = {
107   { "-speed",  ".speed",  XrmoptionSepArg, 0 },
108 };
109
110 ENTRYPOINT ModeSpecOpt logo_opts = {countof(opts), opts, 0, NULL, NULL};
111
112 #define PROBABILITY_SCALE 600
113
114
115 \f
116 /* Calculate the angle (in degrees) between two vectors.
117  */
118 static GLfloat
119 vector_angle (double ax, double ay, double az,
120               double bx, double by, double bz)
121 {
122   double La = sqrt (ax*ax + ay*ay + az*az);
123   double Lb = sqrt (bx*bx + by*by + bz*bz);
124   double cc, angle;
125
126   if (La == 0 || Lb == 0) return 0;
127   if (ax == bx && ay == by && az == bz) return 0;
128
129   /* dot product of two vectors is defined as:
130        La * Lb * cos(angle between vectors)
131      and is also defined as:
132        ax*bx + ay*by + az*bz
133      so:
134       La * Lb * cos(angle) = ax*bx + ay*by + az*bz
135       cos(angle)  = (ax*bx + ay*by + az*bz) / (La * Lb)
136       angle = acos ((ax*bx + ay*by + az*bz) / (La * Lb));
137   */
138   cc = (ax*bx + ay*by + az*bz) / (La * Lb);
139   if (cc > 1) cc = 1;  /* avoid fp rounding error (1.000001 => sqrt error) */
140   angle = acos (cc);
141
142   return (angle * M_PI / 180);
143 }
144
145 \f
146 /* Make the helix
147  */
148
149 static void
150 make_helix (logo_configuration *dc, int facetted, int wire)
151 {
152   int wall_facets = dc->wall_facets / (facetted ? 10 : 1);
153   GLfloat th;
154   GLfloat max_th = M_PI * 2 * dc->turns;
155   GLfloat th_inc = M_PI * 2 / wall_facets;
156
157   GLfloat x1=0,  y1=0,  x2=0,  y2=0;
158   GLfloat x1b=0, y1b=0, x2b=0, y2b=0;
159   GLfloat z1=0, z2=0;
160   GLfloat h1=0, h2=0;
161   GLfloat h1off=0, h2off=0;
162   GLfloat z_inc = dc->turn_spacing / wall_facets;
163
164   th  = 0;
165   x1  = 1;
166   y1  = 0;
167   x1b = 1 - dc->wall_thickness;
168   y1b = 0;
169
170   z1 = -(dc->turn_spacing * dc->turns / 2);
171
172   h1    = (dc->wall_taper > 0 ? 0 : dc->wall_height / 2);
173   h1off = (dc->wall_taper > 0 ?    -dc->wall_height / 2 : 0);
174
175   if (!dc->clockwise)
176     z1 = -z1, z_inc = -z_inc, h1off = -h1off;
177
178   /* Leading end-cap
179    */
180   if (!wire && h1 > 0)
181     {
182       GLfloat nx, ny;
183       glFrontFace(GL_CCW);
184       glBegin(GL_QUADS);
185       nx = cos (th + M_PI/2);
186       ny = sin (th + M_PI/2);
187       glNormal3f(nx, ny, 0);
188       glVertex3f( x1, y1,  z1 - h1 + h1off);
189       glVertex3f( x1, y1,  z1 + h1 + h1off);
190       glVertex3f(x1b, y1b, z1 + h1 + h1off);
191       glVertex3f(x1b, y1b, z1 - h1 + h1off);
192       glEnd();
193     }
194
195   while (th + th_inc <= max_th)
196     {
197       th += th_inc;
198
199       x2 = cos (th);
200       y2 = sin (th);
201       z2 = z1 + z_inc;
202       x2b = x2 * (1 - dc->wall_thickness);
203       y2b = y2 * (1 - dc->wall_thickness);
204
205       h2 = h1;
206       h2off = h1off;
207
208       if (dc->wall_taper > 0)
209         {
210           h2off = 0;
211           if (th < dc->wall_taper)
212             {
213               h2 = dc->wall_height/2 * cos (M_PI / 2
214                                             * (1 - (th / dc->wall_taper)));
215               if (dc->clockwise)
216                 h2off = h2 - dc->wall_height/2;
217               else
218                 h2off = dc->wall_height/2 - h2;
219             }
220           else if (th >= max_th - dc->wall_taper)
221             {
222               if (th + th_inc > max_th) /* edge case: always come to a point */
223                 h2 = 0;
224               else
225                 h2 = dc->wall_height/2 * cos (M_PI / 2
226                                               * (1 - ((max_th - th)
227                                                       / dc->wall_taper)));
228               if (dc->clockwise)
229                 h2off = dc->wall_height/2 - h2;
230               else
231                 h2off = h2 - dc->wall_height/2;
232             }
233         }
234
235       /* outer face
236        */
237       glFrontFace(GL_CW);
238       glBegin(wire ? GL_LINES : GL_QUADS);
239       glNormal3f(x1, y1, 0);
240       glVertex3f(x1, y1, z1 - h1 + h1off);
241       glVertex3f(x1, y1, z1 + h1 + h1off);
242       glNormal3f(x2, y2, 0);
243       glVertex3f(x2, y2, z2 + h2 + h2off);
244       glVertex3f(x2, y2, z2 - h2 + h2off);
245       glEnd();
246
247       /* inner face
248        */
249       glFrontFace(GL_CCW);
250       glBegin(wire ? GL_LINES : GL_QUADS);
251       glNormal3f(-x1b, -y1b, 0);
252       glVertex3f( x1b,  y1b, z1 - h1 + h1off);
253       glVertex3f( x1b,  y1b, z1 + h1 + h1off);
254       glNormal3f(-x2b, -y2b, 0);
255       glVertex3f( x2b,  y2b, z2 + h2 + h2off);
256       glVertex3f( x2b,  y2b, z2 - h2 + h2off);
257       glEnd();
258
259       /* top face
260        */
261       glFrontFace(GL_CCW);
262       /* glNormal3f(0, 0, 1);*/
263       do_normal (x2,   y2,  z2 + h2 + h2off,
264                  x2b,  y2b, z2 + h2 + h2off,
265                  x1b,  y1b, z1 + h1 + h1off);
266       glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
267       glVertex3f( x2,   y2,  z2 + h2 + h2off);
268       glVertex3f( x2b,  y2b, z2 + h2 + h2off);
269       glVertex3f( x1b,  y1b, z1 + h1 + h1off);
270       glVertex3f( x1,   y1,  z1 + h1 + h1off);
271
272       glEnd();
273
274       /* bottom face
275        */
276       glFrontFace(GL_CCW);
277       do_normal ( x1,   y1,  z1 - h1 + h1off,
278                   x1b,  y1b, z1 - h1 + h1off,
279                   x2b,  y2b, z2 - h2 + h2off);
280       glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
281       glNormal3f(0, 0, -1);
282       glVertex3f( x1,   y1,  z1 - h1 + h1off);
283       glVertex3f( x1b,  y1b, z1 - h1 + h1off);
284       glVertex3f( x2b,  y2b, z2 - h2 + h2off);
285       glVertex3f( x2,   y2,  z2 - h2 + h2off);
286       glEnd();
287
288       x1 = x2;
289       y1 = y2;
290       x1b = x2b;
291       y1b = y2b;
292       z1 += z_inc;
293       h1 = h2;
294       h1off = h2off;
295     }
296
297   /* Trailing end-cap
298    */
299   if (!wire && h2 > 0)
300     {
301       GLfloat nx, ny;
302       glFrontFace(GL_CW);
303       glBegin(GL_QUADS);
304       nx = cos (th + M_PI/2);
305       ny = sin (th + M_PI/2);
306       glNormal3f(nx, ny, 0);
307       glVertex3f(x2,  y2,  z1 - h2 + h2off);
308       glVertex3f(x2,  y2,  z1 + h2 + h2off);
309       glVertex3f(x2b, y2b, z1 + h2 + h2off);
310       glVertex3f(x2b, y2b, z1 - h2 + h2off);
311       glEnd();
312     }
313 }
314
315
316 static void
317 make_ladder (logo_configuration *dc, int facetted, int wire)
318 {
319   GLfloat th;
320   GLfloat max_th = dc->turns * M_PI * 2;
321   GLfloat max_z  = dc->turns * dc->turn_spacing;
322   GLfloat z_inc  = dc->bar_spacing;
323   GLfloat th_inc = M_PI * 2 * (dc->bar_spacing / dc->turn_spacing);
324   GLfloat x, y, z;
325
326   /* skip forward to center the bars in the helix... */
327   int i;
328   GLfloat usable_th = max_th - dc->wall_taper;
329   GLfloat usable_z  = max_z / (max_th / usable_th);
330   int nbars = usable_z / dc->bar_spacing;
331   GLfloat used_z, pad_z, pad_ratio;
332
333   if (! (nbars & 1)) nbars--;  /* always an odd number of bars */
334
335   used_z = (nbars - 1) * dc->bar_spacing;
336   pad_z = max_z - used_z;
337   pad_ratio = pad_z / max_z;
338
339   th = (max_th * pad_ratio/2);
340   z  = -(max_z / 2) + (max_z * pad_ratio/2);
341
342   if (!dc->clockwise)
343     z = -z, z_inc = -z_inc;
344
345   for (i = 0; i < nbars; i++)
346     {
347       int facets = dc->bar_facets / (facetted ? 14 : 1);
348       if (facets <= 3) facets = 3;
349       x = cos (th) * (1 - dc->wall_thickness);
350       y = sin (th) * (1 - dc->wall_thickness);
351       tube ( x,  y, z,
352             -x, -y, z,
353              dc->bar_thickness, 0, facets,
354              True, True, wire);
355       z  += z_inc;
356       th += th_inc;
357     }
358 }
359
360
361 \f
362 /* Make the gasket
363  */
364
365
366 static void
367 make_gasket (logo_configuration *dc, int wire)
368 {
369   int i;
370   int points_size;
371   int npoints = 0;
372   int nctrls = 0;
373   int res = 360/8;
374   GLfloat d2r = M_PI / 180;
375
376   GLfloat thick2 = (dc->gasket_thickness / dc->gasket_size) / 2;
377
378   GLfloat *pointsx0, *pointsy0, *pointsx1, *pointsy1, *normals;
379
380   GLfloat r0  = 0.750;  /* 395 */
381   GLfloat r1a = 0.825;                /* bottom of wall below upper left hole */
382   GLfloat r1b = 0.867;                /* center of upper left hole */
383   GLfloat r1c = 0.909;                /* top of wall above hole */
384   GLfloat r1  = 0.916;  /* 471 */
385   GLfloat r2  = 0.963;  /* 490 */
386   GLfloat r3  = 0.960;  /* 499 */
387   GLfloat r4  = 1.000;  /* 507 */
388   GLfloat r5  = 1.080;  /* 553 */
389
390   GLfloat ctrl_r[100], ctrl_th[100];
391
392   glPushMatrix();
393
394 # define POINT(r,th) \
395     ctrl_r [nctrls] = r, \
396     ctrl_th[nctrls] = (th * d2r), \
397     nctrls++
398
399   POINT (0.829, 0);      /* top indentation, right half */
400   POINT (0.831, 0.85);
401   POINT (0.835, 1.81);
402   POINT (0.841, 2.65);
403   POINT (0.851, 3.30);
404   POINT (0.862, 3.81);
405   POINT (0.872, 3.95);
406
407   POINT (r4,    4.0);   /* moving clockwise... */
408   POINT (r4,   47.0);
409   POINT (r1,   47.0);
410   POINT (r1,   53.0);
411   POINT (r2,   55.5);
412   POINT (r2,   72.3);
413   POINT (r1,   74.0);
414   POINT (r1,  100.0);
415   POINT (r3,  102.5);
416   POINT (r3,  132.0);
417   POINT (r1,  133.0);
418
419   POINT (r1,  180.7);
420   POINT (r2,  183.6);
421   POINT (r2,  210.0);
422   POINT (r1,  212.0);
423   POINT (r1,  223.2);
424   POINT (r5,  223.2);
425   POINT (r5,  225.0);
426   POINT (r4,  225.0);
427
428   POINT (r4,    316.8);      /* upper left indentation */
429   POINT (0.990, 316.87);
430   POINT (0.880, 317.21);
431   POINT (0.872, 317.45);
432   POINT (0.869, 317.80);
433   POINT (0.867, 318.10);
434
435   POINT (0.867, 318.85);
436   POINT (0.869, 319.15);
437   POINT (0.872, 319.50);
438   POINT (0.880, 319.74);
439   POINT (0.990, 320.08);
440
441   POINT (r4,  338.5);
442   if (! wire)
443     {
444       POINT (r1a, 338.5);      /* cut-out disc */
445       POINT (r1a, 343.5);
446     }
447   POINT (r4,  343.5);
448   POINT (r4,  356.0);
449
450   POINT (0.872, 356.05);   /* top indentation, left half */
451   POINT (0.862, 356.19);
452   POINT (0.851, 356.70);
453   POINT (0.841, 357.35);
454   POINT (0.835, 358.19);
455   POINT (0.831, 359.15);
456   POINT (0.829, 360);
457 # undef POINT
458
459   points_size = res + (nctrls * 2);
460   pointsx0 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
461   pointsy0 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
462   pointsx1 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
463   pointsy1 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
464   normals  = (GLfloat *) malloc (points_size * sizeof(GLfloat) * 2);
465
466   npoints = 0;
467   for (i = 1; i < nctrls; i++)
468     {
469       GLfloat from_r  = ctrl_r [i-1];
470       GLfloat from_th = ctrl_th[i-1];
471       GLfloat to_r    = ctrl_r [i];
472       GLfloat to_th   = ctrl_th[i];
473
474       GLfloat step = 2*M_PI / res;
475       int nsteps = 1 + ((to_th - from_th) / step);
476       int j;
477
478       for (j = 0; j < nsteps + (i == nctrls-1); j++)
479         {
480           GLfloat r  = from_r  + (j * (to_r  - from_r)  / nsteps);
481           GLfloat th = from_th + (j * (to_th - from_th) / nsteps);
482
483           GLfloat cth = cos(th) * dc->gasket_size;
484           GLfloat sth = sin(th) * dc->gasket_size;
485
486           pointsx0[npoints] = r0 * cth;  /* inner ring */
487           pointsy0[npoints] = r0 * sth;
488           pointsx1[npoints] = r  * cth;  /* outer ring */
489           pointsy1[npoints] = r  * sth;
490           npoints++;
491
492           if (npoints >= points_size) abort();
493         }
494     }
495
496   /* normals for the outer ring */
497   for (i = 1; i < npoints; i++)
498     {
499       XYZ a, b, c, n;
500       a.x = pointsx1[i-1];
501       a.y = pointsy1[i-1];
502       a.z = 0;
503       b.x = pointsx1[i];
504       b.y = pointsy1[i];
505       b.z = 0;
506       c = b;
507       c.z = 1;
508       n = calc_normal (a, b, c);
509       normals[(i-1)*2  ] = n.x;
510       normals[(i-1)*2+1] = n.y;
511     }
512
513   glRotatef(-90, 0, 1, 0);
514   glRotatef(180, 0, 0, 1);
515
516   if (wire)
517     {
518       GLfloat z;
519       for (z = -thick2; z <= thick2; z += thick2*2)
520         {
521 # if 1
522           /* inside edge */
523           glBegin (GL_LINE_LOOP);
524           for (i = 0; i < npoints; i++)
525             glVertex3f (pointsx0[i], pointsy0[i], z);
526           glEnd();
527
528           /* outside edge */
529           glBegin (GL_LINE_LOOP);
530           for (i = 0; i < npoints; i++)
531             glVertex3f (pointsx1[i], pointsy1[i], z);
532           glEnd();
533 # else
534           for (i = 1; i < npoints; i++)
535             {
536               glBegin (GL_LINE_STRIP);
537               glVertex3f (pointsx0[i-1], pointsy0[i-1], z);
538               glVertex3f (pointsx0[i  ], pointsy0[i  ], z);
539               glVertex3f (pointsx1[i  ], pointsy1[i  ], z);
540               glVertex3f (pointsx1[i-1], pointsy1[i-1], z);
541               glEnd();
542             }
543 # endif
544         }
545 #if 1
546       glBegin (GL_LINES);
547       for (i = 0; i < npoints; i++)
548         {
549           /* inside rim */
550           glVertex3f (pointsx0[i], pointsy0[i], -thick2);
551           glVertex3f (pointsx0[i], pointsy0[i],  thick2);
552           /* outside rim */
553           glVertex3f (pointsx1[i], pointsy1[i], -thick2);
554           glVertex3f (pointsx1[i], pointsy1[i],  thick2);
555         }
556       glEnd();
557 #endif
558     }
559   else
560     {
561       /* top */
562       glFrontFace(GL_CW);
563       glNormal3f(0, 0, -1);
564       glBegin (GL_QUAD_STRIP);
565       for (i = 0; i < npoints; i++)
566         {
567           glVertex3f (pointsx0[i], pointsy0[i], -thick2);
568           glVertex3f (pointsx1[i], pointsy1[i], -thick2);
569         }
570       glEnd();
571
572       /* bottom */
573       glFrontFace(GL_CCW);
574       glNormal3f(0, 0, 1);
575       glBegin (GL_QUAD_STRIP);
576       for (i = 0; i < npoints; i++)
577         {
578           glVertex3f (pointsx0[i], pointsy0[i], thick2);
579           glVertex3f (pointsx1[i], pointsy1[i], thick2);
580         }
581       glEnd();
582
583       /* inside edge */
584       glFrontFace(GL_CW);
585       glBegin (GL_QUAD_STRIP);
586       for (i = 0; i < npoints; i++)
587         {
588           glNormal3f (-pointsx0[i], -pointsy0[i],  0);
589           glVertex3f ( pointsx0[i],  pointsy0[i],  thick2);
590           glVertex3f ( pointsx0[i],  pointsy0[i], -thick2);
591         }
592       glEnd();
593
594       /* outside edge */
595       glFrontFace(GL_CCW);
596       glBegin (GL_QUADS);
597       {
598         for (i = 0; i < npoints-1; i++)
599           {
600             int ia = (i == 0 ? npoints-2 : i-1);
601             int iz = (i == npoints-2 ? 0 : i+1);
602             GLfloat  x = pointsx1[i];
603             GLfloat  y = pointsy1[i];
604             GLfloat xz = pointsx1[iz];
605             GLfloat yz = pointsy1[iz];
606
607             GLfloat nxa = normals[ia*2];   /* normal of [i-1 - i] face */
608             GLfloat nya = normals[ia*2+1];
609             GLfloat nx  = normals[i*2];    /* normal of [i - i+1] face */
610             GLfloat ny  = normals[i*2+1];
611             GLfloat nxz = normals[iz*2];    /* normal of [i+1 - i+2] face */
612             GLfloat nyz = normals[iz*2+1];
613
614             GLfloat anglea = vector_angle (nx, ny, 0, nxa, nya, 0);
615             GLfloat anglez = vector_angle (nx, ny, 0, nxz, nyz, 0);
616             GLfloat pointy = 0.005;
617
618             if (anglea > pointy)
619               {
620                 glNormal3f (nx, ny, 0);
621                 glVertex3f (x,  y,   thick2);
622                 glVertex3f (x,  y,  -thick2);
623               }
624             else
625               {
626                 glNormal3f ((nxa + nx) / 2, (nya + ny) / 2, 0);
627                 glVertex3f (x,  y,   thick2);
628                 glVertex3f (x,  y,  -thick2);
629               }
630
631             if (anglez > pointy)
632               {
633                 glNormal3f (nx, ny, 0);
634                 glVertex3f (xz, yz, -thick2);
635                 glVertex3f (xz, yz,  thick2);
636               }
637             else
638               {
639                 glNormal3f ((nx + nxz) / 2, (ny + nyz) / 2, 0);
640                 glVertex3f (xz, yz, -thick2);
641                 glVertex3f (xz, yz,  thick2);
642               }
643           }
644       }
645       glEnd();
646     }
647
648   /* Fill in the upper left hole...
649    */
650   {
651     GLfloat th;
652     npoints = 0;
653
654     th = 338.5 * d2r;
655     pointsx0[npoints] = r1c * cos(th) * dc->gasket_size;
656     pointsy0[npoints] = r1c * sin(th) * dc->gasket_size;
657     npoints++;
658     pointsx0[npoints] = r4 * cos(th) * dc->gasket_size;
659     pointsy0[npoints] = r4 * sin(th) * dc->gasket_size;
660     npoints++;
661
662     th = 343.5 * d2r;
663     pointsx0[npoints] = r1c * cos(th) * dc->gasket_size;
664     pointsy0[npoints] = r1c * sin(th) * dc->gasket_size;
665     npoints++;
666     pointsx0[npoints] = r4 * cos(th) * dc->gasket_size;
667     pointsy0[npoints] = r4 * sin(th) * dc->gasket_size;
668     npoints++;
669
670     if (! wire)
671       {
672         /* front wall */
673         glNormal3f (0, 0, -1);
674         glFrontFace(GL_CW);
675         glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
676         glVertex3f (pointsx0[0], pointsy0[0], -thick2);
677         glVertex3f (pointsx0[1], pointsy0[1], -thick2);
678         glVertex3f (pointsx0[3], pointsy0[3], -thick2);
679         glVertex3f (pointsx0[2], pointsy0[2], -thick2);
680         glEnd();
681
682         /* back wall */
683         glNormal3f (0, 0, 1);
684         glFrontFace(GL_CCW);
685         glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
686         glVertex3f (pointsx0[0], pointsy0[0],  thick2);
687         glVertex3f (pointsx0[1], pointsy0[1],  thick2);
688         glVertex3f (pointsx0[3], pointsy0[3],  thick2);
689         glVertex3f (pointsx0[2], pointsy0[2],  thick2);
690         glEnd();
691       }
692
693     /* top wall */
694     glFrontFace(GL_CW);
695     glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
696     glNormal3f (pointsx0[1], pointsy0[1], 0);
697     glVertex3f (pointsx0[1], pointsy0[1],  thick2);
698     glNormal3f (pointsx0[3], pointsy0[3], 0);
699     glVertex3f (pointsx0[3], pointsy0[3],  thick2);
700     glVertex3f (pointsx0[3], pointsy0[3], -thick2);
701     glNormal3f (pointsx0[1], pointsy0[1], 0);
702     glVertex3f (pointsx0[1], pointsy0[1], -thick2);
703     glEnd();
704
705
706     /* Now make a donut.
707      */
708     {
709       int nsteps = 12;
710       GLfloat r0 = 0.04;
711       GLfloat r1 = 0.060;
712       GLfloat th, cth, sth;
713
714       glPushMatrix ();
715
716       th = ((339.0 + 343.0) / 2) * d2r;
717       
718       glTranslatef (r1b * cos(th) * dc->gasket_size,
719                     r1b * sin(th) * dc->gasket_size,
720                     0);
721
722       npoints = 0;
723       for (i = 0; i < nsteps; i++)
724         {
725           th = 2 * M_PI * i / nsteps;
726           cth = cos (th) * dc->gasket_size;
727           sth = sin (th) * dc->gasket_size;
728           pointsx0[npoints] = r0 * cth;
729           pointsy0[npoints] = r0 * sth;
730           pointsx1[npoints] = r1 * cth;
731           pointsy1[npoints] = r1 * sth;
732           npoints++;
733         }
734
735       pointsx0[npoints] = pointsx0[0];
736       pointsy0[npoints] = pointsy0[0];
737       pointsx1[npoints] = pointsx1[0];
738       pointsy1[npoints] = pointsy1[0];
739       npoints++;
740
741       if (wire)
742         {
743           glBegin (GL_LINE_LOOP);
744           for (i = 0; i < npoints; i++)
745             glVertex3f (pointsx0[i], pointsy0[i], -thick2);
746           glEnd();
747           glBegin (GL_LINE_LOOP);
748           for (i = 0; i < npoints; i++)
749             glVertex3f (pointsx0[i], pointsy0[i],  thick2);
750           glEnd();
751 # if 0
752           glBegin (GL_LINE_LOOP);
753           for (i = 0; i < npoints; i++)
754             glVertex3f (pointsx1[i], pointsy1[i], -thick2);
755           glEnd();
756           glBegin (GL_LINE_LOOP);
757           for (i = 0; i < npoints; i++)
758             glVertex3f (pointsx1[i], pointsy1[i],  thick2);
759           glEnd();
760 # endif
761         }
762       else
763         {
764           /* top */
765           glFrontFace(GL_CW);
766           glNormal3f(0, 0, -1);
767           glBegin (GL_QUAD_STRIP);
768           for (i = 0; i < npoints; i++)
769             {
770               glVertex3f (pointsx0[i], pointsy0[i], -thick2);
771               glVertex3f (pointsx1[i], pointsy1[i], -thick2);
772             }
773           glEnd();
774
775           /* bottom */
776           glFrontFace(GL_CCW);
777           glNormal3f(0, 0, 1);
778           glBegin (GL_QUAD_STRIP);
779           for (i = 0; i < npoints; i++)
780             {
781               glVertex3f (pointsx0[i], pointsy0[i],  thick2);
782               glVertex3f (pointsx1[i], pointsy1[i],  thick2);
783             }
784           glEnd();
785         }
786
787       /* inside edge */
788       glFrontFace(GL_CW);
789       glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
790       for (i = 0; i < npoints; i++)
791         {
792           glNormal3f (-pointsx0[i], -pointsy0[i],  0);
793           glVertex3f ( pointsx0[i],  pointsy0[i],  thick2);
794           glVertex3f ( pointsx0[i],  pointsy0[i], -thick2);
795         }
796       glEnd();
797
798       glPopMatrix();
799     }
800   }
801
802
803   /* Attach the bottom-right dingus...
804    */
805   {
806     GLfloat w = 0.05;
807     GLfloat h = 0.19;
808     GLfloat th;
809
810     glRotatef (49.5, 0, 0, 1);
811     glScalef (dc->gasket_size, dc->gasket_size, 1);
812     glTranslatef (0, (r0+r1)/2, 0);
813
814     /* buried box */
815     if (! wire)
816       {
817         glFrontFace(GL_CCW);
818         glBegin (wire ? GL_LINE_STRIP : GL_QUADS);
819         glNormal3f (0, 0, -1);
820         glVertex3f (-w/2, -h/2, -thick2); glVertex3f (-w/2,  h/2, -thick2);
821         glVertex3f ( w/2,  h/2, -thick2); glVertex3f ( w/2, -h/2, -thick2);
822         glNormal3f (1, 0, 0);
823         glVertex3f ( w/2, -h/2, -thick2); glVertex3f ( w/2,  h/2, -thick2);
824         glVertex3f ( w/2,  h/2,  thick2); glVertex3f ( w/2, -h/2,  thick2);
825         glNormal3f (0, 0, 1);
826         glVertex3f ( w/2, -h/2,  thick2); glVertex3f ( w/2,  h/2,  thick2);
827         glVertex3f (-w/2,  h/2,  thick2); glVertex3f (-w/2, -h/2,  thick2);
828         glNormal3f (-1, 0, 0);
829         glVertex3f (-w/2, -h/2,  thick2); glVertex3f (-w/2,  h/2,  thick2);
830         glVertex3f (-w/2,  h/2, -thick2); glVertex3f (-w/2, -h/2, -thick2);
831         glEnd();
832       }
833
834     npoints = 0;
835     for (th = 0; th < M_PI; th += (M_PI / 6))
836       {
837         pointsx0[npoints] = w/2 * cos(th);
838         pointsy0[npoints] = w/2 * sin(th);
839         npoints++;
840       }
841
842     /* front inside curve */
843     glNormal3f (0, 0, -1);
844     glFrontFace(GL_CW);
845     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
846     if (! wire) glVertex3f (0, h/2, -thick2);
847     for (i = 0; i < npoints; i++)
848       glVertex3f (pointsx0[i], h/2 + pointsy0[i], -thick2);
849     glEnd();
850
851     /* front outside curve */
852     glFrontFace(GL_CCW);
853     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
854     if (! wire) glVertex3f (0, -h/2, -thick2);
855     for (i = 0; i < npoints; i++)
856       glVertex3f (pointsx0[i], -h/2 - pointsy0[i], -thick2);
857     glEnd();
858
859     /* back inside curve */
860     glNormal3f (0, 0, 1);
861     glFrontFace(GL_CCW);
862     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
863     if (! wire) glVertex3f (0, h/2, thick2);
864     for (i = 0; i < npoints; i++)
865       glVertex3f (pointsx0[i], h/2 + pointsy0[i], thick2);
866     glEnd();
867
868     /* back outside curve */
869     glFrontFace(GL_CW);
870     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
871     if (! wire) glVertex3f (0, -h/2, thick2);
872     for (i = 0; i < npoints; i++)
873       glVertex3f (pointsx0[i], -h/2 - pointsy0[i], thick2);
874     glEnd();
875
876     /* inside curve */
877     glFrontFace(GL_CCW);
878     glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
879     for (i = 0; i < npoints; i++)
880       {
881         glNormal3f (pointsx0[i], pointsy0[i], 0);
882         glVertex3f (pointsx0[i], h/2 + pointsy0[i],  thick2);
883         glVertex3f (pointsx0[i], h/2 + pointsy0[i], -thick2);
884       }
885     glEnd();
886
887     /* outside curve */
888     glFrontFace(GL_CW);
889     glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
890     for (i = 0; i < npoints; i++)
891       {
892         glNormal3f (pointsx0[i], -pointsy0[i], 0);
893         glVertex3f (pointsx0[i], -h/2 - pointsy0[i],  thick2);
894         glVertex3f (pointsx0[i], -h/2 - pointsy0[i], -thick2);
895       }
896     glEnd();
897   }
898
899   free (pointsx0);
900   free (pointsy0);
901   free (pointsx1);
902   free (pointsy1);
903   free (normals);
904
905   glPopMatrix();
906 }
907
908 static void
909 make_frame (logo_configuration *dc, int wire)
910 {
911   int i, j;
912   GLfloat x[20], y[20];
913   GLfloat corner_cut = 0.5;
914
915   glPushMatrix();
916   glRotatef (90, 0, 1, 0);
917   glScalef (4 * dc->frame_size,
918             4 * dc->frame_size,
919             4 * dc->frame_size);
920
921   x[0] = -dc->frame_thickness;
922   x[1] = -dc->frame_thickness * corner_cut;
923   x[2] = 0;
924   x[3] = 0.5 - dc->triangle_size;
925   x[4] = 0.5;
926   x[5] = 0.5 + dc->triangle_size;
927   x[6] = 1;
928   x[7] = 1 + dc->frame_thickness * corner_cut;
929   x[8] = 1 + dc->frame_thickness;
930
931   y[0] = -dc->frame_thickness;
932   y[1] = -dc->frame_thickness * corner_cut;
933   y[2] = 0;
934   y[3] = dc->triangle_size;
935
936   /* front and back
937    */
938   glTranslatef (-0.5, -0.5, dc->frame_depth / 4);
939   if (! wire)
940     for (j = 0; j <= 1; j++)
941       {
942         if (j) glTranslatef (0, 0, -dc->frame_depth / 2);
943         glFrontFace (j ? GL_CCW : GL_CW);
944         for (i = 0; i < 4; i++)
945           {
946             glNormal3f (0, 0, (j ? -1 : 1));
947             glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
948             glVertex3f (x[0], y[1], 0); glVertex3f (x[0], y[2], 0);
949             glVertex3f (x[1], y[0], 0); glVertex3f (x[1], y[2], 0);
950             glVertex3f (x[3], y[0], 0); glVertex3f (x[3], y[2], 0);
951             glVertex3f (x[4], y[0], 0); glVertex3f (x[4], y[3], 0);
952             glVertex3f (x[5], y[0], 0); glVertex3f (x[5], y[2], 0); 
953             glVertex3f (x[7], y[0], 0); glVertex3f (x[7], y[2], 0);
954             glVertex3f (x[8], y[1], 0); glVertex3f (x[8], y[2], 0);
955             glEnd ();
956             glTranslatef (0.5, 0.5, 0);
957             glRotatef (90, 0, 0, 1);
958             glTranslatef (-0.5, -0.5, 0);
959           }
960       }
961
962   /* ledges
963    */
964   glFrontFace (GL_CCW);
965   for (i = 0; i < 4; i++)
966     {
967       glNormal3f (0, 1, 0);
968       glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
969       glVertex3f (x[2], y[2], 0); glVertex3f (x[2], y[2], dc->frame_depth/2); 
970       glVertex3f (x[3], y[2], 0); glVertex3f (x[3], y[2], dc->frame_depth/2); 
971       glVertex3f (x[4], y[3], 0); glVertex3f (x[4], y[3], dc->frame_depth/2); 
972       glVertex3f (x[5], y[2], 0); glVertex3f (x[5], y[2], dc->frame_depth/2); 
973       glVertex3f (x[6], y[2], 0); glVertex3f (x[6], y[2], dc->frame_depth/2); 
974       glEnd ();
975
976       glNormal3f (0, -1, 0);
977       glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
978       glVertex3f (x[7], y[0], 0); 
979       glVertex3f (x[7], y[0], dc->frame_depth/2); 
980       glVertex3f (x[1], y[0], dc->frame_depth/2); 
981       glVertex3f (x[1], y[0], 0); 
982       glEnd ();
983
984       glNormal3f (1, -1, 0);
985       glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
986       glVertex3f (x[8], y[1], 0); 
987       glVertex3f (x[8], y[1], dc->frame_depth/2); 
988       glVertex3f (x[7], y[0], dc->frame_depth/2); 
989       glVertex3f (x[7], y[0], 0); 
990       glEnd ();
991
992       if (wire) 
993         {
994           glNormal3f (0, 1, 0);
995           for (j = 0; j <= 1; j++)
996             {
997               glBegin (GL_LINE_STRIP);
998               glVertex3f (x[2], y[2], j*dc->frame_depth/2);
999               glVertex3f (x[3], y[2], j*dc->frame_depth/2);
1000               glVertex3f (x[4], y[3], j*dc->frame_depth/2);
1001               glVertex3f (x[5], y[2], j*dc->frame_depth/2);
1002               glVertex3f (x[6], y[2], j*dc->frame_depth/2);
1003               glEnd ();
1004             }
1005         }
1006
1007       glTranslatef (0.5, 0.5, 0);
1008       glRotatef (90, 0, 0, 1);
1009       glTranslatef (-0.5, -0.5, 0);
1010     }
1011
1012   glPopMatrix();
1013 }
1014
1015
1016 \f
1017 /* Window management, etc
1018  */
1019 ENTRYPOINT void
1020 reshape_logo (ModeInfo *mi, int width, int height)
1021 {
1022   GLfloat h = (GLfloat) height / (GLfloat) width;
1023
1024   glViewport (0, 0, (GLint) width, (GLint) height);
1025
1026   glMatrixMode(GL_PROJECTION);
1027   glLoadIdentity();
1028   gluPerspective (30.0, 1/h, 1.0, 100.0);
1029
1030   glMatrixMode(GL_MODELVIEW);
1031   glLoadIdentity();
1032   gluLookAt( 0.0, 0.0, 30.0,
1033              0.0, 0.0, 0.0,
1034              0.0, 1.0, 0.0);
1035
1036   glClear(GL_COLOR_BUFFER_BIT);
1037 }
1038
1039
1040 static void
1041 gl_init (ModeInfo *mi)
1042 {
1043 /*  logo_configuration *dc = &dcs[MI_SCREEN(mi)]; */
1044   int wire = MI_IS_WIREFRAME(mi);
1045
1046   GLfloat position[]  = {0, 0, 0, 0};
1047   GLfloat direction[] = {3, -1, -3};
1048
1049   position[0] = -direction[0];
1050   position[1] = -direction[1];
1051   position[2] = -direction[2];
1052
1053   if (!wire)
1054     {
1055       glLightfv(GL_LIGHT0, GL_POSITION, position);
1056       glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direction);
1057       glShadeModel(GL_SMOOTH);
1058       glEnable(GL_NORMALIZE);
1059       glEnable(GL_CULL_FACE);
1060       glEnable(GL_LIGHTING);
1061       glEnable(GL_LIGHT0);
1062       glEnable(GL_DEPTH_TEST);
1063     }
1064 }
1065
1066
1067 ENTRYPOINT void 
1068 init_logo (ModeInfo *mi)
1069 {
1070   logo_configuration *dc;
1071   int do_gasket = get_boolean_resource(mi->dpy, "doGasket", "Boolean");
1072   int do_helix = get_boolean_resource(mi->dpy, "doHelix", "Boolean");
1073   int do_ladder = (do_helix && 
1074                    get_boolean_resource(mi->dpy, "doLadder", "Boolean"));
1075   int do_frame = get_boolean_resource(mi->dpy, "doFrame", "Boolean");
1076   GLfloat helix_rot = 147.0;
1077
1078   if (!do_gasket && !do_helix)
1079     {
1080       fprintf (stderr, "%s: no helix or gasket?\n", progname);
1081       exit (1);
1082     }
1083
1084   if (!dcs) {
1085     dcs = (logo_configuration *)
1086       calloc (MI_NUM_SCREENS(mi), sizeof (logo_configuration));
1087     if (!dcs) {
1088       fprintf(stderr, "%s: out of memory\n", progname);
1089       exit(1);
1090     }
1091   }
1092
1093   dc = &dcs[MI_SCREEN(mi)];
1094
1095   if ((dc->glx_context = init_GL(mi)) != NULL) {
1096     gl_init(mi);
1097     reshape_logo (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1098   }
1099
1100   dc->wall_facets    = get_integer_resource(mi->dpy, "wallFacets",  "Integer");
1101   dc->bar_facets     = get_integer_resource(mi->dpy, "barFacets",   "Integer");
1102   dc->clockwise      = get_boolean_resource(mi->dpy, "clockwise",   "Boolean");
1103   dc->turns          = get_float_resource(mi->dpy, "turns",         "Float");
1104   dc->turn_spacing   = get_float_resource(mi->dpy, "turnSpacing",   "Float");
1105   dc->bar_spacing    = get_float_resource(mi->dpy, "barSpacing",    "Float");
1106   dc->wall_height    = get_float_resource(mi->dpy, "wallHeight",    "Float");
1107   dc->wall_thickness = get_float_resource(mi->dpy, "wallThickness", "Float");
1108   dc->bar_thickness  = get_float_resource(mi->dpy, "barThickness",  "Float");
1109   dc->wall_taper     = get_float_resource(mi->dpy, "wallTaper",     "Float");
1110
1111   dc->gasket_size      = get_float_resource(mi->dpy,"gasketSize",     "Float");
1112   dc->gasket_depth     = get_float_resource(mi->dpy,"gasketDepth",    "Float");
1113   dc->gasket_thickness = get_float_resource(mi->dpy,"gasketThickness","Float");
1114
1115   dc->frame_size      = get_float_resource(mi->dpy, "frameSize",      "Float");
1116   dc->frame_depth     = get_float_resource(mi->dpy, "frameDepth",     "Float");
1117   dc->frame_thickness = get_float_resource(mi->dpy, "frameThickness", "Float");
1118   dc->triangle_size   = get_float_resource(mi->dpy, "triangleSize",   "Float");
1119
1120   dc->speed          = get_float_resource(mi->dpy, "speed",         "Float");
1121
1122   {
1123     XColor xcolor;
1124
1125     char *color_name = get_string_resource (mi->dpy, "foreground", "Foreground");
1126     char *s2;
1127     for (s2 = color_name + strlen(color_name) - 1; s2 > color_name; s2--)
1128       if (*s2 == ' ' || *s2 == '\t')
1129         *s2 = 0;
1130       else
1131         break;
1132
1133     if (! XParseColor (MI_DISPLAY(mi), mi->xgwa.colormap, color_name, &xcolor))
1134       {
1135         fprintf (stderr, "%s: can't parse color %s\n", progname, color_name);
1136         exit (1);
1137       }
1138
1139     dc->color[0] = xcolor.red   / 65535.0;
1140     dc->color[1] = xcolor.green / 65535.0;
1141     dc->color[2] = xcolor.blue  / 65535.0;
1142     dc->color[3] = 1.0;
1143   }
1144
1145   dc->trackball = gltrackball_init ();
1146
1147   dc->gasket_spinnery.probability = 0.1;
1148   dc->gasket_spinnerx.probability = 0.1;
1149   dc->gasket_spinnerz.probability = 1.0;
1150   dc->helix_spinnerz.probability  = 0.6;
1151   dc->scene_spinnerx.probability  = 0.1;
1152   dc->scene_spinnery.probability  = 0.0;
1153   dc->frame_spinner.probability   = 5.0;
1154
1155   /* start the frame off-screen */
1156   dc->frame_spinner.spinning_p = True;
1157   dc->frame_spinner.position = 0.3;
1158   dc->frame_spinner.speed = 0.001;
1159
1160   if (dc->speed > 0)    /* start off with the gasket in motion */
1161     {
1162       dc->gasket_spinnerz.spinning_p = True;
1163       dc->gasket_spinnerz.speed = (0.002
1164                                    * ((random() & 1) ? 1 : -1)
1165                                    * dc->speed);
1166     }
1167
1168   glPushMatrix();
1169   dc->helix_list = glGenLists (1);
1170   glNewList (dc->helix_list, GL_COMPILE);
1171   glRotatef(helix_rot, 0, 0, 1);
1172   if (do_ladder) make_ladder (dc, 0, 0);
1173   if (do_helix)  make_helix  (dc, 0, 0);
1174   glRotatef(180, 0, 0, 1);
1175   if (do_helix)  make_helix  (dc, 0, 0);
1176   glEndList ();
1177   glPopMatrix();
1178
1179   glPushMatrix();
1180   dc->helix_list_wire = glGenLists (1);
1181   glNewList (dc->helix_list_wire, GL_COMPILE);
1182 /*  glRotatef(helix_rot, 0, 0, 1); wtf? */
1183   if (do_ladder) make_ladder (dc, 1, 1);
1184   if (do_helix)  make_helix  (dc, 1, 1);
1185   glRotatef(180, 0, 0, 1);
1186   if (do_helix)  make_helix  (dc, 1, 1);
1187   glEndList ();
1188   glPopMatrix();
1189
1190   glPushMatrix();
1191   dc->helix_list_facetted = glGenLists (1);
1192   glNewList (dc->helix_list_facetted, GL_COMPILE);
1193   glRotatef(helix_rot, 0, 0, 1);
1194   if (do_ladder) make_ladder (dc, 1, 0);
1195   if (do_helix)  make_helix  (dc, 1, 0);
1196   glRotatef(180, 0, 0, 1);
1197   if (do_helix)  make_helix  (dc, 1, 0);
1198   glEndList ();
1199   glPopMatrix();
1200
1201   dc->gasket_list = glGenLists (1);
1202   glNewList (dc->gasket_list, GL_COMPILE);
1203   if (do_gasket) make_gasket (dc, 0);
1204   glEndList ();
1205
1206   dc->gasket_list_wire = glGenLists (1);
1207   glNewList (dc->gasket_list_wire, GL_COMPILE);
1208   if (do_gasket) make_gasket (dc, 1);
1209   glEndList ();
1210
1211   dc->frame_list = glGenLists (1);
1212   glNewList (dc->frame_list, GL_COMPILE);
1213   if (do_frame) make_frame (dc, 0);
1214   glEndList ();
1215
1216   dc->frame_list_wire = glGenLists (1);
1217   glNewList (dc->frame_list_wire, GL_COMPILE);
1218   if (do_frame) make_frame (dc, 1);
1219   glEndList ();
1220
1221   /* When drawing both solid and wireframe objects,
1222      make sure the wireframe actually shows up! */
1223   glEnable (GL_POLYGON_OFFSET_FILL);
1224   glPolygonOffset (1.0, 1.0);
1225 }
1226
1227
1228 ENTRYPOINT Bool
1229 logo_handle_event (ModeInfo *mi, XEvent *event)
1230 {
1231   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
1232
1233   if (event->xany.type == ButtonPress &&
1234       event->xbutton.button == Button1)
1235     {
1236       dc->button_down_p = True;
1237       gltrackball_start (dc->trackball,
1238                          event->xbutton.x, event->xbutton.y,
1239                          MI_WIDTH (mi), MI_HEIGHT (mi));
1240       return True;
1241     }
1242   else if (event->xany.type == ButtonRelease &&
1243            event->xbutton.button == Button1)
1244     {
1245       dc->button_down_p = False;
1246       return True;
1247     }
1248   else if (event->xany.type == ButtonPress &&
1249            (event->xbutton.button == Button4 ||
1250             event->xbutton.button == Button5 ||
1251             event->xbutton.button == Button6 ||
1252             event->xbutton.button == Button7))
1253     {
1254       gltrackball_mousewheel (dc->trackball, event->xbutton.button, 10,
1255                               !!event->xbutton.state);
1256       return True;
1257     }
1258   else if (event->xany.type == MotionNotify &&
1259            dc->button_down_p)
1260     {
1261       gltrackball_track (dc->trackball,
1262                          event->xmotion.x, event->xmotion.y,
1263                          MI_WIDTH (mi), MI_HEIGHT (mi));
1264       return True;
1265     }
1266
1267   return False;
1268 }
1269
1270
1271 static void
1272 tick_spinner (ModeInfo *mi, spinner *s)
1273 {
1274   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
1275
1276   if (dc->speed == 0) return;
1277   if (dc->button_down_p) return;
1278
1279   if (s->spinning_p)
1280     {
1281       s->position += s->speed;
1282       if (s->position >=  1.0 || s->position <= -1.0)
1283           
1284         {
1285           s->position = 0;
1286           s->spinning_p = False;
1287         }
1288     }
1289   else if (s->probability &&
1290            (random() % (int) (PROBABILITY_SCALE / s->probability)) == 0)
1291     {
1292       GLfloat ss = 0.004;
1293       s->spinning_p = True;
1294       s->position = 0;
1295       do {
1296         s->speed = dc->speed * (frand(ss/3) + frand(ss/3) + frand(ss/3));
1297       } while (s->speed <= 0);
1298       if (random() & 1)
1299         s->speed = -s->speed;
1300     }
1301 }
1302
1303
1304 static void
1305 link_spinners (ModeInfo *mi, spinner *s0, spinner *s1)
1306 {
1307   if (s0->spinning_p && !s1->spinning_p)
1308     {
1309       GLfloat op = s1->probability;
1310       s1->probability = PROBABILITY_SCALE;
1311       tick_spinner (mi, s1);
1312       s1->probability = op;
1313     }
1314 }
1315
1316
1317 ENTRYPOINT void
1318 draw_logo (ModeInfo *mi)
1319 {
1320   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
1321   Display *dpy = MI_DISPLAY(mi);
1322   Window window = MI_WINDOW(mi);
1323   int wire = MI_IS_WIREFRAME(mi);
1324   GLfloat gcolor[4];
1325   GLfloat specular[]  = {0.8, 0.8, 0.8, 1.0};
1326   GLfloat shininess   = 50.0;
1327
1328   if (!dc->glx_context)
1329     return;
1330
1331   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(dc->glx_context));
1332
1333   if (dc->wire_overlay == 0 &&
1334       (random() % (int) (PROBABILITY_SCALE / 0.2)) == 0)
1335     dc->wire_overlay = ((random() % 200) +
1336                         (random() % 200) +
1337                         (random() % 200));
1338       
1339   tick_spinner (mi, &dc->gasket_spinnerx);
1340   tick_spinner (mi, &dc->gasket_spinnery);
1341   tick_spinner (mi, &dc->gasket_spinnerz);
1342   tick_spinner (mi, &dc->helix_spinnerz);
1343   tick_spinner (mi, &dc->scene_spinnerx);
1344   tick_spinner (mi, &dc->scene_spinnery);
1345   tick_spinner (mi, &dc->frame_spinner);
1346   link_spinners (mi, &dc->scene_spinnerx, &dc->scene_spinnery);
1347
1348   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1349
1350   glPushMatrix ();
1351   {
1352     glScalef(3, 3, 3);
1353
1354     glColor3f(dc->color[0], dc->color[1], dc->color[2]);
1355
1356     /* Draw frame before trackball rotation */
1357     {
1358       GLfloat p = (dc->frame_spinner.position >= 0
1359                    ? dc->frame_spinner.position
1360                    : -dc->frame_spinner.position);
1361       GLfloat size = (p > 0.5 ? 1-p : p);
1362       GLfloat scale = 1 + (size * 10);
1363       glPushMatrix();
1364       /* gltrackball_rotate (dc->trackball); */
1365       glRotatef(90, 1, 0, 0);
1366       glRotatef(90, 0, 0, 1);
1367
1368       glScalef (1, scale, scale);
1369       if (wire)
1370         glCallList (dc->frame_list_wire);
1371       else if (dc->wire_overlay != 0)
1372         {
1373           glCallList (dc->frame_list);
1374           glDisable (GL_LIGHTING);
1375           glCallList (dc->frame_list_wire);
1376           if (!wire) glEnable (GL_LIGHTING);
1377         }
1378       else
1379         glCallList (dc->frame_list);
1380       glPopMatrix();
1381     }
1382
1383     gltrackball_rotate (dc->trackball);
1384
1385     glRotatef(90, 1, 0, 0);
1386     glRotatef(90, 0, 0, 1);
1387
1388     glRotatef (360 * sin (M_PI/2 * dc->scene_spinnerx.position), 0, 1, 0);
1389     glRotatef (360 * sin (M_PI/2 * dc->scene_spinnery.position), 0, 0, 1);
1390
1391     glPushMatrix();
1392     {
1393       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnerx.position), 0, 1, 0);
1394       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnery.position), 0, 0, 1);
1395       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnerz.position), 1, 0, 0);
1396
1397       memcpy (gcolor, dc->color, sizeof (dc->color));
1398       if (dc->wire_overlay != 0)
1399         {
1400           gcolor[0]   = gcolor[1]   = gcolor[2]   = 0;
1401           specular[0] = specular[1] = specular[2] = 0;
1402           shininess = 0;
1403         }
1404       glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gcolor);
1405       glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,  specular);
1406       glMaterialf  (GL_FRONT_AND_BACK, GL_SHININESS, shininess);
1407
1408       if (wire)
1409         glCallList (dc->gasket_list_wire);
1410       else if (dc->wire_overlay != 0)
1411         {
1412           glCallList (dc->gasket_list);
1413           glDisable (GL_LIGHTING);
1414           glCallList (dc->gasket_list_wire);
1415           if (!wire) glEnable (GL_LIGHTING);
1416         }
1417       else
1418         glCallList (dc->gasket_list);
1419     }
1420     glPopMatrix();
1421
1422     glRotatef (360 * sin (M_PI/2 * dc->helix_spinnerz.position), 0, 0, 1);
1423
1424     if (wire)
1425       glCallList (dc->helix_list_wire);
1426     else if (dc->wire_overlay != 0)
1427       {
1428         glCallList (dc->helix_list_facetted);
1429         glDisable (GL_LIGHTING);
1430         glCallList (dc->helix_list_wire);
1431         if (!wire) glEnable (GL_LIGHTING);
1432       }
1433     else
1434       glCallList (dc->helix_list);
1435   }
1436   glPopMatrix();
1437
1438   if (dc->wire_overlay > 0)
1439     dc->wire_overlay--;
1440
1441   if (mi->fps_p) do_fps (mi);
1442   glFinish();
1443
1444   glXSwapBuffers(dpy, window);
1445 }
1446
1447 XSCREENSAVER_MODULE_2 ("DNAlogo", dnalogo, logo)
1448
1449 #endif /* USE_GL */