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