1 /* dangerball, Copyright (c) 2001-2008 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 (event->xany.type == ButtonPress &&
184 event->xbutton.button == Button1)
186 bp->button_down_p = True;
187 gltrackball_start (bp->trackball,
188 event->xbutton.x, event->xbutton.y,
189 MI_WIDTH (mi), MI_HEIGHT (mi));
192 else if (event->xany.type == ButtonRelease &&
193 event->xbutton.button == Button1)
195 bp->button_down_p = False;
198 else if (event->xany.type == ButtonPress &&
199 (event->xbutton.button == Button4 ||
200 event->xbutton.button == Button5 ||
201 event->xbutton.button == Button6 ||
202 event->xbutton.button == Button7))
204 gltrackball_mousewheel (bp->trackball, event->xbutton.button, 10,
205 !!event->xbutton.state);
208 else if (event->xany.type == MotionNotify &&
211 gltrackball_track (bp->trackball,
212 event->xmotion.x, event->xmotion.y,
213 MI_WIDTH (mi), MI_HEIGHT (mi));
222 init_ball (ModeInfo *mi)
224 ball_configuration *bp;
225 int wire = MI_IS_WIREFRAME(mi);
228 bps = (ball_configuration *)
229 calloc (MI_NUM_SCREENS(mi), sizeof (ball_configuration));
231 fprintf(stderr, "%s: out of memory\n", progname);
236 bp = &bps[MI_SCREEN(mi)];
238 bp->glx_context = init_GL(mi);
240 reshape_ball (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
244 GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
245 GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
246 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
247 GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
249 glEnable(GL_LIGHTING);
251 glEnable(GL_DEPTH_TEST);
252 glEnable(GL_CULL_FACE);
254 glLightfv(GL_LIGHT0, GL_POSITION, pos);
255 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
256 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
257 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
261 double spin_speed = 10.0;
262 double wander_speed = 0.12;
263 double spin_accel = 2.0;
265 bp->rot = make_rotator (do_spin ? spin_speed : 0,
266 do_spin ? spin_speed : 0,
267 do_spin ? spin_speed : 0,
269 do_wander ? wander_speed : 0,
271 bp->trackball = gltrackball_init ();
275 bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor));
276 make_smooth_colormap (0, 0, 0,
277 bp->colors, &bp->ncolors,
280 bp->spikes = (int *) calloc(MI_COUNT(mi), sizeof(*bp->spikes) * 2);
282 bp->ball_list = glGenLists (1);
283 bp->spike_list = glGenLists (1);
285 glNewList (bp->ball_list, GL_COMPILE);
286 unit_sphere (SPHERE_STACKS, SPHERE_SLICES, wire);
289 glNewList (bp->spike_list, GL_COMPILE);
292 1, 0, SPIKE_FACES, SMOOTH_SPIKES, False, wire);
295 randomize_spikes (mi);
300 draw_ball (ModeInfo *mi)
302 ball_configuration *bp = &bps[MI_SCREEN(mi)];
303 Display *dpy = MI_DISPLAY(mi);
304 Window window = MI_WINDOW(mi);
307 static const GLfloat bspec[4] = {1.0, 1.0, 1.0, 1.0};
308 static const GLfloat sspec[4] = {0.0, 0.0, 0.0, 1.0};
309 static const GLfloat bshiny = 128.0;
310 static const GLfloat sshiny = 0.0;
312 GLfloat bcolor[4] = {0.0, 0.0, 0.0, 1.0};
313 GLfloat scolor[4] = {0.0, 0.0, 0.0, 1.0};
315 if (!bp->glx_context)
318 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
320 glShadeModel(GL_SMOOTH);
322 glEnable(GL_DEPTH_TEST);
323 glEnable(GL_NORMALIZE);
324 glEnable(GL_CULL_FACE);
326 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
330 glScalef(1.1, 1.1, 1.1);
334 get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
335 glTranslatef((x - 0.5) * 8,
339 /* Do it twice because we don't track the device's orientation. */
340 glRotatef( current_device_rotation(), 0, 0, 1);
341 gltrackball_rotate (bp->trackball);
342 glRotatef(-current_device_rotation(), 0, 0, 1);
344 get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
345 glRotatef (x * 360, 1.0, 0.0, 0.0);
346 glRotatef (y * 360, 0.0, 1.0, 0.0);
347 glRotatef (z * 360, 0.0, 0.0, 1.0);
350 bcolor[0] = bp->colors[bp->ccolor].red / 65536.0;
351 bcolor[1] = bp->colors[bp->ccolor].green / 65536.0;
352 bcolor[2] = bp->colors[bp->ccolor].blue / 65536.0;
354 c2 = (bp->ccolor + bp->color_shift) % bp->ncolors;
355 scolor[0] = bp->colors[c2].red / 65536.0;
356 scolor[1] = bp->colors[c2].green / 65536.0;
357 scolor[2] = bp->colors[c2].blue / 65536.0;
360 if (bp->ccolor >= bp->ncolors) bp->ccolor = 0;
362 mi->polygon_count = 0;
364 glScalef (2.0, 2.0, 2.0);
368 glMaterialfv (GL_FRONT, GL_SPECULAR, bspec);
369 glMateriali (GL_FRONT, GL_SHININESS, bshiny);
370 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, bcolor);
371 glCallList (bp->ball_list);
372 mi->polygon_count += (SPHERE_SLICES * SPHERE_STACKS);
374 glMaterialfv (GL_FRONT, GL_SPECULAR, sspec);
375 glMaterialf (GL_FRONT, GL_SHININESS, sshiny);
376 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, scolor);
380 if (mi->fps_p) do_fps (mi);
383 glXSwapBuffers(dpy, window);
386 XSCREENSAVER_MODULE_2 ("DangerBall", dangerball, ball)