http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / glx / dnalogo.c
1 /* DNA Logo, Copyright (c) 2001, 2002, 2003 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                         "*wallFacets:       360     \n" \
20                         "*tubeFacets:       90      \n" \
21                         "*clockwise:        False   \n" \
22                         "*turns:            0.8     \n" \
23                         "*turnSpacing:      2.40    \n" \
24                         "*barSpacing:       0.30    \n" \
25                         "*wallHeight:       0.4     \n" \
26                         "*wallThickness:    0.1     \n" \
27                         "*tubeThickness:    0.075   \n" \
28                         "*wallTaper:        1.047   \n" \
29                         "*gasketSize:       2.15    \n" \
30                         "*gasketDepth:      0.15    \n" \
31                         "*gasketThickness:  0.4     \n" \
32                         "*speed:            1.0     \n" \
33                         ".foreground:       #00AA00 \n" \
34
35 # define refresh_logo 0
36 # define release_logo 0
37 #undef countof
38 #define countof(x) (sizeof((x))/sizeof((*x)))
39
40 #include "xlockmore.h"
41 #include "normals.h"
42 #include "tube.h"
43 #include "rotator.h"
44 #include "gltrackball.h"
45
46 #ifdef USE_GL /* whole file */
47
48 typedef struct {
49   Bool spinning_p;
50   GLfloat position;     /* 0.0 - 1.0 */
51   GLfloat speed;        /* how far along the path (may be negative) */
52   GLfloat probability;  /* relative likelyhood to start spinning */
53 } spinner;
54
55 typedef struct {
56   GLXContext *glx_context;
57
58   GLuint helix_list,  helix_list_wire,  helix_list_facetted;
59   GLuint gasket_list, gasket_list_wire;
60
61   int wall_facets;
62   int tube_facets;
63   Bool clockwise;
64   GLfloat color[4];
65
66   GLfloat turns;
67   GLfloat turn_spacing;
68   GLfloat bar_spacing;
69   GLfloat wall_height;
70   GLfloat wall_thickness;
71   GLfloat tube_thickness;
72   GLfloat wall_taper;
73
74   GLfloat gasket_size;
75   GLfloat gasket_depth;
76   GLfloat gasket_thickness;
77
78   GLfloat speed;
79
80   spinner gasket_spinnerx, gasket_spinnery, gasket_spinnerz;
81   spinner scene_spinnerx,  scene_spinnery;
82   spinner helix_spinnerz;
83
84   trackball_state *trackball;
85   Bool button_down_p;
86
87   int wire_overlay;  /* frame countdown */
88
89 } logo_configuration;
90
91 static logo_configuration *dcs = NULL;
92
93 static XrmOptionDescRec opts[] = {
94   { "-speed",  ".speed",  XrmoptionSepArg, 0 },
95 };
96
97 ENTRYPOINT ModeSpecOpt logo_opts = {countof(opts), opts, 0, NULL, NULL};
98
99 #define PROBABILITY_SCALE 600
100
101
102 \f
103 /* Calculate the angle (in degrees) between two vectors.
104  */
105 static GLfloat
106 vector_angle (double ax, double ay, double az,
107               double bx, double by, double bz)
108 {
109   double La = sqrt (ax*ax + ay*ay + az*az);
110   double Lb = sqrt (bx*bx + by*by + bz*bz);
111   double cc, angle;
112
113   if (La == 0 || Lb == 0) return 0;
114   if (ax == bx && ay == by && az == bz) return 0;
115
116   /* dot product of two vectors is defined as:
117        La * Lb * cos(angle between vectors)
118      and is also defined as:
119        ax*bx + ay*by + az*bz
120      so:
121       La * Lb * cos(angle) = ax*bx + ay*by + az*bz
122       cos(angle)  = (ax*bx + ay*by + az*bz) / (La * Lb)
123       angle = acos ((ax*bx + ay*by + az*bz) / (La * Lb));
124   */
125   cc = (ax*bx + ay*by + az*bz) / (La * Lb);
126   if (cc > 1) cc = 1;  /* avoid fp rounding error (1.000001 => sqrt error) */
127   angle = acos (cc);
128
129   return (angle * M_PI / 180);
130 }
131
132 \f
133 /* Make the helix
134  */
135
136 static void
137 make_helix (logo_configuration *dc, int facetted, int wire)
138 {
139   int wall_facets = dc->wall_facets / (facetted ? 15 : 1);
140   GLfloat th;
141   GLfloat max_th = M_PI * 2 * dc->turns;
142   GLfloat th_inc = M_PI * 2 / wall_facets;
143
144   GLfloat x1=0,  y1=0,  x2=0,  y2=0;
145   GLfloat x1b=0, y1b=0, x2b=0, y2b=0;
146   GLfloat z1=0, z2=0;
147   GLfloat h1=0, h2=0;
148   GLfloat h1off=0, h2off=0;
149   GLfloat z_inc = dc->turn_spacing / wall_facets;
150
151   th  = 0;
152   x1  = 1;
153   y1  = 0;
154   x1b = 1 - dc->wall_thickness;
155   y1b = 0;
156
157   z1 = -(dc->turn_spacing * dc->turns / 2);
158
159   h1 = (dc->wall_taper > 0 ? 0 : dc->wall_height / 2);
160   h1off = (dc->wall_taper > 0 ? -dc->wall_height / 2 : 0);
161
162   if (!dc->clockwise)
163     z1 = -z1, z_inc = -z_inc, h1off = -h1off;
164
165   /* Leading end-cap
166    */
167   if (!wire && h1 > 0)
168     {
169       GLfloat nx, ny;
170       glFrontFace(GL_CCW);
171       glBegin(GL_QUADS);
172       nx = cos (th + M_PI/2);
173       ny = sin (th + M_PI/2);
174       glNormal3f(nx, ny, 0);
175       glVertex3f( x1, y1,  z1 - h1 + h1off);
176       glVertex3f( x1, y1,  z1 + h1 + h1off);
177       glVertex3f(x1b, y1b, z1 + h1 + h1off);
178       glVertex3f(x1b, y1b, z1 - h1 + h1off);
179       glEnd();
180     }
181
182   while (th + th_inc <= max_th)
183     {
184       th += th_inc;
185
186       x2 = cos (th);
187       y2 = sin (th);
188       z2 = z1 + z_inc;
189       x2b = x2 * (1 - dc->wall_thickness);
190       y2b = y2 * (1 - dc->wall_thickness);
191
192       h2 = h1;
193       h2off = h1off;
194
195       if (dc->wall_taper > 0)
196         {
197           h2off = 0;
198           if (th < dc->wall_taper)
199             {
200               h2 = dc->wall_height/2 * cos (M_PI / 2
201                                             * (1 - (th / dc->wall_taper)));
202               if (dc->clockwise)
203                 h2off = h2 - dc->wall_height/2;
204               else
205                 h2off = dc->wall_height/2 - h2;
206             }
207           else if (th >= max_th - dc->wall_taper)
208             {
209               if (th + th_inc > max_th) /* edge case: always come to a point */
210                 h2 = 0;
211               else
212                 h2 = dc->wall_height/2 * cos (M_PI / 2
213                                               * (1 - ((max_th - th)
214                                                       / dc->wall_taper)));
215               if (dc->clockwise)
216                 h2off = dc->wall_height/2 - h2;
217               else
218                 h2off = h2 - dc->wall_height/2;
219             }
220         }
221
222       /* outer face
223        */
224       glFrontFace(GL_CW);
225       glBegin(wire ? GL_LINES : GL_QUADS);
226       glNormal3f(x1, y1, 0);
227       glVertex3f(x1, y1, z1 - h1 + h1off);
228       glVertex3f(x1, y1, z1 + h1 + h1off);
229       glNormal3f(x2, y2, 0);
230       glVertex3f(x2, y2, z2 + h2 + h2off);
231       glVertex3f(x2, y2, z2 - h2 + h2off);
232       glEnd();
233
234       /* inner face
235        */
236       glFrontFace(GL_CCW);
237       glBegin(wire ? GL_LINES : GL_QUADS);
238       glNormal3f(-x1b, -y1b, 0);
239       glVertex3f( x1b,  y1b, z1 - h1 + h1off);
240       glVertex3f( x1b,  y1b, z1 + h1 + h1off);
241       glNormal3f(-x2b, -y2b, 0);
242       glVertex3f( x2b,  y2b, z2 + h2 + h2off);
243       glVertex3f( x2b,  y2b, z2 - h2 + h2off);
244       glEnd();
245
246       /* top face
247        */
248       glFrontFace(GL_CCW);
249       /* glNormal3f(0, 0, 1);*/
250       do_normal (x2,   y2,  z2 + h2 + h2off,
251                  x2b,  y2b, z2 + h2 + h2off,
252                  x1b,  y1b, z1 + h1 + h1off);
253       glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
254       glVertex3f( x2,   y2,  z2 + h2 + h2off);
255       glVertex3f( x2b,  y2b, z2 + h2 + h2off);
256       glVertex3f( x1b,  y1b, z1 + h1 + h1off);
257       glVertex3f( x1,   y1,  z1 + h1 + h1off);
258
259       glEnd();
260
261       /* bottom face
262        */
263       glFrontFace(GL_CCW);
264       do_normal ( x1,   y1,  z1 - h1 + h1off,
265                   x1b,  y1b, z1 - h1 + h1off,
266                   x2b,  y2b, z2 - h2 + h2off);
267       glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
268       glNormal3f(0, 0, -1);
269       glVertex3f( x1,   y1,  z1 - h1 + h1off);
270       glVertex3f( x1b,  y1b, z1 - h1 + h1off);
271       glVertex3f( x2b,  y2b, z2 - h2 + h2off);
272       glVertex3f( x2,   y2,  z2 - h2 + h2off);
273       glEnd();
274
275       x1 = x2;
276       y1 = y2;
277       x1b = x2b;
278       y1b = y2b;
279       z1 += z_inc;
280       h1 = h2;
281       h1off = h2off;
282     }
283
284   /* Trailing end-cap
285    */
286   if (!wire && h2 > 0)
287     {
288       GLfloat nx, ny;
289       glFrontFace(GL_CW);
290       glBegin(GL_QUADS);
291       nx = cos (th + M_PI/2);
292       ny = sin (th + M_PI/2);
293       glNormal3f(nx, ny, 0);
294       glVertex3f(x2,  y2,  z1 - h2 + h2off);
295       glVertex3f(x2,  y2,  z1 + h2 + h2off);
296       glVertex3f(x2b, y2b, z1 + h2 + h2off);
297       glVertex3f(x2b, y2b, z1 - h2 + h2off);
298       glEnd();
299     }
300 }
301
302
303 static void
304 make_ladder (logo_configuration *dc, int facetted, int wire)
305 {
306   GLfloat th;
307   GLfloat max_th = dc->turns * M_PI * 2;
308   GLfloat max_z  = dc->turns * dc->turn_spacing;
309   GLfloat z_inc  = dc->bar_spacing;
310   GLfloat th_inc = M_PI * 2 * (dc->bar_spacing / dc->turn_spacing);
311   GLfloat x, y, z;
312
313   /* skip forward to center the bars in the helix... */
314   int i;
315   GLfloat usable_th = max_th - dc->wall_taper;
316   GLfloat usable_z  = max_z / (max_th / usable_th);
317   int nbars = usable_z / dc->bar_spacing;
318   GLfloat used_z = (nbars - 1) * dc->bar_spacing;
319   GLfloat pad_z = max_z - used_z;
320   GLfloat pad_ratio = pad_z / max_z;
321
322   th = (max_th * pad_ratio/2);
323   z  = -(max_z / 2) + (max_z * pad_ratio/2);
324
325   if (!dc->clockwise)
326     z = -z, z_inc = -z_inc;
327
328   for (i = 0; i < nbars; i++)
329     {
330       int facets = dc->tube_facets / (facetted ? 14 : 1);
331       if (facets <= 3) facets = 3;
332       x = cos (th) * (1 - dc->wall_thickness);
333       y = sin (th) * (1 - dc->wall_thickness);
334       tube ( x,  y, z,
335             -x, -y, z,
336              dc->tube_thickness, 0, facets,
337              True, True, wire);
338       z  += z_inc;
339       th += th_inc;
340     }
341 }
342
343
344 \f
345 /* Make the gasket
346  */
347
348
349 static void
350 make_gasket (logo_configuration *dc, int wire)
351 {
352   int i;
353   int points_size;
354   int npoints = 0;
355   int nctrls = 0;
356   int res = 360/8;
357   GLfloat d2r = M_PI / 180;
358
359   GLfloat thick2 = (dc->gasket_thickness / dc->gasket_size) / 2;
360
361   GLfloat *pointsx0, *pointsy0, *pointsx1, *pointsy1, *normals;
362
363   GLfloat r0  = 0.780;  /* 395 */
364   GLfloat r1a = 0.855;                /* top of wall below upper left hole */
365   GLfloat r1b = 0.890;                /* center of upper left hole */
366   GLfloat r1c = 0.922;                /* bottom of wall above hole */
367   GLfloat r1  = 0.928;  /* 471 */
368   GLfloat r2  = 0.966;  /* 490 */
369   GLfloat r3  = 0.984;  /* 499 */
370   GLfloat r4  = 1.000;  /* 507 */
371   GLfloat r5  = 1.090;  /* 553 */
372
373   GLfloat ctrl_r[100], ctrl_th[100];
374
375   glPushMatrix();
376
377 # define POINT(r,th) \
378     ctrl_r [nctrls] = r, \
379     ctrl_th[nctrls] = (th * d2r), \
380     nctrls++
381
382   POINT (0.829, 0);      /* top indentation, right half */
383   POINT (0.831, 0.85);
384   POINT (0.835, 1.81);
385   POINT (0.841, 2.65);
386   POINT (0.851, 3.30);
387   POINT (0.862, 3.81);
388   POINT (0.872, 3.95);
389
390   POINT (r4,    4.0);   /* moving clockwise... */
391   POINT (r4,   48.2);
392   POINT (r1,   48.2);
393   POINT (r1,   54.2);
394   POINT (r2,   55.8);
395   POINT (r2,   73.2);
396   POINT (r1,   74.8);
397   POINT (r1,  101.2);
398   POINT (r3,  103.4);
399   POINT (r3,  132.0);
400   POINT (r1,  133.4);
401
402   POINT (r1,  180.7);
403   POINT (r2,  183.6);
404   POINT (r2,  209.8);
405   POINT (r1,  211.0);
406   POINT (r1,  221.8);
407   POINT (r5,  221.8);
408   POINT (r5,  223.2);
409   POINT (r4,  223.2);
410
411   POINT (r4,  316.8);      /* upper left indentation */
412   POINT (0.990, 326.87);
413   POINT (0.880, 327.21);
414   POINT (0.872, 327.45);
415   POINT (0.869, 327.80);
416   POINT (0.867, 328.10);
417
418   POINT (0.867, 328.85);
419   POINT (0.869, 329.15);
420   POINT (0.872, 329.50);
421   POINT (0.880, 329.74);
422   POINT (0.990, 330.08);
423
424   POINT (r4,  339.0);
425   if (! wire)
426     {
427       POINT (r1a, 339.0);      /* cut-out disc */
428       POINT (r1a, 343.0);
429     }
430   POINT (r4,  343.0);
431   POINT (r4,  356.0);
432
433   POINT (0.872, 356.05);   /* top indentation, left half */
434   POINT (0.862, 356.19);
435   POINT (0.851, 356.70);
436   POINT (0.841, 357.35);
437   POINT (0.835, 358.19);
438   POINT (0.831, 359.15);
439   POINT (0.829, 360);
440 # undef POINT
441
442   points_size = res + (nctrls * 2);
443   pointsx0 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
444   pointsy0 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
445   pointsx1 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
446   pointsy1 = (GLfloat *) malloc (points_size * sizeof(GLfloat));
447   normals  = (GLfloat *) malloc (points_size * sizeof(GLfloat) * 2);
448
449   npoints = 0;
450   for (i = 1; i < nctrls; i++)
451     {
452       GLfloat from_r  = ctrl_r [i-1];
453       GLfloat from_th = ctrl_th[i-1];
454       GLfloat to_r    = ctrl_r [i];
455       GLfloat to_th   = ctrl_th[i];
456
457       GLfloat step = 2*M_PI / res;
458       int nsteps = 1 + ((to_th - from_th) / step);
459       int j;
460
461       for (j = 0; j < nsteps + (i == nctrls-1); j++)
462         {
463           GLfloat r  = from_r  + (j * (to_r  - from_r)  / nsteps);
464           GLfloat th = from_th + (j * (to_th - from_th) / nsteps);
465
466           GLfloat cth = cos(th) * dc->gasket_size;
467           GLfloat sth = sin(th) * dc->gasket_size;
468
469           pointsx0[npoints] = r0 * cth;  /* inner ring */
470           pointsy0[npoints] = r0 * sth;
471           pointsx1[npoints] = r  * cth;  /* outer ring */
472           pointsy1[npoints] = r  * sth;
473           npoints++;
474
475           if (npoints >= points_size) abort();
476         }
477     }
478
479   /* normals for the outer ring */
480   for (i = 1; i < npoints; i++)
481     {
482       XYZ a, b, c, n;
483       a.x = pointsx1[i-1];
484       a.y = pointsy1[i-1];
485       a.z = 0;
486       b.x = pointsx1[i];
487       b.y = pointsy1[i];
488       b.z = 0;
489       c = b;
490       c.z = 1;
491       n = calc_normal (a, b, c);
492       normals[(i-1)*2  ] = n.x;
493       normals[(i-1)*2+1] = n.y;
494     }
495
496   glRotatef(-90, 0, 1, 0);
497   glRotatef(180, 0, 0, 1);
498
499   if (wire)
500     {
501       GLfloat z;
502       for (z = -thick2; z <= thick2; z += thick2*2)
503         {
504 # if 1
505           /* inside edge */
506           glBegin (GL_LINE_LOOP);
507           for (i = 0; i < npoints; i++)
508             glVertex3f (pointsx0[i], pointsy0[i], z);
509           glEnd();
510
511           /* outside edge */
512           glBegin (GL_LINE_LOOP);
513           for (i = 0; i < npoints; i++)
514             glVertex3f (pointsx1[i], pointsy1[i], z);
515           glEnd();
516 # else
517           for (i = 1; i < npoints; i++)
518             {
519               glBegin (GL_LINE_STRIP);
520               glVertex3f (pointsx0[i-1], pointsy0[i-1], z);
521               glVertex3f (pointsx0[i  ], pointsy0[i  ], z);
522               glVertex3f (pointsx1[i  ], pointsy1[i  ], z);
523               glVertex3f (pointsx1[i-1], pointsy1[i-1], z);
524               glEnd();
525             }
526 # endif
527         }
528 #if 1
529       glBegin (GL_LINES);
530       for (i = 0; i < npoints; i++)
531         {
532           /* inside rim */
533           glVertex3f (pointsx0[i], pointsy0[i], -thick2);
534           glVertex3f (pointsx0[i], pointsy0[i],  thick2);
535           /* outside rim */
536           glVertex3f (pointsx1[i], pointsy1[i], -thick2);
537           glVertex3f (pointsx1[i], pointsy1[i],  thick2);
538         }
539       glEnd();
540 #endif
541     }
542   else
543     {
544       /* top */
545       glFrontFace(GL_CW);
546       glNormal3f(0, 0, -1);
547       glBegin (GL_QUAD_STRIP);
548       for (i = 0; i < npoints; i++)
549         {
550           glVertex3f (pointsx0[i], pointsy0[i], -thick2);
551           glVertex3f (pointsx1[i], pointsy1[i], -thick2);
552         }
553       glEnd();
554
555       /* bottom */
556       glFrontFace(GL_CCW);
557       glNormal3f(0, 0, 1);
558       glBegin (GL_QUAD_STRIP);
559       for (i = 0; i < npoints; i++)
560         {
561           glVertex3f (pointsx0[i], pointsy0[i], thick2);
562           glVertex3f (pointsx1[i], pointsy1[i], thick2);
563         }
564       glEnd();
565
566       /* inside edge */
567       glFrontFace(GL_CW);
568       glBegin (GL_QUAD_STRIP);
569       for (i = 0; i < npoints; i++)
570         {
571           glNormal3f (-pointsx0[i], -pointsy0[i],  0);
572           glVertex3f ( pointsx0[i],  pointsy0[i],  thick2);
573           glVertex3f ( pointsx0[i],  pointsy0[i], -thick2);
574         }
575       glEnd();
576
577       /* outside edge */
578       glFrontFace(GL_CCW);
579       glBegin (GL_QUADS);
580       {
581         for (i = 0; i < npoints-1; i++)
582           {
583             int ia = (i == 0 ? npoints-2 : i-1);
584             int iz = (i == npoints-2 ? 0 : i+1);
585             GLfloat  x = pointsx1[i];
586             GLfloat  y = pointsy1[i];
587             GLfloat xz = pointsx1[iz];
588             GLfloat yz = pointsy1[iz];
589
590             GLfloat nxa = normals[ia*2];   /* normal of [i-1 - i] face */
591             GLfloat nya = normals[ia*2+1];
592             GLfloat nx  = normals[i*2];    /* normal of [i - i+1] face */
593             GLfloat ny  = normals[i*2+1];
594             GLfloat nxz = normals[iz*2];    /* normal of [i+1 - i+2] face */
595             GLfloat nyz = normals[iz*2+1];
596
597             GLfloat anglea = vector_angle (nx, ny, 0, nxa, nya, 0);
598             GLfloat anglez = vector_angle (nx, ny, 0, nxz, nyz, 0);
599             GLfloat pointy = 0.005;
600
601             if (anglea > pointy)
602               {
603                 glNormal3f (nx, ny, 0);
604                 glVertex3f (x,  y,   thick2);
605                 glVertex3f (x,  y,  -thick2);
606               }
607             else
608               {
609                 glNormal3f ((nxa + nx) / 2, (nya + ny) / 2, 0);
610                 glVertex3f (x,  y,   thick2);
611                 glVertex3f (x,  y,  -thick2);
612               }
613
614             if (anglez > pointy)
615               {
616                 glNormal3f (nx, ny, 0);
617                 glVertex3f (xz, yz, -thick2);
618                 glVertex3f (xz, yz,  thick2);
619               }
620             else
621               {
622                 glNormal3f ((nx + nxz) / 2, (ny + nyz) / 2, 0);
623                 glVertex3f (xz, yz, -thick2);
624                 glVertex3f (xz, yz,  thick2);
625               }
626           }
627       }
628       glEnd();
629     }
630
631   /* Fill in the upper left hole...
632    */
633   {
634     GLfloat th;
635     npoints = 0;
636
637     th = 339.0 * d2r;
638     pointsx0[npoints] = r1c * cos(th) * dc->gasket_size;
639     pointsy0[npoints] = r1c * sin(th) * dc->gasket_size;
640     npoints++;
641     pointsx0[npoints] = r4 * cos(th) * dc->gasket_size;
642     pointsy0[npoints] = r4 * sin(th) * dc->gasket_size;
643     npoints++;
644
645     th = 343.0 * d2r;
646     pointsx0[npoints] = r1c * cos(th) * dc->gasket_size;
647     pointsy0[npoints] = r1c * sin(th) * dc->gasket_size;
648     npoints++;
649     pointsx0[npoints] = r4 * cos(th) * dc->gasket_size;
650     pointsy0[npoints] = r4 * sin(th) * dc->gasket_size;
651     npoints++;
652
653     if (! wire)
654       {
655         /* front wall */
656         glNormal3f (0, 0, -1);
657         glFrontFace(GL_CW);
658         glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
659         glVertex3f (pointsx0[0], pointsy0[0], -thick2);
660         glVertex3f (pointsx0[1], pointsy0[1], -thick2);
661         glVertex3f (pointsx0[3], pointsy0[3], -thick2);
662         glVertex3f (pointsx0[2], pointsy0[2], -thick2);
663         glEnd();
664
665         /* back wall */
666         glNormal3f (0, 0, 1);
667         glFrontFace(GL_CCW);
668         glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
669         glVertex3f (pointsx0[0], pointsy0[0],  thick2);
670         glVertex3f (pointsx0[1], pointsy0[1],  thick2);
671         glVertex3f (pointsx0[3], pointsy0[3],  thick2);
672         glVertex3f (pointsx0[2], pointsy0[2],  thick2);
673         glEnd();
674       }
675
676     /* top wall */
677     glFrontFace(GL_CW);
678     glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
679     glNormal3f (pointsx0[1], pointsy0[1], 0);
680     glVertex3f (pointsx0[1], pointsy0[1],  thick2);
681     glNormal3f (pointsx0[3], pointsy0[3], 0);
682     glVertex3f (pointsx0[3], pointsy0[3],  thick2);
683     glVertex3f (pointsx0[3], pointsy0[3], -thick2);
684     glNormal3f (pointsx0[1], pointsy0[1], 0);
685     glVertex3f (pointsx0[1], pointsy0[1], -thick2);
686     glEnd();
687
688
689     /* Now make a donut.
690      */
691     {
692       int nsteps = 12;
693       GLfloat r0 = 0.026;
694       GLfloat r1 = 0.060;
695       GLfloat th, cth, sth;
696
697       glPushMatrix ();
698
699       th = ((339.0 + 343.0) / 2) * d2r;
700       
701       glTranslatef (r1b * cos(th) * dc->gasket_size,
702                     r1b * sin(th) * dc->gasket_size,
703                     0);
704
705       npoints = 0;
706       for (i = 0; i < nsteps; i++)
707         {
708           th = 2 * M_PI * i / nsteps;
709           cth = cos (th) * dc->gasket_size;
710           sth = sin (th) * dc->gasket_size;
711           pointsx0[npoints] = r0 * cth;
712           pointsy0[npoints] = r0 * sth;
713           pointsx1[npoints] = r1 * cth;
714           pointsy1[npoints] = r1 * sth;
715           npoints++;
716         }
717
718       pointsx0[npoints] = pointsx0[0];
719       pointsy0[npoints] = pointsy0[0];
720       pointsx1[npoints] = pointsx1[0];
721       pointsy1[npoints] = pointsy1[0];
722       npoints++;
723
724       if (wire)
725         {
726           glBegin (GL_LINE_LOOP);
727           for (i = 0; i < npoints; i++)
728             glVertex3f (pointsx0[i], pointsy0[i], -thick2);
729           glEnd();
730           glBegin (GL_LINE_LOOP);
731           for (i = 0; i < npoints; i++)
732             glVertex3f (pointsx0[i], pointsy0[i],  thick2);
733           glEnd();
734 # if 0
735           glBegin (GL_LINE_LOOP);
736           for (i = 0; i < npoints; i++)
737             glVertex3f (pointsx1[i], pointsy1[i], -thick2);
738           glEnd();
739           glBegin (GL_LINE_LOOP);
740           for (i = 0; i < npoints; i++)
741             glVertex3f (pointsx1[i], pointsy1[i],  thick2);
742           glEnd();
743 # endif
744         }
745       else
746         {
747           /* top */
748           glFrontFace(GL_CW);
749           glNormal3f(0, 0, -1);
750           glBegin (GL_QUAD_STRIP);
751           for (i = 0; i < npoints; i++)
752             {
753               glVertex3f (pointsx0[i], pointsy0[i], -thick2);
754               glVertex3f (pointsx1[i], pointsy1[i], -thick2);
755             }
756           glEnd();
757
758           /* bottom */
759           glFrontFace(GL_CCW);
760           glNormal3f(0, 0, 1);
761           glBegin (GL_QUAD_STRIP);
762           for (i = 0; i < npoints; i++)
763             {
764               glVertex3f (pointsx0[i], pointsy0[i],  thick2);
765               glVertex3f (pointsx1[i], pointsy1[i],  thick2);
766             }
767           glEnd();
768         }
769
770       /* inside edge */
771       glFrontFace(GL_CW);
772       glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
773       for (i = 0; i < npoints; i++)
774         {
775           glNormal3f (-pointsx0[i], -pointsy0[i],  0);
776           glVertex3f ( pointsx0[i],  pointsy0[i],  thick2);
777           glVertex3f ( pointsx0[i],  pointsy0[i], -thick2);
778         }
779       glEnd();
780
781       glPopMatrix();
782     }
783   }
784
785
786   /* Attach the bottom-right dingus...
787    */
788   {
789     GLfloat w = 0.04;
790     GLfloat h = 0.17;
791     GLfloat th;
792
793     glRotatef (50, 0, 0, 1);
794     glScalef (dc->gasket_size, dc->gasket_size, 1);
795     glTranslatef (0, (r0+r1)/2, 0);
796
797     /* buried box */
798     if (! wire)
799       {
800         glFrontFace(GL_CCW);
801         glBegin (wire ? GL_LINE_STRIP : GL_QUADS);
802         glNormal3f (0, 0, -1);
803         glVertex3f (-w/2, -h/2, -thick2); glVertex3f (-w/2,  h/2, -thick2);
804         glVertex3f ( w/2,  h/2, -thick2); glVertex3f ( w/2, -h/2, -thick2);
805         glNormal3f (1, 0, 0);
806         glVertex3f ( w/2, -h/2, -thick2); glVertex3f ( w/2,  h/2, -thick2);
807         glVertex3f ( w/2,  h/2,  thick2); glVertex3f ( w/2, -h/2,  thick2);
808         glNormal3f (0, 0, 1);
809         glVertex3f ( w/2, -h/2,  thick2); glVertex3f ( w/2,  h/2,  thick2);
810         glVertex3f (-w/2,  h/2,  thick2); glVertex3f (-w/2, -h/2,  thick2);
811         glNormal3f (-1, 0, 0);
812         glVertex3f (-w/2, -h/2,  thick2); glVertex3f (-w/2,  h/2,  thick2);
813         glVertex3f (-w/2,  h/2, -thick2); glVertex3f (-w/2, -h/2, -thick2);
814         glEnd();
815       }
816
817     npoints = 0;
818     for (th = 0; th < M_PI; th += (M_PI / 6))
819       {
820         pointsx0[npoints] = w/2 * cos(th);
821         pointsy0[npoints] = w/2 * sin(th);
822         npoints++;
823       }
824
825     /* front inside curve */
826     glNormal3f (0, 0, -1);
827     glFrontFace(GL_CW);
828     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
829     if (! wire) glVertex3f (0, h/2, -thick2);
830     for (i = 0; i < npoints; i++)
831       glVertex3f (pointsx0[i], h/2 + pointsy0[i], -thick2);
832     glEnd();
833
834     /* front outside curve */
835     glFrontFace(GL_CCW);
836     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
837     if (! wire) glVertex3f (0, -h/2, -thick2);
838     for (i = 0; i < npoints; i++)
839       glVertex3f (pointsx0[i], -h/2 - pointsy0[i], -thick2);
840     glEnd();
841
842     /* back inside curve */
843     glNormal3f (0, 0, 1);
844     glFrontFace(GL_CCW);
845     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
846     if (! wire) glVertex3f (0, h/2, thick2);
847     for (i = 0; i < npoints; i++)
848       glVertex3f (pointsx0[i], h/2 + pointsy0[i], thick2);
849     glEnd();
850
851     /* back outside curve */
852     glFrontFace(GL_CW);
853     glBegin (wire ? GL_LINE_STRIP : GL_TRIANGLE_FAN);
854     if (! wire) glVertex3f (0, -h/2, thick2);
855     for (i = 0; i < npoints; i++)
856       glVertex3f (pointsx0[i], -h/2 - pointsy0[i], thick2);
857     glEnd();
858
859     /* inside curve */
860     glFrontFace(GL_CCW);
861     glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
862     for (i = 0; i < npoints; i++)
863       {
864         glNormal3f (pointsx0[i], pointsy0[i], 0);
865         glVertex3f (pointsx0[i], h/2 + pointsy0[i],  thick2);
866         glVertex3f (pointsx0[i], h/2 + pointsy0[i], -thick2);
867       }
868     glEnd();
869
870     /* outside curve */
871     glFrontFace(GL_CW);
872     glBegin (wire ? GL_LINES : GL_QUAD_STRIP);
873     for (i = 0; i < npoints; i++)
874       {
875         glNormal3f (pointsx0[i], -pointsy0[i], 0);
876         glVertex3f (pointsx0[i], -h/2 - pointsy0[i],  thick2);
877         glVertex3f (pointsx0[i], -h/2 - pointsy0[i], -thick2);
878       }
879     glEnd();
880   }
881
882   free (pointsx0);
883   free (pointsy0);
884   free (pointsx1);
885   free (pointsy1);
886   free (normals);
887
888   glPopMatrix();
889 }
890
891 \f
892 /* Window management, etc
893  */
894 ENTRYPOINT void
895 reshape_logo (ModeInfo *mi, int width, int height)
896 {
897   GLfloat h = (GLfloat) height / (GLfloat) width;
898
899   glViewport (0, 0, (GLint) width, (GLint) height);
900
901   glMatrixMode(GL_PROJECTION);
902   glLoadIdentity();
903   gluPerspective (30.0, 1/h, 1.0, 100.0);
904
905   glMatrixMode(GL_MODELVIEW);
906   glLoadIdentity();
907   gluLookAt( 0.0, 0.0, 30.0,
908              0.0, 0.0, 0.0,
909              0.0, 1.0, 0.0);
910
911   glClear(GL_COLOR_BUFFER_BIT);
912 }
913
914
915 static void
916 gl_init (ModeInfo *mi)
917 {
918 /*  logo_configuration *dc = &dcs[MI_SCREEN(mi)]; */
919   int wire = MI_IS_WIREFRAME(mi);
920
921   GLfloat position[]  = {0, 0, 0, 0};
922   GLfloat direction[] = {3, -1, -3};
923
924   position[0] = -direction[0];
925   position[1] = -direction[1];
926   position[2] = -direction[2];
927
928   if (!wire)
929     {
930       glLightfv(GL_LIGHT0, GL_POSITION, position);
931       glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, direction);
932       glShadeModel(GL_SMOOTH);
933       glEnable(GL_NORMALIZE);
934       glEnable(GL_CULL_FACE);
935       glEnable(GL_LIGHTING);
936       glEnable(GL_LIGHT0);
937       glEnable(GL_DEPTH_TEST);
938     }
939 }
940
941
942 ENTRYPOINT void 
943 init_logo (ModeInfo *mi)
944 {
945   logo_configuration *dc;
946   int do_gasket = get_boolean_resource(mi->dpy, "doGasket", "Boolean");
947   int do_helix = get_boolean_resource(mi->dpy, "doHelix", "Boolean");
948   int do_ladder = do_helix && get_boolean_resource(mi->dpy, "doLadder", "Boolean");
949
950   if (!do_gasket && !do_helix)
951     {
952       fprintf (stderr, "%s: no helix or gasket?\n", progname);
953       exit (1);
954     }
955
956   if (!dcs) {
957     dcs = (logo_configuration *)
958       calloc (MI_NUM_SCREENS(mi), sizeof (logo_configuration));
959     if (!dcs) {
960       fprintf(stderr, "%s: out of memory\n", progname);
961       exit(1);
962     }
963   }
964
965   dc = &dcs[MI_SCREEN(mi)];
966
967   if ((dc->glx_context = init_GL(mi)) != NULL) {
968     gl_init(mi);
969     reshape_logo (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
970   }
971
972   dc->wall_facets    = get_integer_resource(mi->dpy, "wallFacets",  "Integer");
973   dc->tube_facets    = get_integer_resource(mi->dpy, "tubeFacets",  "Integer");
974   dc->clockwise      = get_boolean_resource(mi->dpy, "clockwise",   "Boolean");
975   dc->turns          = get_float_resource(mi->dpy, "turns",         "Float");
976   dc->turn_spacing   = get_float_resource(mi->dpy, "turnSpacing",   "Float");
977   dc->bar_spacing    = get_float_resource(mi->dpy, "barSpacing",    "Float");
978   dc->wall_height    = get_float_resource(mi->dpy, "wallHeight",    "Float");
979   dc->wall_thickness = get_float_resource(mi->dpy, "wallThickness", "Float");
980   dc->tube_thickness = get_float_resource(mi->dpy, "tubeThickness", "Float");
981   dc->wall_taper     = get_float_resource(mi->dpy, "wallTaper",     "Float");
982
983   dc->gasket_size      = get_float_resource(mi->dpy, "gasketSize",      "Float");
984   dc->gasket_depth     = get_float_resource(mi->dpy, "gasketDepth",     "Float");
985   dc->gasket_thickness = get_float_resource(mi->dpy, "gasketThickness", "Float");
986
987   dc->speed          = get_float_resource(mi->dpy, "speed",         "Float");
988
989   {
990     XColor xcolor;
991
992     char *color_name = get_string_resource (mi->dpy, "foreground", "Foreground");
993     char *s2;
994     for (s2 = color_name + strlen(color_name) - 1; s2 > color_name; s2--)
995       if (*s2 == ' ' || *s2 == '\t')
996         *s2 = 0;
997       else
998         break;
999
1000     if (! XParseColor (MI_DISPLAY(mi), mi->xgwa.colormap, color_name, &xcolor))
1001       {
1002         fprintf (stderr, "%s: can't parse color %s\n", progname, color_name);
1003         exit (1);
1004       }
1005
1006     dc->color[0] = xcolor.red   / 65535.0;
1007     dc->color[1] = xcolor.green / 65535.0;
1008     dc->color[2] = xcolor.blue  / 65535.0;
1009     dc->color[3] = 1.0;
1010   }
1011
1012   dc->trackball = gltrackball_init ();
1013
1014   dc->gasket_spinnery.probability = 0.1;
1015   dc->gasket_spinnerx.probability = 0.1;
1016   dc->gasket_spinnerz.probability = 1.0;
1017   dc->helix_spinnerz.probability  = 0.6;
1018   dc->scene_spinnerx.probability  = 0.1;
1019   dc->scene_spinnery.probability  = 0.0;
1020
1021   if (dc->speed > 0)    /* start off with the gasket in motion */
1022     {
1023       dc->gasket_spinnerz.spinning_p = True;
1024       dc->gasket_spinnerz.speed = (0.002
1025                                    * ((random() & 1) ? 1 : -1)
1026                                    * dc->speed);
1027     }
1028
1029   glPushMatrix();
1030   dc->helix_list = glGenLists (1);
1031   glNewList (dc->helix_list, GL_COMPILE);
1032   glRotatef(126, 0, 0, 1);
1033   if (do_ladder) make_ladder (dc, 0, 0);
1034   if (do_helix)  make_helix  (dc, 0, 0);
1035   glRotatef(180, 0, 0, 1);
1036   if (do_helix)  make_helix  (dc, 0, 0);
1037   glEndList ();
1038   glPopMatrix();
1039
1040   glPushMatrix();
1041   dc->helix_list_wire = glGenLists (1);
1042   glNewList (dc->helix_list_wire, GL_COMPILE);
1043   /* glRotatef(126, 0, 0, 1); wtf? */
1044   if (do_ladder) make_ladder (dc, 1, 1);
1045   if (do_helix)  make_helix  (dc, 1, 1);
1046   glRotatef(180, 0, 0, 1);
1047   if (do_helix)  make_helix  (dc, 1, 1);
1048   glEndList ();
1049   glPopMatrix();
1050
1051   glPushMatrix();
1052   dc->helix_list_facetted = glGenLists (1);
1053   glNewList (dc->helix_list_facetted, GL_COMPILE);
1054   glRotatef(126, 0, 0, 1);
1055   if (do_ladder) make_ladder (dc, 1, 0);
1056   if (do_helix)  make_helix  (dc, 1, 0);
1057   glRotatef(180, 0, 0, 1);
1058   if (do_helix)  make_helix  (dc, 1, 0);
1059   glEndList ();
1060   glPopMatrix();
1061
1062   dc->gasket_list = glGenLists (1);
1063   glNewList (dc->gasket_list, GL_COMPILE);
1064   if (do_gasket) make_gasket (dc, 0);
1065   glEndList ();
1066
1067   dc->gasket_list_wire = glGenLists (1);
1068   glNewList (dc->gasket_list_wire, GL_COMPILE);
1069   if (do_gasket) make_gasket (dc, 1);
1070   glEndList ();
1071
1072   /* When drawing both solid and wireframe objects,
1073      make sure the wireframe actually shows up! */
1074   glEnable (GL_POLYGON_OFFSET_FILL);
1075   glPolygonOffset (1.0, 1.0);
1076 }
1077
1078
1079 ENTRYPOINT Bool
1080 logo_handle_event (ModeInfo *mi, XEvent *event)
1081 {
1082   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
1083
1084   if (event->xany.type == ButtonPress &&
1085       event->xbutton.button == Button1)
1086     {
1087       dc->button_down_p = True;
1088       gltrackball_start (dc->trackball,
1089                          event->xbutton.x, event->xbutton.y,
1090                          MI_WIDTH (mi), MI_HEIGHT (mi));
1091       return True;
1092     }
1093   else if (event->xany.type == ButtonRelease &&
1094            event->xbutton.button == Button1)
1095     {
1096       dc->button_down_p = False;
1097       return True;
1098     }
1099   else if (event->xany.type == ButtonPress &&
1100            (event->xbutton.button == Button4 ||
1101             event->xbutton.button == Button5 ||
1102             event->xbutton.button == Button6 ||
1103             event->xbutton.button == Button7))
1104     {
1105       gltrackball_mousewheel (dc->trackball, event->xbutton.button, 10,
1106                               !!event->xbutton.state);
1107       return True;
1108     }
1109   else if (event->xany.type == MotionNotify &&
1110            dc->button_down_p)
1111     {
1112       gltrackball_track (dc->trackball,
1113                          event->xmotion.x, event->xmotion.y,
1114                          MI_WIDTH (mi), MI_HEIGHT (mi));
1115       return True;
1116     }
1117
1118   return False;
1119 }
1120
1121
1122 static void
1123 tick_spinner (ModeInfo *mi, spinner *s)
1124 {
1125   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
1126
1127   if (dc->speed == 0) return;
1128   if (dc->button_down_p) return;
1129
1130   if (s->spinning_p)
1131     {
1132       s->position += s->speed;
1133       if (s->position >=  1.0 || s->position <= -1.0)
1134           
1135         {
1136           s->position = 0;
1137           s->spinning_p = False;
1138         }
1139     }
1140   else if (s->probability &&
1141            (random() % (int) (PROBABILITY_SCALE / s->probability)) == 0)
1142     {
1143       GLfloat ss = 0.004;
1144       s->spinning_p = True;
1145       s->position = 0;
1146       do {
1147         s->speed = dc->speed * (frand(ss/3) + frand(ss/3) + frand(ss/3));
1148       } while (s->speed <= 0);
1149       if (random() & 1)
1150         s->speed = -s->speed;
1151     }
1152 }
1153
1154
1155 static void
1156 link_spinners (ModeInfo *mi, spinner *s0, spinner *s1)
1157 {
1158   if (s0->spinning_p && !s1->spinning_p)
1159     {
1160       GLfloat op = s1->probability;
1161       s1->probability = PROBABILITY_SCALE;
1162       tick_spinner (mi, s1);
1163       s1->probability = op;
1164     }
1165 }
1166
1167
1168 ENTRYPOINT void
1169 draw_logo (ModeInfo *mi)
1170 {
1171   logo_configuration *dc = &dcs[MI_SCREEN(mi)];
1172   Display *dpy = MI_DISPLAY(mi);
1173   Window window = MI_WINDOW(mi);
1174   int wire = MI_IS_WIREFRAME(mi);
1175   GLfloat gcolor[4];
1176   GLfloat specular[]  = {0.8, 0.8, 0.8, 1.0};
1177   GLfloat shininess   = 50.0;
1178
1179   if (!dc->glx_context)
1180     return;
1181
1182   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(dc->glx_context));
1183
1184   if (dc->wire_overlay == 0 &&
1185       (random() % (int) (PROBABILITY_SCALE / 0.2)) == 0)
1186     dc->wire_overlay = ((random() % 200) +
1187                         (random() % 200) +
1188                         (random() % 200));
1189       
1190   tick_spinner (mi, &dc->gasket_spinnerx);
1191   tick_spinner (mi, &dc->gasket_spinnery);
1192   tick_spinner (mi, &dc->gasket_spinnerz);
1193   tick_spinner (mi, &dc->helix_spinnerz);
1194   tick_spinner (mi, &dc->scene_spinnerx);
1195   tick_spinner (mi, &dc->scene_spinnery);
1196   link_spinners (mi, &dc->scene_spinnerx, &dc->scene_spinnery);
1197
1198   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1199
1200   glPushMatrix ();
1201   {
1202     glScalef(3.3, 3.3, 3.3);
1203
1204     gltrackball_rotate (dc->trackball);
1205
1206     glRotatef(90, 1, 0, 0);
1207     glRotatef(90, 0, 0, 1);
1208
1209     glColor3f(dc->color[0], dc->color[1], dc->color[2]);
1210
1211     glRotatef (360 * sin (M_PI/2 * dc->scene_spinnerx.position), 0, 1, 0);
1212     glRotatef (360 * sin (M_PI/2 * dc->scene_spinnery.position), 0, 0, 1);
1213
1214     glPushMatrix();
1215     {
1216       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnerx.position), 0, 1, 0);
1217       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnery.position), 0, 0, 1);
1218       glRotatef (360 * sin (M_PI/2 * dc->gasket_spinnerz.position), 1, 0, 0);
1219
1220       memcpy (gcolor, dc->color, sizeof (dc->color));
1221       if (dc->wire_overlay != 0)
1222         {
1223           gcolor[0]   = gcolor[1]   = gcolor[2]   = 0;
1224           specular[0] = specular[1] = specular[2] = 0;
1225           shininess = 0;
1226         }
1227       glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, gcolor);
1228       glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,  specular);
1229       glMaterialf  (GL_FRONT_AND_BACK, GL_SHININESS, shininess);
1230
1231       if (wire)
1232         glCallList (dc->gasket_list_wire);
1233       else if (dc->wire_overlay != 0)
1234         {
1235           glCallList (dc->gasket_list);
1236           glDisable (GL_LIGHTING);
1237           glCallList (dc->gasket_list_wire);
1238           if (!wire) glEnable (GL_LIGHTING);
1239         }
1240       else
1241         glCallList (dc->gasket_list);
1242     }
1243     glPopMatrix();
1244
1245     glRotatef (360 * sin (M_PI/2 * dc->helix_spinnerz.position), 0, 0, 1);
1246
1247     if (wire)
1248       glCallList (dc->helix_list_wire);
1249     else if (dc->wire_overlay != 0)
1250       {
1251         glCallList (dc->helix_list_facetted);
1252         glDisable (GL_LIGHTING);
1253         glCallList (dc->helix_list_wire);
1254         if (!wire) glEnable (GL_LIGHTING);
1255       }
1256     else
1257       glCallList (dc->helix_list);
1258   }
1259   glPopMatrix();
1260
1261   if (dc->wire_overlay > 0)
1262     dc->wire_overlay--;
1263
1264   if (mi->fps_p) do_fps (mi);
1265   glFinish();
1266
1267   glXSwapBuffers(dpy, window);
1268 }
1269
1270 XSCREENSAVER_MODULE_2 ("DNAlogo", dnalogo, logo)
1271
1272 #endif /* USE_GL */