1 /* xscreensaver, Copyright (c) 1993, 1995, 1996, 1998
2 * Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 /* This file was ported from xlock for use in xscreensaver (and standalone)
14 * by jwz on 18-Oct-93. (And again, 11-May-97.) Original copyright reads:
16 * static char sccsid[] = "@(#)flame.c 1.4 91/09/27 XLOCK";
18 * flame.c - recursive fractal cosmic flames.
20 * Copyright (c) 1991 by Patrick J. Naughton.
22 * Permission to use, copy, modify, and distribute this software and its
23 * documentation for any purpose and without fee is hereby granted,
24 * provided that the above copyright notice appear in all copies and that
25 * both that copyright notice and this permission notice appear in
26 * supporting documentation.
28 * This file is provided AS IS with no warranties of any kind. The author
29 * shall have no liability with respect to the infringement of copyrights,
30 * trade secrets or any patents by this file or any part thereof. In no
31 * event will the author be liable for any lost revenue or profits or
32 * other special, indirect and consequential damages.
34 * Comments and additions should be sent to the author:
36 * naughton@eng.sun.com
40 * Sun Laboritories, Inc.
42 * Mountain View, CA 94043
45 * 01-Jun-95: This should look more like the original with some updates by
47 * 27-Jun-91: vary number of functions used.
48 * 24-Jun-91: fixed portability problem with integer mod (%).
49 * 06-Jun-91: Written. (received from Scott Draves, spot@cs.cmu.edu).
53 #include "screenhack.h"
55 #include <signal.h> /* so we can ignore SIGFPE */
57 #define POINT_BUFFER_SIZE 10
61 static double f[2][3][MAXLEV]; /* three non-homogeneous transforms */
63 static int max_levels;
64 static int max_points;
69 static int num_points;
70 static int total_points;
73 static XColor *colors;
74 static XPoint points [POINT_BUFFER_SIZE];
77 static int delay, delay2;
78 static int width, height;
83 static short lasthalf = 0;
100 init_flame (Display *dpy, Window window)
103 XWindowAttributes xgwa;
106 #if defined(SIGFPE) && defined(SIG_IGN)
107 /* No doubt a better fix would be to track down where the NaN is coming
108 from, and code around that; but this should do. Apparently most systems
109 (Linux, Solaris, Irix, ...) ignore FPE by default -- but FreeBSD dumps
111 signal (SIGFPE, SIG_IGN);
114 XGetWindowAttributes (dpy, window, &xgwa);
116 height = xgwa.height;
117 cmap = xgwa.colormap;
119 max_points = get_integer_resource ("iterations", "Integer");
120 if (max_points <= 0) max_points = 100;
122 max_levels = max_points;
124 max_total = get_integer_resource ("points", "Integer");
125 if (max_total <= 0) max_total = 10000;
127 delay = get_integer_resource ("delay", "Integer");
128 if (delay < 0) delay = 0;
129 delay2 = get_integer_resource ("delay2", "Integer");
130 if (delay2 < 0) delay2 = 0;
132 variation = random() % MAXKINDS;
138 ncolors = get_integer_resource ("colors", "Integer");
139 if (ncolors <= 0) ncolors = 128;
140 colors = (XColor *) malloc ((ncolors+1) * sizeof (*colors));
141 make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
144 mono_p = True, ncolors = 0;
147 gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
148 gcv.background = get_pixel_resource ("background", "Background", dpy, cmap);
152 pixcol = halfrandom (ncolors);
153 gcv.foreground = (colors [pixcol].pixel);
156 gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
160 recurse (double x, double y, int l, Display *dpy, Window win)
168 if (total_points > max_total) /* how long each fractal runs */
171 if (x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0)
173 xp = points[num_points].x = (int) ((width / 2) * (x + 1.0));
174 yp = points[num_points].y = (int) ((height / 2) * (y + 1.0));
176 if (num_points >= POINT_BUFFER_SIZE)
178 XDrawPoints (dpy, win, gc, points, num_points, CoordModeOrigin);
180 /* if (delay) usleep (delay); */
181 /* XSync (dpy, False); */
187 for (i = 0; i < snum; i++)
190 /* Scale back when values get very large. Spot sez:
191 "I think this happens on HPUX. I think it's non-IEEE
192 to generate an exception instead of a silent NaN."
194 if ((abs(x) > 1.0E5) || (abs(y) > 1.0E5))
197 nx = f[0][0][i] * x + f[0][1][i] * y + f[0][2][i];
198 ny = f[1][0][i] * x + f[1][1][i] * y + f[1][2][i];
203 case 0: /* sinusoidal */
207 case 1: /* complex */
209 double r2 = nx * nx + ny * ny + 1e-6;
222 double r = (nx * nx + ny * ny); /* times k here is fun */
227 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
230 ny = c2 * t + c1 * ny;
231 nx = c1 * nx - c2 * ny;
234 case 4: /* horseshoe */
238 /* Avoid atan2: DOMAIN error message */
239 if (nx == 0.0 && ny == 0.0)
242 r = atan2(nx, ny); /* times k here is fun */
247 nx = c1 * nx - c2 * ny;
248 ny = c2 * t + c1 * ny;
255 /* Avoid atan2: DOMAIN error message */
256 if (nx == 0.0 && ny == 0.0)
259 t = atan2(nx, ny) / M_PI;
261 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
264 ny = sqrt(nx * nx + ny * ny) - 1.0;
278 case 7: /* spherical */
280 double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
287 nx = atan(nx) / M_PI_2;
288 ny = atan(ny) / M_PI_2;
290 /* #if 0 */ /* core dumps on some machines, why not all? */
291 case 9: /* complex sine */
296 double emv = exp(-v);
298 nx = (ev + emv) * sin(u) / 2.0;
299 ny = (ev - emv) * cos(u) / 2.0;
302 case 10: /* polynomial */
318 if (!recurse (nx, ny, l + 1, dpy, win))
327 flame (Display *dpy, Window window)
332 if (!(cur_level++ % max_levels))
334 if (delay2) usleep (delay2);
335 XClearWindow (dpy, window);
338 variation = random() % MAXKINDS;
344 XSetForeground (dpy, gc, colors [pixcol].pixel);
346 pixcol = ncolors - 1;
350 /* number of functions */
351 snum = 2 + (cur_level % (MAXLEV - 1));
353 /* how many of them are of alternate form */
357 anum = halfrandom (snum) + 2;
359 /* 6 coefs per function */
360 for (k = 0; k < snum; k++)
362 for (i = 0; i < 2; i++)
363 for (j = 0; j < 3; j++)
364 f[i][j][k] = ((double) (random() & 1023) / 512.0 - 1.0);
368 (void) recurse (0.0, 0.0, 0, dpy, window);
369 XDrawPoints (dpy, window, gc, points, num_points, CoordModeOrigin);
371 if (delay) usleep (delay);
375 #if defined(__hpux) && defined(PLOSS)
376 /* I don't understand why this is necessary, but I'm told that this program
377 does nothing at all on HP-sUX without it.
379 I'm further told that HPUX 11.0 doesn't define PLOSS, and works ok without
380 this section. Go figure.
386 register struct exception *x;
388 if (x->type == PLOSS) return 1;
395 char *progclass = "Flame";
397 char *defaults [] = {
398 ".background: black",
399 ".foreground: white",
408 XrmOptionDescRec options [] = {
409 { "-colors", ".colors", XrmoptionSepArg, 0 },
410 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
411 { "-delay", ".delay", XrmoptionSepArg, 0 },
412 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
413 { "-points", ".points", XrmoptionSepArg, 0 },
418 screenhack (Display *dpy, Window window)
420 init_flame (dpy, window);
424 screenhack_handle_events (dpy);