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);
110 hsv_to_rgb (random () % 360, 1.0, 1.0,
111 &p->color.red, &p->color.green, &p->color.blue);
112 p->color.flags = DoRed | DoGreen | DoBlue;
113 if (!XAllocColor (dpy, cmap, &p->color))
115 p->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
116 p->color.red = p->color.green = p->color.blue = 0xFFFF;
121 static struct projectile *
122 shrapnel (struct projectile *parent, Display *dpy, Colormap cmap)
124 struct projectile *p = get_projectile ();
129 v=random () % PI_2000;
130 p->dx =(sin_cache[v]) + parent->dx;
131 p->dy =(cos_cache[v]) + parent->dx;
132 p->decay = (random () % 50) - 60;
133 p->size = (parent->size * 2) / 3;
137 p->color = parent->color;
139 XAllocColor (dpy, cmap, &p->color); /* dup the lock */
144 static GC draw_gc, erase_gc;
145 static unsigned int default_fg_pixel;
147 static int how_many, frequency, scatter;
150 init_pyro (Display *dpy, Window window)
155 XWindowAttributes xgwa;
156 XGetWindowAttributes (dpy, window, &xgwa);
157 cmap = xgwa.colormap;
158 how_many = get_integer_resource ("count", "Integer");
159 frequency = get_integer_resource ("frequency", "Integer");
160 scatter = get_integer_resource ("scatter", "Integer");
161 if (how_many <= 0) how_many = 100;
162 if (frequency <= 0) frequency = 30;
163 if (scatter <= 0) scatter = 20;
165 free_projectiles = 0;
166 projectiles = (struct projectile *)
167 calloc (how_many, sizeof (*projectiles));
168 sorted_projectiles = (struct projectile **)
169 calloc (how_many, sizeof (*sorted_projectiles));
170 for (i = 0; i < how_many; i++)
171 free_projectile (&projectiles [i]);
172 for (i = 0; i < how_many; i++)
173 sorted_projectiles[i] = &projectiles[i];
174 gcv.foreground = default_fg_pixel =
175 get_pixel_resource ("foreground", "Foreground", dpy, cmap);
176 draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
177 gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
178 erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
179 XClearWindow (dpy, window);
186 projectile_pixel_sorter (const void *a, const void *b)
188 struct projectile *pa = *(struct projectile **) a;
189 struct projectile *pb = *(struct projectile **) b;
190 if (pa->color.pixel == pb->color.pixel) return 0;
191 else if (pa->color.pixel < pb->color.pixel) return -1;
196 sort_by_pixel (int length)
198 qsort ((void *) sorted_projectiles,
200 sizeof(*sorted_projectiles),
201 projectile_pixel_sorter);
206 pyro (Display *dpy, Window window, Colormap cmap)
208 XWindowAttributes xgwa;
209 static int xlim, ylim, real_xlim, real_ylim;
214 for (i = 0; i < how_many; i++)
216 struct projectile *p = sorted_projectiles [i];
217 int old_x, old_y, old_size;
219 if (p->dead) continue;
222 old_size = p->size >> 10;
223 size = (p->size += p->decay) >> 10;
224 x = (p->x += p->dx) >> 10;
225 y = (p->y += p->dy) >> 10;
226 p->dy += (p->size >> 6);
227 if (p->primary) p->fuse--;
233 XDrawPoint (dpy, window, erase_gc, old_x, old_y);
235 XFillRectangle (dpy, window, erase_gc, old_x, old_y,
239 if ((p->primary ? (p->fuse > 0) : (p->size > 0)) &&
247 static unsigned long last_pixel = ~0;
250 if (mono_p || p->primary)
251 pixel = default_fg_pixel;
253 pixel = p->color.pixel;
255 if (pixel != last_pixel)
258 XSetForeground (dpy, draw_gc, pixel);
262 XDrawPoint (dpy, window, draw_gc, x, y);
264 XFillRectangle (dpy, window, draw_gc, x, y, size, size);
266 XFillArc (dpy, window, draw_gc, x, y, size, size, 0, 360*64);
273 if (p->color.pixel != WhitePixel (dpy, DefaultScreen (dpy)))
274 XFreeColors (dpy, cmap, &p->color.pixel, 1, 0);
277 if (p->primary && p->fuse <= 0)
279 int j = (random () % scatter) + (scatter/2);
281 shrapnel (p, dpy, cmap);
286 if ((random () % frequency) == 0)
288 XGetWindowAttributes (dpy, window, &xgwa);
289 real_xlim = xgwa.width;
290 real_ylim = xgwa.height;
291 xlim = real_xlim * 1000;
292 ylim = real_ylim * 1000;
293 launch (xlim, ylim, g, dpy, cmap);
297 /* being sorted lets us avoid changing the GC's foreground color as often. */
299 sort_by_pixel (how_many);
303 char *progclass = "Pyro";
305 char *defaults [] = {
306 ".background: black",
307 ".foreground: white",
312 "*geometry: 800x500",
316 XrmOptionDescRec options [] = {
317 { "-delay", ".delay", XrmoptionSepArg, 0 },
318 { "-count", ".count", XrmoptionSepArg, 0 },
319 { "-frequency", ".frequency", XrmoptionSepArg, 0 },
320 { "-scatter", ".scatter", XrmoptionSepArg, 0 },
325 screenhack (Display *dpy, Window window)
327 Colormap cmap = init_pyro (dpy, window);
328 int delay = get_integer_resource ("delay", "Integer");
332 pyro (dpy, window, cmap);
335 screenhack_handle_events (dpy);