From http://www.jwz.org/xscreensaver/xscreensaver-5.39.tar.gz
[xscreensaver] / hacks / glx / razzledazzle.c
1 /* razzledazzle, Copyright (c) 2018 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        "*delay:        30000       \n" \
13                         "*showFPS:      False       \n" \
14                         "*wireframe:    False       \n" \
15                         "*ncolors:      2           \n" \
16                         "*suppressRotationAnimation: True\n" \
17
18 # define release_dazzle 0
19 #undef countof
20 #define countof(x) (sizeof((x))/sizeof((*x)))
21
22 #include "xlockmore.h"
23 #include "colors.h"
24 #include "normals.h"
25 #include "gllist.h"
26 #include <ctype.h>
27
28 #ifdef USE_GL /* whole file */
29
30 #define DEF_SPEED       "1.0"
31 #define DEF_DENSITY     "5.0"
32 #define DEF_THICKNESS   "0.1"
33 #define DEF_MODE        "Random"
34
35 #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
36 #undef RANDSIGN
37 #define RANDSIGN() ((random() & 1) ? 1 : -1)
38
39 extern const struct gllist
40   *ships_ship1, *ships_ship2, *ships_ship3, *ships_ship4,
41   *ships_ship5, *ships_ship6, *ships_ship7, *ships_ship8;
42
43 static const struct gllist * const *all_ships[] = {
44   &ships_ship1, &ships_ship2, &ships_ship3, &ships_ship4,
45   &ships_ship5, &ships_ship6, &ships_ship7, &ships_ship8,
46 };
47
48
49 typedef enum { LEFT, RIGHT, UP, DOWN } direction;
50
51 typedef struct node node;
52
53 struct node {
54   long gx, gy;
55   GLfloat x, y;
56   GLfloat dx, dy;
57   int nstripes;
58   Bool horiz_p;
59   Bool drawn_p;
60   GLfloat color1[4], color2[4];
61 };
62
63 typedef struct {
64   GLXContext *glx_context;
65   Bool button_down_p;
66   GLfloat xoff, yoff, dx, dy;
67   node *nodes;
68   node *dragging;
69   int drag_x, drag_y;
70   int ncolors;
71   XColor *colors;
72   GLuint *dlists;
73   enum { SHIPS, FLAT, RANDOM } mode;
74   int which_ship;
75   long frames;
76 } dazzle_configuration;
77
78 static dazzle_configuration *bps = NULL;
79
80 static GLfloat speed, thickness, density;
81 static char *mode_arg;
82
83 static XrmOptionDescRec opts[] = {
84   { "-speed",     ".speed",     XrmoptionSepArg, 0 },
85   { "-thickness", ".thickness", XrmoptionSepArg, 0 },
86   { "-density",   ".density",   XrmoptionSepArg, 0 },
87   { "-mode",      ".mode",      XrmoptionSepArg,  0  },
88   { "-ships",     ".mode",      XrmoptionNoArg,  "ships"  },
89   { "-flat",      ".mode",      XrmoptionNoArg,  "flat"   },
90 };
91
92 static argtype vars[] = {
93   {&speed,     "speed",     "Speed",     DEF_SPEED,     t_Float},
94   {&thickness, "thickness", "Thickness", DEF_THICKNESS, t_Float},
95   {&density,   "density",   "Density",   DEF_DENSITY,   t_Float},
96   {&mode_arg,  "mode",      "Mode",      DEF_MODE,      t_String},
97 };
98
99 ENTRYPOINT ModeSpecOpt dazzle_opts = {countof(opts), opts, countof(vars), vars, NULL};
100
101
102
103 static void
104 draw_grid (ModeInfo *mi, int gx, int gy)
105 {
106   dazzle_configuration *bp = &bps[MI_SCREEN(mi)];
107   Bool wire = MI_IS_WIREFRAME(mi);
108   long x, y;
109   long wh = density * 2;
110
111   if (wire)
112     glColor3f (1, 1, 1);
113
114   if (!wire)
115     glBegin (GL_QUADS);
116
117   for (y = 0; y < wh; y++)
118     for (x = 0; x < wh; x++)
119       {
120         node *n0 = &bp->nodes[(y     % wh) * wh + (x     % wh)];
121         node *n1 = &bp->nodes[(y     % wh) * wh + ((x+1) % wh)];
122         node *n2 = &bp->nodes[((y+1) % wh) * wh + ((x+1) % wh)];
123         node *n3 = &bp->nodes[((y+1) % wh) * wh + (x     % wh)];
124         int nstripes, i;
125         Bool horiz_p, visible;
126         GLfloat x0, y0, x1, y1, x2, y2, x3, y3;
127         GLfloat xoff = (x < wh-1 ? 0 : wh);
128         GLfloat yoff = (y < wh-1 ? 0 : wh);
129         GLfloat bx = fmod ((double) bp->xoff, 2.0);
130         GLfloat by = fmod ((double) bp->yoff, 2.0);
131
132         bx += gx*2;
133         by += gy*2;
134
135         if (wire)
136           {
137             GLfloat a;
138             glColor3f (0, 0, 1);
139             glBegin (GL_LINE_LOOP);
140             for (a = 0; a < 360; a += 10)
141               glVertex3f ((n0->x / density-1) + 0.05 * cos(a * M_PI/180) + bx,
142                           (n0->y / density-1) + 0.05 * sin(a * M_PI/180) + by,
143                           0);
144             glEnd();
145           }
146
147         x0 = n0->x        / density - 1 + bx;
148         y0 = n0->y        / density - 1 + by;
149
150         x1 = (n1->x+xoff) / density - 1 + bx;
151         y1 = n1->y        / density - 1 + by;
152         x2 = (n2->x+xoff) / density - 1 + bx;
153         y2 = (n2->y+yoff) / density - 1 + by;
154         x3 = n3->x        / density - 1 + bx;
155         y3 = (n3->y+yoff) / density - 1 + by;
156
157         if (wire)
158           {
159             if (gx == 0 && gy == 0)
160               {
161                 glLineWidth (4);
162                 glColor3f(1, 0, 0);
163               }
164             else
165               glColor3f(0.5, 0, 0.5);
166             if (wire) glBegin (GL_LINE_LOOP);
167             glVertex3f (x0, y0, 0);
168             glVertex3f (x1, y1, 0);
169             glVertex3f (x2, y2, 0);
170             glVertex3f (x3, y3, 0);
171             mi->polygon_count++;
172             if (wire) glEnd();
173             glLineWidth (1);
174           }
175
176         /* This isn't quite right: just because all corners are off screen
177            doesn't mean the quad isn't visible. We need to intersect the
178            edges with the screen rectangle.
179          */
180         {
181           GLfloat max = 0.75;
182           visible = ((x0 >= -max && y0 >= -max && x0 <= max && y0  <= max) ||
183                      (x1 >= -max && y1 >= -max && x1 <= max && y1  <= max) ||
184                      (x2 >= -max && y2 >= -max && x2 <= max && y2  <= max) ||
185                      (x3 >= -max && y3 >= -max && x3 <= max && y3  <= max));
186         }
187
188         if (!visible) continue;
189
190         if (visible)
191           n0->drawn_p = True;
192
193         nstripes = n0->nstripes;
194         horiz_p  = n0->horiz_p;
195
196         for (i = 0; i < nstripes; i++)
197           {
198             GLfloat ss  = (GLfloat) i     / nstripes;
199             GLfloat ss1 = (GLfloat) (i+1) / nstripes;
200             if (i & 1)
201               glColor4fv (n0->color1);
202             else if (wire)
203               continue;
204             else
205               glColor4fv (n0->color2);
206
207             if (horiz_p)
208               {
209                 x0 = n0->x        + (n3->x        - n0->x)        * ss;
210                 y0 = n0->y        + ((n3->y+yoff) - n0->y)        * ss;
211                 x1 = (n1->x+xoff) + ((n2->x+xoff) - (n1->x+xoff)) * ss;
212                 y1 = n1->y        + ((n2->y+yoff) - n1->y)        * ss;
213
214                 x2 = (n1->x+xoff) + ((n2->x+xoff) - (n1->x+xoff)) * ss1;
215                 y2 = n1->y        + ((n2->y+yoff) - n1->y)        * ss1;
216                 x3 = n0->x        + (n3->x        - n0->x)        * ss1;
217                 y3 = n0->y        + ((n3->y+yoff) - n0->y)        * ss1;
218               }
219             else
220               {
221                 x0 = n0->x        + ((n1->x+xoff) - n0->x)        * ss;
222                 y0 = n0->y        + (n1->y        - n0->y)        * ss;
223                 x1 = n3->x        + ((n2->x+xoff) - n3->x)        * ss;
224                 y1 = (n3->y+yoff) + ((n2->y+yoff) - (n3->y+yoff)) * ss;
225
226                 x2 = n3->x        + ((n2->x+xoff) - n3->x)        * ss1;
227                 y2 = (n3->y+yoff) + ((n2->y+yoff) - (n3->y+yoff)) * ss1;
228                 x3 = n0->x        + ((n1->x+xoff) - n0->x)        * ss1;
229                 y3 = n0->y        + (n1->y        - n0->y)        * ss1;
230               }
231
232             if (wire) glBegin (GL_LINES);
233             glVertex3f (x0 / density - 1 + bx, y0 / density - 1 + by, 0);
234             glVertex3f (x1 / density - 1 + bx, y1 / density - 1 + by, 0);
235             glVertex3f (x2 / density - 1 + bx, y2 / density - 1 + by, 0);
236             glVertex3f (x3 / density - 1 + bx, y3 / density - 1 + by, 0);
237             mi->polygon_count++;
238             if (wire) glEnd();
239           }
240       }
241
242   if (!wire)
243     glEnd();
244 }
245
246
247 static void
248 move_grid (ModeInfo *mi)
249 {
250   dazzle_configuration *bp = &bps[MI_SCREEN(mi)];
251   long x, y;
252   long wh = density * 2;
253   Bool wire = MI_IS_WIREFRAME(mi);
254   GLfloat max = 1.0 / density * 3;
255
256   if (bp->button_down_p)
257     return;
258
259   bp->xoff += bp->dx;
260   bp->yoff += bp->dy;
261
262   if (! (random() % 50))
263     {
264       bp->dx += frand(0.0002) * RANDSIGN() * speed;
265       bp->dy += frand(0.0002) * RANDSIGN() * speed;
266     }
267
268   if (bp->dx > 0.003 * speed) bp->dx = 0.003 * speed;
269   if (bp->dy > 0.003 * speed) bp->dy = 0.003 * speed;
270
271   for (y = 0; y < wh; y++)
272     for (x = 0; x < wh; x++)
273       {
274         node *n = &bp->nodes[y * wh + x];
275         GLfloat x2 = n->x + n->dx;
276         GLfloat y2 = n->y + n->dy;
277
278         if (x2 < n->gx + max && x2 >= n->gx - max &&
279             y2 < n->gy + max && y2 >= n->gy - max)
280           {
281             n->x = x2;
282             n->y = y2;
283           }
284
285         if (! (random() % 50))
286           {
287             n->dx += frand(0.0005) * RANDSIGN() * speed;
288             n->dy += frand(0.0005) * RANDSIGN() * speed;
289           }
290
291         /* If this quad was not drawn, it's ok to re-randomize stripes, */
292         if (! n->drawn_p)
293           {
294             int i = random() % bp->ncolors;
295             int j = (i + bp->ncolors / 2) % bp->ncolors;
296             GLfloat cscale = 0.3;
297
298             n->color1[0] = bp->colors[i].red   / 65536.0;
299             n->color1[1] = bp->colors[i].green / 65536.0;
300             n->color1[2] = bp->colors[i].blue  / 65536.0;
301             n->color1[3] = 1.0;
302
303             n->color2[0] = bp->colors[j].red   / 65536.0;
304             n->color2[1] = bp->colors[j].green / 65536.0;
305             n->color2[2] = bp->colors[j].blue  / 65536.0;
306             n->color2[3] = 1.0;
307
308             if (! wire)
309               {
310                 n->color1[0] = cscale * n->color1[0] + 1 - cscale;
311                 n->color1[1] = cscale * n->color1[1] + 1 - cscale;
312                 n->color1[2] = cscale * n->color1[2] + 1 - cscale;
313                 n->color2[0] = cscale * n->color2[0];
314                 n->color2[1] = cscale * n->color2[1];
315                 n->color2[2] = cscale * n->color2[2];
316               }
317
318             n->horiz_p  = random() & 1;
319             n->nstripes = 2 + (int) (BELLRAND(1.0 / thickness));
320           }
321         n->drawn_p = False;
322       }
323 }
324
325
326 /* Window management, etc
327  */
328 ENTRYPOINT void
329 reshape_dazzle (ModeInfo *mi, int width, int height)
330 {
331   glViewport (0, 0, (GLint) width, (GLint) height);
332
333   glMatrixMode(GL_PROJECTION);
334   glLoadIdentity();
335   glOrtho (0, 1, 1, 0, -1, 1);
336
337   if (width > height * 5) {   /* tiny window: show middle */
338     GLfloat s = (GLfloat)height/width;
339     glOrtho (0, 1, 0.5-s, 0.5+s, -1, 1);
340   }
341
342 # ifdef USE_IPHONE      /* So much WTF */
343   {
344     int rot = current_device_rotation();
345
346     glTranslatef (0.5, 0.5, 0);
347
348     if (rot == 180 || rot == -180) {
349       glTranslatef (1, 1, 0);
350     } else if (rot == 90 || rot == -270) {
351       glRotatef (180, 0, 0, 1);
352       glTranslatef (0, 1, 0);
353     } else if (rot == -90 || rot == 270) {
354       glRotatef (180, 0, 0, 1);
355       glTranslatef (1, 0, 0);
356     }
357
358     glTranslatef(-0.5, -0.5, 0);
359   }
360 # endif
361
362   glMatrixMode(GL_MODELVIEW);
363   glLoadIdentity();
364
365   glClear(GL_COLOR_BUFFER_BIT);
366 }
367
368
369 static void
370 dazzle_randomize (ModeInfo *mi)
371 {
372   dazzle_configuration *bp = &bps[MI_SCREEN(mi)];
373   long x, y;
374   long wh = density * 2;
375
376   bp->ncolors = MI_NCOLORS(mi) - 1;
377   if (bp->ncolors < 1) bp->ncolors = 1;
378   if (bp->colors) free (bp->colors);
379   bp->colors = (XColor *) calloc (bp->ncolors, sizeof(XColor));
380   if (bp->ncolors < 3)
381     make_random_colormap (0, 0, 0, bp->colors, &bp->ncolors,
382                           True, False, 0, False);
383   else
384     make_smooth_colormap (0, 0, 0,
385                           bp->colors, &bp->ncolors,
386                           False, False, False);
387   if (bp->ncolors < 1) abort();
388
389   bp->dragging = 0;
390   if (bp->nodes) free (bp->nodes);
391
392   bp->nodes = (node *) calloc (wh * wh, sizeof (node));
393   for (y = 0; y < wh; y++)
394     for (x = 0; x < wh; x++)
395       {
396         node *n = &bp->nodes[wh * y + x];
397         n->gx = n->x = x;
398         n->gy = n->y = y;
399       }
400
401   bp->dx = bp->dy = 0;
402   bp->xoff = bp->yoff = 0;
403   for (x = 0; x < 1000; x++)
404     move_grid (mi);
405
406   bp->dx = frand(0.0005) * RANDSIGN() * speed;
407   bp->dy = frand(0.0005) * RANDSIGN() * speed;
408
409   if (bp->mode == SHIPS || bp->mode == RANDOM)
410     {
411       bp->which_ship = random() % countof(all_ships);
412       if (bp->mode == RANDOM && !(random() % 3))
413         bp->which_ship = -1;
414     }
415
416   if (bp->which_ship != -1)
417     {
418       bp->dx /= 10;
419       bp->dy /= 10;
420     }
421 }
422
423
424 ENTRYPOINT Bool
425 dazzle_handle_event (ModeInfo *mi, XEvent *event)
426 {
427   dazzle_configuration *bp = &bps[MI_SCREEN(mi)];
428   Bool wire = MI_IS_WIREFRAME(mi);
429   GLfloat bx = fmod ((double) bp->xoff, 2.0);
430   GLfloat by = fmod ((double) bp->yoff, 2.0);
431   long wh = density * 2;
432
433   if (event->xany.type == ButtonPress)
434     {
435       GLfloat x = (GLfloat) event->xbutton.x / MI_WIDTH (mi)  - 0.5;
436       GLfloat y = (GLfloat) event->xbutton.y / MI_HEIGHT (mi) - 0.5;
437       node *nn = 0;
438       int xoff = 0, yoff = 0;
439       GLfloat d2 = 999999;
440       long x0, y0, x1, y1;
441
442       if (wire) x /= 0.2, y /= 0.2;
443
444       for (y0 = -1; y0 <= 1; y0++)
445         for (x0 = -1; x0 <= 1; x0++)
446           for (y1 = 0; y1 < wh; y1++)
447             for (x1 = 0; x1 < wh; x1++)
448               {
449                 node *n0 = &bp->nodes[(y1 % wh) * wh + (x1 % wh)];
450                 double dist2;
451                 GLfloat x2 = n0->x / density - 1 + bx + x0*2;
452                 GLfloat y2 = n0->y / density - 1 + by + y0*2;
453
454                 dist2 = (x - x2) * (x - x2) + (y - y2) * (y - y2);
455                 if (dist2 < d2)
456                   {
457                     d2 = dist2;
458                     nn = n0;
459                     xoff = x0;
460                     yoff = y0;
461                   }
462               }
463
464       bp->button_down_p = True;
465       bp->dragging = nn;
466       bp->drag_x = xoff;
467       bp->drag_y = yoff;
468       return True;
469     }
470   else if (event->xany.type == ButtonRelease)
471     {
472       bp->dragging = 0;
473       bp->button_down_p = False;
474       return True;
475     }
476   else if (event->xany.type == MotionNotify && bp->dragging)
477     {
478       GLfloat x = (GLfloat) event->xmotion.x / MI_WIDTH (mi)  - 0.5;
479       GLfloat y = (GLfloat) event->xmotion.y / MI_HEIGHT (mi) - 0.5;
480       if (wire) x /= 0.2, y /= 0.2;
481       x -= bx;
482       y -= by;
483       x -= bp->drag_x * 2;
484       y -= bp->drag_y * 2;
485       bp->dragging->x = x * density + density;
486       bp->dragging->y = y * density + density;
487       bp->dragging->dx = bp->dragging->dy = 0;
488       return True;
489     }
490   else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
491     {
492       dazzle_randomize (mi);
493       return True;
494     }
495
496   return False;
497 }
498
499
500 ENTRYPOINT void 
501 init_dazzle (ModeInfo *mi)
502 {
503   dazzle_configuration *bp;
504
505   MI_INIT (mi, bps);
506
507   bp = &bps[MI_SCREEN(mi)];
508
509   bp->glx_context = init_GL(mi);
510
511   if (!mode_arg || !*mode_arg || !strcasecmp(mode_arg, "random"))
512     bp->mode = RANDOM;
513   else if (!strcasecmp(mode_arg, "ship") || !strcasecmp(mode_arg, "ships"))
514     bp->mode = SHIPS;
515   else if (!strcasecmp(mode_arg, "flat"))
516     bp->mode = FLAT;
517   else
518     {
519       fprintf (stderr, "%s: mode must be ship, flat or random, not %s\n",
520                progname, mode_arg);
521       exit (1);
522     }
523
524   bp->which_ship = -1;
525   if (bp->mode == SHIPS || bp->mode == RANDOM)
526     {
527       int i;
528       bp->dlists = (GLuint *) calloc (countof(all_ships)+1, sizeof(GLuint));
529       for (i = 0; i < countof(all_ships); i++)
530         {
531           const struct gllist *gll = *all_ships[i];
532
533           bp->dlists[i] = glGenLists (1);
534           glNewList (bp->dlists[i], GL_COMPILE);
535
536           glMatrixMode(GL_MODELVIEW);
537           glPushMatrix();
538           glMatrixMode(GL_TEXTURE);
539           glPushMatrix();
540           glMatrixMode(GL_MODELVIEW);
541
542           if (random() & 1)
543             {
544               glScalef (-1, 1, 1);
545               glTranslatef (-1, 0, 0);
546             }
547           renderList (gll, MI_IS_WIREFRAME(mi));
548
549           glMatrixMode(GL_TEXTURE);
550           glPopMatrix();
551           glMatrixMode(GL_MODELVIEW);
552           glPopMatrix();
553           glEndList ();
554         }
555     }
556
557   dazzle_randomize (mi);
558   reshape_dazzle (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
559 }
560
561
562 ENTRYPOINT void
563 draw_dazzle (ModeInfo *mi)
564 {
565   dazzle_configuration *bp = &bps[MI_SCREEN(mi)];
566   Bool wire = MI_IS_WIREFRAME(mi);
567   Display *dpy = MI_DISPLAY(mi);
568   Window window = MI_WINDOW(mi);
569   int x, y;
570
571   if (!bp->glx_context)
572     return;
573
574   glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
575
576   glShadeModel(GL_SMOOTH);
577   glDisable(GL_DEPTH_TEST);
578   glEnable(GL_NORMALIZE);
579   glDisable(GL_CULL_FACE);
580
581   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
582
583   glPushMatrix ();
584   mi->polygon_count = 0;
585
586   glTranslatef (0.5, 0.5, 0);
587
588   if (wire)
589     glScalef (0.2, 0.2, 1);
590
591   move_grid (mi);
592
593   for (y = -1; y <= 1; y++)
594     for (x = -1; x <= 1; x++)
595       draw_grid (mi, x, y);
596
597   if (bp->which_ship != -1)
598     {
599 # ifdef USE_IPHONE
600       int rot = current_device_rotation();
601 # endif
602
603       if (wire)
604         glColor3f (1, 0, 0);
605       else
606         {
607           glColor3f (0, 0, 0);
608
609           /* Draw into the depth buffer but not the frame buffer */
610           glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
611           glClear (GL_DEPTH_BUFFER_BIT);
612           glEnable (GL_DEPTH_TEST);
613         }
614
615 # ifdef USE_IPHONE
616       glRotatef (90, 0, 0, 1);
617       if (rot == 90 || rot == -270)
618         glRotatef (180, 0, 0, 1);
619 # endif
620
621       glPushMatrix();
622       glRotatef (90, 1, 0, 0);
623       glScalef (0.9, 0.9, 0.9);
624       glTranslatef (-0.5, 0, -0.2);
625
626 # ifdef USE_IPHONE
627       if (rot == 0 || rot == 180 || rot == -180)
628         glScalef (1, 1, (GLfloat) MI_HEIGHT(mi) / MI_WIDTH(mi));
629       else
630 # endif
631         glScalef (1, 1, (GLfloat) MI_WIDTH(mi) / MI_HEIGHT(mi));
632
633       /* Wave boat horizontally and vertically */
634       glTranslatef (cos ((double) bp->frames / 80 * M_PI * speed) / 200,
635                     0,
636                     cos ((double) bp->frames / 60 * M_PI * speed) / 300);
637
638       glCallList (bp->dlists[bp->which_ship]);
639       mi->polygon_count += (*all_ships[bp->which_ship])->points / 3;
640       glPopMatrix();
641
642       /* Wave horizon vertically */
643       glTranslatef (0,
644                     cos ((double) bp->frames / 120 * M_PI * speed) / 200,
645                     0);
646
647       if (! wire)
648         {
649           glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
650
651           /* Black out everything that isn't a ship. */
652 # if 0
653           glBegin (GL_QUADS);
654           glVertex3f (-1, -1, 0);
655           glVertex3f (-1,  1, 0);
656           glVertex3f ( 1,  1, 0);
657           glVertex3f ( 1, -1, 0);
658           glEnd();
659 # else
660           {
661             GLfloat horizon = 0.15;
662
663             glColor3f (0.7, 0.7, 1.0);
664             glBegin (GL_QUADS);
665             glVertex3f (-1, -1, 0);
666             glVertex3f (-1,  horizon, 0);
667             glVertex3f ( 1,  horizon, 0);
668             glVertex3f ( 1, -1, 0);
669             glEnd();
670
671             glColor3f (0.0, 0.05, 0.2);
672             glBegin (GL_QUADS);
673             glVertex3f (-1, horizon, 0);
674             glVertex3f (-1, 1, 0);
675             glVertex3f ( 1, 1, 0);
676             glVertex3f ( 1, horizon, 0);
677             glEnd();
678           }
679 # endif
680
681           glDisable (GL_DEPTH_TEST);
682         }
683     }
684
685   if (wire)
686     {
687       glColor3f(0,1,1);
688       glLineWidth(4);
689       glBegin(GL_LINE_LOOP);
690       glVertex3f(-0.5, -0.5, 0);
691       glVertex3f(-0.5,  0.5, 0);
692       glVertex3f( 0.5,  0.5, 0);
693       glVertex3f( 0.5, -0.5, 0);
694       glEnd();
695       glLineWidth(1);
696     }
697
698   glPopMatrix ();
699
700   bp->frames++;
701   if (mi->fps_p) do_fps (mi);
702   glFinish();
703
704   glXSwapBuffers(dpy, window);
705 }
706
707
708 ENTRYPOINT void
709 free_dazzle (ModeInfo *mi)
710 {
711   dazzle_configuration *bp = &bps[MI_SCREEN(mi)];
712   if (bp->nodes) free (bp->nodes);
713   if (bp->colors) free (bp->colors);
714   if (bp->dlists)
715     {
716       int i;
717       for (i = 0; i < countof(all_ships); i++)
718         glDeleteLists (bp->dlists[i], 1);
719       free (bp->dlists);
720     }
721 }
722
723 XSCREENSAVER_MODULE_2 ("RazzleDazzle", razzledazzle, dazzle)
724
725 #endif /* USE_GL */