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 */
53 # include <sys/utsname.h>
54 #endif /* HAVE_UNAME */
58 #include "glutstroke.h"
59 #include "glut_roman.h"
60 #define GLUT_FONT (&glutStrokeRoman)
64 GLXContext *glx_context;
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 */
84 static ball_configuration *bps = NULL;
88 static Bool do_wander;
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" }
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},
104 ModeSpecOpt sws_opts = {countof(opts), opts, countof(vars), vars, NULL};
107 /* Window management, etc
110 reshape_ball (ModeInfo *mi, int width, int height)
112 GLfloat h = (GLfloat) height / (GLfloat) width;
114 glViewport (0, 0, (GLint) width, (GLint) height);
116 glMatrixMode(GL_PROJECTION);
119 gluPerspective( 30.0, 1/h, 1.0, 100.0 );
120 gluLookAt( 0.0, 0.0, 15.0,
123 glMatrixMode(GL_MODELVIEW);
125 glTranslatef(0.0, 0.0, -15.0);
127 glClear(GL_COLOR_BUFFER_BIT);
132 gl_init (ModeInfo *mi)
134 /* ball_configuration *bp = &bps[MI_SCREEN(mi)]; */
135 int wire = MI_IS_WIREFRAME(mi);
137 static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
141 glLightfv(GL_LIGHT0, GL_POSITION, pos);
142 glEnable(GL_CULL_FACE);
143 glEnable(GL_LIGHTING);
145 glEnable(GL_DEPTH_TEST);
150 /* lifted from lament.c */
151 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
152 #define RANDSIGN() ((random() & 1) ? 1 : -1)
155 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
170 if (ppos < 0) abort();
171 if (ppos > 1.0) abort();
172 *pos = (*pos > 0 ? ppos : -ppos);
178 if (*v > max_v || *v < -max_v)
182 /* If it stops, start it going in the other direction. */
189 /* keep going in the same direction */
204 /* Alter direction of rotational acceleration randomly. */
205 if (! (random() % 120))
208 /* Change acceleration very occasionally. */
209 if (! (random() % 200))
213 else if (random() & 1)
222 randomize_spikes (ModeInfo *mi)
224 ball_configuration *bp = &bps[MI_SCREEN(mi)];
227 for (i = 0; i < MI_COUNT(mi); i++)
229 bp->spikes[i*2] = (random() % 360) - 180;
230 bp->spikes[i*2+1] = (random() % 180) - 90;
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;
237 if ((random() % 3) == 0)
238 bp->color_shift = random() % (bp->ncolors / 2);
244 draw_spikes (ModeInfo *mi)
246 ball_configuration *bp = &bps[MI_SCREEN(mi)];
248 GLfloat pos = bp->pos;
251 if (pos < 0) pos = -pos;
253 pos = (asin (0.5 + pos/2) - 0.5) * 2;
255 for (i = 0; i < MI_COUNT(mi); i++)
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);
270 move_spikes (ModeInfo *mi)
272 ball_configuration *bp = &bps[MI_SCREEN(mi)];
274 if (bp->pos >= 0) /* moving outward */
277 if (bp->pos >= 1) /* reverse gears at apex */
280 else /* moving inward */
283 if (bp->pos >= 0) /* stop at end */
284 randomize_spikes (mi);
290 init_ball (ModeInfo *mi)
292 ball_configuration *bp;
293 int wire = MI_IS_WIREFRAME(mi);
296 bps = (ball_configuration *)
297 calloc (MI_NUM_SCREENS(mi), sizeof (ball_configuration));
299 fprintf(stderr, "%s: out of memory\n", progname);
303 bp = &bps[MI_SCREEN(mi)];
306 bp = &bps[MI_SCREEN(mi)];
308 if ((bp->glx_context = init_GL(mi)) != NULL) {
310 reshape_ball (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
313 bp->rotx = frand(1.0) * RANDSIGN();
314 bp->roty = frand(1.0) * RANDSIGN();
315 bp->rotz = frand(1.0) * RANDSIGN();
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);
322 bp->d_max = bp->dx * 2;
324 bp->ddx = 0.00006 + frand(0.00003);
325 bp->ddy = 0.00006 + frand(0.00003);
326 bp->ddz = 0.00006 + frand(0.00003);
329 bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor));
330 make_smooth_colormap (0, 0, 0,
331 bp->colors, &bp->ncolors,
334 bp->spikes = (int *) calloc(MI_COUNT(mi), sizeof(*bp->spikes) * 2);
336 bp->ball_list = glGenLists (1);
337 bp->spike_list = glGenLists (1);
339 glNewList (bp->ball_list, GL_COMPILE);
340 unit_sphere (SPHERE_STACKS, SPHERE_SLICES, wire);
343 glNewList (bp->spike_list, GL_COMPILE);
346 1, 0, SPIKE_FACES, SMOOTH_SPIKES, wire);
349 randomize_spikes (mi);
354 draw_ball (ModeInfo *mi)
356 ball_configuration *bp = &bps[MI_SCREEN(mi)];
357 Display *dpy = MI_DISPLAY(mi);
358 Window window = MI_WINDOW(mi);
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};
364 if (!bp->glx_context)
367 glShadeModel(GL_SMOOTH);
369 glEnable(GL_DEPTH_TEST);
370 glEnable(GL_NORMALIZE);
371 glEnable(GL_CULL_FACE);
373 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
377 glScalef(1.1, 1.1, 1.1);
384 static int frame = 0;
386 # define SINOID(SCALE,SIZE) \
387 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
389 x = SINOID(0.051, 8.0);
390 y = SINOID(0.037, 8.0);
391 z = SINOID(0.131, 13.0);
393 glTranslatef(x, y, z);
401 if (x < 0) x = 1 - (x + 1);
402 if (y < 0) y = 1 - (y + 1);
403 if (z < 0) z = 1 - (z + 1);
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);
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);
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;
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;
425 if (bp->ccolor >= bp->ncolors) bp->ccolor = 0;
427 glScalef (2.0, 2.0, 2.0);
431 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color1);
432 glCallList (bp->ball_list);
434 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color2);
438 if (mi->fps_p) do_fps (mi);
441 glXSwapBuffers(dpy, window);