source: trunk/third/xscreensaver/hacks/pyro.c @ 20148

Revision 20148, 8.6 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* xscreensaver, Copyright (c) 1992, 1994, 1996, 1998, 2001
2 *  Jamie Zawinski <jwz@jwz.org>
3 *
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
10 * implied warranty.
11 */
12
13/* Draw some fireworks.  Inspired from TI Explorer Lisp code by
14   John S. Pezaris <pz@hx.lcs.mit.edu>
15 */
16
17#include <math.h>
18#include "screenhack.h"
19
20struct projectile {
21  int x, y;     /* position */
22  int dx, dy;   /* velocity */
23  int decay;
24  int size;
25  int fuse;
26  Bool primary;
27  Bool dead;
28  XColor color;
29  struct projectile *next_free;
30};
31
32static struct projectile *projectiles, *free_projectiles;
33static struct projectile **sorted_projectiles;
34
35
36/* Slightly whacked, for better explosions
37 */
38#define PI_2000 6284
39
40static int sin_cache[PI_2000];
41static int cos_cache[PI_2000];
42
43static void
44cache(void)
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++)
49    {
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);
57    }
58}
59
60
61static struct projectile *
62get_projectile (void)
63{
64  struct projectile *p;
65  if (free_projectiles)
66    {
67      p = free_projectiles;
68      free_projectiles = p->next_free;
69      p->next_free = 0;
70      p->dead = False;
71      return p;
72    }
73  else
74    return 0;
75}
76
77static void
78free_projectile (struct projectile *p)
79{
80  p->next_free = free_projectiles;
81  free_projectiles = p;
82  p->dead = True;
83}
84
85static void
86launch (int xlim, int ylim, int g,
87        Display *dpy, Colormap cmap)
88{
89  struct projectile *p = get_projectile ();
90  int x, dx, xxx;
91  if (! p) return;
92
93  do {
94    x = (random () % xlim);
95    dx = 30000 - (random () % 60000);
96    xxx = x + (dx * 200);
97  } while (xxx <= 0 || xxx >= xlim);
98
99  p->x = x;
100  p->y = ylim;
101  p->dx = dx;
102  p->size = 8000;
103  p->decay = 0;
104  p->dy = (random () % 4000) - 13000;
105  p->fuse = ((((random () % 500) + 500) * abs (p->dy / g)) / 1000);
106  p->primary = True;
107
108  /* cope with small windows -- those constants assume big windows. */
109  {
110    int div = 1000000 / ylim;
111    if (div > 1)
112      p->fuse /= div;
113  }
114
115  if (! mono_p)
116    {
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))
121        {
122          p->color.pixel = WhitePixel (dpy, DefaultScreen (dpy));
123          p->color.red = p->color.green = p->color.blue = 0xFFFF;
124        }
125    }
126}
127
128static struct projectile *
129shrapnel (struct projectile *parent, Display *dpy, Colormap cmap)
130{
131  struct projectile *p = get_projectile ();
132  int v;
133  if (! p) return 0;
134  p->x = parent->x;
135  p->y = parent->y;
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;
141  p->fuse = 0;
142  p->primary = False;
143
144  p->color = parent->color;
145  if (! mono_p)
146    XAllocColor (dpy, cmap, &p->color); /* dup the lock */
147 
148  return p;
149}
150
151static GC draw_gc, erase_gc;
152static unsigned int default_fg_pixel;
153
154static int how_many, frequency, scatter;
155
156static Colormap
157init_pyro (Display *dpy, Window window)
158{
159  int i;
160  Colormap cmap;
161  XGCValues gcv;
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;
171  projectiles = 0;
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);
187  cache(); 
188  return cmap;
189}
190
191
192static int
193projectile_pixel_sorter (const void *a, const void *b)
194{
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;
199  else return 1;
200}
201
202static void
203sort_by_pixel (int length)
204{
205  qsort ((void *) sorted_projectiles,
206         length,
207         sizeof(*sorted_projectiles),
208         projectile_pixel_sorter);
209}
210
211
212static void
213pyro (Display *dpy, Window window, Colormap cmap)
214{
215  XWindowAttributes xgwa;
216  static int xlim, ylim, real_xlim, real_ylim;
217  int g = 100;
218  int resort = 0;
219  int i;
220 
221  for (i = 0; i < how_many; i++)
222    {
223      struct projectile *p = sorted_projectiles [i];
224      int old_x, old_y, old_size;
225      int size, x, y;
226      if (p->dead) continue;
227      old_x = p->x >> 10;
228      old_y = p->y >> 10;
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--;
235
236      /* erase old one */
237      if (old_size > 0)
238        {
239          if (old_size == 1)
240            XDrawPoint (dpy, window, erase_gc, old_x, old_y);
241          else
242            XFillRectangle (dpy, window, erase_gc, old_x, old_y,
243                            old_size, old_size);
244        }
245
246      if ((p->primary ? (p->fuse > 0) : (p->size > 0)) &&
247          x < real_xlim &&
248          y < real_ylim &&
249          x > 0 &&
250          y > 0)
251        {
252          if (size > 0)
253            {
254              static unsigned long last_pixel = ~0;
255              unsigned long pixel;
256
257              if (mono_p || p->primary)
258                pixel = default_fg_pixel;
259              else
260                pixel = p->color.pixel;
261
262              if (pixel != last_pixel)
263                {
264                  last_pixel = pixel;
265                  XSetForeground (dpy, draw_gc, pixel);
266                }
267
268              if (size == 1)
269                XDrawPoint (dpy, window, draw_gc, x, y);
270              else if (size < 4)
271                XFillRectangle (dpy, window, draw_gc, x, y, size, size);
272              else
273                XFillArc (dpy, window, draw_gc, x, y, size, size, 0, 360*64);
274            }
275        }
276      else
277        {
278          free_projectile (p);
279          if (! mono_p)
280            if (p->color.pixel != WhitePixel (dpy, DefaultScreen (dpy)))
281              XFreeColors (dpy, cmap, &p->color.pixel, 1, 0);
282        }
283
284      if (p->primary && p->fuse <= 0)
285        {
286          int j = (random () % scatter) + (scatter/2);
287          while (j--)
288            shrapnel (p, dpy, cmap);
289          resort = 1;
290        }
291    }
292
293  if ((random () % frequency) == 0)
294    {
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);
301      resort = 1;
302    }
303
304  /* being sorted lets us avoid changing the GC's foreground color as often. */
305  if (resort)
306    sort_by_pixel (how_many);
307}
308
309
310char *progclass = "Pyro";
311
312char *defaults [] = {
313  ".background: black",
314  ".foreground: white",
315  "*count:      600",
316  "*delay:      5000",
317  "*frequency:  30",
318  "*scatter:    100",
319  "*geometry:   800x500",
320  0
321};
322
323XrmOptionDescRec options [] = {
324  { "-delay",           ".delay",       XrmoptionSepArg, 0 },
325  { "-count",           ".count",       XrmoptionSepArg, 0 },
326  { "-frequency",       ".frequency",   XrmoptionSepArg, 0 },
327  { "-scatter",         ".scatter",     XrmoptionSepArg, 0 },
328  { 0, 0, 0, 0 }
329};
330
331void
332screenhack (Display *dpy, Window window)
333{
334  Colormap cmap = init_pyro (dpy, window);
335  int delay = get_integer_resource ("delay", "Integer");
336
337  while (1)
338    {
339      pyro (dpy, window, cmap);
340
341      XSync (dpy, False);
342      screenhack_handle_events (dpy);
343      usleep (delay);
344    }
345}
Note: See TracBrowser for help on using the repository browser.