1 /* xscreensaver, Copyright (c) 1992, 1994, 1996, 1998, 2001
2 * Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 /* Draw some fireworks. Inspired from TI Explorer Lisp code by
14 John S. Pezaris <pz@hx.lcs.mit.edu>
18 #include "screenhack.h"
21 int x, y; /* position */
22 int dx, dy; /* velocity */
29 struct projectile *next_free;
32 static struct projectile *projectiles, *free_projectiles;
33 static struct projectile **sorted_projectiles;
36 /* Slightly whacked, for better explosions
40 static int sin_cache[PI_2000];
41 static int cos_cache[PI_2000];
45 { /*needs to be run once. Could easily be */
46 int i; /*reimplemented to run and cache at compile-time,*/
47 double dA; /*saving on init_pyro time */
48 for (i=0; i<PI_2000; i++)
50 dA=sin(((double) (random() % (PI_2000/2)))/1000.0);
51 /*Emulation of spherical distribution*/
52 dA+=asin(frand(1.0))/M_PI_2*0.1;
53 /*Approximating the integration of the binominal, for
54 well-distributed randomness*/
55 cos_cache[i]=(int) (cos(((double)i)/1000.0)*dA*2500.0);
56 sin_cache[i]=(int) (sin(((double)i)/1000.0)*dA*2500.0);
61 static struct projectile *
68 free_projectiles = p->next_free;
78 free_projectile (struct projectile *p)
80 p->next_free = free_projectiles;
86 launch (int xlim, int ylim, int g,
87 Display *dpy, Colormap cmap)
89 struct projectile *p = get_projectile ();
94 x = (random () % xlim);
95 dx = 30000 - (random () % 60000);
97 } while (xxx <= 0 || xxx >= xlim);
104 p->dy = (random () % 4000) - 13000;
105 p->fuse = ((((random () % 500) + 500) * abs (p->dy / g)) / 1000);
108 /* cope with small windows -- those constants assume big windows. */
110 int div = 1000000 / ylim;
117 hsv_to_rgb (random () % 360, 1.0, 1.0,
118 &p->color.red, &p->color.green, &p->color.blue);
119 p->color.flags = DoRed | DoGreen | DoBlue;
120 if (!XAllocColor (dpy, cmap, &p->color))
122 p->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
123 p->color.red = p->color.green = p->color.blue = 0xFFFF;
128 static struct projectile *
129 shrapnel (struct projectile *parent, Display *dpy, Colormap cmap)
131 struct projectile *p = get_projectile ();
136 v=random () % PI_2000;
137 p->dx =(sin_cache[v]) + parent->dx;
138 p->dy =(cos_cache[v]) + parent->dx;
139 p->decay = (random () % 50) - 60;
140 p->size = (parent->size * 2) / 3;
144 p->color = parent->color;
146 XAllocColor (dpy, cmap, &p->color); /* dup the lock */
151 static GC draw_gc, erase_gc;
152 static unsigned int default_fg_pixel;
154 static int how_many, frequency, scatter;
157 init_pyro (Display *dpy, Window window)
162 XWindowAttributes xgwa;
163 XGetWindowAttributes (dpy, window, &xgwa);
164 cmap = xgwa.colormap;
165 how_many = get_integer_resource ("count", "Integer");
166 frequency = get_integer_resource ("frequency", "Integer");
167 scatter = get_integer_resource ("scatter", "Integer");
168 if (how_many <= 0) how_many = 100;
169 if (frequency <= 0) frequency = 30;
170 if (scatter <= 0) scatter = 20;
172 free_projectiles = 0;
173 projectiles = (struct projectile *)
174 calloc (how_many, sizeof (*projectiles));
175 sorted_projectiles = (struct projectile **)
176 calloc (how_many, sizeof (*sorted_projectiles));
177 for (i = 0; i < how_many; i++)
178 free_projectile (&projectiles [i]);
179 for (i = 0; i < how_many; i++)
180 sorted_projectiles[i] = &projectiles[i];
181 gcv.foreground = default_fg_pixel =
182 get_pixel_resource ("foreground", "Foreground", dpy, cmap);
183 draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
184 gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
185 erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
186 XClearWindow (dpy, window);
193 projectile_pixel_sorter (const void *a, const void *b)
195 struct projectile *pa = *(struct projectile **) a;
196 struct projectile *pb = *(struct projectile **) b;
197 if (pa->color.pixel == pb->color.pixel) return 0;
198 else if (pa->color.pixel < pb->color.pixel) return -1;
203 sort_by_pixel (int length)
205 qsort ((void *) sorted_projectiles,
207 sizeof(*sorted_projectiles),
208 projectile_pixel_sorter);
213 pyro (Display *dpy, Window window, Colormap cmap)
215 XWindowAttributes xgwa;
216 static int xlim, ylim, real_xlim, real_ylim;
221 for (i = 0; i < how_many; i++)
223 struct projectile *p = sorted_projectiles [i];
224 int old_x, old_y, old_size;
226 if (p->dead) continue;
229 old_size = p->size >> 10;
230 size = (p->size += p->decay) >> 10;
231 x = (p->x += p->dx) >> 10;
232 y = (p->y += p->dy) >> 10;
233 p->dy += (p->size >> 6);
234 if (p->primary) p->fuse--;
240 XDrawPoint (dpy, window, erase_gc, old_x, old_y);
242 XFillRectangle (dpy, window, erase_gc, old_x, old_y,
246 if ((p->primary ? (p->fuse > 0) : (p->size > 0)) &&
254 static unsigned long last_pixel = ~0;
257 if (mono_p || p->primary)
258 pixel = default_fg_pixel;
260 pixel = p->color.pixel;
262 if (pixel != last_pixel)
265 XSetForeground (dpy, draw_gc, pixel);
269 XDrawPoint (dpy, window, draw_gc, x, y);
271 XFillRectangle (dpy, window, draw_gc, x, y, size, size);
273 XFillArc (dpy, window, draw_gc, x, y, size, size, 0, 360*64);
280 if (p->color.pixel != WhitePixel (dpy, DefaultScreen (dpy)))
281 XFreeColors (dpy, cmap, &p->color.pixel, 1, 0);
284 if (p->primary && p->fuse <= 0)
286 int j = (random () % scatter) + (scatter/2);
288 shrapnel (p, dpy, cmap);
293 if ((random () % frequency) == 0)
295 XGetWindowAttributes (dpy, window, &xgwa);
296 real_xlim = xgwa.width;
297 real_ylim = xgwa.height;
298 xlim = real_xlim * 1000;
299 ylim = real_ylim * 1000;
300 launch (xlim, ylim, g, dpy, cmap);
304 /* being sorted lets us avoid changing the GC's foreground color as often. */
306 sort_by_pixel (how_many);
310 char *progclass = "Pyro";
312 char *defaults [] = {
313 ".background: black",
314 ".foreground: white",
319 "*geometry: 800x500",
323 XrmOptionDescRec options [] = {
324 { "-delay", ".delay", XrmoptionSepArg, 0 },
325 { "-count", ".count", XrmoptionSepArg, 0 },
326 { "-frequency", ".frequency", XrmoptionSepArg, 0 },
327 { "-scatter", ".scatter", XrmoptionSepArg, 0 },
332 screenhack (Display *dpy, Window window)
334 Colormap cmap = init_pyro (dpy, window);
335 int delay = get_integer_resource ("delay", "Integer");
339 pyro (dpy, window, cmap);
342 screenhack_handle_events (dpy);