X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fpyro.c;h=442ea7f0da67ddb5a6a416b7793c088767bf5e1a;hb=39809ded547bdbb08207d3e514950425215b4410;hp=f7df260bfd11c7d8ed06c5e6e732863ecd82c8f8;hpb=6edc84f12f15860a71430c45e8392a5e4ef8203c;p=xscreensaver diff --git a/hacks/pyro.c b/hacks/pyro.c index f7df260b..442ea7f0 100644 --- a/hacks/pyro.c +++ b/hacks/pyro.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1992, 1994 Jamie Zawinski +/* xscreensaver, Copyright (c) 1992-2008 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 +13,7 @@ John S. Pezaris */ +#include #include "screenhack.h" struct projectile { @@ -27,16 +28,61 @@ struct projectile { struct projectile *next_free; }; -static struct projectile *projectiles, *free_projectiles; +#define PI_2000 6284 + + +struct state { + Display *dpy; + Window window; + + struct projectile *projectiles, *free_projectiles; + struct projectile **sorted_projectiles; + + GC draw_gc, erase_gc; + unsigned int default_fg_pixel; + Colormap cmap; + + int how_many, frequency, scatter, delay; + + int sin_cache[PI_2000]; + int cos_cache[PI_2000]; + + int draw_xlim, draw_ylim, real_draw_xlim, real_draw_ylim; + + unsigned long last_pixel; +}; + + + +/* Slightly whacked, for better explosions + */ + +static void +cache(struct state *st) +{ /*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; icos_cache[i]=(int) (cos(((double)i)/1000.0)*dA*2500.0); + st->sin_cache[i]=(int) (sin(((double)i)/1000.0)*dA*2500.0); + } +} + static struct projectile * -get_projectile () +get_projectile (struct state *st) { struct projectile *p; - if (free_projectiles) + if (st->free_projectiles) { - p = free_projectiles; - free_projectiles = p->next_free; + p = st->free_projectiles; + st->free_projectiles = p->next_free; p->next_free = 0; p->dead = False; return p; @@ -46,21 +92,18 @@ get_projectile () } static void -free_projectile (p) - struct projectile *p; +free_projectile (struct state *st, struct projectile *p) { - p->next_free = free_projectiles; - free_projectiles = p; + p->next_free = st->free_projectiles; + st->free_projectiles = p; p->dead = True; } static void -launch (xlim, ylim, g, dpy, cmap) - int xlim, ylim, g; - Display *dpy; - Colormap cmap; +launch (struct state *st, + int xlim, int ylim, int g) { - struct projectile *p = get_projectile (); + struct projectile *p = get_projectile (st); int x, dx, xxx; if (! p) return; @@ -79,31 +122,37 @@ 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 dd = 1000000 / ylim; + if (dd > 1) + p->fuse /= dd; + } + 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)) + if (!XAllocColor (st->dpy, st->cmap, &p->color)) { - p->color.pixel = WhitePixel (dpy, DefaultScreen (dpy)); - p->color.red = p->color.green = p->color.blue = 0; + p->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); + 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 state *st, struct projectile *parent) { - struct projectile *p = get_projectile (); + struct projectile *p = get_projectile (st); + 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 =(st->sin_cache[v]) + parent->dx; + p->dy =(st->cos_cache[v]) + parent->dy; p->decay = (random () % 50) - 60; p->size = (parent->size * 2) / 3; p->fuse = 0; @@ -111,75 +160,84 @@ shrapnel (parent, dpy, cmap) p->color = parent->color; if (! mono_p) - XAllocColor (dpy, cmap, &p->color); /* dup the lock */ + XAllocColor (st->dpy, st->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; +static void * +pyro_init (Display *dpy, Window window) { + struct state *st = (struct state *) calloc (1, sizeof(*st)); 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; + st->dpy = dpy; + st->window = window; + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->last_pixel = ~0; + st->cmap = xgwa.colormap; + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->how_many = get_integer_resource (st->dpy, "count", "Integer"); + st->frequency = get_integer_resource (st->dpy, "frequency", "Integer"); + st->scatter = get_integer_resource (st->dpy, "scatter", "Integer"); + if (st->how_many <= 0) st->how_many = 100; + if (st->frequency <= 0) st->frequency = 30; + if (st->scatter <= 0) st->scatter = 20; + st->projectiles = 0; + st->free_projectiles = 0; + st->projectiles = (struct projectile *) + calloc (st->how_many, sizeof (*st->projectiles)); + st->sorted_projectiles = (struct projectile **) + calloc (st->how_many, sizeof (*st->sorted_projectiles)); + for (i = 0; i < st->how_many; i++) + free_projectile (st, &st->projectiles [i]); + for (i = 0; i < st->how_many; i++) + st->sorted_projectiles[i] = &st->projectiles[i]; + gcv.foreground = st->default_fg_pixel = + get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground"); + st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "background", "Background"); + st->erase_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv); + XClearWindow (st->dpy, st->window); + cache(st); + + return st; +} + + +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 -pyro (dpy, window, cmap) - Display *dpy; - Window window; - Colormap cmap; +sort_by_pixel (struct state *st, int length) { + qsort ((void *) st->sorted_projectiles, + length, + sizeof(*st->sorted_projectiles), + projectile_pixel_sorter); +} + + +static unsigned long +pyro_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; 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++) + + for (i = 0; i < st->how_many; i++) { - struct projectile *p = &projectiles [i]; + struct projectile *p = st->sorted_projectiles [i]; int old_x, old_y, old_size; int size, x, y; if (p->dead) continue; @@ -193,66 +251,118 @@ 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 (st->dpy, st->window, st->erase_gc, old_x, old_y); + else + XFillRectangle (st->dpy, st->window, st->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 < st->real_draw_xlim && + y < st->real_draw_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)*/ (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) + { + unsigned long pixel; + + if (mono_p || p->primary) + pixel = st->default_fg_pixel; + else + pixel = p->color.pixel; + + if (pixel != st->last_pixel) + { + st->last_pixel = pixel; + XSetForeground (st->dpy, st->draw_gc, pixel); + } + + if (size == 1) + XDrawPoint (st->dpy, st->window, st->draw_gc, x, y); + else if (size < 4) + XFillRectangle (st->dpy, st->window, st->draw_gc, x, y, size, size); + else + XFillArc (st->dpy, st->window, st->draw_gc, x, y, size, size, 0, 360*64); + } + } else { - free_projectile (p); - if (! mono_p) XFreeColors (dpy, cmap, &p->color.pixel, 1, 0); + free_projectile (st, p); + if (! mono_p) + if (p->color.pixel != WhitePixel (st->dpy, DefaultScreen (st->dpy))) + XFreeColors (st->dpy, st->cmap, &p->color.pixel, 1, 0); } if (p->primary && p->fuse <= 0) { - int i = (random () % scatter) + (scatter/2); - while (i--) - shrapnel (p, dpy, cmap); + int j = (random () % st->scatter) + (st->scatter/2); + while (j--) + shrapnel (st, p); + resort = 1; } } + + if ((random () % st->frequency) == 0) + { + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->real_draw_xlim = xgwa.width; + st->real_draw_ylim = xgwa.height; + st->draw_xlim = st->real_draw_xlim * 1000; + st->draw_ylim = st->real_draw_ylim * 1000; + launch (st, st->draw_xlim, st->draw_ylim, g); + resort = 1; + } + + /* being sorted lets us avoid changing the GC's foreground color as often. */ + if (resort) + sort_by_pixel (st, st->how_many); + + return st->delay; +} + +static void +pyro_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ +} + +static Bool +pyro_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +pyro_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); } -char *progclass = "Pyro"; -char *defaults [] = { - "Pyro.background: black", /* to placate SGI */ - "Pyro.foreground: white", - "*count: 100", +static const char *pyro_defaults [] = { + ".lowrez: true", + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*count: 600", + "*delay: 10000", "*frequency: 30", - "*scatter: 20", - "*geometry: 800x500", + "*scatter: 100", 0 }; -XrmOptionDescRec options [] = { +static XrmOptionDescRec pyro_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; -{ - Colormap cmap = init_pyro (dpy, window); - while (1) - pyro (dpy, window, cmap); -} +XSCREENSAVER_MODULE ("Pyro", pyro)