http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.02.tar.gz
[xscreensaver] / hacks / glx / cubenetic.c
1 /* cubenetic, Copyright (c) 2002 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 #include <X11/Intrinsic.h>
13
14 extern XtAppContext app;
15
16 #define PROGCLASS       "Cubenetic"
17 #define HACK_INIT       init_cube
18 #define HACK_DRAW       draw_cube
19 #define HACK_RESHAPE    reshape_cube
20 #define ccs_opts        xlockmore_opts
21
22 #define DEF_SPIN        "XYZ"
23 #define DEF_WANDER      "True"
24 #define DEF_TEXTURE     "True"
25
26 #define DEF_WAVE_COUNT  "3"
27 #define DEF_WAVE_SPEED  "80"
28 #define DEF_WAVE_RADIUS "512"
29
30 #define DEFAULTS        "*delay:        30000       \n" \
31                         "*count:        5           \n" \
32                         "*showFPS:      False       \n" \
33                         "*wireframe:    False       \n" \
34                         "*spin:       " DEF_SPIN   "\n" \
35                         "*wander:     " DEF_WANDER "\n" \
36                         "*texture:    " DEF_TEXTURE"\n" \
37                         "*waves:      " DEF_WAVE_COUNT  "\n" \
38                         "*waveSpeed:  " DEF_WAVE_SPEED  "\n" \
39                         "*waveRadius: " DEF_WAVE_RADIUS "\n" \
40
41 #undef countof
42 #define countof(x) (sizeof((x))/sizeof((*x)))
43
44 #include "xlockmore.h"
45 #include "colors.h"
46 #include <ctype.h>
47
48 #ifdef USE_GL /* whole file */
49
50 #include <GL/glu.h>
51
52 typedef struct {
53   int color;
54   GLfloat x, y, z;
55   GLfloat w, h, d;
56   int frame;
57   GLfloat dx, dy, dz;
58   GLfloat dw, dh, dd;
59 } cube;
60
61 typedef struct {
62   int x, y;
63   double xth, yth;
64 } wave_src;
65
66 typedef struct {
67   int nwaves;
68   int radius;
69   int speed;
70   wave_src *srcs;
71   int *heights;
72 } waves;
73
74
75 typedef struct {
76   GLXContext *glx_context;
77
78   GLfloat rotx, roty, rotz;        /* current object rotation */
79   GLfloat dx, dy, dz;              /* current rotational velocity */
80   GLfloat ddx, ddy, ddz;           /* current rotational acceleration */
81   GLfloat d_max;                   /* max velocity */
82   Bool spin_x, spin_y, spin_z;
83
84   GLuint cube_list;
85   GLuint texture_id;
86   int ncubes;
87   cube *cubes;
88   waves *waves;
89
90   int texture_width, texture_height;
91   unsigned char *texture;
92
93   int ncolors;
94   XColor *cube_colors;
95   XColor *texture_colors;
96
97 } cube_configuration;
98
99 static cube_configuration *ccs = NULL;
100
101 static char *do_spin;
102 static Bool do_wander;
103 static Bool do_texture;
104
105 static int wave_count;
106 static int wave_speed;
107 static int wave_radius;
108 static int texture_size = 256;
109
110 static XrmOptionDescRec opts[] = {
111   { "-spin",   ".spin",   XrmoptionSepArg, 0 },
112   { "+spin",   ".spin",   XrmoptionNoArg, "" },
113   { "-wander", ".wander", XrmoptionNoArg, "True" },
114   { "+wander", ".wander", XrmoptionNoArg, "False" },
115   {"-texture", ".texture", XrmoptionNoArg, (caddr_t) "true" },
116   {"+texture", ".texture", XrmoptionNoArg, (caddr_t) "false" },
117   {"-waves",       ".waves",      XrmoptionSepArg, 0 },
118   {"-wave-speed",  ".waveSpeed",  XrmoptionSepArg, 0 },
119   {"-wave-radius", ".waveRadius", XrmoptionSepArg, 0 },
120 };
121
122 static argtype vars[] = {
123   {(caddr_t *) &do_spin,   "spin",   "Spin",   DEF_SPIN,   t_String},
124   {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
125   {(caddr_t *) &do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
126   {(caddr_t *) &wave_count, "waves",     "Waves",      DEF_WAVE_COUNT, t_Int},
127   {(caddr_t *) &wave_speed, "waveSpeed", "WaveSpeed",  DEF_WAVE_SPEED, t_Int},
128   {(caddr_t *) &wave_radius,"waveRadius","WaveRadius", DEF_WAVE_RADIUS,t_Int},
129 };
130
131 ModeSpecOpt ccs_opts = {countof(opts), opts, countof(vars), vars, NULL};
132
133
134 static void
135 unit_cube (Bool wire)
136 {
137   glBegin (wire ? GL_LINE_LOOP : GL_QUADS);     /* front */
138   glNormal3f (0, 0, 1);
139   glTexCoord2f(1, 0); glVertex3f ( 0.5, -0.5,  0.5);
140   glTexCoord2f(0, 0); glVertex3f ( 0.5,  0.5,  0.5);
141   glTexCoord2f(0, 1); glVertex3f (-0.5,  0.5,  0.5);
142   glTexCoord2f(1, 1); glVertex3f (-0.5, -0.5,  0.5);
143   glEnd();
144
145   glBegin (wire ? GL_LINE_LOOP : GL_QUADS);     /* back */
146   glNormal3f (0, 0, -1);
147   glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
148   glTexCoord2f(0, 1); glVertex3f (-0.5,  0.5, -0.5);
149   glTexCoord2f(1, 1); glVertex3f ( 0.5,  0.5, -0.5);
150   glTexCoord2f(1, 0); glVertex3f ( 0.5, -0.5, -0.5);
151   glEnd();
152
153   glBegin (wire ? GL_LINE_LOOP : GL_QUADS);     /* left */
154   glNormal3f (-1, 0, 0);
155   glTexCoord2f(1, 1); glVertex3f (-0.5,  0.5,  0.5);
156   glTexCoord2f(1, 0); glVertex3f (-0.5,  0.5, -0.5);
157   glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
158   glTexCoord2f(0, 1); glVertex3f (-0.5, -0.5,  0.5);
159   glEnd();
160
161   glBegin (wire ? GL_LINE_LOOP : GL_QUADS);     /* right */
162   glNormal3f (1, 0, 0);
163   glTexCoord2f(1, 1); glVertex3f ( 0.5, -0.5, -0.5);
164   glTexCoord2f(1, 0); glVertex3f ( 0.5,  0.5, -0.5);
165   glTexCoord2f(0, 0); glVertex3f ( 0.5,  0.5,  0.5);
166   glTexCoord2f(0, 1); glVertex3f ( 0.5, -0.5,  0.5);
167   glEnd();
168
169   if (wire) return;
170
171   glBegin (wire ? GL_LINE_LOOP : GL_QUADS);     /* top */
172   glNormal3f (0, 1, 0);
173   glTexCoord2f(0, 0); glVertex3f ( 0.5,  0.5,  0.5);
174   glTexCoord2f(0, 1); glVertex3f ( 0.5,  0.5, -0.5);
175   glTexCoord2f(1, 1); glVertex3f (-0.5,  0.5, -0.5);
176   glTexCoord2f(1, 0); glVertex3f (-0.5,  0.5,  0.5);
177   glEnd();
178
179   glBegin (wire ? GL_LINE_LOOP : GL_QUADS);     /* bottom */
180   glNormal3f (0, -1, 0);
181   glTexCoord2f(1, 0); glVertex3f (-0.5, -0.5,  0.5);
182   glTexCoord2f(0, 0); glVertex3f (-0.5, -0.5, -0.5);
183   glTexCoord2f(0, 1); glVertex3f ( 0.5, -0.5, -0.5);
184   glTexCoord2f(1, 1); glVertex3f ( 0.5, -0.5,  0.5);
185   glEnd();
186 }
187
188
189
190 /* Window management, etc
191  */
192 void
193 reshape_cube (ModeInfo *mi, int width, int height)
194 {
195   GLfloat h = (GLfloat) height / (GLfloat) width;
196
197   glViewport (0, 0, (GLint) width, (GLint) height);
198
199   glMatrixMode(GL_PROJECTION);
200   glLoadIdentity();
201
202   gluPerspective( 30.0, 1/h, 1.0, 100.0 );
203   gluLookAt( 0.0, 0.0, 15.0,
204              0.0, 0.0, 0.0,
205              0.0, 1.0, 0.0);
206   glMatrixMode(GL_MODELVIEW);
207   glLoadIdentity();
208   glTranslatef(0.0, 0.0, -15.0);
209
210   glClear(GL_COLOR_BUFFER_BIT);
211 }
212
213
214 /* lifted from lament.c */
215 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
216 #define RANDSIGN() ((random() & 1) ? 1 : -1)
217
218 static void
219 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
220 {
221   double ppos = *pos;
222
223   /* tick position */
224   if (ppos < 0)
225     ppos = -(ppos + *v);
226   else
227     ppos += *v;
228
229   if (ppos > 1.0)
230     ppos -= 1.0;
231   else if (ppos < 0)
232     ppos += 1.0;
233
234   if (ppos < 0) abort();
235   if (ppos > 1.0) abort();
236   *pos = (*pos > 0 ? ppos : -ppos);
237
238   /* accelerate */
239   *v += *dv;
240
241   /* clamp velocity */
242   if (*v > max_v || *v < -max_v)
243     {
244       *dv = -*dv;
245     }
246   /* If it stops, start it going in the other direction. */
247   else if (*v < 0)
248     {
249       if (random() % 4)
250         {
251           *v = 0;
252
253           /* keep going in the same direction */
254           if (random() % 2)
255             *dv = 0;
256           else if (*dv < 0)
257             *dv = -*dv;
258         }
259       else
260         {
261           /* reverse gears */
262           *v = -*v;
263           *dv = -*dv;
264           *pos = -*pos;
265         }
266     }
267
268   /* Alter direction of rotational acceleration randomly. */
269   if (! (random() % 120))
270     *dv = -*dv;
271
272   /* Change acceleration very occasionally. */
273   if (! (random() % 200))
274     {
275       if (*dv == 0)
276         *dv = 0.00001;
277       else if (random() & 1)
278         *dv *= 1.2;
279       else
280         *dv *= 0.8;
281     }
282 }
283
284
285 \f
286 /* Waves.
287    Adapted from ../hacks/interference.c by Hannu Mallat.
288  */
289
290 static void
291 init_wave (ModeInfo *mi)
292 {
293   cube_configuration *cc = &ccs[MI_SCREEN(mi)];
294   waves *ww;
295   int i;
296   cc->waves = ww = (waves *) calloc (sizeof(*cc->waves), 1);
297   ww->nwaves = wave_count;
298   ww->radius = wave_radius;
299   ww->speed  = wave_speed;
300   ww->heights = (int *) calloc (sizeof(*ww->heights), ww->radius);
301   ww->srcs = (wave_src *) calloc (sizeof(*ww->srcs), ww->nwaves);
302
303   for (i = 0; i < ww->radius; i++)
304     {
305       float max = (cc->ncolors * (ww->radius - i) / (float) ww->radius);
306       ww->heights[i] = ((max + max * cos(i / 50.0)) / 2.0);
307     }
308
309   for (i = 0; i < ww->nwaves; i++)
310     {
311       ww->srcs[i].xth = frand(2.0) * M_PI;
312       ww->srcs[i].yth = frand(2.0) * M_PI;
313     }
314 }
315
316 static void
317 interference (ModeInfo *mi)
318 {
319   cube_configuration *cc = &ccs[MI_SCREEN(mi)];
320   waves *ww = cc->waves;
321   int x, y, i;
322
323   /* Move the wave origins around
324    */
325   for (i = 0; i < ww->nwaves; i++)
326     {
327       ww->srcs[i].xth += (ww->speed / 1000.0);
328       if (ww->srcs[i].xth > 2*M_PI)
329         ww->srcs[i].xth -= 2*M_PI;
330       ww->srcs[i].yth += (ww->speed / 1000.0);
331       if (ww->srcs[i].yth > 2*M_PI)
332         ww->srcs[i].yth -= 2*M_PI;
333
334       ww->srcs[i].x = (cc->texture_width/2 +
335                        (cos (ww->srcs[i].xth) *
336                         cc->texture_width / 2));
337       ww->srcs[i].y = (cc->texture_height/2 +
338                        (cos (ww->srcs[i].yth) *
339                         cc->texture_height / 2));
340     }
341
342   /* Compute the effect of the waves on each pixel,
343      and generate the output map.
344    */
345   for (y = 0; y < cc->texture_height; y++)
346     for (x = 0; x < cc->texture_width; x++)
347       {
348         int result = 0;
349         unsigned char *o;
350         for (i = 0; i < ww->nwaves; i++)
351           {
352             int dx = x - ww->srcs[i].x;
353             int dy = y - ww->srcs[i].y;
354             int dist = sqrt (dx*dx + dy*dy);
355             result += (dist > ww->radius ? 0 : ww->heights[dist]);
356           }
357         result %= cc->ncolors;
358
359         o = cc->texture + (((y * cc->texture_width) + x) << 2);
360         o[0] = (cc->texture_colors[result].red   >> 8);
361         o[1] = (cc->texture_colors[result].green >> 8);
362         o[2] = (cc->texture_colors[result].blue  >> 8);
363      /* o[3] = 0xFF; */
364       }
365 }
366
367 \f
368 /* Textures
369  */
370
371 static void
372 init_texture (ModeInfo *mi)
373 {
374   cube_configuration *cc = &ccs[MI_SCREEN(mi)];
375   int i;
376
377   glEnable(GL_TEXTURE_2D);
378
379   clear_gl_error();
380   glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
381   glGenTextures (1, &cc->texture_id);
382   glBindTexture (GL_TEXTURE_2D, cc->texture_id);
383   check_gl_error("texture binding");
384
385   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
386   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
387   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
388   glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
389   glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
390   glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
391   glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
392   check_gl_error("texture initialization");
393
394   cc->texture_width  = texture_size;
395   cc->texture_height = texture_size;
396
397   i = texture_size * texture_size * 4;
398   cc->texture = (char *) malloc (i);
399   memset (cc->texture, 0xFF, i);
400 }
401
402
403 static void
404 shuffle_texture (ModeInfo *mi)
405 {
406   cube_configuration *cc = &ccs[MI_SCREEN(mi)];
407   interference (mi);
408   clear_gl_error();
409   glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
410                 cc->texture_width, cc->texture_height, 0,
411                 GL_RGBA, GL_UNSIGNED_BYTE,
412                 cc->texture);
413   check_gl_error("texture");
414 }
415
416
417 void 
418 init_cube (ModeInfo *mi)
419 {
420   int i;
421   cube_configuration *cc;
422   int wire = MI_IS_WIREFRAME(mi);
423
424   if (!ccs) {
425     ccs = (cube_configuration *)
426       calloc (MI_NUM_SCREENS(mi), sizeof (cube_configuration));
427     if (!ccs) {
428       fprintf(stderr, "%s: out of memory\n", progname);
429       exit(1);
430     }
431   }
432
433   cc = &ccs[MI_SCREEN(mi)];
434
435   if ((cc->glx_context = init_GL(mi)) != NULL) {
436     reshape_cube (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
437   }
438
439   if (!wire)
440     {
441       static GLfloat pos[4] = {1.0, 0.5, 1.0, 0.0};
442       static GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
443       static GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
444
445       glLightfv(GL_LIGHT0, GL_POSITION, pos);
446       glLightfv(GL_LIGHT0, GL_AMBIENT,  amb);
447       glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif);
448
449       glEnable(GL_LIGHTING);
450       glEnable(GL_LIGHT0);
451       glEnable(GL_DEPTH_TEST);
452       glEnable(GL_CULL_FACE);
453     }
454
455
456   {
457     char *s = do_spin;
458     while (*s)
459       {
460         if      (*s == 'x' || *s == 'X') cc->spin_x = 1;
461         else if (*s == 'y' || *s == 'Y') cc->spin_y = 1;
462         else if (*s == 'z' || *s == 'Z') cc->spin_z = 1;
463         else
464           {
465             fprintf (stderr,
466          "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
467                      progname, do_spin);
468             exit (1);
469           }
470         s++;
471       }
472   }
473
474   cc->rotx = frand(1.0) * RANDSIGN();
475   cc->roty = frand(1.0) * RANDSIGN();
476   cc->rotz = frand(1.0) * RANDSIGN();
477
478   /* bell curve from 0-6 degrees, avg 3 */
479   cc->dx = (frand(0.7) + frand(0.7) + frand(0.7)) / (360/2);
480   cc->dy = (frand(0.7) + frand(0.7) + frand(0.7)) / (360/2);
481   cc->dz = (frand(0.7) + frand(0.7) + frand(0.7)) / (360/2);
482
483   cc->d_max = cc->dx * 2;
484
485   cc->ddx = 0.00006 + frand(0.00003);
486   cc->ddy = 0.00006 + frand(0.00003);
487   cc->ddz = 0.00006 + frand(0.00003);
488
489   cc->ncolors = 256;
490   cc->texture_colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
491   cc->cube_colors    = (XColor *) calloc(cc->ncolors, sizeof(XColor));
492
493   {
494     double H[3], S[3], V[3];
495     int shift = 60;
496     H[0] = frand(360.0); 
497     H[1] = ((H[0] + shift) < 360) ? (H[0]+shift) : (H[0] + shift - 360);
498     H[2] = ((H[1] + shift) < 360) ? (H[1]+shift) : (H[1] + shift - 360);
499     S[0] = S[1] = S[2] = 1.0;
500     V[0] = V[1] = V[2] = 1.0;
501     make_color_loop(0, 0,
502                     H[0], S[0], V[0], 
503                     H[1], S[1], V[1], 
504                     H[2], S[2], V[2], 
505                     cc->texture_colors, &cc->ncolors,
506                     False, False);
507
508     make_smooth_colormap (0, 0, 0,
509                           cc->cube_colors, &cc->ncolors, 
510                           False, 0, False);
511   }
512
513   cc->ncubes = MI_COUNT (mi);
514   cc->cubes = (cube *) calloc (sizeof(cube), cc->ncubes);
515   for (i = 0; i < cc->ncubes; i++)
516     {
517       cube *cube = &cc->cubes[i];
518       cube->color = random() % cc->ncolors;
519       cube->w = 1.0;
520       cube->h = 1.0;
521       cube->d = 1.0;
522       cube->dx = frand(0.1);
523       cube->dy = frand(0.1);
524       cube->dz = frand(0.1);
525       cube->dw = frand(0.1);
526       cube->dh = frand(0.1);
527       cube->dd = frand(0.1);
528     }
529
530   if (wire)
531     do_texture = False;
532     
533   if (do_texture)
534     {
535       init_texture (mi);
536       init_wave (mi);
537       shuffle_texture (mi);
538     }
539
540   cc->cube_list = glGenLists (1);
541   glNewList (cc->cube_list, GL_COMPILE);
542   unit_cube (wire);
543   glEndList ();
544 }
545
546
547 static void
548 shuffle_cubes (ModeInfo *mi)
549 {
550   cube_configuration *cc = &ccs[MI_SCREEN(mi)];
551   int i;
552   for (i = 0; i < cc->ncubes; i++)
553     {
554 #     define SINOID(SCALE,FRAME,SIZE) \
555         ((((1 + sin((FRAME * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
556
557       cube *cube = &cc->cubes[i];
558       cube->x = SINOID(cube->dx, cube->frame, 0.5);
559       cube->y = SINOID(cube->dy, cube->frame, 0.5);
560       cube->z = SINOID(cube->dz, cube->frame, 0.5);
561       cube->w = SINOID(cube->dw, cube->frame, 0.9) + 1.0;
562       cube->h = SINOID(cube->dh, cube->frame, 0.9) + 1.0;
563       cube->d = SINOID(cube->dd, cube->frame, 0.9) + 1.0;
564       cube->frame++;
565 #     undef SINOID
566     }
567 }
568
569
570 void
571 draw_cube (ModeInfo *mi)
572 {
573   cube_configuration *cc = &ccs[MI_SCREEN(mi)];
574   Display *dpy = MI_DISPLAY(mi);
575   Window window = MI_WINDOW(mi);
576   int i;
577
578   if (!cc->glx_context)
579     return;
580
581   glShadeModel(GL_FLAT);
582
583   glEnable(GL_DEPTH_TEST);
584   glEnable(GL_NORMALIZE);
585   glEnable(GL_CULL_FACE);
586
587   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
588
589   glPushMatrix ();
590
591   glScalef(1.1, 1.1, 1.1);
592
593   {
594     GLfloat x, y, z;
595
596     if (do_wander)
597       {
598         static int frame = 0;
599
600 #       define SINOID(SCALE,SIZE) \
601         ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
602
603         x = SINOID(0.0071, 8.0);
604         y = SINOID(0.0053, 6.0);
605         z = SINOID(0.0037, 15.0);
606         frame++;
607         glTranslatef(x, y, z);
608       }
609
610     if (cc->spin_x || cc->spin_y || cc->spin_z)
611       {
612         x = cc->rotx;
613         y = cc->roty;
614         z = cc->rotz;
615         if (x < 0) x = 1 - (x + 1);
616         if (y < 0) y = 1 - (y + 1);
617         if (z < 0) z = 1 - (z + 1);
618
619         if (cc->spin_x) glRotatef(x * 360, 1.0, 0.0, 0.0);
620         if (cc->spin_y) glRotatef(y * 360, 0.0, 1.0, 0.0);
621         if (cc->spin_z) glRotatef(z * 360, 0.0, 0.0, 1.0);
622
623         rotate(&cc->rotx, &cc->dx, &cc->ddx, cc->d_max);
624         rotate(&cc->roty, &cc->dy, &cc->ddy, cc->d_max);
625         rotate(&cc->rotz, &cc->dz, &cc->ddz, cc->d_max);
626       }
627   }
628
629   glScalef (2.5, 2.5, 2.5);
630
631   for (i = 0; i < cc->ncubes; i++)
632     {
633       cube *cube = &cc->cubes[i];
634       GLfloat color[4];
635       color[0] = cc->cube_colors[cube->color].red   / 65536.0;
636       color[1] = cc->cube_colors[cube->color].green / 65536.0;
637       color[2] = cc->cube_colors[cube->color].blue  / 65536.0;
638       color[3] = 1.0;
639       cube->color++;
640       if (cube->color >= cc->ncolors) cube->color = 0;
641
642       glPushMatrix ();
643       glTranslatef (cube->x, cube->y, cube->z);
644       glScalef (cube->w, cube->h, cube->d);
645       glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
646       glCallList (cc->cube_list);
647       glPopMatrix ();
648     }
649
650   shuffle_cubes (mi);
651   if (do_texture)
652     shuffle_texture (mi);
653
654   glPopMatrix();
655
656   if (mi->fps_p) do_fps (mi);
657   glFinish();
658
659   glXSwapBuffers(dpy, window);
660 }
661
662 #endif /* USE_GL */