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