From d3a98cf6cbc3bd0b9efc570f58e8812c03931c18 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 16 Oct 2018 10:08:48 +0200 Subject: Original 5.40 --- hacks/pyro.c | 368 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 368 insertions(+) create mode 100644 hacks/pyro.c (limited to 'hacks/pyro.c') diff --git a/hacks/pyro.c b/hacks/pyro.c new file mode 100644 index 0000000..442ea7f --- /dev/null +++ b/hacks/pyro.c @@ -0,0 +1,368 @@ +/* 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 + * 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 + */ + +#include +#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; +}; + +#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 (struct state *st) +{ + struct projectile *p; + if (st->free_projectiles) + { + p = st->free_projectiles; + st->free_projectiles = p->next_free; + p->next_free = 0; + p->dead = False; + return p; + } + else + return 0; +} + +static void +free_projectile (struct state *st, struct projectile *p) +{ + p->next_free = st->free_projectiles; + st->free_projectiles = p; + p->dead = True; +} + +static void +launch (struct state *st, + int xlim, int ylim, int g) +{ + struct projectile *p = get_projectile (st); + 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; + + /* 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 (st->dpy, st->cmap, &p->color)) + { + p->color.pixel = WhitePixel (st->dpy, DefaultScreen (st->dpy)); + p->color.red = p->color.green = p->color.blue = 0xFFFF; + } + } +} + +static struct projectile * +shrapnel (struct state *st, struct projectile *parent) +{ + struct projectile *p = get_projectile (st); + int v; + if (! p) return 0; + p->x = parent->x; + p->y = parent->y; + 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; + p->primary = False; + + p->color = parent->color; + if (! mono_p) + XAllocColor (st->dpy, st->cmap, &p->color); /* dup the lock */ + + return p; +} + +static void * +pyro_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int i; + XGCValues gcv; + XWindowAttributes xgwa; + 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 +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; + int g = 100; + int resort = 0; + int i; + + for (i = 0; i < st->how_many; i++) + { + struct projectile *p = st->sorted_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 */ + 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 < st->real_draw_xlim && + y < st->real_draw_ylim && + x > 0 && + y > 0) + { + 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 (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 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); +} + + + +static const char *pyro_defaults [] = { + ".lowrez: true", + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*count: 600", + "*delay: 10000", + "*frequency: 30", + "*scatter: 100", + 0 +}; + +static XrmOptionDescRec pyro_options [] = { + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-count", ".count", XrmoptionSepArg, 0 }, + { "-frequency", ".frequency", XrmoptionSepArg, 0 }, + { "-scatter", ".scatter", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } +}; + +XSCREENSAVER_MODULE ("Pyro", pyro) -- cgit v1.2.3-55-g7522