1 /* dangerball, Copyright (c) 2001 Jamie Zawinski <jwz@jwz.org>
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
12 #include <X11/Intrinsic.h>
14 extern XtAppContext app;
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
22 #define DEF_SPIN "True"
23 #define DEF_WANDER "True"
24 #define DEF_SPEED "0.05"
26 #define DEFAULTS "*delay: 30000 \n" \
28 "*showFPS: False \n" \
29 "*wireframe: False \n" \
30 "*speed: " DEF_SPEED " \n" \
31 "*spin: " DEF_SPIN "\n" \
32 "*wander: " DEF_WANDER "\n" \
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
42 #define countof(x) (sizeof((x))/sizeof((*x)))
44 #include "xlockmore.h"
50 #ifdef USE_GL /* whole file */
55 GLXContext *glx_context;
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 */
75 static ball_configuration *bps = NULL;
79 static Bool do_wander;
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" }
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},
95 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
98 /* Window management, etc
101 reshape_ball (ModeInfo *mi, int width, int height)
103 GLfloat h = (GLfloat) height / (GLfloat) width;
105 glViewport (0, 0, (GLint) width, (GLint) height);
107 glMatrixMode(GL_PROJECTION);
110 gluPerspective( 30.0, 1/h, 1.0, 100.0 );
111 gluLookAt( 0.0, 0.0, 15.0,
114 glMatrixMode(GL_MODELVIEW);
116 glTranslatef(0.0, 0.0, -15.0);
118 glClear(GL_COLOR_BUFFER_BIT);
123 gl_init (ModeInfo *mi)
125 /* ball_configuration *bp = &bps[MI_SCREEN(mi)]; */
126 int wire = MI_IS_WIREFRAME(mi);
128 static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
132 glLightfv(GL_LIGHT0, GL_POSITION, pos);
133 glEnable(GL_CULL_FACE);
134 glEnable(GL_LIGHTING);
136 glEnable(GL_DEPTH_TEST);
141 /* lifted from lament.c */
142 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
143 #define RANDSIGN() ((random() & 1) ? 1 : -1)
146 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
161 if (ppos < 0) abort();
162 if (ppos > 1.0) abort();
163 *pos = (*pos > 0 ? ppos : -ppos);
169 if (*v > max_v || *v < -max_v)
173 /* If it stops, start it going in the other direction. */
180 /* keep going in the same direction */
195 /* Alter direction of rotational acceleration randomly. */
196 if (! (random() % 120))
199 /* Change acceleration very occasionally. */
200 if (! (random() % 200))
204 else if (random() & 1)
213 randomize_spikes (ModeInfo *mi)
215 ball_configuration *bp = &bps[MI_SCREEN(mi)];
218 for (i = 0; i < MI_COUNT(mi); i++)
220 bp->spikes[i*2] = (random() % 360) - 180;
221 bp->spikes[i*2+1] = (random() % 180) - 90;
224 # define ROT_SCALE 22
225 for (i = 0; i < MI_COUNT(mi) * 2; i++)
226 bp->spikes[i] = (bp->spikes[i] / ROT_SCALE) * ROT_SCALE;
228 if ((random() % 3) == 0)
229 bp->color_shift = random() % (bp->ncolors / 2);
235 draw_spikes (ModeInfo *mi)
237 ball_configuration *bp = &bps[MI_SCREEN(mi)];
239 GLfloat pos = bp->pos;
242 if (pos < 0) pos = -pos;
244 pos = (asin (0.5 + pos/2) - 0.5) * 2;
246 for (i = 0; i < MI_COUNT(mi); i++)
249 glRotatef(bp->spikes[i*2], 0, 1, 0);
250 glRotatef(bp->spikes[i*2+1], 0, 0, 1);
251 glTranslatef(0.7, 0, 0);
252 glRotatef(-90, 0, 0, 1);
253 glScalef (diam, pos, diam);
254 glCallList (bp->spike_list);
261 move_spikes (ModeInfo *mi)
263 ball_configuration *bp = &bps[MI_SCREEN(mi)];
265 if (bp->pos >= 0) /* moving outward */
268 if (bp->pos >= 1) /* reverse gears at apex */
271 else /* moving inward */
274 if (bp->pos >= 0) /* stop at end */
275 randomize_spikes (mi);
281 init_ball (ModeInfo *mi)
283 ball_configuration *bp;
284 int wire = MI_IS_WIREFRAME(mi);
287 bps = (ball_configuration *)
288 calloc (MI_NUM_SCREENS(mi), sizeof (ball_configuration));
290 fprintf(stderr, "%s: out of memory\n", progname);
294 bp = &bps[MI_SCREEN(mi)];
297 bp = &bps[MI_SCREEN(mi)];
299 if ((bp->glx_context = init_GL(mi)) != NULL) {
301 reshape_ball (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
304 bp->rotx = frand(1.0) * RANDSIGN();
305 bp->roty = frand(1.0) * RANDSIGN();
306 bp->rotz = frand(1.0) * RANDSIGN();
308 /* bell curve from 0-6 degrees, avg 3 */
309 bp->dx = (frand(2) + frand(2) + frand(2)) / (360/2);
310 bp->dy = (frand(2) + frand(2) + frand(2)) / (360/2);
311 bp->dz = (frand(2) + frand(2) + frand(2)) / (360/2);
313 bp->d_max = bp->dx * 2;
315 bp->ddx = 0.00006 + frand(0.00003);
316 bp->ddy = 0.00006 + frand(0.00003);
317 bp->ddz = 0.00006 + frand(0.00003);
320 bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor));
321 make_smooth_colormap (0, 0, 0,
322 bp->colors, &bp->ncolors,
325 bp->spikes = (int *) calloc(MI_COUNT(mi), sizeof(*bp->spikes) * 2);
327 bp->ball_list = glGenLists (1);
328 bp->spike_list = glGenLists (1);
330 glNewList (bp->ball_list, GL_COMPILE);
331 unit_sphere (SPHERE_STACKS, SPHERE_SLICES, wire);
334 glNewList (bp->spike_list, GL_COMPILE);
337 1, 0, SPIKE_FACES, SMOOTH_SPIKES, wire);
340 randomize_spikes (mi);
345 draw_ball (ModeInfo *mi)
347 ball_configuration *bp = &bps[MI_SCREEN(mi)];
348 Display *dpy = MI_DISPLAY(mi);
349 Window window = MI_WINDOW(mi);
352 static GLfloat color1[4] = {0.0, 0.0, 0.0, 1.0};
353 static GLfloat color2[4] = {0.0, 0.0, 0.0, 1.0};
355 if (!bp->glx_context)
358 glShadeModel(GL_SMOOTH);
360 glEnable(GL_DEPTH_TEST);
361 glEnable(GL_NORMALIZE);
362 glEnable(GL_CULL_FACE);
364 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
368 glScalef(1.1, 1.1, 1.1);
375 static int frame = 0;
377 # define SINOID(SCALE,SIZE) \
378 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
380 x = SINOID(0.051, 8.0);
381 y = SINOID(0.037, 8.0);
382 z = SINOID(0.131, 13.0);
384 glTranslatef(x, y, z);
392 if (x < 0) x = 1 - (x + 1);
393 if (y < 0) y = 1 - (y + 1);
394 if (z < 0) z = 1 - (z + 1);
396 glRotatef(x * 360, 1.0, 0.0, 0.0);
397 glRotatef(y * 360, 0.0, 1.0, 0.0);
398 glRotatef(z * 360, 0.0, 0.0, 1.0);
400 rotate(&bp->rotx, &bp->dx, &bp->ddx, bp->d_max);
401 rotate(&bp->roty, &bp->dy, &bp->ddy, bp->d_max);
402 rotate(&bp->rotz, &bp->dz, &bp->ddz, bp->d_max);
406 color1[0] = bp->colors[bp->ccolor].red / 65536.0;
407 color1[1] = bp->colors[bp->ccolor].green / 65536.0;
408 color1[2] = bp->colors[bp->ccolor].blue / 65536.0;
410 c2 = (bp->ccolor + bp->color_shift) % bp->ncolors;
411 color2[0] = bp->colors[c2].red / 65536.0;
412 color2[1] = bp->colors[c2].green / 65536.0;
413 color2[2] = bp->colors[c2].blue / 65536.0;
416 if (bp->ccolor >= bp->ncolors) bp->ccolor = 0;
418 glScalef (2.0, 2.0, 2.0);
422 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);
423 glCallList (bp->ball_list);
425 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);
429 if (mi->fps_p) do_fps (mi);
432 glXSwapBuffers(dpy, window);