1 /* xscreensaver, Copyright (c) 1993-2014 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* This file was ported from xlock for use in xscreensaver (and standalone)
13 * by jwz on 18-Oct-93. (And again, 11-May-97.) Original copyright reads:
15 * static char sccsid[] = "@(#)flame.c 1.4 91/09/27 XLOCK";
17 * flame.c - recursive fractal cosmic flames.
19 * Copyright (c) 1991 by Patrick J. Naughton.
21 * Permission to use, copy, modify, and distribute this software and its
22 * documentation for any purpose and without fee is hereby granted,
23 * provided that the above copyright notice appear in all copies and that
24 * both that copyright notice and this permission notice appear in
25 * supporting documentation.
27 * This file is provided AS IS with no warranties of any kind. The author
28 * shall have no liability with respect to the infringement of copyrights,
29 * trade secrets or any patents by this file or any part thereof. In no
30 * event will the author be liable for any lost revenue or profits or
31 * other special, indirect and consequential damages.
33 * Comments and additions should be sent to the author:
35 * naughton@eng.sun.com
39 * Sun Laboritories, Inc.
41 * Mountain View, CA 94043
44 * 01-Jun-95: This should look more like the original with some updates by
46 * 27-Jun-91: vary number of functions used.
47 * 24-Jun-91: fixed portability problem with integer mod (%).
48 * 06-Jun-91: Written. (received from Scott Draves, spot@cs.cmu.edu).
52 #include "screenhack.h"
54 #include <signal.h> /* so we can ignore SIGFPE */
56 #define POINT_BUFFER_SIZE 10
64 double f[2][3][MAXLEV]; /* three non-homogeneous transforms */
77 XPoint points [POINT_BUFFER_SIZE];
91 halfrandom (struct state *st, int mv)
103 st->lasthalf = r >> 16;
109 flame_init (Display *dpy, Window window)
111 struct state *st = (struct state *) calloc (1, sizeof(*st));
113 XWindowAttributes xgwa;
119 #if defined(SIGFPE) && defined(SIG_IGN)
120 /* No doubt a better fix would be to track down where the NaN is coming
121 from, and code around that; but this should do. Apparently most systems
122 (Linux, Solaris, Irix, ...) ignore FPE by default -- but FreeBSD dumps
124 signal (SIGFPE, SIG_IGN);
127 XGetWindowAttributes (st->dpy, st->window, &xgwa);
128 st->width = xgwa.width;
129 st->height = xgwa.height;
130 cmap = xgwa.colormap;
132 st->max_points = get_integer_resource (st->dpy, "iterations", "Integer");
133 if (st->max_points <= 0) st->max_points = 100;
135 st->max_levels = st->max_points;
137 st->max_total = get_integer_resource (st->dpy, "points", "Integer");
138 if (st->max_total <= 0) st->max_total = 10000;
140 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
141 if (st->delay < 0) st->delay = 0;
142 st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer");
143 if (st->delay2 < 0) st->delay2 = 0;
145 st->variation = random() % MAXKINDS;
151 st->ncolors = get_integer_resource (st->dpy, "colors", "Integer");
152 if (st->ncolors <= 0) st->ncolors = 128;
153 st->colors = (XColor *) malloc ((st->ncolors+1) * sizeof (*st->colors));
154 make_smooth_colormap (xgwa.screen, xgwa.visual, xgwa.colormap,
155 st->colors, &st->ncolors,
157 if (st->ncolors <= 2)
158 mono_p = True, st->ncolors = 0;
161 gcv.foreground = get_pixel_resource (st->dpy, cmap, "foreground", "Foreground");
162 gcv.background = get_pixel_resource (st->dpy, cmap, "background", "Background");
166 st->pixcol = halfrandom (st, st->ncolors);
167 gcv.foreground = (st->colors [st->pixcol].pixel);
170 st->gc = XCreateGC (st->dpy, st->window, GCForeground | GCBackground, &gcv);
175 recurse (struct state *st, double x, double y, int l, Display *dpy, Window win)
180 if (l == st->max_levels)
183 if (st->total_points > st->max_total) /* how long each fractal runs */
186 if (x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0)
188 st->points[st->num_points].x = (int) ((st->width / 2) * (x + 1.0));
189 st->points[st->num_points].y = (int) ((st->height / 2) * (y + 1.0));
191 if (st->num_points >= POINT_BUFFER_SIZE)
193 XDrawPoints (st->dpy, win, st->gc, st->points, st->num_points, CoordModeOrigin);
200 for (i = 0; i < st->snum; i++)
203 /* Scale back when values get very large. Spot sez:
204 "I think this happens on HPUX. I think it's non-IEEE
205 to generate an exception instead of a silent NaN."
207 if ((fabs(x) > 1.0E5) || (fabs(y) > 1.0E5))
210 nx = st->f[0][0][i] * x + st->f[0][1][i] * y + st->f[0][2][i];
211 ny = st->f[1][0][i] * x + st->f[1][1][i] * y + st->f[1][2][i];
214 switch (st->variation)
216 case 0: /* sinusoidal */
220 case 1: /* complex */
222 double r2 = nx * nx + ny * ny + 1e-6;
235 double r = (nx * nx + ny * ny); /* times k here is fun */
240 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
243 ny = c2 * t + c1 * ny;
244 nx = c1 * nx - c2 * ny;
247 case 4: /* horseshoe */
251 /* Avoid atan2: DOMAIN error message */
252 if (nx == 0.0 && ny == 0.0)
255 r = atan2(nx, ny); /* times k here is fun */
260 nx = c1 * nx - c2 * ny;
261 ny = c2 * t + c1 * ny;
268 /* Avoid atan2: DOMAIN error message */
269 if (nx == 0.0 && ny == 0.0)
272 t = atan2(nx, ny) / M_PI;
274 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
277 ny = sqrt(nx * nx + ny * ny) - 1.0;
291 case 7: /* spherical */
293 double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
300 nx = atan(nx) / M_PI_2;
301 ny = atan(ny) / M_PI_2;
303 /* #if 0 */ /* core dumps on some machines, why not all? */
304 case 9: /* complex sine */
309 double emv = exp(-v);
311 nx = (ev + emv) * sin(u) / 2.0;
312 ny = (ev - emv) * cos(u) / 2.0;
315 case 10: /* polynomial */
331 if (!recurse (st, nx, ny, l + 1, st->dpy, win))
339 flame_draw (Display *dpy, Window window, void *closure)
341 struct state *st = (struct state *) closure;
343 unsigned long this_delay = st->delay;
348 XClearWindow (st->dpy, st->window);
351 if (!(st->cur_level++ % st->max_levels))
354 this_delay = st->delay2;
355 st->flame_alt = !st->flame_alt;
356 st->variation = random() % MAXKINDS;
362 XSetForeground (st->dpy, st->gc, st->colors [st->pixcol].pixel);
363 if (--st->pixcol < 0)
364 st->pixcol = st->ncolors - 1;
368 /* number of functions */
369 st->snum = 2 + (st->cur_level % (MAXLEV - 1));
371 /* how many of them are of alternate form */
375 st->anum = halfrandom (st, st->snum) + 2;
377 /* 6 coefs per function */
378 for (k = 0; k < st->snum; k++)
380 for (i = 0; i < 2; i++)
381 for (j = 0; j < 3; j++)
382 st->f[i][j][k] = ((double) (random() & 1023) / 512.0 - 1.0);
385 st->total_points = 0;
386 recurse (st, 0.0, 0.0, 0, st->dpy, st->window);
387 XDrawPoints (st->dpy, st->window, st->gc, st->points, st->num_points, CoordModeOrigin);
393 #if defined(__hpux) && defined(PLOSS)
394 /* I don't understand why this is necessary, but I'm told that this program
395 does nothing at all on HP-sUX without it.
397 I'm further told that HPUX 11.0 doesn't define PLOSS, and works ok without
398 this section. Go figure.
404 register struct exception *x;
406 if (x->type == PLOSS) return 1;
413 static const char *flame_defaults [] = {
414 ".background: black",
415 ".foreground: white",
423 "*ignoreRotation: True",
428 static XrmOptionDescRec flame_options [] = {
429 { "-colors", ".colors", XrmoptionSepArg, 0 },
430 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
431 { "-delay", ".delay", XrmoptionSepArg, 0 },
432 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
433 { "-points", ".points", XrmoptionSepArg, 0 },
438 flame_reshape (Display *dpy, Window window, void *closure,
439 unsigned int w, unsigned int h)
441 struct state *st = (struct state *) closure;
447 flame_event (Display *dpy, Window window, void *closure, XEvent *event)
449 struct state *st = (struct state *) closure;
450 if (screenhack_event_helper (dpy, window, event))
459 flame_free (Display *dpy, Window window, void *closure)
461 struct state *st = (struct state *) closure;
465 XSCREENSAVER_MODULE ("Flame", flame)