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