ftp://ftp.uni-heidelberg.de/pub/X11/contrib/applications/xscreensaver-1.27.tar.Z
[xscreensaver] / hacks / pyro.c
1 /* xscreensaver, Copyright (c) 1992, 1994 Jamie Zawinski <jwz@netscape.com>
2  *
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 
9  * implied warranty.
10  */
11
12 /* Draw some fireworks.  Inspired from TI Explorer Lisp code by 
13    John S. Pezaris <pz@hx.lcs.mit.edu>
14  */
15
16 #include "screenhack.h"
17
18 struct projectile {
19   int x, y;     /* position */
20   int dx, dy;   /* velocity */
21   int decay;
22   int size;
23   int fuse;
24   Bool primary;
25   Bool dead;
26   XColor color;
27   struct projectile *next_free;
28 };
29
30 static struct projectile *projectiles, *free_projectiles;
31
32 static struct projectile *
33 get_projectile ()
34 {
35   struct projectile *p;
36   if (free_projectiles)
37     {
38       p = free_projectiles;
39       free_projectiles = p->next_free;
40       p->next_free = 0;
41       p->dead = False;
42       return p;
43     }
44   else
45     return 0;
46 }
47
48 static void
49 free_projectile (p)
50      struct projectile *p;
51 {
52   p->next_free = free_projectiles;
53   free_projectiles = p;
54   p->dead = True;
55 }
56
57 static void
58 launch (xlim, ylim, g, dpy, cmap)
59      int xlim, ylim, g;
60      Display *dpy;
61      Colormap cmap;
62 {
63   struct projectile *p = get_projectile ();
64   int x, dx, xxx;
65   if (! p) return;
66
67   do {
68     x = (random () % xlim);
69     dx = 30000 - (random () % 60000);
70     xxx = x + (dx * 200);
71   } while (xxx <= 0 || xxx >= xlim);
72
73   p->x = x;
74   p->y = ylim;
75   p->dx = dx;
76   p->size = 8000;
77   p->decay = 0;
78   p->dy = (random () % 4000) - 13000;
79   p->fuse = ((((random () % 500) + 500) * abs (p->dy / g)) / 1000);
80   p->primary = True;
81
82   if (! mono_p)
83     {
84       hsv_to_rgb (random () % 360, 1.0, 1.0,
85                   &p->color.red, &p->color.green, &p->color.blue);
86       p->color.flags = DoRed | DoGreen | DoBlue;
87       if (!XAllocColor (dpy, cmap, &p->color))
88         {
89           p->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
90           p->color.red = p->color.green = p->color.blue = 0;
91         }
92     }
93 }
94
95 static struct projectile *
96 shrapnel (parent, dpy, cmap)
97      struct projectile *parent;
98      Display *dpy;
99      Colormap cmap;
100 {
101   struct projectile *p = get_projectile ();
102   if (! p) return 0;
103   p->x = parent->x;
104   p->y = parent->y;
105   p->dx = (random () % 5000) - 2500 + parent->dx;
106   p->dy = (random () % 5000) - 2500 + parent->dy;
107   p->decay = (random () % 50) - 60;
108   p->size = (parent->size * 2) / 3;
109   p->fuse = 0;
110   p->primary = False;
111
112   p->color = parent->color;
113   if (! mono_p)
114     XAllocColor (dpy, cmap, &p->color); /* dup the lock */
115   
116   return p;
117 }
118
119 static GC draw_gc, erase_gc;
120 static unsigned int default_fg_pixel;
121
122 static int how_many, frequency, scatter;
123
124 static Colormap
125 init_pyro (dpy, window)
126      Display *dpy;
127      Window window;
128 {
129   int i;
130   Colormap cmap;
131   XGCValues gcv;
132   XWindowAttributes xgwa;
133   XGetWindowAttributes (dpy, window, &xgwa);
134   cmap = xgwa.colormap;
135   how_many = get_integer_resource ("count", "Integer");
136   frequency = get_integer_resource ("frequency", "Integer");
137   scatter = get_integer_resource ("scatter", "Integer");
138   if (how_many <= 0) how_many = 100;
139   if (frequency <= 0) frequency = 30;
140   if (scatter <= 0) scatter = 20;
141   projectiles = 0;
142   free_projectiles = 0;
143   projectiles = (struct projectile *)
144     calloc (how_many, sizeof (struct projectile));
145   for (i = 0; i < how_many; i++)
146     free_projectile (&projectiles [i]);
147   gcv.foreground = default_fg_pixel =
148     get_pixel_resource ("foreground", "Foreground", dpy, cmap);
149   draw_gc = XCreateGC (dpy, window, GCForeground, &gcv);
150   gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap);
151   erase_gc = XCreateGC (dpy, window, GCForeground, &gcv);
152   XClearWindow (dpy, window);
153   return cmap;
154 }
155
156 static void
157 pyro (dpy, window, cmap)
158      Display *dpy;
159      Window window;
160      Colormap cmap;
161 {
162   XWindowAttributes xgwa;
163   static int xlim, ylim, real_xlim, real_ylim;
164   int g = 100;
165   int i;
166
167   if ((random () % frequency) == 0)
168     {
169       XGetWindowAttributes (dpy, window, &xgwa);
170       real_xlim = xgwa.width;
171       real_ylim = xgwa.height;
172       xlim = real_xlim * 1000;
173       ylim = real_ylim * 1000;
174       launch (xlim, ylim, g, dpy, cmap);
175     }
176
177   XSync (dpy, True);
178   usleep (10000);
179
180   for (i = 0; i < how_many; i++)
181     {
182       struct projectile *p = &projectiles [i];
183       int old_x, old_y, old_size;
184       int size, x, y;
185       if (p->dead) continue;
186       old_x = p->x >> 10;
187       old_y = p->y >> 10;
188       old_size = p->size >> 10;
189       size = (p->size += p->decay) >> 10;
190       x = (p->x += p->dx) >> 10;
191       y = (p->y += p->dy) >> 10;
192       p->dy += (p->size >> 6);
193       if (p->primary) p->fuse--;
194
195       /* erase old one */
196       XFillRectangle (dpy, window, erase_gc, old_x, old_y,
197                       old_size, old_size);
198
199       if ((p->primary ? (p->fuse > 0) : (p->size > 0)) &&
200           x < real_xlim &&
201           y < real_ylim &&
202           x > 0 &&
203           y > 0)
204         {
205           if (mono_p || p->primary)
206             XSetForeground (dpy, draw_gc, default_fg_pixel);
207           else
208             XSetForeground (dpy, draw_gc, p->color.pixel);
209
210           if /*(p->primary)*/ (size > 2)
211             XFillArc (dpy, window, draw_gc, x, y, size, size, 0, 360*64);
212           else
213             XFillRectangle (dpy, window, draw_gc, x, y, size, size);
214         }
215       else
216         {
217           free_projectile (p);
218           if (! mono_p) XFreeColors (dpy, cmap, &p->color.pixel, 1, 0);
219         }
220
221       if (p->primary && p->fuse <= 0)
222         {
223           int i = (random () % scatter) + (scatter/2);
224           while (i--)
225             shrapnel (p, dpy, cmap);
226         }
227     }
228 }
229
230 \f
231 char *progclass = "Pyro";
232
233 char *defaults [] = {
234   "Pyro.background:     black",         /* to placate SGI */
235   "Pyro.foreground:     white",
236   "*count:      100",
237   "*frequency:  30",
238   "*scatter:    20",
239   "*geometry:   800x500",
240   0
241 };
242
243 XrmOptionDescRec options [] = {
244   { "-count",           ".count",       XrmoptionSepArg, 0 },
245   { "-frequency",       ".frequency",   XrmoptionSepArg, 0 },
246   { "-scatter",         ".scatter",     XrmoptionSepArg, 0 }
247 };
248 int options_size = (sizeof (options) / sizeof (options[0]));
249
250 void
251 screenhack (dpy, window)
252      Display *dpy;
253      Window window;
254 {
255   Colormap cmap = init_pyro (dpy, window);
256   while (1)
257     pyro (dpy, window, cmap);
258 }