1 /* dangerball, Copyright (c) 2001-2014 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 #define DEFAULTS "*delay: 30000 \n" \
14 "*showFPS: False \n" \
15 "*wireframe: False \n" \
17 # define refresh_ball 0
18 # define release_ball 0
20 #define countof(x) (sizeof((x))/sizeof((*x)))
22 #include "xlockmore.h"
27 #include "gltrackball.h"
30 #ifdef USE_GL /* whole file */
33 #define DEF_SPIN "True"
34 #define DEF_WANDER "True"
35 #define DEF_SPEED "0.05"
37 #define SPIKE_FACES 12 /* how densely to render spikes */
38 #define SMOOTH_SPIKES True
39 #define SPHERE_SLICES 32 /* how densely to render spheres */
40 #define SPHERE_STACKS 16
44 GLXContext *glx_context;
46 trackball_state *trackball;
62 static ball_configuration *bps = NULL;
66 static Bool do_wander;
68 static XrmOptionDescRec opts[] = {
69 { "-spin", ".spin", XrmoptionNoArg, "True" },
70 { "+spin", ".spin", XrmoptionNoArg, "False" },
71 { "-speed", ".speed", XrmoptionSepArg, 0 },
72 { "-wander", ".wander", XrmoptionNoArg, "True" },
73 { "+wander", ".wander", XrmoptionNoArg, "False" }
76 static argtype vars[] = {
77 {&do_spin, "spin", "Spin", DEF_SPIN, t_Bool},
78 {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
79 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
82 ENTRYPOINT ModeSpecOpt ball_opts = {countof(opts), opts, countof(vars), vars, NULL};
85 /* Window management, etc
88 reshape_ball (ModeInfo *mi, int width, int height)
90 GLfloat h = (GLfloat) height / (GLfloat) width;
92 glViewport (0, 0, (GLint) width, (GLint) height);
94 glMatrixMode(GL_PROJECTION);
96 gluPerspective (30.0, 1/h, 1.0, 100.0);
98 glMatrixMode(GL_MODELVIEW);
100 gluLookAt( 0.0, 0.0, 30.0,
104 glClear(GL_COLOR_BUFFER_BIT);
109 randomize_spikes (ModeInfo *mi)
111 ball_configuration *bp = &bps[MI_SCREEN(mi)];
114 for (i = 0; i < MI_COUNT(mi); i++)
116 bp->spikes[i*2] = (random() % 360) - 180;
117 bp->spikes[i*2+1] = (random() % 180) - 90;
120 # define ROT_SCALE 22
121 for (i = 0; i < MI_COUNT(mi) * 2; i++)
122 bp->spikes[i] = (bp->spikes[i] / ROT_SCALE) * ROT_SCALE;
124 if ((random() % 3) == 0)
125 bp->color_shift = random() % (bp->ncolors / 2);
131 draw_spikes (ModeInfo *mi)
133 ball_configuration *bp = &bps[MI_SCREEN(mi)];
135 GLfloat pos = bp->pos;
138 if (pos < 0) pos = -pos;
140 pos = (asin (0.5 + pos/2) - 0.5) * 2;
142 for (i = 0; i < MI_COUNT(mi); i++)
145 glRotatef(bp->spikes[i*2], 0, 1, 0);
146 glRotatef(bp->spikes[i*2+1], 0, 0, 1);
147 glTranslatef(0.7, 0, 0);
148 glRotatef(-90, 0, 0, 1);
149 glScalef (diam, pos, diam);
150 glCallList (bp->spike_list);
153 mi->polygon_count += (SPIKE_FACES + 1);
159 move_spikes (ModeInfo *mi)
161 ball_configuration *bp = &bps[MI_SCREEN(mi)];
163 if (bp->pos >= 0) /* moving outward */
166 if (bp->pos >= 1) /* reverse gears at apex */
169 else /* moving inward */
172 if (bp->pos >= 0) /* stop at end */
173 randomize_spikes (mi);
179 ball_handle_event (ModeInfo *mi, XEvent *event)
181 ball_configuration *bp = &bps[MI_SCREEN(mi)];
183 if (gltrackball_event_handler (event, bp->trackball,
184 MI_WIDTH (mi), MI_HEIGHT (mi),
193 init_ball (ModeInfo *mi)
195 ball_configuration *bp;
196 int wire = MI_IS_WIREFRAME(mi);
199 bps = (ball_configuration *)
200 calloc (MI_NUM_SCREENS(mi), sizeof (ball_configuration));
202 fprintf(stderr, "%s: out of memory\n", progname);
207 bp = &bps[MI_SCREEN(mi)];
209 bp->glx_context = init_GL(mi);
211 reshape_ball (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
215 GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
216 GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
217 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
218 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
220 glEnable(GL_LIGHTING);
222 glEnable(GL_DEPTH_TEST);
223 glEnable(GL_CULL_FACE);
225 glLightfv(GL_LIGHT0, GL_POSITION, pos);
226 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
227 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
228 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
232 double spin_speed = 10.0;
233 double wander_speed = 0.12;
234 double spin_accel = 2.0;
236 bp->rot = make_rotator (do_spin ? spin_speed : 0,
237 do_spin ? spin_speed : 0,
238 do_spin ? spin_speed : 0,
240 do_wander ? wander_speed : 0,
242 bp->trackball = gltrackball_init (True);
246 bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor));
247 make_smooth_colormap (0, 0, 0,
248 bp->colors, &bp->ncolors,
251 bp->spikes = (int *) calloc(MI_COUNT(mi), sizeof(*bp->spikes) * 2);
253 bp->ball_list = glGenLists (1);
254 bp->spike_list = glGenLists (1);
256 glNewList (bp->ball_list, GL_COMPILE);
257 unit_sphere (SPHERE_STACKS, SPHERE_SLICES, wire);
260 glNewList (bp->spike_list, GL_COMPILE);
263 1, 0, SPIKE_FACES, SMOOTH_SPIKES, False, wire);
266 randomize_spikes (mi);
271 draw_ball (ModeInfo *mi)
273 ball_configuration *bp = &bps[MI_SCREEN(mi)];
274 Display *dpy = MI_DISPLAY(mi);
275 Window window = MI_WINDOW(mi);
278 static const GLfloat bspec[4] = {1.0, 1.0, 1.0, 1.0};
279 static const GLfloat sspec[4] = {0.0, 0.0, 0.0, 1.0};
280 static const GLfloat bshiny = 128.0;
281 static const GLfloat sshiny = 0.0;
283 GLfloat bcolor[4] = {0.0, 0.0, 0.0, 1.0};
284 GLfloat scolor[4] = {0.0, 0.0, 0.0, 1.0};
286 if (!bp->glx_context)
289 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
291 glShadeModel(GL_SMOOTH);
293 glEnable(GL_DEPTH_TEST);
294 glEnable(GL_NORMALIZE);
295 glEnable(GL_CULL_FACE);
297 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
301 glScalef(1.1, 1.1, 1.1);
305 get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
306 glTranslatef((x - 0.5) * 8,
310 gltrackball_rotate (bp->trackball);
312 get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
313 glRotatef (x * 360, 1.0, 0.0, 0.0);
314 glRotatef (y * 360, 0.0, 1.0, 0.0);
315 glRotatef (z * 360, 0.0, 0.0, 1.0);
318 bcolor[0] = bp->colors[bp->ccolor].red / 65536.0;
319 bcolor[1] = bp->colors[bp->ccolor].green / 65536.0;
320 bcolor[2] = bp->colors[bp->ccolor].blue / 65536.0;
322 c2 = (bp->ccolor + bp->color_shift) % bp->ncolors;
323 scolor[0] = bp->colors[c2].red / 65536.0;
324 scolor[1] = bp->colors[c2].green / 65536.0;
325 scolor[2] = bp->colors[c2].blue / 65536.0;
328 if (bp->ccolor >= bp->ncolors) bp->ccolor = 0;
330 mi->polygon_count = 0;
332 glScalef (2.0, 2.0, 2.0);
336 glMaterialfv (GL_FRONT, GL_SPECULAR, bspec);
337 glMateriali (GL_FRONT, GL_SHININESS, bshiny);
338 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, bcolor);
339 glCallList (bp->ball_list);
340 mi->polygon_count += (SPHERE_SLICES * SPHERE_STACKS);
342 glMaterialfv (GL_FRONT, GL_SPECULAR, sspec);
343 glMaterialf (GL_FRONT, GL_SHININESS, sshiny);
344 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, scolor);
348 if (mi->fps_p) do_fps (mi);
351 glXSwapBuffers(dpy, window);
354 XSCREENSAVER_MODULE_2 ("DangerBall", dangerball, ball)