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