http://www.jwz.org/xscreensaver/xscreensaver-5.13.tar.gz
[xscreensaver] / hacks / glx / dnalogo.c
1 /* DNA Logo, Copyright (c) 2001-2011 Jamie Zawinski <jwz@jwz.org>
2  *
3  *      DNA Lounge
4  *
5  *      Restaurant -- Bar -- Nightclub -- Cafe -- Est. 1985.
6  *
7  *      375 Eleventh Street
8  *      San Francisco, CA
9  *      94103
10  *
11  *      http://www.dnalounge.com/
12  *      http://www.dnapizza.com/
13  *
14  * Permission to use, copy, modify, distribute, and sell this software and its
15  * documentation for any purpose is hereby granted without fee, provided that
16  * the above copyright notice appear in all copies and that both that
17  * copyright notice and this permission notice appear in supporting
18  * documentation.  No representations are made about the suitability of this
19  * software for any purpose.  It is provided "as is" without express or 
20  * implied warranty.
21  */
22
23 #define DEFAULTS        __extension__ \
24                         "*delay:            25000   \n" \
25                         "*showFPS:          False   \n" \
26                         "*wireframe:        False   \n" \
27                         "*doGasket:         True    \n" \
28                         "*doHelix:          True    \n" \
29                         "*doLadder:         True    \n" \
30                         "*doFrame:          True    \n" \
31                         "*wallFacets:       360     \n" \
32                         "*barFacets:        90      \n" \
33                         "*clockwise:        False   \n" \
34                         "*turns:            0.69    \n" \
35                         "*turnSpacing:      2.2     \n" \
36                         "*barSpacing:       0.24    \n" \
37                         "*wallHeight:       0.45    \n" \
38                         "*wallThickness:    0.12    \n" \
39                         "*barThickness:     0.058   \n" \
40                         "*wallTaper:        0.95    \n" \
41                         "*gasketSize:       1.88    \n" \
42                         "*gasketDepth:      0.15    \n" \
43                         "*gasketThickness:  0.4     \n" \
44                         "*frameSize:        1.20    \n" \
45                         "*frameDepth:       0.01    \n" \
46                         "*frameThickness:   0.03    \n" \
47                         "*triangleSize:     0.045   \n" \
48                         "*speed:            1.0     \n" \
49                         "*pizza:            False   \n" \
50                         ".foreground:       #00AA00 \n" \
51                         "*geometry:         =640x640\n" \
52
53 # define refresh_logo 0
54 # define release_logo 0
55 #undef countof
56 #define countof(x) (sizeof((x))/sizeof((*x)))
57
58 #ifdef DXF_OUTPUT_HACK   /* When this is defined, instead of rendering
59                             to the screen, we write a DXF CAD file to stdout.
60                             This is a kludge of shocking magnitude...
61                             Maybe there's some other way to intercept all
62                             glVertex3f calls than with a #define? */
63 # define unit_tube dxf_unit_tube
64 # define unit_cone dxf_unit_cone
65 # define tube_1    dxf_tube_1
66 # define tube      dxf_tube
67 # define cone      dxf_cone
68 #endif /* DXF_OUTPUT_HACK */
69
70 #include "xlockmore.h"
71 #include "normals.h"
72 #include "tube.h"
73 #include "rotator.h"
74 #include "gltrackball.h"
75
76 #ifdef USE_GL /* whole file */
77
78 typedef struct {
79   Bool spinning_p;
80   GLfloat position;     /* 0.0 - 1.0 */
81   GLfloat speed;        /* how far along the path (may be negative) */
82   GLfloat probability;  /* relative likelyhood to start spinning */
83 } spinner;
84
85 typedef struct {
86   GLXContext *glx_context;
87
88   GLuint helix_list,  helix_list_wire,  helix_list_facetted;
89   GLuint pizza_list,  pizza_list_wire,  pizza_list_facetted;
90   GLuint gasket_list, gasket_list_wire;
91   GLuint frame_list,  frame_list_wire;
92   int polys[7];
93
94   int wall_facets;
95   int bar_facets;
96   Bool clockwise;
97   GLfloat color[4];
98
99   GLfloat turns;
100   GLfloat turn_spacing;
101   GLfloat bar_spacing;
102   GLfloat wall_height;
103   GLfloat wall_thickness;
104   GLfloat bar_thickness;
105   GLfloat wall_taper;
106
107   GLfloat gasket_size;
108   GLfloat gasket_depth;
109   GLfloat gasket_thickness;
110
111   GLfloat frame_size;
112   GLfloat frame_depth;
113   GLfloat frame_thickness;
114   GLfloat triangle_size;
115
116   GLfloat speed;
117   Bool pizza_p;
118
119   spinner gasket_spinnerx, gasket_spinnery, gasket_spinnerz;
120   spinner scene_spinnerx,  scene_spinnery;
121   spinner helix_spinnery, helix_spinnerz;
122   spinner frame_spinner;
123
124   trackball_state *trackball;
125   Bool button_down_p;
126
127   int wire_overlay;  /* frame countdown */
128
129 } logo_configuration;
130
131 static logo_configuration *dcs = NULL;
132
133 static XrmOptionDescRec opts[] = {
134   { "-speed",  ".speed",  XrmoptionSepArg, 0 },
135   { "-pizza",  ".pizza",  XrmoptionNoArg, "True" },
136 };
137
138 ENTRYPOINT ModeSpecOpt logo_opts = {countof(opts), opts, 0, NULL, NULL};
139
140 #define PROBABILITY_SCALE 600
141
142
143 #ifdef DXF_OUTPUT_HACK
144
145 # define glBegin         dxf_glBegin
146 # define glVertex3f      dxf_glVertex3f
147 # define glVertex3dv     dxf_glVertex3dv
148 # define glEnd           dxf_glEnd
149 # define glVertexPointer dxf_glVertexPointer
150 # define glDrawArrays    dxf_glDrawArrays
151
152 static int dxf_type, dxf_point, dxf_point_total, dxf_layer, dxf_color;
153 static GLfloat dxf_quads[4*4];
154
155 static void
156 dxf_glBegin (int type)
157 {
158   dxf_type = type; 
159   dxf_point = 0;
160   dxf_point_total = 0;
161 }
162
163 static void
164 dxf_glVertex3f (GLfloat ox, GLfloat oy, GLfloat oz)
165 {
166   int i = 0;
167   GLfloat m[4*4];
168   GLfloat x, y, z;
169
170   /* Transform the point into modelview space. */
171   glGetFloatv (GL_MODELVIEW_MATRIX, m);
172   x = ox * m[0] + oy * m[4] + oz * m[8]  + m[12];
173   y = ox * m[1] + oy * m[5] + oz * m[9]  + m[13];
174   z = ox * m[2] + oy * m[6] + oz * m[10] + m[14];
175
176   dxf_quads[dxf_point*3+0] = x;
177   dxf_quads[dxf_point*3+1] = y;
178   dxf_quads[dxf_point*3+2] = z;
179   dxf_point++;
180   dxf_point_total++;
181
182   switch (dxf_type) {
183   case GL_QUADS:
184     if (dxf_point < 4) return;
185
186     fprintf (stdout, "0\n3DFACE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color);
187     fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]);
188     fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]);
189     fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]);
190
191     fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]);
192     fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]);
193     fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]);
194
195     fprintf (stdout, "12\n%.6f\n", dxf_quads[i++]);
196     fprintf (stdout, "22\n%.6f\n", dxf_quads[i++]);
197     fprintf (stdout, "32\n%.6f\n", dxf_quads[i++]);
198
199     fprintf (stdout, "13\n%.6f\n", dxf_quads[i++]);
200     fprintf (stdout, "23\n%.6f\n", dxf_quads[i++]);
201     fprintf (stdout, "33\n%.6f\n", dxf_quads[i++]);
202     dxf_point = 0;
203     break;
204
205   case GL_QUAD_STRIP:
206     if (dxf_point < 4) return;
207
208     fprintf (stdout, "0\n3DFACE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color);
209     fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]);
210     fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]);
211     fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]);
212
213     fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]);
214     fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]);
215     fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]);
216
217     fprintf (stdout, "12\n%.6f\n", dxf_quads[i+3]);  /* funky quad strip */
218     fprintf (stdout, "22\n%.6f\n", dxf_quads[i+4]);  /* vert order: 1243. */
219     fprintf (stdout, "32\n%.6f\n", dxf_quads[i+5]);
220
221     fprintf (stdout, "13\n%.6f\n", dxf_quads[i]);
222     fprintf (stdout, "23\n%.6f\n", dxf_quads[i+1]);
223     fprintf (stdout, "33\n%.6f\n", dxf_quads[i+2]);
224     i += 6;
225
226     dxf_quads[0] = dxf_quads[6];        /* copy point 3 to pos 1 */
227     dxf_quads[1] = dxf_quads[7];
228     dxf_quads[2] = dxf_quads[8];
229     dxf_quads[3] = dxf_quads[9];        /* copy point 4 to pos 2 */
230     dxf_quads[4] = dxf_quads[10];
231     dxf_quads[5] = dxf_quads[11];
232     dxf_point = 2;                      /* leave those two points in queue */
233     break;
234
235   case GL_TRIANGLES:
236   case GL_TRIANGLE_FAN:
237     if (dxf_point < 3) return;
238
239     fprintf (stdout, "0\n3DFACE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color);
240     fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]);
241     fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]);
242     fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]);
243
244     fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]);
245     fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]);
246     fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]);
247
248     fprintf (stdout, "12\n%.6f\n", dxf_quads[i++]);
249     fprintf (stdout, "22\n%.6f\n", dxf_quads[i++]);
250     fprintf (stdout, "32\n%.6f\n", dxf_quads[i++]);
251
252     i -= 3;
253     fprintf (stdout, "13\n%.6f\n", dxf_quads[i++]);  /* dup pt 4 as pt 3. */
254     fprintf (stdout, "23\n%.6f\n", dxf_quads[i++]);
255     fprintf (stdout, "33\n%.6f\n", dxf_quads[i++]);
256
257     dxf_point = 0;
258     if (dxf_type == GL_TRIANGLE_FAN)
259       {
260         dxf_quads[3] = dxf_quads[6];    /* copy point 3 to point 2 */
261         dxf_quads[4] = dxf_quads[7];
262         dxf_quads[5] = dxf_quads[8];
263         dxf_point = 2;                  /* leave two points in queue */
264       }
265     break;
266
267   case GL_TRIANGLE_STRIP:
268     if (dxf_point < 3) return;
269
270     fprintf (stdout, "0\n3DFACE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color);
271
272     fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]);
273     fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]);
274     fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]);
275
276     fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]);
277     fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]);
278     fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]);
279
280     fprintf (stdout, "12\n%.6f\n", dxf_quads[i++]);
281     fprintf (stdout, "22\n%.6f\n", dxf_quads[i++]);
282     fprintf (stdout, "32\n%.6f\n", dxf_quads[i++]);
283
284     i -= 3;
285     fprintf (stdout, "13\n%.6f\n", dxf_quads[i++]);  /* dup pt 4 as pt 3. */
286     fprintf (stdout, "23\n%.6f\n", dxf_quads[i++]);
287     fprintf (stdout, "33\n%.6f\n", dxf_quads[i++]);
288
289     dxf_quads[0] = dxf_quads[3];        /* copy point 2 to pos 1 */
290     dxf_quads[1] = dxf_quads[4];
291     dxf_quads[2] = dxf_quads[5];
292     dxf_quads[3] = dxf_quads[6];        /* copy point 3 to pos 2 */
293     dxf_quads[4] = dxf_quads[7];
294     dxf_quads[5] = dxf_quads[8];
295     dxf_point = 2;                      /* leave those two points in queue */
296     break;
297
298   case GL_LINES:
299   case GL_LINE_STRIP:
300   case GL_LINE_LOOP:
301
302     if (dxf_point_total == 1)
303       {
304         dxf_quads[6] = ox;
305         dxf_quads[7] = oy;
306         dxf_quads[8] = oz;
307       }
308
309     if (dxf_point < 2) return;
310
311     fprintf (stdout, "0\nLINE\n8\n%d\n62\n%d\n", dxf_layer, dxf_color);
312
313     fprintf (stdout, "10\n%.6f\n", dxf_quads[i++]);
314     fprintf (stdout, "20\n%.6f\n", dxf_quads[i++]);
315     fprintf (stdout, "30\n%.6f\n", dxf_quads[i++]);
316
317     fprintf (stdout, "11\n%.6f\n", dxf_quads[i++]);
318     fprintf (stdout, "21\n%.6f\n", dxf_quads[i++]);
319     fprintf (stdout, "31\n%.6f\n", dxf_quads[i++]);
320
321     dxf_point = 0;
322     if (dxf_type != GL_LINES)
323       {
324         dxf_quads[0] = dxf_quads[3];
325         dxf_quads[1] = dxf_quads[4];
326         dxf_quads[2] = dxf_quads[5];
327         dxf_point = 1;
328       }
329     break;
330
331   default:
332     abort();
333     break;
334   }
335 }
336
337
338 static void
339 dxf_glVertex3dv (const GLdouble *v)
340 {
341   glVertex3f (v[0], v[1], v[2]);
342 }
343
344
345 static void
346 dxf_glEnd(void)
347 {
348   if (dxf_type == GL_LINE_LOOP)  /* close loop */
349     glVertex3f (dxf_quads[6], dxf_quads[7], dxf_quads[8]);
350   dxf_type = -1;
351   dxf_point = 0;
352   dxf_point_total = 0;
353 }
354
355
356 static void
357 dxf_start (void)
358 {
359   fprintf (stdout, "0\nSECTION\n2\nHEADER\n0\nENDSEC\n");
360   fprintf (stdout, "0\nSECTION\n2\nENTITIES\n");
361 }
362
363 static void
364 dxf_end (void)
365 {
366   fprintf (stdout, "0\nENDSEC\n0\nEOF\n");
367   exit (0);
368 }
369
370
371 static const GLvoid *dxf_vp;
372 static GLsizei dxf_vp_size;
373 static GLsizei dxf_vp_stride;
374
375 static void
376 dxf_glVertexPointer (GLint size, GLenum type, GLsizei stride,
377                      const GLvoid *pointer)
378 {
379   if (type != GL_FLOAT) abort();
380   if (stride <= 0) abort();
381   dxf_vp = pointer;
382   dxf_vp_size = size;
383   dxf_vp_stride = stride;
384 }
385
386 static void
387 dxf_glDrawArrays (GLenum mode, GLint first, GLsizei count)
388 {
389   int i;
390   unsigned char *a = (unsigned char *) dxf_vp;
391   dxf_glBegin (mode);
392   for (i = first; i < first+count; i++)
393     {
394       GLfloat *fa = (GLfloat *) a;
395       dxf_glVertex3f (fa[0], fa[1], fa[2]);
396       a += dxf_vp_stride;
397     }
398   dxf_glEnd();
399 }
400
401
402 # define XYZ tube_XYZ /* avoid conflict with normals.h */
403 # include "tube.c"    /* Yes, I really am including a C file. */
404 # undef XYZ
405
406 #endif /* DXF_OUTPUT_HACK */
407
408
409 \f
410 /* Calculate the angle (in degrees) between two vectors.
411  */
412 static GLfloat
413 vector_angle (double ax, double ay, double az,
414               double bx, double by, double bz)
415 {
416   double La = sqrt (ax*ax + ay*ay + az*az);
417   double Lb = sqrt (bx*bx + by*by + bz*bz);
418   double cc, angle;
419
420   if (La == 0 || Lb == 0) return 0;
421   if (ax == bx && ay == by && az == bz) return 0;
422
423   /* dot product of two vectors is defined as:
424        La * Lb * cos(angle between vectors)
425      and is also defined as:
426        ax*bx + ay*by + az*bz
427      so:
428       La * Lb * cos(angle) = ax*bx + ay*by + az*bz
429       cos(angle)  = (ax*bx + ay*by + az*bz) / (La * Lb)
430       angle = acos ((ax*bx + ay*by + az*bz) / (La * Lb));
431   */
432   cc = (ax*bx + ay*by + az*bz) / (La * Lb);
433   if (cc > 1) cc = 1;  /* avoid fp rounding error (1.000001 => sqrt error) */
434   angle = acos (cc);
435
436   return (angle * M_PI / 180);
437 }
438
439 \f
440 /* Make the helix
441  */
442
443 static int
444 make_helix (logo_configuration *dc, int facetted, int wire)
445 {
446   int polys = 0;
447   int wall_facets = dc->wall_facets / (facetted ? 10 : 1);
448   GLfloat th;
449   GLfloat max_th = M_PI * 2 * dc->turns;
450   GLfloat th_inc = M_PI * 2 / wall_facets;
451
452   GLfloat x1=0,  y1=0,  x2=0,  y2=0;
453   GLfloat x1b=0, y1b=0, x2b=0, y2b=0;
454   GLfloat z1=0, z2=0;
455   GLfloat h1=0, h2=0;
456   GLfloat h1off=0, h2off=0;
457   GLfloat z_inc = dc->turn_spacing / wall_facets;
458
459   th  = 0;
460   x1  = 1;
461   y1  = 0;
462   x1b = 1 - dc->wall_thickness;
463   y1b = 0;
464
465   z1 = -(dc->turn_spacing * dc->turns / 2);
466
467   h1    = (dc->wall_taper > 0 ? 0 : dc->wall_height / 2);
468   h1off = (dc->wall_taper > 0 ?    -dc->wall_height / 2 : 0);
469
470   if (!dc->clockwise)
471     z1 = -z1, z_inc = -z_inc, h1off = -h1off;
472
473   /* Leading end-cap
474    */
475   if (!wire && h1 > 0)
476     {
477       GLfloat nx, ny;
478       glFrontFace(GL_CCW);
479       glBegin(GL_QUADS);
480       nx = cos (th + M_PI/2);
481       ny = sin (th + M_PI/2);
482       glNormal3f(nx, ny, 0);
483       glVertex3f( x1, y1,  z1 - h1 + h1off);
484       glVertex3f( x1, y1,  z1 + h1 + h1off);
485       glVertex3f(x1b, y1b, z1 + h1 + h1off);
486       glVertex3f(x1b, y1b, z1 - h1 + h1off);
487       polys++;
488       glEnd();
489     }
490
491   while (th + th_inc <= max_th)
492     {
493       th += th_inc;
494
495       x2 = cos (th);
496       y2 = sin (th);
497       z2 = z1 + z_inc;
498       x2b = x2 * (1 - dc->wall_thickness);
499       y2b = y2 * (1 - dc->wall_thickness);
500
501       h2 = h1;
502       h2off = h1off;
503
504       if (dc->wall_taper > 0)
505         {
506           h2off = 0;
507           if (th < dc->wall_taper)
508             {
509               h2 = dc->wall_height/2 * cos (M_PI / 2
510                                             * (1 - (th / dc->wall_taper)));
511               if (dc->clockwise)
512                 h2off = h2 - dc->wall_height/2;
513               else
514                 h2off = dc->wall_height/2 - h2;
515             }
516           else if (th >= max_th - dc->wall_taper)
517             {
518               if (th + th_inc > max_th) /* edge case: always come to a point */
519                 h2 = 0;
520               else
521                 h2 = dc->wall_height/2 * cos (M_PI / 2
522                                               * (1 - ((max_th - th)
523                                                       / dc->wall_taper)));
524               if (dc->clockwise)
525                 h2off = dc->wall_height/2 - h2;
526               else
527                 h2off = h2 - dc->wall_height/2;
528             }
529         }
530
531       /* outer face
532        */
533       glFrontFace(GL_CW);
534       glBegin(wire ? GL_LINES : GL_QUADS);
535       glNormal3f(x1, y1, 0);
536       glVertex3f(x1, y1, z1 - h1 + h1off);
537       glVertex3f(x1, y1, z1 + h1 + h1off);
538       glNormal3f(x2, y2, 0);
539       glVertex3f(x2, y2, z2 + h2 + h2off);
540       glVertex3f(x2, y2, z2 - h2 + h2off);
541       polys++;
542       glEnd();
543
544       /* inner face
545        */
546       glFrontFace(GL_CCW);
547       glBegin(wire ? GL_LINES : GL_QUADS);
548       glNormal3f(-x1b, -y1b, 0);
549       glVertex3f( x1b,  y1b, z1 - h1 + h1off);
550       glVertex3f( x1b,  y1b, z1 + h1 + h1off);
551       glNormal3f(-x2b, -y2b, 0);
552       glVertex3f( x2b,  y2b, z2 + h2 + h2off);
553       glVertex3f( x2b,  y2b, z2 - h2 + h2off);
554       polys++;
555       glEnd();
556
557       /* top face
558        */
559       glFrontFace(GL_CCW);
560       /* glNormal3f(0, 0, 1);*/
561       do_normal (x2,   y2,  z2 + h2 + h2off,
562                  x2b,  y2b, z2 + h2 + h2off,
563                  x1b,  y1b, z1 + h1 + h1off);
564       glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
565       glVertex3f( x2,   y2,  z2 + h2 + h2off);
566       glVertex3f( x2b,  y2b, z2 + h2 + h2off);
567       glVertex3f( x1b,  y1b, z1 + h1 + h1off);
568       glVertex3f( x1,   y1,  z1 + h1 + h1off);
569       polys++;
570       glEnd();
571
572       /* bottom face
573        */
574       glFrontFace(GL_CCW);
575       do_normal ( x1,   y1,  z1 - h1 + h1off,
576                   x1b,  y1b, z1 - h1 + h1off,
577                   x2b,  y2b, z2 - h2 + h2off);
578       glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
579       glNormal3f(0, 0, -1);
580       glVertex3f( x1,   y1,  z1 - h1 + h1off);
581       glVertex3f( x1b,  y1b, z1 - h1 + h1off);
582       glVertex3f( x2b,  y2b, z2 - h2 + h2off);
583       glVertex3f( x2,   y2,  z2 - h2 + h2off);
584       polys++;
585       glEnd();
586
587       x1 = x2;
588       y1 = y2;
589       x1b = x2b;
590       y1b = y2b;
591       z1 += z_inc;
592       h1 = h2;
593       h1off = h2off;
594     }
595
596   /* Trailing end-cap
597    */
598   if (!wire && h2 > 0)
599     {
600       GLfloat nx, ny;
601       glFrontFace(GL_CW);
602       glBegin(GL_QUADS);
603       nx = cos (th + M_PI/2);
604       ny = sin (th + M_PI/2);
605       glNormal3f(nx, ny, 0);
606       glVertex3f(x2,  y2,  z1 - h2 + h2off);
607       glVertex3f(x2,  y2,  z1 + h2 + h2off);
608       glVertex3f(x2b, y2b, z1 + h2 + h2off);
609       glVertex3f(x2b, y2b, z1 - h2 + h2off);
610       polys++;
611       glEnd();
612     }
613   return polys;
614 }
615
616
617 static int
618 make_ladder (logo_configuration *dc, int facetted, int wire)
619 {
620   int polys = 0;
621   GLfloat th;
622   GLfloat max_th = dc->turns * M_PI * 2;
623   GLfloat max_z  = dc->turns * dc->turn_spacing;
624   GLfloat z_inc  = dc->bar_spacing;
625   GLfloat th_inc = M_PI * 2 * (dc->bar_spacing / dc->turn_spacing);
626   GLfloat x, y, z;
627
628   /* skip forward to center the bars in the helix... */
629   int i;
630   GLfloat usable_th = max_th - dc->wall_taper;
631   GLfloat usable_z  = max_z / (max_th / usable_th);
632   int nbars = usable_z / dc->bar_spacing;
633   GLfloat used_z, pad_z, pad_ratio;
634
635   if (! (nbars & 1)) nbars--;  /* always an odd number of bars */
636
637   used_z = (nbars - 1) * dc->bar_spacing;
638   pad_z = max_z - used_z;
639   pad_ratio = pad_z / max_z;
640
641   th = (max_th * pad_ratio/2);
642   z  = -(max_z / 2) + (max_z * pad_ratio/2);
643
644   if (!dc->clockwise)
645     z = -z, z_inc = -z_inc;
646
647   glFrontFace(GL_CCW);
648   for (i = 0; i < nbars; i++)
649     {
650       int facets = dc->bar_facets / (facetted ? 14 : 1);
651       if (facets <= 3) facets = 3;
652       x = cos (th) * (1 - dc->wall_thickness);
653       y = sin (th) * (1 - dc->wall_thickness);
654       polys += tube ( x,  y, z,
655                      -x, -y, z,
656                       dc->bar_thickness, 0, facets,
657                       True, True, wire);
658       z  += z_inc;
659       th += th_inc;
660     }
661   return polys;
662 }
663
664
665 \f
666 /* Make the gasket
667  */
668
669
670 static int
671 make_gasket (logo_configuration *dc, int wire)
672 {
673   int polys = 0;
674   int i;
675   int points_size;
676   int npoints = 0;
677   int nctrls = 0;
678   int res = 360/8;
679   GLfloat d2r = M_PI / 180;
680
681   GLfloat thick2 = (dc->gasket_thickness / dc->gasket_size) / 2;
682
683   GLfloat *pointsx0, *pointsy0, *pointsx1, *pointsy1, *normals;
684
685   GLfloat r0  = 0.750;  /* 395 */
686   GLfloat r1a = 0.825;                /* bottom of wall below upper left hole */
687   GLfloat r1b = 0.867;                /* center of upper left hole */
688   GLfloat r1c = 0.909;                /* top of wall above hole */
689   GLfloat r1  = 0.916;  /* 471 */
690   GLfloat r2  = 0.963;  /* 490 */
691   GLfloat r3  = 0.960;  /* 499 */
692   GLfloat r4  = 1.000;  /* 507 */
693   GLfloat r5  = 1.080;  /* 553 */
694
695   GLfloat ctrl_r[100], ctrl_th[100];
696
697   glPushMatrix();
698
699 # ifdef DXF_OUTPUT_HACK
700   if (! wire) res *= 8;
701 # endif
702
703 # define POINT(r,th) \
704     ctrl_r [nctrls] = r, \
705     ctrl_th[nctrls] = (th * d2r), \
706     nctrls++
707
708   POINT (0.829, 0);      /* top indentation, right half */
709   POINT (0.831, 0.85);
710   POINT (0.835, 1.81);
711   POINT (0.841, 2.65);
712   POINT (0.851, 3.30);
713   POINT (0.862, 3.81);
714   POINT (0.872, 3.95);
715
716   POINT (r4,    4.0);   /* moving clockwise... */
717   POINT (r4,   47.0);
718   POINT (r1,   47.0);
719   POINT (r1,   53.0);
720   POINT (r2,   55.5);
721   POINT (r2,   72.3);
722   POINT (r1,   74.0);
723   POINT (r1,  100.0);
724   POINT (r3,  102.5);
725   POINT (r3,  132.0);
726   POINT (r1,  133.0);
727
728   POINT (r1,  180.7);
729   POINT (r2,  183.6);
730   POINT (r2,  210.0);
731   POINT (r1,  212.0);
732   POINT (r1,  223.2);
733   POINT (r5,  223.2);
734   POINT (r5,  225.0);
735   POINT (r4,  225.0);
736
737   POINT (r4,    316.8);      /* upper left indentation */
738   POINT (0.990, 316.87);
739   POINT (0.880, 317.21);
740   POINT (0.872, 317.45);
741   POINT (0.869, 317.80);
742   POINT (0.867, 318.10);
743
744   POINT (0.867, 318.85);
745   POINT (0.869, 319.15);
746   POINT (0.872, 319.50);
747   POINT (0.880, 319.74);
748   POINT (0.990, 320.08);
749
750   POINT (r4,  338.0);
751   if (! wire)
752     {
753       POINT (r1a, 338.0);      /* cut-out disc */
754       POINT (r1a, 344.0);
755     }
756   POINT (r4,  344.0);
757   POINT (r4,  356.0);
758
759   POINT (0.872, 356.05);   /* top indentation, left half */
760   POINT (0.862, 356.19);
761   POINT (0.851, 356.70);
762   POINT (0.841, 357.35);
763   POINT (0.835, 358.19);
764   POINT (0.831, 359.15);
765   POINT (0.829, 360);
766 # undef POINT
767
768   points_size = res + (nctrls * 2);
769   pointsx0 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
770   pointsy0 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
771   pointsx1 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
772   pointsy1 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
773   normals  = (GLfloat *) malloc (points_size * sizeof(GLfloat) * 2);
774
775   npoints = 0;
776   for (i = 1; i < nctrls; i++)
777     {
778       GLfloat from_r  = ctrl_r [i-1];
779       GLfloat from_th = ctrl_th[i-1];
780       GLfloat to_r    = ctrl_r [i];
781       GLfloat to_th   = ctrl_th[i];
782
783       GLfloat step = 2*M_PI / res;
784       int nsteps = 1 + ((to_th - from_th) / step);
785       int j;
786
787       for (j = 0; j < nsteps + (i == nctrls-1); j++)
788         {
789           GLfloat r  = from_r  + (j * (to_r  - from_r)  / nsteps);
790           GLfloat th = from_th + (j * (to_th - from_th) / nsteps);
791
792           GLfloat cth = cos(th) * dc->gasket_size;
793           GLfloat sth = sin(th) * dc->gasket_size;
794
795           pointsx0[npoints] = r0 * cth;  /* inner ring */
796           pointsy0[npoints] = r0 * sth;
797           pointsx1[npoints] = r  * cth;  /* outer ring */
798           pointsy1[npoints] = r  * sth;
799           npoints++;
800
801           if (npoints >= points_size) abort();
802         }
803     }
804
805   /* normals for the outer ring */
806   for (i = 1; i < npoints; i++)
807     {
808       XYZ a, b, c, n;
809       a.x = pointsx1[i-1];
810       a.y = pointsy1[i-1];
811       a.z = 0;
812       b.x = pointsx1[i];
813       b.y = pointsy1[i];
814       b.z = 0;
815       c = b;
816       c.z = 1;
817       n = calc_normal (a, b, c);
818       normals[(i-1)*2  ] = n.x;
819       normals[(i-1)*2+1] = n.y;
820     }
821
822   glRotatef(-90, 0, 1, 0);
823   glRotatef(180, 0, 0, 1);
824
825   if (wire)
826     {
827       GLfloat z;
828       for (z = -thick2; z <= thick2; z += thick2*2)
829         {
830 # if 1
831           /* inside edge */
832           glBegin (GL_LINE_LOOP);
833           for (i = 0; i < npoints; i++)
834             glVertex3f (pointsx0[i], pointsy0[i], z);
835           polys += npoints;
836           glEnd();
837
838           /* outside edge */
839           glBegin (GL_LINE_LOOP);
840           for (i = 0; i < npoints; i++)
841             glVertex3f (pointsx1[i], pointsy1[i], z);
842           polys += npoints;
843           glEnd();
844 # else
845           for (i = 1; i < npoints; i++)
846             {
847               glBegin (GL_LINE_STRIP);
848               glVertex3f (pointsx0[i-1], pointsy0[i-1], z);
849               glVertex3f (pointsx0[i  ], pointsy0[i  ], z);
850               glVertex3f (pointsx1[i  ], pointsy1[i  ], z);
851               glVertex3f (pointsx1[i-1], pointsy1[i-1], z);
852               glEnd();
853             }
854           polys += npoints;
855 # endif
856         }
857 #if 1
858       glBegin (GL_LINES);
859       for (i = 0; i < npoints; i++)
860         {
861           /* inside rim */
862           glVertex3f (pointsx0[i], pointsy0[i], -thick2);
863           glVertex3f (pointsx0[i], pointsy0[i],  thick2);
864           /* outside rim */
865           glVertex3f (pointsx1[i], pointsy1[i], -thick2);
866           glVertex3f (pointsx1[i], pointsy1[i],  thick2);
867         }
868       polys += npoints;
869       glEnd();
870 #endif
871     }
872   else
873     {
874       /* top */
875       glFrontFace(GL_CW);
876       glNormal3f(0, 0, -1);
877       glBegin (GL_QUAD_STRIP);
878       for (i = 0; i < npoints; i++)
879         {
880           glVertex3f (pointsx0[i], pointsy0[i], -thick2);
881           glVertex3f (pointsx1[i], pointsy1[i], -thick2);
882         }
883       polys += npoints;
884       glEnd();
885
886       /* bottom */
887       glFrontFace(GL_CCW);
888       glNormal3f(0, 0, 1);
889       glBegin (GL_QUAD_STRIP);
890       for (i = 0; i < npoints; i++)
891         {
892           glVertex3f (pointsx0[i], pointsy0[i], thick2);
893           glVertex3f (pointsx1[i], pointsy1[i], thick2);
894         }
895       polys += npoints;
896       glEnd();
897
898       /* inside edge */
899       glFrontFace(GL_CW);
900       glBegin (GL_QUAD_STRIP);
901       for (i = 0; i < npoints; i++)
902         {
903           glNormal3f (-pointsx0[i], -pointsy0[i],  0);
904           glVertex3f ( pointsx0[i],  pointsy0[i],  thick2);
905           glVertex3f ( pointsx0[i],  pointsy0[i], -thick2);
906         }
907       polys += npoints;
908       glEnd();
909
910       /* outside edge */
911       glFrontFace(GL_CCW);
912       glBegin (GL_QUADS);
913       {
914         for (i = 0; i < npoints-1; i++)
915           {
916             int ia = (i == 0 ? npoints-2 : i-1);
917             int iz = (i == npoints-2 ? 0 : i+1);
918             GLfloat  x = pointsx1[i];
919             GLfloat  y = pointsy1[i];
920             GLfloat xz = pointsx1[iz];
921             GLfloat yz = pointsy1[iz];
922
923             GLfloat nxa = normals[ia*2];   /* normal of [i-1 - i] face */
924             GLfloat nya = normals[ia*2+1];
925             GLfloat nx  = normals[i*2];    /* normal of [i - i+1] face */
926             GLfloat ny  = normals[i*2+1];
927             GLfloat nxz = normals[iz*2];    /* normal of [i+1 - i+2] face */
928             GLfloat nyz = normals[iz*2+1];
929
930             GLfloat anglea = vector_angle (nx, ny, 0, nxa, nya, 0);
931             GLfloat anglez = vector_angle (nx, ny, 0, nxz, nyz, 0);
932             GLfloat pointy = 0.005;
933
934             if (anglea > pointy)
935               {
936                 glNormal3f (nx, ny, 0);
937                 glVertex3f (x,  y,   thick2);
938                 glVertex3f (x,  y,  -thick2);
939               }
940             else
941               {
942                 glNormal3f ((nxa + nx) / 2, (nya + ny) / 2, 0);
943                 glVertex3f (x,  y,   thick2);
944                 glVertex3f (x,  y,  -thick2);
945               }
946
947             if (anglez > pointy)
948               {
949                 glNormal3f (nx, ny, 0);
950                 glVertex3f (xz, yz, -thick2);
951                 glVertex3f (xz, yz,  thick2);
952               }
953             else
954               {
955                 glNormal3f ((nx + nxz) / 2, (ny + nyz) / 2, 0);
956                 glVertex3f (xz, yz, -thick2);
957                 glVertex3f (xz, yz,  thick2);
958               }
959           }
960         polys += npoints;
961       }
962       glEnd();
963     }
964
965   /* Fill in the upper left hole...
966    */
967   {
968     GLfloat th;
969     npoints = 0;
970
971     th = 338.0 * d2r;
972     pointsx0[npoints] = r1c * cos(th) * dc->gasket_size;
973     pointsy0[npoints] = r1c * sin(th) * dc->gasket_size;
974     npoints++;
975     pointsx0[npoints] = r4 * cos(th) * dc->gasket_size;
976     pointsy0[npoints] = r4 * sin(th) * dc->gasket_size;
977     npoints++;
978
979     th = 344.0 * d2r;
980     pointsx0[npoints] = r1c * cos(th) * dc->gasket_size;
981     pointsy0[npoints] = r1c * sin(th) * dc->gasket_size;
982     npoints++;
983     pointsx0[npoints] = r4 * cos(th) * dc->gasket_size;
984     pointsy0[npoints] = r4 * sin(th) * dc->gasket_size;
985
986     if (! wire)
987       {
988         /* front wall */
989         glNormal3f (0, 0, -1);
990         glFrontFace(GL_CW);
991         glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
992         glVertex3f (pointsx0[0], pointsy0[0], -thick2);
993         glVertex3f (pointsx0[1], pointsy0[1], -thick2);
994         glVertex3f (pointsx0[3], pointsy0[3], -thick2);
995         glVertex3f (pointsx0[2], pointsy0[2], -thick2);
996         glEnd();
997         polys++;
998
999         /* back wall */
1000         glNormal3f (0, 0, 1);
1001         glFrontFace(GL_CCW);
1002         glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
1003         glVertex3f (pointsx0[0], pointsy0[0],  thick2);
1004         glVertex3f (pointsx0[1], pointsy0[1],  thick2);
1005         glVertex3f (pointsx0[3], pointsy0[3],  thick2);
1006         glVertex3f (pointsx0[2], pointsy0[2],  thick2);
1007         glEnd();
1008         polys++;
1009       }
1010
1011     /* top wall */
1012     glFrontFace(GL_CW);
1013     glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
1014     glNormal3f (pointsx0[1], pointsy0[1], 0);
1015     glVertex3f (pointsx0[1], pointsy0[1],  thick2);
1016     glNormal3f (pointsx0[3], pointsy0[3], 0);
1017     glVertex3f (pointsx0[3], pointsy0[3],  thick2);
1018     glVertex3f (pointsx0[3], pointsy0[3], -thick2);
1019     glNormal3f (pointsx0[1], pointsy0[1], 0);
1020     glVertex3f (pointsx0[1], pointsy0[1], -thick2);
1021     glEnd();
1022     polys++;
1023
1024
1025     /* Now make a donut.
1026      */
1027     {
1028       int nsteps = (wire ? 12 : 64);
1029       GLfloat r0 = 0.04;
1030       GLfloat r1 = 0.070;
1031       GLfloat th, cth, sth;
1032
1033       glPushMatrix ();
1034
1035       th = ((339.0 + 343.0) / 2) * d2r;
1036       
1037       glTranslatef (r1b * cos(th) * dc->gasket_size,
1038                     r1b * sin(th) * dc->gasket_size,
1039                     0);
1040
1041       npoints = 0;
1042       for (i = 0; i < nsteps; i++)
1043         {
1044           th = 2 * M_PI * i / nsteps;
1045           cth = cos (th) * dc->gasket_size;
1046           sth = sin (th) * dc->gasket_size;
1047           pointsx0[npoints] = r0 * cth;
1048           pointsy0[npoints] = r0 * sth;
1049           pointsx1[npoints] = r1 * cth;
1050           pointsy1[npoints] = r1 * sth;
1051           npoints++;
1052           polys++;
1053         }
1054
1055       pointsx0[npoints] = pointsx0[0];
1056       pointsy0[npoints] = pointsy0[0];
1057       pointsx1[npoints] = pointsx1[0];
1058       pointsy1[npoints] = pointsy1[0];
1059       npoints++;
1060
1061       if (wire)
1062         {
1063           glBegin (GL_LINE_LOOP);
1064           for (i = 0; i < npoints; i++)
1065             glVertex3f (pointsx0[i], pointsy0[i], -thick2);
1066           polys += npoints;
1067           glEnd();
1068           glBegin (GL_LINE_LOOP);
1069           for (i = 0; i < npoints; i++)
1070             glVertex3f (pointsx0[i], pointsy0[i],  thick2);
1071           polys += npoints;
1072           glEnd();
1073 # if 0
1074           glBegin (GL_LINE_LOOP);
1075           for (i = 0; i < npoints; i++)
1076             glVertex3f (pointsx1[i], pointsy1[i], -thick2);
1077           polys += npoints;
1078           glEnd();
1079           glBegin (GL_LINE_LOOP);
1080           for (i = 0; i < npoints; i++)
1081             glVertex3f (pointsx1[i], pointsy1[i],  thick2);
1082           polys += npoints;
1083           glEnd();
1084 # endif
1085         }
1086       else
1087         {
1088           /* top */
1089           glFrontFace(GL_CW);
1090           glNormal3f(0, 0, -1);
1091           glBegin (GL_QUAD_STRIP);
1092           for (i = 0; i < npoints; i++)
1093             {
1094               glVertex3f (pointsx0[i], pointsy0[i], -thick2);
1095               glVertex3f (pointsx1[i], pointsy1[i], -thick2);
1096             }
1097           polys += npoints;
1098           glEnd();
1099
1100           /* bottom */
1101           glFrontFace(GL_CCW);
1102           glNormal3f(0, 0, 1);
1103           glBegin (GL_QUAD_STRIP);
1104           for (i = 0; i < npoints; i++)
1105             {
1106               glVertex3f (pointsx0[i], pointsy0[i],  thick2);
1107               glVertex3f (pointsx1[i], pointsy1[i],  thick2);
1108             }
1109           polys += npoints;
1110           glEnd();
1111         }
1112
1113       /* inside edge */
1114       glFrontFace(GL_CW);
1115       glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
1116       for (i = 0; i < npoints; i++)
1117         {
1118           glNormal3f (-pointsx0[i], -pointsy0[i],  0);
1119           glVertex3f ( pointsx0[i],  pointsy0[i],  thick2);
1120           glVertex3f ( pointsx0[i],  pointsy0[i], -thick2);
1121         }
1122       polys += npoints;
1123       glEnd();
1124
1125       glPopMatrix();
1126     }
1127   }
1128
1129
1130   /* Attach the bottom-right dingus...
1131    */
1132   {
1133     GLfloat w = 0.05;
1134     GLfloat h = 0.19;
1135     GLfloat th;
1136
1137     glRotatef (49.5, 0, 0, 1);
1138     glScalef (dc->gasket_size, dc->gasket_size, 1);
1139     glTranslatef (0, (r0+r1)/2, 0);
1140
1141     /* buried box */
1142     if (! wire)
1143       {
1144         glFrontFace(GL_CCW);
1145         glBegin (wire ? GL_LINE_STRIP : GL_QUADS);
1146         glNormal3f (0, 0, -1);
1147         glVertex3f (-w/2, -h/2, -thick2); glVertex3f (-w/2,  h/2, -thick2);
1148         glVertex3f ( w/2,  h/2, -thick2); glVertex3f ( w/2, -h/2, -thick2);
1149         glNormal3f (1, 0, 0);
1150         glVertex3f ( w/2, -h/2, -thick2); glVertex3f ( w/2,  h/2, -thick2);
1151         glVertex3f ( w/2,  h/2,  thick2); glVertex3f ( w/2, -h/2,  thick2);
1152         glNormal3f (0, 0, 1);
1153         glVertex3f ( w/2, -h/2,  thick2); glVertex3f ( w/2,  h/2,  thick2);
1154         glVertex3f (-w/2,  h/2,  thick2); glVertex3f (-w/2, -h/2,  thick2);
1155         glNormal3f (-1, 0, 0);
1156         glVertex3f (-w/2, -h/2,  thick2); glVertex3f (-w/2,  h/2,  thick2);
1157         glVertex3f (-w/2,  h/2, -thick2); glVertex3f (-w/2, -h/2, -thick2);
1158         polys++;
1159         glEnd();
1160       }
1161
1162     npoints = 0;
1163     for (th = (wire ? 0 : -0.1);
1164          th <= M_PI + 0.1;
1165          th += (M_PI / (wire ? 5 : 32)))
1166       {
1167         pointsx0[npoints] = w/2 * cos(th);
1168         pointsy0[npoints] = w/2 * sin(th);
1169         npoints++;
1170         polys++;
1171       }
1172
1173     /* front inside curve */
1174     glNormal3f (0, 0, -1);
1175     glFrontFace(GL_CW);
1176     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
1177     if (! wire) glVertex3f (0, h/2, -thick2);
1178     for (i = 0; i < npoints; i++)
1179       glVertex3f (pointsx0[i], h/2 + pointsy0[i], -thick2);
1180     polys += npoints;
1181     glEnd();
1182
1183     /* front outside curve */
1184     glFrontFace(GL_CCW);
1185     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
1186     if (! wire) glVertex3f (0, -h/2, -thick2);
1187     for (i = 0; i < npoints; i++)
1188       glVertex3f (pointsx0[i], -h/2 - pointsy0[i], -thick2);
1189     polys += npoints;
1190     glEnd();
1191
1192     /* back inside curve */
1193     glNormal3f (0, 0, 1);
1194     glFrontFace(GL_CCW);
1195     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
1196     if (! wire) glVertex3f (0, h/2, thick2);
1197     for (i = 0; i < npoints; i++)
1198       glVertex3f (pointsx0[i], h/2 + pointsy0[i], thick2);
1199     polys += npoints;
1200     glEnd();
1201
1202     /* back outside curve */
1203     glFrontFace(GL_CW);
1204     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
1205     if (! wire) glVertex3f (0, -h/2, thick2);
1206     for (i = 0; i < npoints; i++)
1207       glVertex3f (pointsx0[i], -h/2 - pointsy0[i], thick2);
1208     polys += npoints;
1209     glEnd();
1210
1211     /* inside curve */
1212     glFrontFace(GL_CCW);
1213     glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
1214     for (i = 0; i < npoints; i++)
1215       {
1216         glNormal3f (pointsx0[i], pointsy0[i], 0);
1217         glVertex3f (pointsx0[i], h/2 + pointsy0[i],  thick2);
1218         glVertex3f (pointsx0[i], h/2 + pointsy0[i], -thick2);
1219       }
1220     polys += npoints;
1221     glEnd();
1222
1223     /* outside curve */
1224     glFrontFace(GL_CW);
1225     glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
1226     for (i = 0; i < npoints; i++)
1227       {
1228         glNormal3f (pointsx0[i], -pointsy0[i], 0);
1229         glVertex3f (pointsx0[i], -h/2 - pointsy0[i],  thick2);
1230         glVertex3f (pointsx0[i], -h/2 - pointsy0[i], -thick2);
1231       }
1232     polys += npoints;
1233     glEnd();
1234   }
1235
1236   free (pointsx0);
1237   free (pointsy0);
1238   free (pointsx1);
1239   free (pointsy1);
1240   free (normals);
1241
1242   glPopMatrix();
1243   return polys;
1244 }
1245
1246 static int
1247 make_frame (logo_configuration *dc, int wire)
1248 {
1249   int polys = 0;
1250   int i, j;
1251   GLfloat x[20], y[20];
1252   GLfloat corner_cut = 0.5;
1253
1254   glPushMatrix();
1255   glRotatef (90, 0, 1, 0);
1256   glScalef (4 * dc->frame_size,
1257             4 * dc->frame_size,
1258             4 * dc->frame_size);
1259
1260   x[0] = -dc->frame_thickness;
1261   x[1] = -dc->frame_thickness * corner_cut;
1262   x[2] = 0;
1263   x[3] = 0.5 - dc->triangle_size;
1264   x[4] = 0.5;
1265   x[5] = 0.5 + dc->triangle_size;
1266   x[6] = 1;
1267   x[7] = 1 + dc->frame_thickness * corner_cut;
1268   x[8] = 1 + dc->frame_thickness;
1269
1270   y[0] = -dc->frame_thickness;
1271   y[1] = -dc->frame_thickness * corner_cut;
1272   y[2] = 0;
1273   y[3] = dc->triangle_size;
1274
1275   /* front and back
1276    */
1277   glTranslatef (-0.5, -0.5, dc->frame_depth / 4);
1278   if (! wire)
1279     for (j = 0; j <= 1; j++)
1280       {
1281         if (j) glTranslatef (0, 0, -dc->frame_depth / 2);
1282         glFrontFace (j ? GL_CCW : GL_CW);
1283         for (i = 0; i < 4; i++)
1284           {
1285             glNormal3f (0, 0, (j ? -1 : 1));
1286             glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
1287             glVertex3f (x[0], y[1], 0); glVertex3f (x[0], y[2], 0);
1288             glVertex3f (x[1], y[0], 0); glVertex3f (x[1], y[2], 0);
1289             glVertex3f (x[3], y[0], 0); glVertex3f (x[3], y[2], 0);
1290             glVertex3f (x[4], y[0], 0); glVertex3f (x[4], y[3], 0);
1291             glVertex3f (x[5], y[0], 0); glVertex3f (x[5], y[2], 0); 
1292             glVertex3f (x[7], y[0], 0); glVertex3f (x[7], y[2], 0);
1293             glVertex3f (x[8], y[1], 0); glVertex3f (x[8], y[2], 0);
1294             polys += 6;
1295             glEnd ();
1296             glTranslatef (0.5, 0.5, 0);
1297             glRotatef (90, 0, 0, 1);
1298             glTranslatef (-0.5, -0.5, 0);
1299           }
1300       }
1301
1302   /* ledges
1303    */
1304   glFrontFace (GL_CCW);
1305   for (i = 0; i < 4; i++)
1306     {
1307       glNormal3f (0, 1, 0);
1308       glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
1309       glVertex3f (x[2], y[2], 0); glVertex3f (x[2], y[2], dc->frame_depth/2); 
1310       glVertex3f (x[3], y[2], 0); glVertex3f (x[3], y[2], dc->frame_depth/2); 
1311       glVertex3f (x[4], y[3], 0); glVertex3f (x[4], y[3], dc->frame_depth/2); 
1312       glVertex3f (x[5], y[2], 0); glVertex3f (x[5], y[2], dc->frame_depth/2); 
1313       glVertex3f (x[6], y[2], 0); glVertex3f (x[6], y[2], dc->frame_depth/2); 
1314       polys += 4;
1315       glEnd ();
1316
1317       glNormal3f (0, -1, 0);
1318       glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
1319       glVertex3f (x[7], y[0], 0); 
1320       glVertex3f (x[7], y[0], dc->frame_depth/2); 
1321       glVertex3f (x[1], y[0], dc->frame_depth/2); 
1322       glVertex3f (x[1], y[0], 0); 
1323       polys++;
1324       glEnd ();
1325
1326       glNormal3f (1, -1, 0);
1327       glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
1328       glVertex3f (x[8], y[1], 0); 
1329       glVertex3f (x[8], y[1], dc->frame_depth/2); 
1330       glVertex3f (x[7], y[0], dc->frame_depth/2); 
1331       glVertex3f (x[7], y[0], 0); 
1332       polys++;
1333       glEnd ();
1334
1335       if (wire) 
1336         {
1337           glNormal3f (0, 1, 0);
1338           for (j = 0; j <= 1; j++)
1339             {
1340               glBegin (GL_LINE_STRIP);
1341               glVertex3f (x[2], y[2], j*dc->frame_depth/2);
1342               glVertex3f (x[3], y[2], j*dc->frame_depth/2);
1343               glVertex3f (x[4], y[3], j*dc->frame_depth/2);
1344               glVertex3f (x[5], y[2], j*dc->frame_depth/2);
1345               glVertex3f (x[6], y[2], j*dc->frame_depth/2);
1346               polys += 4;
1347               glEnd ();
1348             }
1349         }
1350
1351       glTranslatef (0.5, 0.5, 0);
1352       glRotatef (90, 0, 0, 1);
1353       glTranslatef (-0.5, -0.5, 0);
1354     }
1355
1356   glPopMatrix();
1357   return polys;
1358 }
1359
1360 \f
1361 /* Make some pizza.
1362  */
1363
1364 typedef struct {
1365   GLdouble *points;
1366   int i;
1367 } tess_out;
1368
1369
1370 static void
1371 tess_error_cb (GLenum errorCode)
1372 {
1373   fprintf (stderr, "%s: tesselation error: %s\n",
1374            progname, gluErrorString(errorCode));
1375   exit (0);
1376 }
1377
1378 static void
1379 tess_combine_cb (GLdouble coords[3], GLdouble *d[4], GLfloat w[4], 
1380                  GLdouble **data_out)
1381 {
1382   GLdouble *new = (GLdouble *) malloc (3 * sizeof(*new));
1383   new[0] = coords[0];
1384   new[1] = coords[1];
1385   new[2] = coords[2];
1386   *data_out = new;
1387 }
1388
1389
1390 static void
1391 tess_vertex_cb (void *vertex_data, void *closure)
1392 {
1393   tess_out *to = (tess_out *) closure;
1394   GLdouble *v = (GLdouble *) vertex_data;
1395   to->points[to->i++] = v[0];
1396   to->points[to->i++] = v[1];
1397   to->points[to->i++] = v[2];
1398 }
1399
1400 static void
1401 tess_begin_cb (GLenum which)
1402 {
1403   glBegin(which);
1404 }
1405
1406 static void
1407 tess_end_cb (void)
1408 {
1409   glEnd();
1410 }
1411
1412
1413 static int
1414 make_pizza (logo_configuration *dc, int facetted, int wire)
1415 {
1416   int polys = 0;
1417
1418   int topfaces = (facetted ? 48 : 120);
1419   int discfaces = (facetted ? 12 : 120);
1420   int npoints = topfaces * 2 + 100;
1421   GLdouble *points = (GLdouble *) calloc (npoints * 3, sizeof(GLdouble));
1422   int nholes = 3;
1423   GLdouble *holes  = (GLdouble *) calloc (topfaces*nholes*3, sizeof(GLdouble));
1424
1425   GLfloat step = M_PI * 2 / 6 / topfaces;
1426   GLfloat thick2 = (dc->gasket_thickness / dc->gasket_size) / 4;
1427   GLfloat th, x, y, s;
1428   int i, j, k;
1429   tess_out TO, *to = &TO;
1430   GLUtesselator *tess = gluNewTess();
1431   int endpoints;
1432   int endedge1;
1433
1434   to->points = (GLdouble *) calloc (topfaces * 20, sizeof(GLdouble));
1435   to->i = 0;
1436
1437
1438 # ifndef  _GLUfuncptr
1439 #  define _GLUfuncptr void(*)(void)
1440 # endif
1441
1442   gluTessCallback(tess,GLU_TESS_BEGIN,      (_GLUfuncptr)tess_begin_cb);
1443   gluTessCallback(tess,GLU_TESS_VERTEX,     (_GLUfuncptr)glVertex3dv);
1444   gluTessCallback(tess,GLU_TESS_END,        (_GLUfuncptr)tess_end_cb);
1445   gluTessCallback(tess,GLU_TESS_COMBINE,    (_GLUfuncptr)tess_combine_cb);
1446   gluTessCallback(tess,GLU_TESS_ERROR,      (_GLUfuncptr)tess_error_cb);
1447
1448   gluTessProperty (tess, GLU_TESS_BOUNDARY_ONLY, wire);
1449   gluTessProperty (tess,GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD);
1450
1451   glPushMatrix();
1452
1453   s = 1.9;
1454   glRotatef (180, 0, 0, 1);
1455   glScalef (s, s, s);
1456   glRotatef (90, 0, 1, 0);
1457   glTranslatef (-0.53, 0, 0);
1458   glRotatef (-30, 0, 0, 1);
1459
1460   /* Compute the wedge */
1461   th = 0;
1462   j = 0;
1463
1464   /* Edge 1 */
1465   {
1466     GLfloat edge[] = {
1467       0.000, 0.000,
1468       0.000, 0.210,
1469       0.042, 0.230,
1470       0.042, 0.616,
1471       0.000, 0.641,
1472     };
1473     for (i = 0; i < countof(edge)/2; i++)
1474       {
1475         points[j++] = edge[i*2+1];
1476         points[j++] = edge[i*2];
1477         points[j++] = 0;
1478       }
1479     endedge1 = i;
1480   }
1481
1482   s = 0.798;  /* radius of end of slice, before crust gap */
1483   for (i = 0; i < topfaces; i++)
1484     {
1485       points[j++] = cos(th) * s;
1486       points[j++] = sin(th) * s;
1487       points[j++] = 0;
1488       th += step;
1489     }
1490
1491   /* Edge 2 */
1492   {
1493     GLfloat edge[] = {
1494       0.613, 0.353,
1495       0.572, 0.376,
1496       0.455, 0.309,
1497       0.452, 0.260,
1498       0.332, 0.192,
1499       0.293, 0.216,
1500       0.178, 0.149,
1501       0.178, 0.102,
1502     };
1503     for (i = 0; i < countof(edge)/2; i++)
1504       {
1505         points[j++] = edge[i*2+1];
1506         points[j++] = edge[i*2];
1507         points[j++] = 0;
1508       }
1509     endpoints = j/3;
1510   }
1511
1512
1513   /* Draw the rim of the slice */
1514   glBegin (wire ? GL_LINES : GL_QUADS);
1515   x = points[0];
1516   y = points[1];
1517   for (i = (wire ? 0 : 1); i < endpoints; i++)
1518     {
1519       GLdouble *p = points + (i*3);
1520
1521       do_normal (p[0], p[1],  -thick2,
1522                  p[0], p[1],   thick2,
1523                  x,    y,     thick2);
1524       if (!wire)
1525         {
1526           glVertex3f (x, y, -thick2);
1527           glVertex3f (x, y,  thick2);
1528         }
1529       glVertex3f (p[0], p[1],  thick2);
1530       glVertex3f (p[0], p[1], -thick2);
1531       x = p[0];
1532       y = p[1];
1533       polys++;
1534     }
1535   do_normal (points[0], points[1],  -thick2,
1536              points[0], points[1],   thick2,
1537              x,         y,           thick2);
1538   glVertex3f (x, y, -thick2);
1539   glVertex3f (x, y,  thick2);
1540   glVertex3f (points[0], points[1],  thick2);
1541   glVertex3f (points[0], points[1], -thick2);
1542   polys++;
1543   glEnd();
1544
1545   /* Compute the holes */
1546   step = M_PI * 2 / discfaces;
1547   for (k = 0; k < nholes; k++)
1548     {
1549       GLdouble *p = holes + (discfaces * 3 * k);
1550       th = 0;
1551       j = 0;
1552       switch (k) {
1553         case 0: x = 0.34; y = 0.17; s = 0.05; break;
1554         case 1: x = 0.54; y = 0.17; s = 0.06; break;
1555         case 2: x = 0.55; y = 0.36; s = 0.06; break;
1556       default: abort(); break;
1557       }
1558       for (i = 0; i < discfaces; i++)
1559         {
1560           p[j++] = x + cos(M_PI*2 - th) * s;
1561           p[j++] = y + sin(M_PI*2 - th) * s;
1562           p[j++] = 0;
1563           th += step;
1564         }
1565     }
1566
1567
1568   /* Draw the inside rim of the holes */
1569   for (k = 0; k < nholes; k++)
1570     {
1571       GLdouble *p = holes + (discfaces * 3 * k);
1572       glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
1573       for (i = 0; i < discfaces; i++)
1574         {
1575           GLdouble *p2 = p + (i*3);
1576           if (i > 0)
1577             do_normal (p2[0],  p2[1],  -thick2,
1578                        p2[0],  p2[1],   thick2,
1579                        p2[-3], p2[-2],  thick2);
1580           glVertex3f (p2[0], p2[1], -thick2);
1581           glVertex3f (p2[0], p2[1],  thick2);
1582           polys++;
1583         }
1584       glVertex3f (p[0], p[1], -thick2);
1585       glVertex3f (p[0], p[1],  thick2);
1586       polys++;
1587       glEnd();
1588     }
1589
1590   glTranslatef (0, 0, -thick2);
1591   for (y = 0; y <= 1; y++)
1592     {
1593       if (y) glTranslatef (0, 0, thick2*2);
1594
1595       /* A non-convex polygon */
1596       gluTessBeginPolygon (tess, to);
1597
1598       glNormal3f (0, 0, (y > 0 ? 1 : -1));
1599       gluTessNormal (tess, 0, 0, (y > 0 ? 1 : -1));
1600       glFrontFace (GL_CCW);
1601
1602       /* Tess the wedge */
1603       gluTessBeginContour (tess);
1604       for (i = 0; i < endpoints; i++)
1605         {
1606           GLdouble *p = points + (i*3);
1607           gluTessVertex (tess, p, p);
1608           polys++;
1609         }
1610       gluTessVertex (tess, points, points);
1611       gluTessEndContour (tess);
1612
1613       /* Tess the holes */
1614       for (k = 0; k < nholes; k++)
1615         {
1616           GLdouble *p = holes + (discfaces * 3 * k);
1617           gluTessBeginContour (tess);
1618           for (i = 0; i < discfaces; i++)
1619             {
1620               GLdouble *p2 = p + (i*3);
1621               gluTessVertex (tess, p2, p2);
1622               polys++;
1623             }
1624           gluTessEndContour (tess);
1625         }
1626
1627       gluTessEndPolygon (tess);
1628     }
1629   glTranslatef (0, 0, -thick2);
1630
1631
1632   /* Compute the crust */
1633
1634   s = 0.861;  /* radius of inside of crust */
1635   step = M_PI * 2 / 6 / topfaces;
1636   th = 0;
1637   j = 0;
1638   for (i = 0; i < topfaces; i++)
1639     {
1640       points[j++] = cos(th) * s;
1641       points[j++] = sin(th) * s;
1642       points[j++] = 0;
1643       th += step;
1644     }
1645
1646   s = 1;
1647   for (i = 0; i < topfaces; i++)
1648     {
1649       points[j++] = cos(th) * s;
1650       points[j++] = sin(th) * s;
1651       points[j++] = 0;
1652       th -= step;
1653     }
1654
1655   /* Draw the rim of the crust */
1656   glFrontFace (GL_CCW);
1657   glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
1658   for (i = 0; i < topfaces * 2; i++)
1659     {
1660       GLdouble *p = points + (i*3);
1661       if (i == 0 || i == (topfaces*2)-1)
1662         glNormal3f (0, -1, 0);
1663       else if (i == topfaces-1 || i == topfaces)
1664         glNormal3f (0, 1, 0);
1665       else
1666         do_normal (p[-3], p[-2], thick2,
1667                    p[0], p[1],   thick2,
1668                    p[0], p[1],  -thick2);
1669       glVertex3f (p[0], p[1], -thick2);
1670       glVertex3f (p[0], p[1],  thick2);
1671       polys++;
1672     }
1673   glVertex3f (points[0], points[1], -thick2);
1674   glVertex3f (points[0], points[1],  thick2);
1675   polys++;
1676   glEnd();
1677
1678   if (wire)
1679     {
1680       glBegin (GL_LINE_STRIP);
1681       for (i = 0; i < topfaces * 2; i++)
1682         {
1683           GLdouble *p = points + (i*3);
1684           glVertex3f (p[0], p[1], -thick2);
1685           polys++;
1686         }
1687       glVertex3f (points[0], points[1], -thick2);
1688       glEnd();
1689
1690       glBegin (GL_LINE_STRIP);
1691       for (i = 0; i < topfaces * 2; i++)
1692         {
1693           GLdouble *p = points + (i*3);
1694           glVertex3f (p[0], p[1], thick2);
1695           polys++;
1696         }
1697       glVertex3f (points[0], points[1], thick2);
1698       glEnd();
1699     }
1700
1701   /* Draw the top of the crust */
1702   if (! wire)
1703     {
1704       glFrontFace (GL_CW);
1705       glBegin (wire ? GL_LINE_STRIP : GL_QUAD_STRIP);
1706       glNormal3f (0, 0, -1);
1707       if (!wire)
1708         for (i = 0; i < topfaces; i++)
1709           {
1710             int ii = topfaces + (topfaces - i - 1);
1711             GLdouble *p1 = points + (i*3);
1712             GLdouble *p2 = points + (ii*3);
1713             glVertex3f (p1[0], p1[1], -thick2);
1714             glVertex3f (p2[0], p2[1], -thick2);
1715             polys++;
1716           }
1717       polys++;
1718       glEnd();
1719
1720       /* Draw the bottom of the crust */
1721       glFrontFace (GL_CCW);
1722       glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
1723       glNormal3f (0, 0, 1);
1724       for (i = 0; i < topfaces; i++)
1725         {
1726           int ii = topfaces + (topfaces - i - 1);
1727           GLdouble *p1 = points + (i*3);
1728           GLdouble *p2 = points + (ii*3);
1729           glVertex3f (p1[0], p1[1], thick2);
1730           glVertex3f (p2[0], p2[1], thick2);
1731           polys++;
1732         }
1733       polys++;
1734       glEnd();
1735     }
1736
1737   gluDeleteTess (tess);
1738   free (points);
1739   free (holes);
1740   free (to->points);
1741
1742   glPopMatrix();
1743
1744   return polys;
1745 }
1746
1747
1748
1749 \f
1750 /* Window management, etc
1751  */
1752 ENTRYPOINT void
1753 reshape_logo (ModeInfo *mi, int width, int height)
1754 {
1755   GLfloat h = (GLfloat) height / (GLfloat) width;
1756
1757   glViewport (0, 0, (GLint) width, (GLint) height);
1758
1759   glMatrixMode(GL_PROJECTION);
1760   glLoadIdentity();
1761   gluPerspective (30.0, 1/h, 1.0, 100.0);
1762
1763   glMatrixMode(GL_MODELVIEW);
1764   glLoadIdentity();
1765   gluLookAt( 0.0, 0.0, 30.0,
1766              0.0, 0.0, 0.0,
1767              0.0, 1.0, 0.0);
1768
1769   glClear(GL_COLOR_BUFFER_BIT);
1770 }
1771
1772
1773 static void
1774 gl_init (ModeInfo *mi)
1775 {
1776 /*  logo_configuration *dc = &dcs[MI_SCREEN(mi)]; */
1777   int wire = MI_IS_WIREFRAME(mi);
1778
1779   GLfloat position[]  = {0, 0, 0, 0};
1780   GLfloat direction[] = {3, -1, -3};
1781
1782   position[0] = -direction[0];
1783   position[1] = -direction[1];
1784   position[2] = -direction[2];
1785
1786   if (!wire)
1787     {
1788       glLightfv(GL_LIGHT0, GL_POSITION, position);
1789       glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direction);
1790       glShadeModel(GL_SMOOTH);
1791       glEnable(GL_NORMALIZE);
1792       glEnable(GL_CULL_FACE);
1793       glEnable(GL_LIGHTING);
1794       glEnable(GL_LIGHT0);
1795       glEnable(GL_DEPTH_TEST);
1796     }
1797 }
1798
1799
1800 ENTRYPOINT void 
1801 init_logo (ModeInfo *mi)
1802 {
1803   logo_configuration *dc;
1804   int do_gasket = get_boolean_resource(mi->dpy, "doGasket", "Boolean");
1805   int do_helix = get_boolean_resource(mi->dpy, "doHelix", "Boolean");
1806   int do_ladder = (do_helix && 
1807                    get_boolean_resource(mi->dpy, "doLadder", "Boolean"));
1808   int do_frame = get_boolean_resource(mi->dpy, "doFrame", "Boolean");
1809   GLfloat helix_rot = 147.0;
1810
1811   if (!do_gasket && !do_helix)
1812     {
1813       fprintf (stderr, "%s: no helix or gasket?\n", progname);
1814       exit (1);
1815     }
1816
1817   if (!dcs) {
1818     dcs = (logo_configuration *)
1819       calloc (MI_NUM_SCREENS(mi), sizeof (logo_configuration));
1820     if (!dcs) {
1821       fprintf(stderr, "%s: out of memory\n", progname);
1822       exit(1);
1823     }
1824   }
1825
1826   dc = &dcs[MI_SCREEN(mi)];
1827
1828   if ((dc->glx_context = init_GL(mi)) != NULL) {
1829     gl_init(mi);
1830     reshape_logo (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1831   }
1832
1833   dc->wall_facets    = get_integer_resource(mi->dpy, "wallFacets",  "Integer");
1834   dc->bar_facets     = get_integer_resource(mi->dpy, "barFacets",   "Integer");
1835   dc->clockwise      = get_boolean_resource(mi->dpy, "clockwise",   "Boolean");
1836   dc->turns          = get_float_resource(mi->dpy, "turns",         "Float");
1837   dc->turn_spacing   = get_float_resource(mi->dpy, "turnSpacing",   "Float");
1838   dc->bar_spacing    = get_float_resource(mi->dpy, "barSpacing",    "Float");
1839   dc->wall_height    = get_float_resource(mi->dpy, "wallHeight",    "Float");
1840   dc->wall_thickness = get_float_resource(mi->dpy, "wallThickness", "Float");
1841   dc->bar_thickness  = get_float_resource(mi->dpy, "barThickness",  "Float");
1842   dc->wall_taper     = get_float_resource(mi->dpy, "wallTaper",     "Float");
1843
1844   dc->gasket_size      = get_float_resource(mi->dpy,"gasketSize",     "Float");
1845   dc->gasket_depth     = get_float_resource(mi->dpy,"gasketDepth",    "Float");
1846   dc->gasket_thickness = get_float_resource(mi->dpy,"gasketThickness","Float");
1847
1848   dc->frame_size      = get_float_resource(mi->dpy, "frameSize",      "Float");
1849   dc->frame_depth     = get_float_resource(mi->dpy, "frameDepth",     "Float");
1850   dc->frame_thickness = get_float_resource(mi->dpy, "frameThickness", "Float");
1851   dc->triangle_size   = get_float_resource(mi->dpy, "triangleSize",   "Float");
1852
1853   dc->speed          = get_float_resource(mi->dpy,   "speed",         "Float");
1854   dc->pizza_p        = get_boolean_resource(mi->dpy, "pizza",       "Boolean");
1855
1856   {
1857     XColor xcolor;
1858
1859     char *color_name = get_string_resource (mi->dpy, "foreground", "Foreground");
1860     char *s2;
1861     for (s2 = color_name + strlen(color_name) - 1; s2 > color_name; s2--)
1862       if (*s2 == ' ' || *s2 == '\t')
1863         *s2 = 0;
1864       else
1865         break;
1866
1867     if (! XParseColor (MI_DISPLAY(mi), mi->xgwa.colormap, color_name, &xcolor))
1868       {
1869         fprintf (stderr, "%s: can't parse color %s\n", progname, color_name);
1870         exit (1);
1871       }
1872
1873     dc->color[0] = xcolor.red   / 65535.0;
1874     dc->color[1] = xcolor.green / 65535.0;
1875     dc->color[2] = xcolor.blue  / 65535.0;
1876     dc->color[3] = 1.0;
1877   }
1878
1879   dc->trackball = gltrackball_init ();
1880
1881   dc->gasket_spinnery.probability = 0.1;
1882   dc->gasket_spinnerx.probability = 0.1;
1883   dc->gasket_spinnerz.probability = 1.0;
1884   dc->helix_spinnerz.probability  = 0.6;
1885   dc->helix_spinnery.probability  = (dc->pizza_p ? 0.6 : 0);
1886   dc->scene_spinnerx.probability  = 0.1;
1887   dc->scene_spinnery.probability  = 0.0;
1888   dc->frame_spinner.probability   = 5.0;
1889
1890   /* start the frame off-screen */
1891   dc->frame_spinner.spinning_p = True;
1892   dc->frame_spinner.position = 0.3;
1893   dc->frame_spinner.speed = 0.001;
1894
1895   if (dc->speed > 0)    /* start off with the gasket in motion */
1896     {
1897       dc->gasket_spinnerz.spinning_p = True;
1898       dc->gasket_spinnerz.speed = (0.002
1899                                    * ((random() & 1) ? 1 : -1)
1900                                    * dc->speed);
1901     }
1902
1903 # ifdef DXF_OUTPUT_HACK
1904   {
1905     dc->frame_depth = dc->gasket_depth;
1906     dxf_layer = 1;
1907     dxf_color = 3;
1908     dxf_start();
1909     glPushMatrix();
1910     glRotatef(90, 1, 0, 0);
1911     glRotatef(90, 0, 0, 1);
1912     if (dc->pizza_p)
1913       make_pizza (dc, 0, 0);
1914     else
1915       {
1916         glPushMatrix();
1917         glRotatef(helix_rot, 0, 0, 1);
1918         make_ladder (dc, 0, 0);
1919         make_helix  (dc, 0, 0);
1920         glRotatef (180, 0, 0, 1);
1921         make_helix  (dc, 0, 0);
1922         glPopMatrix();
1923       }
1924     dxf_layer++;
1925     make_gasket (dc, 0);
1926     dxf_layer++;
1927     make_frame (dc, 0);
1928     glPopMatrix();
1929     dxf_end();
1930   }
1931 # endif
1932
1933   glPushMatrix();
1934   dc->helix_list = glGenLists (1);
1935   glNewList (dc->helix_list, GL_COMPILE);
1936   glRotatef(helix_rot, 0, 0, 1);
1937   if (do_ladder) dc->polys[0] += make_ladder (dc, 0, 0);
1938   if (do_helix)  dc->polys[0] += make_helix  (dc, 0, 0);
1939   glRotatef(180, 0, 0, 1);
1940   if (do_helix)  dc->polys[0] += make_helix  (dc, 0, 0);
1941   glEndList ();
1942   glPopMatrix();
1943
1944   glPushMatrix();
1945   dc->helix_list_wire = glGenLists (1);
1946   glNewList (dc->helix_list_wire, GL_COMPILE);
1947 /*  glRotatef(helix_rot, 0, 0, 1); wtf? */
1948   if (do_ladder) dc->polys[1] += make_ladder (dc, 1, 1);
1949   if (do_helix)  dc->polys[1] += make_helix  (dc, 1, 1);
1950   glRotatef(180, 0, 0, 1);
1951   if (do_helix)  dc->polys[1] += make_helix  (dc, 1, 1);
1952   glEndList ();
1953   glPopMatrix();
1954
1955   glPushMatrix();
1956   dc->helix_list_facetted = glGenLists (1);
1957   glNewList (dc->helix_list_facetted, GL_COMPILE);
1958   glRotatef(helix_rot, 0, 0, 1);
1959   if (do_ladder) dc->polys[2] += make_ladder (dc, 1, 0);
1960   if (do_helix)  dc->polys[2] += make_helix  (dc, 1, 0);
1961   glRotatef(180, 0, 0, 1);
1962   if (do_helix)  dc->polys[2] += make_helix  (dc, 1, 0);
1963   glEndList ();
1964   glPopMatrix();
1965
1966   dc->pizza_list = glGenLists (1);
1967   glNewList (dc->pizza_list, GL_COMPILE);
1968   if (do_frame) dc->polys[5] += make_pizza (dc, 0, 0);
1969   glEndList ();
1970
1971   dc->pizza_list_wire = glGenLists (1);
1972   glNewList (dc->pizza_list_wire, GL_COMPILE);
1973   if (do_frame) dc->polys[6] += make_pizza (dc, 1, 1);
1974   glEndList ();
1975
1976   dc->pizza_list_facetted = glGenLists (1);
1977   glNewList (dc->pizza_list_facetted, GL_COMPILE);
1978   if (do_frame) dc->polys[6] += make_pizza (dc, 1, 0);
1979   glEndList ();
1980
1981   dc->gasket_list = glGenLists (1);
1982   glNewList (dc->gasket_list, GL_COMPILE);
1983   if (do_gasket) dc->polys[3] += make_gasket (dc, 0);
1984   glEndList ();
1985
1986   dc->gasket_list_wire = glGenLists (1);
1987   glNewList (dc->gasket_list_wire, GL_COMPILE);
1988   if (do_gasket) dc->polys[4] += make_gasket (dc, 1);
1989   glEndList ();
1990
1991   dc->frame_list = glGenLists (1);
1992   glNewList (dc->frame_list, GL_COMPILE);
1993   if (do_frame) dc->polys[5] += make_frame (dc, 0);
1994   glEndList ();
1995
1996   dc->frame_list_wire = glGenLists (1);
1997   glNewList (dc->frame_list_wire, GL_COMPILE);
1998   if (do_frame) dc->polys[6] += make_frame (dc, 1);
1999   glEndList ();
2000
2001   /* When drawing both solid and wireframe objects,
2002      make sure the wireframe actually shows up! */
2003   glEnable (GL_POLYGON_OFFSET_FILL);
2004   glPolygonOffset (1.0, 1.0);
2005 }
2006
2007
2008 ENTRYPOINT Bool
2009 logo_handle_event (ModeInfo *mi, XEvent *event)
2010 {
2011   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
2012
2013   if (event->xany.type == ButtonPress &&
2014       event->xbutton.button == Button1)
2015     {
2016       dc->button_down_p = True;
2017       gltrackball_start (dc->trackball,
2018                          event->xbutton.x, event->xbutton.y,
2019                          MI_WIDTH (mi), MI_HEIGHT (mi));
2020       return True;
2021     }
2022   else if (event->xany.type == ButtonRelease &&
2023            event->xbutton.button == Button1)
2024     {
2025       dc->button_down_p = False;
2026       return True;
2027     }
2028   else if (event->xany.type == ButtonPress &&
2029            (event->xbutton.button == Button4 ||
2030             event->xbutton.button == Button5 ||
2031             event->xbutton.button == Button6 ||
2032             event->xbutton.button == Button7))
2033     {
2034       gltrackball_mousewheel (dc->trackball, event->xbutton.button, 10,
2035                               !!event->xbutton.state);
2036       return True;
2037     }
2038   else if (event->xany.type == MotionNotify &&
2039            dc->button_down_p)
2040     {
2041       gltrackball_track (dc->trackball,
2042                          event->xmotion.x, event->xmotion.y,
2043                          MI_WIDTH (mi), MI_HEIGHT (mi));
2044       return True;
2045     }
2046
2047   return False;
2048 }
2049
2050
2051 static void
2052 tick_spinner (ModeInfo *mi, spinner *s)
2053 {
2054   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
2055
2056   if (dc->speed == 0) return;
2057   if (dc->button_down_p) return;
2058
2059   if (s->spinning_p)
2060     {
2061       s->position += s->speed;
2062       if (s->position >=  1.0 || s->position <= -1.0)
2063           
2064         {
2065           s->position = 0;
2066           s->spinning_p = False;
2067         }
2068     }
2069   else if (s->probability &&
2070            (random() % (int) (PROBABILITY_SCALE / s->probability)) == 0)
2071     {
2072       GLfloat ss = 0.004;
2073       s->spinning_p = True;
2074       s->position = 0;
2075       do {
2076         s->speed = dc->speed * (frand(ss/3) + frand(ss/3) + frand(ss/3));
2077       } while (s->speed <= 0);
2078       if (random() & 1)
2079         s->speed = -s->speed;
2080     }
2081 }
2082
2083
2084 static void
2085 link_spinners (ModeInfo *mi, spinner *s0, spinner *s1)
2086 {
2087   if (s0->spinning_p && !s1->spinning_p)
2088     {
2089       GLfloat op = s1->probability;
2090       s1->probability = PROBABILITY_SCALE;
2091       tick_spinner (mi, s1);
2092       s1->probability = op;
2093     }
2094 }
2095
2096
2097 ENTRYPOINT void
2098 draw_logo (ModeInfo *mi)
2099 {
2100   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
2101   Display *dpy = MI_DISPLAY(mi);
2102   Window window = MI_WINDOW(mi);
2103   int wire = MI_IS_WIREFRAME(mi);
2104   GLfloat gcolor[4];
2105   GLfloat specular[]  = {0.8, 0.8, 0.8, 1.0};
2106   GLfloat shininess   = 50.0;
2107
2108   if (!dc->glx_context)
2109     return;
2110
2111   mi->polygon_count = 0;
2112   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(dc->glx_context));
2113
2114   if (dc->wire_overlay == 0 &&
2115       (random() % (int) (PROBABILITY_SCALE / 0.2)) == 0)
2116     dc->wire_overlay = ((random() % 200) +
2117                         (random() % 200) +
2118                         (random() % 200));
2119       
2120   tick_spinner (mi, &dc->gasket_spinnerx);
2121   tick_spinner (mi, &dc->gasket_spinnery);
2122   tick_spinner (mi, &dc->gasket_spinnerz);
2123   tick_spinner (mi, &dc->helix_spinnery);
2124   tick_spinner (mi, &dc->helix_spinnerz);
2125   tick_spinner (mi, &dc->scene_spinnerx);
2126   tick_spinner (mi, &dc->scene_spinnery);
2127   tick_spinner (mi, &dc->frame_spinner);
2128   link_spinners (mi, &dc->scene_spinnerx, &dc->scene_spinnery);
2129
2130   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
2131
2132   glPushMatrix ();
2133   {
2134     glScalef(3, 3, 3);
2135
2136     glColor3f(dc->color[0], dc->color[1], dc->color[2]);
2137
2138     /* Draw frame before trackball rotation */
2139     {
2140       GLfloat p = (dc->frame_spinner.position >= 0
2141                    ? dc->frame_spinner.position
2142                    : -dc->frame_spinner.position);
2143       GLfloat size = (p > 0.5 ? 1-p : p);
2144       GLfloat scale = 1 + (size * 10);
2145       glPushMatrix();
2146       /* gltrackball_rotate (dc->trackball); */
2147       glRotatef(90, 1, 0, 0);
2148       glRotatef(90, 0, 0, 1);
2149
2150       glScalef (1, scale, scale);
2151       if (wire)
2152         {
2153           glCallList (dc->frame_list_wire);
2154           mi->polygon_count += dc->polys[6];
2155         }
2156       else if (dc->wire_overlay != 0)
2157         {
2158           glCallList (dc->frame_list);
2159           glDisable (GL_LIGHTING);
2160           glCallList (dc->frame_list_wire);
2161           mi->polygon_count += dc->polys[6];
2162           if (!wire) glEnable (GL_LIGHTING);
2163         }
2164       else
2165         {
2166           glCallList (dc->frame_list);
2167           mi->polygon_count += dc->polys[5];
2168         }
2169       glPopMatrix();
2170     }
2171
2172     gltrackball_rotate (dc->trackball);
2173
2174     glRotatef(90, 1, 0, 0);
2175     glRotatef(90, 0, 0, 1);
2176
2177     glRotatef (360 * sin (M_PI/2 * dc->scene_spinnerx.position), 0, 1, 0);
2178     glRotatef (360 * sin (M_PI/2 * dc->scene_spinnery.position), 0, 0, 1);
2179
2180     glPushMatrix();
2181     {
2182       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnerx.position), 0, 1, 0);
2183       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnery.position), 0, 0, 1);
2184       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnerz.position), 1, 0, 0);
2185
2186       memcpy (gcolor, dc->color, sizeof (dc->color));
2187       if (dc->wire_overlay != 0)
2188         {
2189           gcolor[0]   = gcolor[1]   = gcolor[2]   = 0;
2190           specular[0] = specular[1] = specular[2] = 0;
2191           shininess = 0;
2192         }
2193       glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gcolor);
2194       glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,  specular);
2195       glMaterialf  (GL_FRONT_AND_BACK, GL_SHININESS, shininess);
2196
2197       if (wire)
2198         {
2199           glCallList (dc->gasket_list_wire);
2200           mi->polygon_count += dc->polys[4];
2201         }
2202       else if (dc->wire_overlay != 0)
2203         {
2204           glCallList (dc->gasket_list);
2205           glDisable (GL_LIGHTING);
2206           glCallList (dc->gasket_list_wire);
2207           mi->polygon_count += dc->polys[4];
2208           if (!wire) glEnable (GL_LIGHTING);
2209         }
2210       else
2211         {
2212           glCallList (dc->gasket_list);
2213           mi->polygon_count += dc->polys[3];
2214         }
2215     }
2216     glPopMatrix();
2217
2218     glRotatef (360 * sin (M_PI/2 * dc->helix_spinnery.position), 1, 0, 0);
2219     glRotatef (360 * sin (M_PI/2 * dc->helix_spinnerz.position), 0, 0, 1);
2220
2221     if (wire)
2222       {
2223         if (dc->pizza_p)
2224           glCallList (dc->pizza_list_wire);
2225         else
2226           glCallList (dc->helix_list_wire);
2227         mi->polygon_count += dc->polys[1];
2228       }
2229     else if (dc->wire_overlay != 0)
2230       {
2231         if (dc->pizza_p)
2232           glCallList (dc->pizza_list_facetted);
2233         else
2234           glCallList (dc->helix_list_facetted);
2235
2236         glDisable (GL_LIGHTING);
2237
2238         if (dc->pizza_p)
2239           glCallList (dc->pizza_list_wire);
2240         else
2241           glCallList (dc->helix_list_wire);
2242
2243         mi->polygon_count += dc->polys[2];
2244         if (!wire) glEnable (GL_LIGHTING);
2245       }
2246     else
2247       {
2248         if (dc->pizza_p)
2249           glCallList (dc->pizza_list);
2250         else
2251           glCallList (dc->helix_list);
2252         mi->polygon_count += dc->polys[0];
2253       }
2254   }
2255   glPopMatrix();
2256
2257   if (dc->wire_overlay > 0)
2258     dc->wire_overlay--;
2259
2260   if (mi->fps_p) do_fps (mi);
2261   glFinish();
2262
2263   glXSwapBuffers(dpy, window);
2264 }
2265
2266 XSCREENSAVER_MODULE_2 ("DNAlogo", dnalogo, logo)
2267
2268 #endif /* USE_GL */