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