http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.31.tar.gz
[xscreensaver] / hacks / glx / dangerball.c
1 /* dangerball, Copyright (c) 2001 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       "DangerBall"
17 #define HACK_INIT       init_ball
18 #define HACK_DRAW       draw_ball
19 #define HACK_RESHAPE    reshape_ball
20 #define sws_opts        xlockmore_opts
21
22 #define DEF_SPIN        "True"
23 #define DEF_WANDER      "True"
24 #define DEF_SPEED       "0.05"
25
26 #define DEFAULTS        "*delay:        30000       \n" \
27                         "*count:        30          \n" \
28                         "*showFPS:      False       \n" \
29                         "*wireframe:    False       \n" \
30                         "*speed:      " DEF_SPEED " \n" \
31                         "*spin:       " DEF_SPIN   "\n" \
32                         "*wander:     " DEF_WANDER "\n" \
33
34
35 #define SPIKE_FACES   12  /* how densely to render spikes */
36 #define SMOOTH_SPIKES True
37 #define SPHERE_SLICES 32  /* how densely to render spheres */
38 #define SPHERE_STACKS 16
39
40
41 #undef countof
42 #define countof(x) (sizeof((x))/sizeof((*x)))
43
44 #include "xlockmore.h"
45 #include "colors.h"
46 #include "sphere.h"
47 #include "tube.h"
48 #include <ctype.h>
49
50 #ifdef USE_GL /* whole file */
51
52 #ifdef HAVE_UNAME
53 # include <sys/utsname.h>
54 #endif /* HAVE_UNAME */
55
56
57 #include <GL/glu.h>
58 #include "glutstroke.h"
59 #include "glut_roman.h"
60 #define GLUT_FONT (&glutStrokeRoman)
61
62
63 typedef struct {
64   GLXContext *glx_context;
65
66   GLfloat rotx, roty, rotz;        /* current object rotation */
67   GLfloat dx, dy, dz;              /* current rotational velocity */
68   GLfloat ddx, ddy, ddz;           /* current rotational acceleration */
69   GLfloat d_max;                   /* max velocity */
70
71   GLuint ball_list;
72   GLuint spike_list;
73
74   GLfloat pos;
75   int *spikes;
76
77   int ncolors;
78   XColor *colors;
79   int ccolor;
80   int color_shift;
81
82 } ball_configuration;
83
84 static ball_configuration *bps = NULL;
85
86 static char *do_spin;
87 static GLfloat speed;
88 static Bool do_wander;
89
90 static XrmOptionDescRec opts[] = {
91   { "-spin",   ".spin",   XrmoptionNoArg, "True" },
92   { "+spin",   ".spin",   XrmoptionNoArg, "False" },
93   { "-speed",  ".speed",  XrmoptionSepArg, 0 },
94   { "-wander", ".wander", XrmoptionNoArg, "True" },
95   { "+wander", ".wander", XrmoptionNoArg, "False" }
96 };
97
98 static argtype vars[] = {
99   {(caddr_t *) &do_spin,   "spin",   "Spin",   DEF_SPIN,   t_Bool},
100   {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
101   {(caddr_t *) &speed,     "speed",  "Speed",  DEF_SPEED,  t_Float},
102 };
103
104 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
105
106
107 /* Window management, etc
108  */
109 void
110 reshape_ball (ModeInfo *mi, int width, int height)
111 {
112   GLfloat h = (GLfloat) height / (GLfloat) width;
113
114   glViewport (0, 0, (GLint) width, (GLint) height);
115
116   glMatrixMode(GL_PROJECTION);
117   glLoadIdentity();
118
119   gluPerspective( 30.0, 1/h, 1.0, 100.0 );
120   gluLookAt( 0.0, 0.0, 15.0,
121              0.0, 0.0, 0.0,
122              0.0, 1.0, 0.0);
123   glMatrixMode(GL_MODELVIEW);
124   glLoadIdentity();
125   glTranslatef(0.0, 0.0, -15.0);
126
127   glClear(GL_COLOR_BUFFER_BIT);
128 }
129
130
131 static void
132 gl_init (ModeInfo *mi)
133 {
134 /*  ball_configuration *bp = &bps[MI_SCREEN(mi)]; */
135   int wire = MI_IS_WIREFRAME(mi);
136
137   static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
138
139   if (!wire)
140     {
141       glLightfv(GL_LIGHT0, GL_POSITION, pos);
142       glEnable(GL_CULL_FACE);
143       glEnable(GL_LIGHTING);
144       glEnable(GL_LIGHT0);
145       glEnable(GL_DEPTH_TEST);
146     }
147 }
148
149
150 /* lifted from lament.c */
151 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
152 #define RANDSIGN() ((random() & 1) ? 1 : -1)
153
154 static void
155 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
156 {
157   double ppos = *pos;
158
159   /* tick position */
160   if (ppos < 0)
161     ppos = -(ppos + *v);
162   else
163     ppos += *v;
164
165   if (ppos > 1.0)
166     ppos -= 1.0;
167   else if (ppos < 0)
168     ppos += 1.0;
169
170   if (ppos < 0) abort();
171   if (ppos > 1.0) abort();
172   *pos = (*pos > 0 ? ppos : -ppos);
173
174   /* accelerate */
175   *v += *dv;
176
177   /* clamp velocity */
178   if (*v > max_v || *v < -max_v)
179     {
180       *dv = -*dv;
181     }
182   /* If it stops, start it going in the other direction. */
183   else if (*v < 0)
184     {
185       if (random() % 4)
186         {
187           *v = 0;
188
189           /* keep going in the same direction */
190           if (random() % 2)
191             *dv = 0;
192           else if (*dv < 0)
193             *dv = -*dv;
194         }
195       else
196         {
197           /* reverse gears */
198           *v = -*v;
199           *dv = -*dv;
200           *pos = -*pos;
201         }
202     }
203
204   /* Alter direction of rotational acceleration randomly. */
205   if (! (random() % 120))
206     *dv = -*dv;
207
208   /* Change acceleration very occasionally. */
209   if (! (random() % 200))
210     {
211       if (*dv == 0)
212         *dv = 0.00001;
213       else if (random() & 1)
214         *dv *= 1.2;
215       else
216         *dv *= 0.8;
217     }
218 }
219
220
221 static void
222 randomize_spikes (ModeInfo *mi)
223 {
224   ball_configuration *bp = &bps[MI_SCREEN(mi)];
225   int i;
226   bp->pos = 0;
227   for (i = 0; i < MI_COUNT(mi); i++)
228     {
229       bp->spikes[i*2]   = (random() % 360) - 180;
230       bp->spikes[i*2+1] = (random() % 180) - 90;
231     }
232
233 # define ROT_SCALE 22
234   for (i = 0; i < MI_COUNT(mi) * 2; i++)
235     bp->spikes[i] = (bp->spikes[i] / ROT_SCALE) * ROT_SCALE;
236
237   if ((random() % 3) == 0)
238     bp->color_shift = random() % (bp->ncolors / 2);
239   else
240     bp->color_shift = 0;
241 }
242
243 static void
244 draw_spikes (ModeInfo *mi)
245 {
246   ball_configuration *bp = &bps[MI_SCREEN(mi)];
247   GLfloat diam = 0.2;
248   GLfloat pos = bp->pos;
249   int i;
250
251   if (pos < 0) pos = -pos;
252
253   pos = (asin (0.5 + pos/2) - 0.5) * 2;
254
255   for (i = 0; i < MI_COUNT(mi); i++)
256     {
257       glPushMatrix();
258       glRotatef(bp->spikes[i*2],   0, 1, 0);
259       glRotatef(bp->spikes[i*2+1], 0, 0, 1);
260       glTranslatef(0.7, 0, 0);
261       glRotatef(-90, 0, 0, 1);
262       glScalef (diam, pos, diam);
263       glCallList (bp->spike_list);
264       glPopMatrix();
265     }
266 }
267
268
269 static void
270 move_spikes (ModeInfo *mi)
271 {
272   ball_configuration *bp = &bps[MI_SCREEN(mi)];
273
274   if (bp->pos >= 0)             /* moving outward */
275     {
276       bp->pos += speed;
277       if (bp->pos >= 1)         /*  reverse gears at apex */
278         bp->pos = -1;
279     }
280   else                          /* moving inward */
281     {
282       bp->pos += speed;
283       if (bp->pos >= 0)         /*  stop at end */
284         randomize_spikes (mi);
285     }
286 }
287
288
289 void 
290 init_ball (ModeInfo *mi)
291 {
292   ball_configuration *bp;
293   int wire = MI_IS_WIREFRAME(mi);
294
295   if (!bps) {
296     bps = (ball_configuration *)
297       calloc (MI_NUM_SCREENS(mi), sizeof (ball_configuration));
298     if (!bps) {
299       fprintf(stderr, "%s: out of memory\n", progname);
300       exit(1);
301     }
302
303     bp = &bps[MI_SCREEN(mi)];
304   }
305
306   bp = &bps[MI_SCREEN(mi)];
307
308   if ((bp->glx_context = init_GL(mi)) != NULL) {
309     gl_init(mi);
310     reshape_ball (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
311   }
312
313   bp->rotx = frand(1.0) * RANDSIGN();
314   bp->roty = frand(1.0) * RANDSIGN();
315   bp->rotz = frand(1.0) * RANDSIGN();
316
317   /* bell curve from 0-6 degrees, avg 3 */
318   bp->dx = (frand(2) + frand(2) + frand(2)) / (360/2);
319   bp->dy = (frand(2) + frand(2) + frand(2)) / (360/2);
320   bp->dz = (frand(2) + frand(2) + frand(2)) / (360/2);
321
322   bp->d_max = bp->dx * 2;
323
324   bp->ddx = 0.00006 + frand(0.00003);
325   bp->ddy = 0.00006 + frand(0.00003);
326   bp->ddz = 0.00006 + frand(0.00003);
327
328   bp->ncolors = 128;
329   bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor));
330   make_smooth_colormap (0, 0, 0,
331                         bp->colors, &bp->ncolors,
332                         False, 0, False);
333
334   bp->spikes = (int *) calloc(MI_COUNT(mi), sizeof(*bp->spikes) * 2);
335
336   bp->ball_list = glGenLists (1);
337   bp->spike_list = glGenLists (1);
338
339   glNewList (bp->ball_list, GL_COMPILE);
340   unit_sphere (SPHERE_STACKS, SPHERE_SLICES, wire);
341   glEndList ();
342
343   glNewList (bp->spike_list, GL_COMPILE);
344   cone (0, 0, 0,
345         0, 1, 0,
346         1, 0, SPIKE_FACES, SMOOTH_SPIKES, wire);
347   glEndList ();
348
349   randomize_spikes (mi);
350 }
351
352
353 void
354 draw_ball (ModeInfo *mi)
355 {
356   ball_configuration *bp = &bps[MI_SCREEN(mi)];
357   Display *dpy = MI_DISPLAY(mi);
358   Window window = MI_WINDOW(mi);
359   int c2;
360
361   static GLfloat color1[4] = {0.0, 0.0, 0.0, 1.0};
362   static GLfloat color2[4] = {0.0, 0.0, 0.0, 1.0};
363
364   if (!bp->glx_context)
365     return;
366
367   glShadeModel(GL_SMOOTH);
368
369   glEnable(GL_DEPTH_TEST);
370   glEnable(GL_NORMALIZE);
371   glEnable(GL_CULL_FACE);
372
373   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
374
375   glPushMatrix ();
376
377   glScalef(1.1, 1.1, 1.1);
378
379   {
380     GLfloat x, y, z;
381
382     if (do_wander)
383       {
384         static int frame = 0;
385
386 #       define SINOID(SCALE,SIZE) \
387         ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
388
389         x = SINOID(0.051, 8.0);
390         y = SINOID(0.037, 8.0);
391         z = SINOID(0.131, 13.0);
392         frame++;
393         glTranslatef(x, y, z);
394       }
395
396     if (do_spin)
397       {
398         x = bp->rotx;
399         y = bp->roty;
400         z = bp->rotz;
401         if (x < 0) x = 1 - (x + 1);
402         if (y < 0) y = 1 - (y + 1);
403         if (z < 0) z = 1 - (z + 1);
404
405         glRotatef(x * 360, 1.0, 0.0, 0.0);
406         glRotatef(y * 360, 0.0, 1.0, 0.0);
407         glRotatef(z * 360, 0.0, 0.0, 1.0);
408
409         rotate(&bp->rotx, &bp->dx, &bp->ddx, bp->d_max);
410         rotate(&bp->roty, &bp->dy, &bp->ddy, bp->d_max);
411         rotate(&bp->rotz, &bp->dz, &bp->ddz, bp->d_max);
412       }
413   }
414
415   color1[0] = bp->colors[bp->ccolor].red   / 65536.0;
416   color1[1] = bp->colors[bp->ccolor].green / 65536.0;
417   color1[2] = bp->colors[bp->ccolor].blue  / 65536.0;
418
419   c2 = (bp->ccolor + bp->color_shift) % bp->ncolors;
420   color2[0] = bp->colors[c2].red   / 65536.0;
421   color2[1] = bp->colors[c2].green / 65536.0;
422   color2[2] = bp->colors[c2].blue  / 65536.0;
423
424   bp->ccolor++;
425   if (bp->ccolor >= bp->ncolors) bp->ccolor = 0;
426
427   glScalef (2.0, 2.0, 2.0);
428
429   move_spikes (mi);
430
431   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);
432   glCallList (bp->ball_list);
433
434   glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);
435   draw_spikes (mi);
436   glPopMatrix ();
437
438   if (mi->fps_p) do_fps (mi);
439   glFinish();
440
441   glXSwapBuffers(dpy, window);
442 }
443
444 #endif /* USE_GL */