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