X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fflame.c;h=01f16ababa6c235a7e66b03c2781d0992570d9f6;hb=50be9bb40dc60130c99ffa568e6677779904ff70;hp=370ab4d7bce8c7a66cef1ee399fbc3b225aa2886;hpb=0cac953ce8d5139c1a264b417951ee15a3176b51;p=xscreensaver diff --git a/hacks/flame.c b/hacks/flame.c index 370ab4d7..01f16aba 100644 --- a/hacks/flame.c +++ b/hacks/flame.c @@ -1,4 +1,4 @@ -/* xscreensaver, Copyright (c) 1993 Jamie Zawinski +/* xscreensaver, Copyright (c) 1993-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 @@ -10,7 +10,7 @@ */ /* This file was ported from xlock for use in xscreensaver (and standalone) - * by jwz on 18-Oct-93. Original copyright reads: + * by jwz on 18-Oct-93. (And again, 11-May-97.) Original copyright reads: * * static char sccsid[] = "@(#)flame.c 1.4 91/09/27 XLOCK"; * @@ -41,221 +41,379 @@ * Mountain View, CA 94043 * * Revision History: + * 01-Jun-95: This should look more like the original with some updates by + * Scott Draves. * 27-Jun-91: vary number of functions used. * 24-Jun-91: fixed portability problem with integer mod (%). - * 06-Jun-91: Written. (received from Scott Graves, spot@cs.cmu.edu). + * 06-Jun-91: Written. (received from Scott Draves, spot@cs.cmu.edu). */ +#include #include "screenhack.h" -/*#include */ +#include /* so we can ignore SIGFPE */ #define POINT_BUFFER_SIZE 10 #define MAXLEV 4 +#define MAXKINDS 10 + +struct state { + Display *dpy; + Window window; + + double f[2][3][MAXLEV]; /* three non-homogeneous transforms */ + int max_total; + int max_levels; + int max_points; + int cur_level; + int variation; + int snum; + int anum; + int num_points; + int total_points; + int pixcol; + int ncolors; + XColor *colors; + XPoint points [POINT_BUFFER_SIZE]; + GC gc; + + int delay, delay2; + int width, height; + + short lasthalf; + + int flame_alt; + int do_reset; +}; -static double f[2][3][MAXLEV]; /* three non-homogeneous transforms */ -static int max_total; -static int max_levels; -static int max_points; -static int cur_level; -static int snum; -static int anum; -static int num_points; -static int total_points; -static int pixcol; -static int npixels; -static unsigned long *pixels; -static XPoint points [POINT_BUFFER_SIZE]; -static GC gc; - -static int delay, delay2; -static int width, height; static short -halfrandom (mv) - int mv; +halfrandom (struct state *st, int mv) { - static short lasthalf = 0; unsigned long r; - if (lasthalf) + if (st->lasthalf) { - r = lasthalf; - lasthalf = 0; + r = st->lasthalf; + st->lasthalf = 0; } else { r = random (); - lasthalf = r >> 16; + st->lasthalf = r >> 16; } return (r % mv); } - -static void -init_flame (dpy, window) - Display *dpy; - Window window; +static void * +flame_init (Display *dpy, Window window) { - int i; + struct state *st = (struct state *) calloc (1, sizeof(*st)); XGCValues gcv; XWindowAttributes xgwa; Colormap cmap; - XGetWindowAttributes (dpy, window, &xgwa); - width = xgwa.width; - height = xgwa.height; + + st->dpy = dpy; + st->window = window; + +#if defined(SIGFPE) && defined(SIG_IGN) + /* No doubt a better fix would be to track down where the NaN is coming + from, and code around that; but this should do. Apparently most systems + (Linux, Solaris, Irix, ...) ignore FPE by default -- but FreeBSD dumps + core by default. */ + signal (SIGFPE, SIG_IGN); +#endif + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + st->width = xgwa.width; + st->height = xgwa.height; cmap = xgwa.colormap; - max_points = get_integer_resource ("iterations", "Integer"); - if (max_points <= 0) max_points = 100; + st->max_points = get_integer_resource (st->dpy, "iterations", "Integer"); + if (st->max_points <= 0) st->max_points = 100; + + st->max_levels = st->max_points; - max_levels = max_points; + st->max_total = get_integer_resource (st->dpy, "points", "Integer"); + if (st->max_total <= 0) st->max_total = 10000; - max_total = get_integer_resource ("points", "Integer"); - if (max_total <= 0) max_total = 10000; + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + if (st->delay < 0) st->delay = 0; + st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer"); + if (st->delay2 < 0) st->delay2 = 0; - delay = get_integer_resource ("delay", "Integer"); - if (delay < 0) delay = 0; - delay2 = get_integer_resource ("delay2", "Integer"); - if (delay2 < 0) delay2 = 0; + st->variation = random() % MAXKINDS; if (mono_p) - npixels = 0; + st->ncolors = 0; else { - int i = get_integer_resource ("ncolors", "Integer"); - double saturation = 1.0; - double value = 1.0; - XColor color; - if (i <= 0) i = 128; - - pixels = (unsigned long *) malloc ((i+1) * sizeof (*pixels)); - for (npixels = 0; npixels < i; npixels++) - { - hsv_to_rgb ((360*npixels)/i, saturation, value, - &color.red, &color.green, &color.blue); - if (! XAllocColor (dpy, cmap, &color)) - break; - pixels [npixels] = color.pixel; - } + st->ncolors = get_integer_resource (st->dpy, "colors", "Integer"); + if (st->ncolors <= 0) st->ncolors = 128; + st->colors = (XColor *) malloc ((st->ncolors+1) * sizeof (*st->colors)); + make_smooth_colormap (st->dpy, xgwa.visual, xgwa.colormap, st->colors, &st->ncolors, + True, 0, True); + if (st->ncolors <= 2) + mono_p = True, st->ncolors = 0; } - gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap); - gcv.background = get_pixel_resource ("background", "Background", dpy, cmap); + gcv.foreground = get_pixel_resource (st->dpy, cmap, "foreground", "Foreground"); + gcv.background = get_pixel_resource (st->dpy, cmap, "background", "Background"); if (! mono_p) { - pixcol = halfrandom (npixels); - gcv.foreground = (pixels [pixcol]); + st->pixcol = halfrandom (st, st->ncolors); + gcv.foreground = (st->colors [st->pixcol].pixel); } - gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv); + st->gc = XCreateGC (st->dpy, st->window, GCForeground | GCBackground, &gcv); + return st; } static int -recurse (x, y, l, dpy, win) - register double x, y; - register int l; - Display *dpy; - Window win; +recurse (struct state *st, double x, double y, int l, Display *dpy, Window win) { - int xp, yp, i; + int /*xp, yp,*/ i; double nx, ny; - if (l == max_levels) + if (l == st->max_levels) { - total_points++; - if (total_points > max_total) /* how long each fractal runs */ + st->total_points++; + if (st->total_points > st->max_total) /* how long each fractal runs */ return 0; if (x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0) { - xp = points[num_points].x = (int) ((width / 2) * (x + 1.0)); - yp = points[num_points].y = (int) ((height / 2) * (y + 1.0)); - num_points++; - if (num_points >= POINT_BUFFER_SIZE) +/* xp = st->points[st->num_points].x = (int) ((st->width / 2) * (x + 1.0)); + yp = st->points[st->num_points].y = (int) ((st->height / 2) * (y + 1.0));*/ + st->num_points++; + if (st->num_points >= POINT_BUFFER_SIZE) { - XDrawPoints (dpy, win, gc, points, num_points, CoordModeOrigin); - num_points = 0; - /* if (delay) usleep (delay); */ - /* XSync (dpy, True); */ + XDrawPoints (st->dpy, win, st->gc, st->points, st->num_points, CoordModeOrigin); + st->num_points = 0; } } } else { - for (i = 0; i < snum; i++) + for (i = 0; i < st->snum; i++) { - nx = f[0][0][i] * x + f[0][1][i] * y + f[0][2][i]; - ny = f[1][0][i] * x + f[1][1][i] * y + f[1][2][i]; - if (i < anum) + + /* Scale back when values get very large. Spot sez: + "I think this happens on HPUX. I think it's non-IEEE + to generate an exception instead of a silent NaN." + */ + if ((abs(x) > 1.0E5) || (abs(y) > 1.0E5)) + x = x / y; + + nx = st->f[0][0][i] * x + st->f[0][1][i] * y + st->f[0][2][i]; + ny = st->f[1][0][i] * x + st->f[1][1][i] * y + st->f[1][2][i]; + if (i < st->anum) { - nx = sin(nx); - ny = sin(ny); + switch (st->variation) + { + case 0: /* sinusoidal */ + nx = sin(nx); + ny = sin(ny); + break; + case 1: /* complex */ + { + double r2 = nx * nx + ny * ny + 1e-6; + nx = nx / r2; + ny = ny / r2; + } + break; + case 2: /* bent */ + if (nx < 0.0) + nx = nx * 2.0; + if (ny < 0.0) + ny = ny / 2.0; + break; + case 3: /* swirl */ + { + double r = (nx * nx + ny * ny); /* times k here is fun */ + double c1 = sin(r); + double c2 = cos(r); + double t = nx; + + if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4) + ny = 1e4; + else + ny = c2 * t + c1 * ny; + nx = c1 * nx - c2 * ny; + } + break; + case 4: /* horseshoe */ + { + double r, c1, c2, t; + + /* Avoid atan2: DOMAIN error message */ + if (nx == 0.0 && ny == 0.0) + r = 0.0; + else + r = atan2(nx, ny); /* times k here is fun */ + c1 = sin(r); + c2 = cos(r); + t = nx; + + nx = c1 * nx - c2 * ny; + ny = c2 * t + c1 * ny; + } + break; + case 5: /* drape */ + { + double t; + + /* Avoid atan2: DOMAIN error message */ + if (nx == 0.0 && ny == 0.0) + t = 0.0; + else + t = atan2(nx, ny) / M_PI; + + if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4) + ny = 1e4; + else + ny = sqrt(nx * nx + ny * ny) - 1.0; + nx = t; + } + break; + case 6: /* broken */ + if (nx > 1.0) + nx = nx - 1.0; + if (nx < -1.0) + nx = nx + 1.0; + if (ny > 1.0) + ny = ny - 1.0; + if (ny < -1.0) + ny = ny + 1.0; + break; + case 7: /* spherical */ + { + double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6); + + nx = nx / r; + ny = ny / r; + } + break; + case 8: /* */ + nx = atan(nx) / M_PI_2; + ny = atan(ny) / M_PI_2; + break; +/* #if 0 */ /* core dumps on some machines, why not all? */ + case 9: /* complex sine */ + { + double u = nx; + double v = ny; + double ev = exp(v); + double emv = exp(-v); + + nx = (ev + emv) * sin(u) / 2.0; + ny = (ev - emv) * cos(u) / 2.0; + } + break; + case 10: /* polynomial */ + if (nx < 0) + nx = -nx * nx; + else + nx = nx * nx; + if (ny < 0) + ny = -ny * ny; + else + ny = ny * ny; + break; +/* #endif */ + default: + nx = sin(nx); + ny = sin(ny); + } } - if (!recurse (nx, ny, l + 1, dpy, win)) + if (!recurse (st, nx, ny, l + 1, st->dpy, win)) return 0; } } return 1; } - -static void -flame (dpy, window) - Display *dpy; - Window window; +static unsigned long +flame_draw (Display *dpy, Window window, void *closure) { + struct state *st = (struct state *) closure; int i, j, k; - static int alt = 0; + unsigned long this_delay = st->delay; - if (!(cur_level++ % max_levels)) + if (st->do_reset) { - if (delay2) usleep (delay2); - XClearWindow (dpy, window); - alt = !alt; + st->do_reset = 0; + XClearWindow (st->dpy, st->window); + } + + if (!(st->cur_level++ % st->max_levels)) + { + st->do_reset = 1; + this_delay = st->delay2; + st->flame_alt = !st->flame_alt; + st->variation = random() % MAXKINDS; } else { - if (npixels > 2) + if (st->ncolors > 2) { - XSetForeground (dpy, gc, pixels [pixcol]); - if (--pixcol < 0) - pixcol = npixels - 1; + XSetForeground (st->dpy, st->gc, st->colors [st->pixcol].pixel); + if (--st->pixcol < 0) + st->pixcol = st->ncolors - 1; } } /* number of functions */ - snum = 2 + (cur_level % (MAXLEV - 1)); + st->snum = 2 + (st->cur_level % (MAXLEV - 1)); /* how many of them are of alternate form */ - if (alt) - anum = 0; + if (st->flame_alt) + st->anum = 0; else - anum = halfrandom (snum) + 2; + st->anum = halfrandom (st, st->snum) + 2; /* 6 coefs per function */ - for (k = 0; k < snum; k++) + for (k = 0; k < st->snum; k++) { for (i = 0; i < 2; i++) for (j = 0; j < 3; j++) - f[i][j][k] = ((double) (random() & 1023) / 512.0 - 1.0); + st->f[i][j][k] = ((double) (random() & 1023) / 512.0 - 1.0); } - num_points = 0; - total_points = 0; - (void) recurse (0.0, 0.0, 0, dpy, window); - XDrawPoints (dpy, window, gc, points, num_points, CoordModeOrigin); - XSync (dpy, True); - if (delay) usleep (delay); + st->num_points = 0; + st->total_points = 0; + recurse (st, 0.0, 0.0, 0, st->dpy, st->window); + XDrawPoints (st->dpy, st->window, st->gc, st->points, st->num_points, CoordModeOrigin); + + return this_delay; } - -char *progclass = "Flame"; -char *defaults [] = { - "*background: black", - "*foreground: white", - "*colors: 128", +#if defined(__hpux) && defined(PLOSS) +/* I don't understand why this is necessary, but I'm told that this program + does nothing at all on HP-sUX without it. + + I'm further told that HPUX 11.0 doesn't define PLOSS, and works ok without + this section. Go figure. + */ +#undef random +#undef srandom +#include +int matherr(x) + register struct exception *x; +{ + if (x->type == PLOSS) return 1; + else return 0; +} +#endif /* __hpux */ + + + +static const char *flame_defaults [] = { + ".background: black", + ".foreground: white", + "*fpsSolid: true", + "*colors: 64", "*iterations: 25", "*delay: 50000", "*delay2: 2000000", @@ -263,21 +421,33 @@ char *defaults [] = { 0 }; -XrmOptionDescRec options [] = { - { "-ncolors", ".colors", XrmoptionSepArg, 0 }, +static XrmOptionDescRec flame_options [] = { + { "-colors", ".colors", XrmoptionSepArg, 0 }, { "-iterations", ".iterations", XrmoptionSepArg, 0 }, { "-delay", ".delay", XrmoptionSepArg, 0 }, { "-delay2", ".delay2", XrmoptionSepArg, 0 }, - { "-points", ".points", XrmoptionSepArg, 0 } + { "-points", ".points", XrmoptionSepArg, 0 }, + { 0, 0, 0, 0 } }; -int options_size = (sizeof (options) / sizeof (options[0])); -void -screenhack (dpy, window) - Display *dpy; - Window window; +static void +flame_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) { - init_flame (dpy, window); - while (1) - flame (dpy, window); } + +static Bool +flame_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + return False; +} + +static void +flame_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + free (st); +} + +XSCREENSAVER_MODULE ("Flame", flame) +