1 /* dangerball, Copyright (c) 2001, 2002 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);
122 /* lifted from lament.c */
123 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
124 #define RANDSIGN() ((random() & 1) ? 1 : -1)
127 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
142 if (ppos < 0) abort();
143 if (ppos > 1.0) abort();
144 *pos = (*pos > 0 ? ppos : -ppos);
150 if (*v > max_v || *v < -max_v)
154 /* If it stops, start it going in the other direction. */
161 /* keep going in the same direction */
176 /* Alter direction of rotational acceleration randomly. */
177 if (! (random() % 120))
180 /* Change acceleration very occasionally. */
181 if (! (random() % 200))
185 else if (random() & 1)
194 randomize_spikes (ModeInfo *mi)
196 ball_configuration *bp = &bps[MI_SCREEN(mi)];
199 for (i = 0; i < MI_COUNT(mi); i++)
201 bp->spikes[i*2] = (random() % 360) - 180;
202 bp->spikes[i*2+1] = (random() % 180) - 90;
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;
209 if ((random() % 3) == 0)
210 bp->color_shift = random() % (bp->ncolors / 2);
216 draw_spikes (ModeInfo *mi)
218 ball_configuration *bp = &bps[MI_SCREEN(mi)];
220 GLfloat pos = bp->pos;
223 if (pos < 0) pos = -pos;
225 pos = (asin (0.5 + pos/2) - 0.5) * 2;
227 for (i = 0; i < MI_COUNT(mi); i++)
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);
242 move_spikes (ModeInfo *mi)
244 ball_configuration *bp = &bps[MI_SCREEN(mi)];
246 if (bp->pos >= 0) /* moving outward */
249 if (bp->pos >= 1) /* reverse gears at apex */
252 else /* moving inward */
255 if (bp->pos >= 0) /* stop at end */
256 randomize_spikes (mi);
262 init_ball (ModeInfo *mi)
264 ball_configuration *bp;
265 int wire = MI_IS_WIREFRAME(mi);
268 bps = (ball_configuration *)
269 calloc (MI_NUM_SCREENS(mi), sizeof (ball_configuration));
271 fprintf(stderr, "%s: out of memory\n", progname);
275 bp = &bps[MI_SCREEN(mi)];
278 bp = &bps[MI_SCREEN(mi)];
280 bp->glx_context = init_GL(mi);
282 reshape_ball (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
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};
291 glEnable(GL_LIGHTING);
293 glEnable(GL_DEPTH_TEST);
294 glEnable(GL_CULL_FACE);
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);
302 bp->rotx = frand(1.0) * RANDSIGN();
303 bp->roty = frand(1.0) * RANDSIGN();
304 bp->rotz = frand(1.0) * RANDSIGN();
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);
311 bp->d_max = bp->dx * 2;
313 bp->ddx = 0.00006 + frand(0.00003);
314 bp->ddy = 0.00006 + frand(0.00003);
315 bp->ddz = 0.00006 + frand(0.00003);
318 bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor));
319 make_smooth_colormap (0, 0, 0,
320 bp->colors, &bp->ncolors,
323 bp->spikes = (int *) calloc(MI_COUNT(mi), sizeof(*bp->spikes) * 2);
325 bp->ball_list = glGenLists (1);
326 bp->spike_list = glGenLists (1);
328 glNewList (bp->ball_list, GL_COMPILE);
329 unit_sphere (SPHERE_STACKS, SPHERE_SLICES, wire);
332 glNewList (bp->spike_list, GL_COMPILE);
335 1, 0, SPIKE_FACES, SMOOTH_SPIKES, wire);
338 randomize_spikes (mi);
343 draw_ball (ModeInfo *mi)
345 ball_configuration *bp = &bps[MI_SCREEN(mi)];
346 Display *dpy = MI_DISPLAY(mi);
347 Window window = MI_WINDOW(mi);
350 /* #### I'm not getting specular reflections on the ball,
351 and I can't figure out why.
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;
361 if (!bp->glx_context)
364 glShadeModel(GL_SMOOTH);
366 glEnable(GL_DEPTH_TEST);
367 glEnable(GL_NORMALIZE);
368 glEnable(GL_CULL_FACE);
370 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
374 glScalef(1.1, 1.1, 1.1);
381 static int frame = 0;
383 # define SINOID(SCALE,SIZE) \
384 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
386 x = SINOID(0.051, 8.0);
387 y = SINOID(0.037, 8.0);
388 z = SINOID(0.131, 13.0);
390 glTranslatef(x, y, z);
398 if (x < 0) x = 1 - (x + 1);
399 if (y < 0) y = 1 - (y + 1);
400 if (z < 0) z = 1 - (z + 1);
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);
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);
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;
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;
422 if (bp->ccolor >= bp->ncolors) bp->ccolor = 0;
424 glScalef (2.0, 2.0, 2.0);
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);
433 glMaterialfv (GL_FRONT, GL_SPECULAR, sspec);
434 glMaterialf (GL_FRONT, GL_SHININESS, sshiny);
435 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, scolor);
439 if (mi->fps_p) do_fps (mi);
442 glXSwapBuffers(dpy, window);