1 /* xscreensaver, Copyright (c) 1992, 1994, 1996, 1998, 2001, 2005, 2006
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;
39 struct projectile *projectiles, *free_projectiles;
40 struct projectile **sorted_projectiles;
43 unsigned int default_fg_pixel;
46 int how_many, frequency, scatter, delay;
48 int sin_cache[PI_2000];
49 int cos_cache[PI_2000];
51 int draw_xlim, draw_ylim, real_draw_xlim, real_draw_ylim;
53 unsigned long last_pixel;
58 /* Slightly whacked, for better explosions
62 cache(struct state *st)
63 { /*needs to be run once. Could easily be */
64 int i; /*reimplemented to run and cache at compile-time,*/
65 double dA; /*saving on init_pyro time */
66 for (i=0; i<PI_2000; i++)
68 dA=sin(((double) (random() % (PI_2000/2)))/1000.0);
69 /*Emulation of spherical distribution*/
70 dA+=asin(frand(1.0))/M_PI_2*0.1;
71 /*Approximating the integration of the binominal, for
72 well-distributed randomness*/
73 st->cos_cache[i]=(int) (cos(((double)i)/1000.0)*dA*2500.0);
74 st->sin_cache[i]=(int) (sin(((double)i)/1000.0)*dA*2500.0);
79 static struct projectile *
80 get_projectile (struct state *st)
83 if (st->free_projectiles)
85 p = st->free_projectiles;
86 st->free_projectiles = p->next_free;
96 free_projectile (struct state *st, struct projectile *p)
98 p->next_free = st->free_projectiles;
99 st->free_projectiles = p;
104 launch (struct state *st,
105 int xlim, int ylim, int g)
107 struct projectile *p = get_projectile (st);
112 x = (random () % xlim);
113 dx = 30000 - (random () % 60000);
114 xxx = x + (dx * 200);
115 } while (xxx <= 0 || xxx >= xlim);
122 p->dy = (random () % 4000) - 13000;
123 p->fuse = ((((random () % 500) + 500) * abs (p->dy / g)) / 1000);
126 /* cope with small windows -- those constants assume big windows. */
128 int dd = 1000000 / ylim;
135 hsv_to_rgb (random () % 360, 1.0, 1.0,
136 &p->color.red, &p->color.green, &p->color.blue);
137 p->color.flags = DoRed | DoGreen | DoBlue;
138 if (!XAllocColor (st->dpy, st->cmap, &p->color))
140 p->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy));
141 p->color.red = p->color.green = p->color.blue = 0xFFFF;
146 static struct projectile *
147 shrapnel (struct state *st, struct projectile *parent)
149 struct projectile *p = get_projectile (st);
154 v=random () % PI_2000;
155 p->dx =(st->sin_cache[v]) + parent->dx;
156 p->dy =(st->cos_cache[v]) + parent->dy;
157 p->decay = (random () % 50) - 60;
158 p->size = (parent->size * 2) / 3;
162 p->color = parent->color;
164 XAllocColor (st->dpy, st->cmap, &p->color); /* dup the lock */
170 pyro_init (Display *dpy, Window window)
172 struct state *st = (struct state *) calloc (1, sizeof(*st));
175 XWindowAttributes xgwa;
178 XGetWindowAttributes (st->dpy, st->window, &xgwa);
180 st->cmap = xgwa.colormap;
181 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
182 st->how_many = get_integer_resource (st->dpy, "count", "Integer");
183 st->frequency = get_integer_resource (st->dpy, "frequency", "Integer");
184 st->scatter = get_integer_resource (st->dpy, "scatter", "Integer");
185 if (st->how_many <= 0) st->how_many = 100;
186 if (st->frequency <= 0) st->frequency = 30;
187 if (st->scatter <= 0) st->scatter = 20;
189 st->free_projectiles = 0;
190 st->projectiles = (struct projectile *)
191 calloc (st->how_many, sizeof (*st->projectiles));
192 st->sorted_projectiles = (struct projectile **)
193 calloc (st->how_many, sizeof (*st->sorted_projectiles));
194 for (i = 0; i < st->how_many; i++)
195 free_projectile (st, &st->projectiles [i]);
196 for (i = 0; i < st->how_many; i++)
197 st->sorted_projectiles[i] = &st->projectiles[i];
198 gcv.foreground = st->default_fg_pixel =
199 get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground");
200 st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
201 gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "background", "Background");
202 st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
203 XClearWindow (st->dpy, st->window);
211 projectile_pixel_sorter (const void *a, const void *b)
213 struct projectile *pa = *(struct projectile **) a;
214 struct projectile *pb = *(struct projectile **) b;
215 if (pa->color.pixel == pb->color.pixel) return 0;
216 else if (pa->color.pixel < pb->color.pixel) return -1;
221 sort_by_pixel (struct state *st, int length)
223 qsort ((void *) st->sorted_projectiles,
225 sizeof(*st->sorted_projectiles),
226 projectile_pixel_sorter);
231 pyro_draw (Display *dpy, Window window, void *closure)
233 struct state *st = (struct state *) closure;
234 XWindowAttributes xgwa;
239 for (i = 0; i < st->how_many; i++)
241 struct projectile *p = st->sorted_projectiles [i];
242 int old_x, old_y, old_size;
244 if (p->dead) continue;
247 old_size = p->size >> 10;
248 size = (p->size += p->decay) >> 10;
249 x = (p->x += p->dx) >> 10;
250 y = (p->y += p->dy) >> 10;
251 p->dy += (p->size >> 6);
252 if (p->primary) p->fuse--;
258 XDrawPoint (st->dpy, st->window, st->erase_gc, old_x, old_y);
260 XFillRectangle (st->dpy, st->window, st->erase_gc, old_x, old_y,
264 if ((p->primary ? (p->fuse > 0) : (p->size > 0)) &&
265 x < st->real_draw_xlim &&
266 y < st->real_draw_ylim &&
274 if (mono_p || p->primary)
275 pixel = st->default_fg_pixel;
277 pixel = p->color.pixel;
279 if (pixel != st->last_pixel)
281 st->last_pixel = pixel;
282 XSetForeground (st->dpy, st->draw_gc, pixel);
286 XDrawPoint (st->dpy, st->window, st->draw_gc, x, y);
288 XFillRectangle (st->dpy, st->window, st->draw_gc, x, y, size, size);
290 XFillArc (st->dpy, st->window, st->draw_gc, x, y, size, size, 0, 360*64);
295 free_projectile (st, p);
297 if (p->color.pixel != WhitePixel (st->dpy, DefaultScreen (st->dpy)))
298 XFreeColors (st->dpy, st->cmap, &p->color.pixel, 1, 0);
301 if (p->primary && p->fuse <= 0)
303 int j = (random () % st->scatter) + (st->scatter/2);
310 if ((random () % st->frequency) == 0)
312 XGetWindowAttributes (st->dpy, st->window, &xgwa);
313 st->real_draw_xlim = xgwa.width;
314 st->real_draw_ylim = xgwa.height;
315 st->draw_xlim = st->real_draw_xlim * 1000;
316 st->draw_ylim = st->real_draw_ylim * 1000;
317 launch (st, st->draw_xlim, st->draw_ylim, g);
321 /* being sorted lets us avoid changing the GC's foreground color as often. */
323 sort_by_pixel (st, st->how_many);
329 pyro_reshape (Display *dpy, Window window, void *closure,
330 unsigned int w, unsigned int h)
335 pyro_event (Display *dpy, Window window, void *closure, XEvent *event)
341 pyro_free (Display *dpy, Window window, void *closure)
343 struct state *st = (struct state *) closure;
349 static const char *pyro_defaults [] = {
350 ".background: black",
351 ".foreground: white",
356 "*geometry: 800x500",
360 static XrmOptionDescRec pyro_options [] = {
361 { "-delay", ".delay", XrmoptionSepArg, 0 },
362 { "-count", ".count", XrmoptionSepArg, 0 },
363 { "-frequency", ".frequency", XrmoptionSepArg, 0 },
364 { "-scatter", ".scatter", XrmoptionSepArg, 0 },
368 XSCREENSAVER_MODULE ("Pyro", pyro)