--- /dev/null
+/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@lucid.com>
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation. No representations are made about the suitability of this
+ * software for any purpose. It is provided "as is" without express or
+ * implied warranty.
+ */
+
+/* Draw some fireworks. Inspired from TI Explorer Lisp code by
+ John S. Pezaris <pz@hx.lcs.mit.edu>
+ */
+
+#include "screenhack.h"
+
+struct projectile {
+ int x, y; /* position */
+ int dx, dy; /* velocity */
+ int decay;
+ int size;
+ int fuse;
+ Bool primary;
+ Bool dead;
+ XColor color;
+ struct projectile *next_free;
+};
+
+static struct projectile *projectiles, *free_projectiles;
+
+static struct projectile *
+get_projectile ()
+{
+ struct projectile *p;
+ if (free_projectiles)
+ {
+ p = free_projectiles;
+ free_projectiles = p->next_free;
+ p->next_free = 0;
+ p->dead = False;
+ return p;
+ }
+ else
+ return 0;
+}
+
+static void
+free_projectile (p)
+ struct projectile *p;
+{
+ p->next_free = free_projectiles;
+ free_projectiles = p;
+ p->dead = True;
+}
+
+static void
+launch (xlim, ylim, g, dpy, cmap)
+ int xlim, ylim, g;
+ Display *dpy;
+ Colormap cmap;
+{
+ struct projectile *p = get_projectile ();
+ int x, dx, xxx;
+ if (! p) return;
+
+ do {
+ x = (random () % xlim);
+ dx = 30000 - (random () % 60000);
+ xxx = x + (dx * 200);
+ } while (xxx <= 0 || xxx >= xlim);
+
+ p->x = x;
+ p->y = ylim;
+ p->dx = dx;
+ p->size = 8000;
+ p->decay = 0;
+ p->dy = (random () % 4000) - 13000;
+ p->fuse = ((((random () % 500) + 500) * abs (p->dy / g)) / 1000);
+ p->primary = True;
+
+ if (! mono_p)
+ {
+ hsv_to_rgb (random () % 360, 1.0, 1.0,
+ &p->color.red, &p->color.green, &p->color.blue);
+ p->color.flags = DoRed | DoGreen | DoBlue;
+ if (!XAllocColor (dpy, cmap, &p->color))
+ {
+ p->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
+ p->color.red = p->color.green = p->color.blue = 0;
+ }
+ }
+}
+
+static struct projectile *
+shrapnel (parent, dpy, cmap)
+ struct projectile *parent;
+ Display *dpy;
+ Colormap cmap;
+{
+ struct projectile *p = get_projectile ();
+ if (! p) return 0;
+ p->x = parent->x;
+ p->y = parent->y;
+ p->dx = (random () % 5000) - 2500 + parent->dx;
+ p->dy = (random () % 5000) - 2500 + parent->dy;
+ p->decay = (random () % 50) - 60;
+ p->size = 6000;
+ p->fuse = 0;
+ p->primary = False;
+
+ p->color = parent->color;
+ if (! mono_p)
+ XAllocColor (dpy, cmap, &p->color); /* dup the lock */
+
+ return p;
+}
+
+static GC draw_gc, erase_gc;
+static unsigned int default_fg_pixel;
+
+static int how_many, frequency, scatter;
+
+static Colormap
+init_pyro (dpy, window)
+ Display *dpy;
+ Window window;
+{
+ int i;
+ Colormap cmap;
+ XGCValues gcv;
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, window, &xgwa);
+ cmap = xgwa.colormap;
+ how_many = get_integer_resource ("count", "Integer");
+ frequency = get_integer_resource ("frequency", "Integer");
+ scatter = get_integer_resource ("scatter", "Integer");
+ if (how_many <= 0) how_many = 100;
+ if (frequency <= 0) frequency = 30;
+ if (scatter <= 0) scatter = 20;
+ projectiles = 0;
+ free_projectiles = 0;
+ projectiles = (struct projectile *)
+ calloc (how_many, sizeof (struct projectile));
+ for (i = 0; i < how_many; i++)
+ free_projectile (&projectiles [i]);
+ gcv.foreground = default_fg_pixel =
+ get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+ draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+ gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
+ erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
+ XClearWindow (dpy, window);
+ return cmap;
+}
+
+static void
+pyro (dpy, window, cmap)
+ Display *dpy;
+ Window window;
+ Colormap cmap;
+{
+ XWindowAttributes xgwa;
+ static int xlim, ylim, real_xlim, real_ylim;
+ int g = 100;
+ int i;
+
+ if ((random () % frequency) == 0)
+ {
+ XGetWindowAttributes (dpy, window, &xgwa);
+ real_xlim = xgwa.width;
+ real_ylim = xgwa.height;
+ xlim = real_xlim * 1000;
+ ylim = real_ylim * 1000;
+ launch (xlim, ylim, g, dpy, cmap);
+ }
+
+ XSync (dpy, True);
+ usleep (10000);
+
+ for (i = 0; i < how_many; i++)
+ {
+ struct projectile *p = &projectiles [i];
+ int old_x, old_y, old_size;
+ int size, x, y;
+ if (p->dead) continue;
+ old_x = p->x >> 10;
+ old_y = p->y >> 10;
+ old_size = p->size >> 10;
+ size = (p->size += p->decay) >> 10;
+ x = (p->x += p->dx) >> 10;
+ y = (p->y += p->dy) >> 10;
+ p->dy += (p->size >> 6);
+ if (p->primary) p->fuse--;
+
+ /* erase old one */
+ XFillRectangle (dpy, window, erase_gc, old_x, old_y,
+ old_size, old_size);
+
+ if ((p->primary ? (p->fuse > 0) : (p->size > 0)) &&
+ x < real_xlim &&
+ y < real_ylim &&
+ x > 0 &&
+ y > 0)
+ {
+ if (mono_p || p->primary)
+ XSetForeground (dpy, draw_gc, default_fg_pixel);
+ else
+ XSetForeground (dpy, draw_gc, p->color.pixel);
+
+ if (p->primary)
+ XFillArc (dpy, window, draw_gc, x, y, size, size, 0, 360*64);
+ else
+ XFillRectangle (dpy, window, draw_gc, x, y, size, size);
+ }
+ else
+ {
+ free_projectile (p);
+ if (! mono_p) XFreeColors (dpy, cmap, &p->color.pixel, 1, 0);
+ }
+
+ if (p->primary && p->fuse <= 0)
+ {
+ int i = (random () % scatter) + (scatter/2);
+ while (i--)
+ shrapnel (p, dpy, cmap);
+ }
+ }
+}
+
+\f
+char *progclass = "Pyro";
+
+char *defaults [] = {
+ "*background: black",
+ "*foreground: white",
+ "*count: 100",
+ "*frequency: 30",
+ "*scatter: 20",
+ "*geometry: 800x500",
+ 0
+};
+
+XrmOptionDescRec options [] = {
+ { "-count", ".count", XrmoptionSepArg, 0 },
+ { "-frequency", ".frequency", XrmoptionSepArg, 0 },
+ { "-scatter", ".scatter", XrmoptionSepArg, 0 }
+};
+int options_size = (sizeof (options) / sizeof (options[0]));
+
+void
+screenhack (dpy, window)
+ Display *dpy;
+ Window window;
+{
+ Colormap cmap = init_pyro (dpy, window);
+ while (1)
+ pyro (dpy, window, cmap);
+}