-/* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@mcom.com>
+/* xscreensaver, Copyright (c) 1993, 1995, 1996, 1998
+ * Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
*/
/* 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";
*
* 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 <math.h>
#include "screenhack.h"
-/*#include <math.h>*/
+#include <signal.h> /* so we can ignore SIGFPE */
#define POINT_BUFFER_SIZE 10
#define MAXLEV 4
+#define MAXKINDS 10
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 variation;
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 int ncolors;
+static XColor *colors;
static XPoint points [POINT_BUFFER_SIZE];
static GC gc;
static int width, height;
static short
-halfrandom (mv)
- int mv;
+halfrandom (int mv)
{
static short lasthalf = 0;
unsigned long r;
return (r % mv);
}
-
static void
-init_flame (dpy, window)
- Display *dpy;
- Window window;
+init_flame (Display *dpy, Window window)
{
XGCValues gcv;
XWindowAttributes xgwa;
Colormap cmap;
+
+#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 (dpy, window, &xgwa);
width = xgwa.width;
height = xgwa.height;
delay2 = get_integer_resource ("delay2", "Integer");
if (delay2 < 0) delay2 = 0;
+ variation = random() % MAXKINDS;
+
if (mono_p)
- npixels = 0;
+ 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;
- }
+ ncolors = get_integer_resource ("colors", "Integer");
+ if (ncolors <= 0) ncolors = 128;
+ colors = (XColor *) malloc ((ncolors+1) * sizeof (*colors));
+ make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
+ True, 0, True);
+ if (ncolors <= 2)
+ mono_p = True, ncolors = 0;
}
gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
if (! mono_p)
{
- pixcol = halfrandom (npixels);
- gcv.foreground = (pixels [pixcol]);
+ pixcol = halfrandom (ncolors);
+ gcv.foreground = (colors [pixcol].pixel);
}
gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
}
static int
-recurse (x, y, l, dpy, win)
- register double x, y;
- register int l;
- Display *dpy;
- Window win;
+recurse (double x, double y, int l, Display *dpy, Window win)
{
int xp, yp, i;
double nx, ny;
XDrawPoints (dpy, win, gc, points, num_points, CoordModeOrigin);
num_points = 0;
/* if (delay) usleep (delay); */
- /* XSync (dpy, True); */
+ /* XSync (dpy, False); */
}
}
}
{
for (i = 0; i < snum; i++)
{
+
+ /* 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 = 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)
{
- nx = sin(nx);
- ny = sin(ny);
+ switch (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))
return 0;
static void
-flame (dpy, window)
- Display *dpy;
- Window window;
+flame (Display *dpy, Window window)
{
int i, j, k;
static int alt = 0;
if (delay2) usleep (delay2);
XClearWindow (dpy, window);
alt = !alt;
+
+ variation = random() % MAXKINDS;
}
else
{
- if (npixels > 2)
+ if (ncolors > 2)
{
- XSetForeground (dpy, gc, pixels [pixcol]);
+ XSetForeground (dpy, gc, colors [pixcol].pixel);
if (--pixcol < 0)
- pixcol = npixels - 1;
+ pixcol = ncolors - 1;
}
}
total_points = 0;
(void) recurse (0.0, 0.0, 0, dpy, window);
XDrawPoints (dpy, window, gc, points, num_points, CoordModeOrigin);
- XSync (dpy, True);
+ XSync (dpy, False);
if (delay) usleep (delay);
}
+
+#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 <math.h>
+int matherr(x)
+ register struct exception *x;
+{
+ if (x->type == PLOSS) return 1;
+ else return 0;
+}
+#endif /* __hpux */
+
+
\f
char *progclass = "Flame";
char *defaults [] = {
- "Flame.background: black", /* to placate SGI */
- "Flame.foreground: white",
- "*colors: 128",
+ ".background: black",
+ ".foreground: white",
+ "*colors: 64",
"*iterations: 25",
"*delay: 50000",
"*delay2: 2000000",
};
XrmOptionDescRec options [] = {
- { "-ncolors", ".colors", XrmoptionSepArg, 0 },
+ { "-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;
+screenhack (Display *dpy, Window window)
{
init_flame (dpy, window);
while (1)
- flame (dpy, window);
+ {
+ flame (dpy, window);
+ screenhack_handle_events (dpy);
+ }
}