X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fpyro.c;h=c2297636dda26fabfc2fc96600013178a340a41d;hb=8eb2873d7054e705c4e83f22d18c40946a9e2529;hp=f7df260bfd11c7d8ed06c5e6e732863ecd82c8f8;hpb=6edc84f12f15860a71430c45e8392a5e4ef8203c;p=xscreensaver diff --git a/hacks/pyro.c b/hacks/pyro.c index f7df260b..c2297636 100644 --- a/hacks/pyro.c +++ b/hacks/pyro.c @@ -1,4 +1,5 @@ -/* xscreensaver, Copyright (c) 1992, 1994 Jamie Zawinski +/* xscreensaver, Copyright (c) 1992, 1994, 1996, 1998, 2001 + * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -13,6 +14,7 @@ John S. Pezaris */ +#include #include "screenhack.h" struct projectile { @@ -28,9 +30,36 @@ struct projectile { }; static struct projectile *projectiles, *free_projectiles; +static struct projectile **sorted_projectiles; + + +/* Slightly whacked, for better explosions + */ +#define PI_2000 6284 + +static int sin_cache[PI_2000]; +static int cos_cache[PI_2000]; + +static void +cache(void) +{ /*needs to be run once. Could easily be */ + int i; /*reimplemented to run and cache at compile-time,*/ + double dA; /*saving on init_pyro time */ + for (i=0; inext_free = free_projectiles; free_projectiles = p; @@ -55,10 +83,8 @@ free_projectile (p) } static void -launch (xlim, ylim, g, dpy, cmap) - int xlim, ylim, g; - Display *dpy; - Colormap cmap; +launch (int xlim, int ylim, int g, + Display *dpy, Colormap cmap) { struct projectile *p = get_projectile (); int x, dx, xxx; @@ -79,6 +105,13 @@ launch (xlim, ylim, g, dpy, cmap) p->fuse = ((((random () % 500) + 500) * abs (p->dy / g)) / 1000); p->primary = True; + /* cope with small windows -- those constants assume big windows. */ + { + int div = 1000000 / ylim; + if (div > 1) + p->fuse /= div; + } + if (! mono_p) { hsv_to_rgb (random () % 360, 1.0, 1.0, @@ -87,23 +120,22 @@ launch (xlim, ylim, g, dpy, cmap) if (!XAllocColor (dpy, cmap, &p->color)) { p->color.pixel = WhitePixel (dpy, DefaultScreen (dpy)); - p->color.red = p->color.green = p->color.blue = 0; + p->color.red = p->color.green = p->color.blue = 0xFFFF; } } } static struct projectile * -shrapnel (parent, dpy, cmap) - struct projectile *parent; - Display *dpy; - Colormap cmap; +shrapnel (struct projectile *parent, Display *dpy, Colormap cmap) { struct projectile *p = get_projectile (); + int v; 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; + v=random () % PI_2000; + p->dx =(sin_cache[v]) + parent->dx; + p->dy =(cos_cache[v]) + parent->dx; p->decay = (random () % 50) - 60; p->size = (parent->size * 2) / 3; p->fuse = 0; @@ -122,9 +154,7 @@ static unsigned int default_fg_pixel; static int how_many, frequency, scatter; static Colormap -init_pyro (dpy, window) - Display *dpy; - Window window; +init_pyro (Display *dpy, Window window) { int i; Colormap cmap; @@ -141,45 +171,56 @@ init_pyro (dpy, window) projectiles = 0; free_projectiles = 0; projectiles = (struct projectile *) - calloc (how_many, sizeof (struct projectile)); + calloc (how_many, sizeof (*projectiles)); + sorted_projectiles = (struct projectile **) + calloc (how_many, sizeof (*sorted_projectiles)); for (i = 0; i < how_many; i++) free_projectile (&projectiles [i]); + for (i = 0; i < how_many; i++) + sorted_projectiles[i] = &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); + cache(); return cmap; } + +static int +projectile_pixel_sorter (const void *a, const void *b) +{ + struct projectile *pa = *(struct projectile **) a; + struct projectile *pb = *(struct projectile **) b; + if (pa->color.pixel == pb->color.pixel) return 0; + else if (pa->color.pixel < pb->color.pixel) return -1; + else return 1; +} + +static void +sort_by_pixel (int length) +{ + qsort ((void *) sorted_projectiles, + length, + sizeof(*sorted_projectiles), + projectile_pixel_sorter); +} + + static void -pyro (dpy, window, cmap) - Display *dpy; - Window window; - Colormap cmap; +pyro (Display *dpy, Window window, Colormap cmap) { XWindowAttributes xgwa; static int xlim, ylim, real_xlim, real_ylim; int g = 100; + int resort = 0; 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]; + struct projectile *p = sorted_projectiles [i]; int old_x, old_y, old_size; int size, x, y; if (p->dead) continue; @@ -193,8 +234,14 @@ pyro (dpy, window, cmap) if (p->primary) p->fuse--; /* erase old one */ - XFillRectangle (dpy, window, erase_gc, old_x, old_y, - old_size, old_size); + if (old_size > 0) + { + if (old_size == 1) + XDrawPoint (dpy, window, erase_gc, old_x, old_y); + else + 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 && @@ -202,57 +249,97 @@ pyro (dpy, window, cmap) 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)*/ (size > 2) - XFillArc (dpy, window, draw_gc, x, y, size, size, 0, 360*64); - else - XFillRectangle (dpy, window, draw_gc, x, y, size, size); - } + if (size > 0) + { + static unsigned long last_pixel = ~0; + unsigned long pixel; + + if (mono_p || p->primary) + pixel = default_fg_pixel; + else + pixel = p->color.pixel; + + if (pixel != last_pixel) + { + last_pixel = pixel; + XSetForeground (dpy, draw_gc, pixel); + } + + if (size == 1) + XDrawPoint (dpy, window, draw_gc, x, y); + else if (size < 4) + XFillRectangle (dpy, window, draw_gc, x, y, size, size); + else + XFillArc (dpy, window, draw_gc, x, y, size, size, 0, 360*64); + } + } else { free_projectile (p); - if (! mono_p) XFreeColors (dpy, cmap, &p->color.pixel, 1, 0); + if (! mono_p) + if (p->color.pixel != WhitePixel (dpy, DefaultScreen (dpy))) + XFreeColors (dpy, cmap, &p->color.pixel, 1, 0); } if (p->primary && p->fuse <= 0) { - int i = (random () % scatter) + (scatter/2); - while (i--) + int j = (random () % scatter) + (scatter/2); + while (j--) shrapnel (p, dpy, cmap); + resort = 1; } } + + 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); + resort = 1; + } + + /* being sorted lets us avoid changing the GC's foreground color as often. */ + if (resort) + sort_by_pixel (how_many); } char *progclass = "Pyro"; char *defaults [] = { - "Pyro.background: black", /* to placate SGI */ - "Pyro.foreground: white", - "*count: 100", + ".background: black", + ".foreground: white", + "*count: 600", + "*delay: 5000", "*frequency: 30", - "*scatter: 20", + "*scatter: 100", "*geometry: 800x500", 0 }; XrmOptionDescRec options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, { "-count", ".count", XrmoptionSepArg, 0 }, { "-frequency", ".frequency", XrmoptionSepArg, 0 }, - { "-scatter", ".scatter", XrmoptionSepArg, 0 } + { "-scatter", ".scatter", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } }; -int options_size = (sizeof (options) / sizeof (options[0])); void -screenhack (dpy, window) - Display *dpy; - Window window; +screenhack (Display *dpy, Window window) { Colormap cmap = init_pyro (dpy, window); + int delay = get_integer_resource ("delay", "Integer"); + while (1) - pyro (dpy, window, cmap); + { + pyro (dpy, window, cmap); + + XSync (dpy, False); + screenhack_handle_events (dpy); + usleep (delay); + } }