http://ftp.x.org/contrib/applications/xscreensaver-2.23.tar.gz
[xscreensaver] / hacks / flame.c
1 /* xscreensaver, Copyright (c) 1993, 1995, 1996
2  *  Jamie Zawinski <jwz@netscape.com>
3  *
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 
10  * implied warranty.
11  */
12
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:
15  *
16  *   static char sccsid[] = "@(#)flame.c 1.4 91/09/27 XLOCK";
17  *
18  * flame.c - recursive fractal cosmic flames.
19  *
20  * Copyright (c) 1991 by Patrick J. Naughton.
21  *
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.
27  *
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.
33  *
34  * Comments and additions should be sent to the author:
35  *
36  *                     naughton@eng.sun.com
37  *
38  *                     Patrick J. Naughton
39  *                     MS 21-14
40  *                     Sun Laboritories, Inc.
41  *                     2550 Garcia Ave
42  *                     Mountain View, CA  94043
43  *
44  * Revision History:
45  * 01-Jun-95: This should look more like the original with some updates by
46  *            Scott Draves.
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).
50  */
51
52 #include <math.h>
53 #include "screenhack.h"
54
55 #define POINT_BUFFER_SIZE 10
56 #define MAXLEV 4
57 #define MAXKINDS  10
58
59 static double f[2][3][MAXLEV];  /* three non-homogeneous transforms */
60 static int max_total;
61 static int max_levels;
62 static int max_points;
63 static int cur_level;
64 static int variation;
65 static int snum;
66 static int anum;
67 static int num_points;
68 static int total_points;
69 static int pixcol;
70 static int ncolors;
71 static XColor *colors;
72 static XPoint points [POINT_BUFFER_SIZE];
73 static GC gc;
74
75 static int delay, delay2;
76 static int width, height;
77
78 static short
79 halfrandom (int mv)
80 {
81   static short lasthalf = 0;
82   unsigned long r;
83
84   if (lasthalf)
85     {
86       r = lasthalf;
87       lasthalf = 0;
88     }
89   else
90     {
91       r = random ();
92       lasthalf = r >> 16;
93     }
94   return (r % mv);
95 }
96
97 static void
98 init_flame (Display *dpy, Window window)
99 {
100   XGCValues gcv;
101   XWindowAttributes xgwa;
102   Colormap cmap;
103   XGetWindowAttributes (dpy, window, &xgwa);
104   width = xgwa.width;
105   height = xgwa.height;
106   cmap = xgwa.colormap;
107
108   max_points = get_integer_resource ("iterations", "Integer");
109   if (max_points <= 0) max_points = 100;
110
111   max_levels = max_points;
112
113   max_total = get_integer_resource ("points", "Integer");
114   if (max_total <= 0) max_total = 10000;
115
116   delay = get_integer_resource ("delay", "Integer");
117   if (delay < 0) delay = 0;
118   delay2 = get_integer_resource ("delay2", "Integer");
119   if (delay2 < 0) delay2 = 0;
120
121   variation = random() % MAXKINDS;
122
123   if (mono_p)
124     ncolors = 0;
125   else
126     {
127       ncolors = get_integer_resource ("colors", "Integer");
128       if (ncolors <= 0) ncolors = 128;
129       colors = (XColor *) malloc ((ncolors+1) * sizeof (*colors));
130       make_smooth_colormap (dpy, xgwa.visual, xgwa.colormap, colors, &ncolors,
131                             True, 0, True);
132       if (ncolors <= 2)
133         mono_p = True, ncolors = 0;
134     }
135
136   gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
137   gcv.background = get_pixel_resource ("background", "Background", dpy, cmap);
138
139   if (! mono_p)
140     {
141       pixcol = halfrandom (ncolors);
142       gcv.foreground = (colors [pixcol].pixel);
143     }
144
145   gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
146 }
147
148 static int
149 recurse (double x, double y, int l, Display *dpy, Window win)
150 {
151   int xp, yp, i;
152   double nx, ny;
153
154   if (l == max_levels)
155     {
156       total_points++;
157       if (total_points > max_total) /* how long each fractal runs */
158         return 0;
159
160       if (x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0)
161         {
162           xp = points[num_points].x = (int) ((width / 2) * (x + 1.0));
163           yp = points[num_points].y = (int) ((height / 2) * (y + 1.0));
164           num_points++;
165           if (num_points >= POINT_BUFFER_SIZE)
166             {
167               XDrawPoints (dpy, win, gc, points, num_points, CoordModeOrigin);
168               num_points = 0;
169               /* if (delay) usleep (delay); */
170               /* XSync (dpy, True); */
171             }
172         }
173     }
174   else
175     {
176       for (i = 0; i < snum; i++)
177         {
178
179           /* Scale back when values get very large. Spot sez:
180              "I think this happens on HPUX.  I think it's non-IEEE
181              to generate an exception instead of a silent NaN."
182            */
183           if ((abs(x) > 1.0E5) || (abs(y) > 1.0E5))
184             x = x / y;
185
186           nx = f[0][0][i] * x + f[0][1][i] * y + f[0][2][i];
187           ny = f[1][0][i] * x + f[1][1][i] * y + f[1][2][i];
188           if (i < anum)
189             {
190               switch (variation)
191                 {
192                 case 0: /* sinusoidal */
193                   nx = sin(nx);
194                   ny = sin(ny);
195                   break;
196                 case 1: /* complex */
197                   {
198                     double r2 = nx * nx + ny * ny + 1e-6;
199                     nx = nx / r2;
200                     ny = ny / r2;
201                   }
202                   break;
203                 case 2: /* bent */
204                   if (nx < 0.0)
205                     nx = nx * 2.0;
206                   if (ny < 0.0)
207                     ny = ny / 2.0;
208                   break;
209                 case 3: /* swirl */
210                   {
211                     double r = (nx * nx + ny * ny);     /* times k here is fun */
212                     double c1 = sin(r);
213                     double c2 = cos(r);
214                     double t = nx;
215
216                     if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
217                       ny = 1e4;
218                     else
219                       ny = c2 * t + c1 * ny;
220                     nx = c1 * nx - c2 * ny;
221                   }
222                   break;
223                 case 4: /* horseshoe */
224                   {
225                     double r, c1, c2, t;
226
227                     /* Avoid atan2: DOMAIN error message */
228                     if (nx == 0.0 && ny == 0.0)
229                       r = 0.0;
230                     else
231                       r = atan2(nx, ny);      /* times k here is fun */
232                     c1 = sin(r);
233                     c2 = cos(r);
234                     t = nx;
235
236                     nx = c1 * nx - c2 * ny;
237                     ny = c2 * t + c1 * ny;
238                   }
239                   break;
240                 case 5: /* drape */
241                   {
242                     double t;
243
244                     /* Avoid atan2: DOMAIN error message */
245                     if (nx == 0.0 && ny == 0.0)
246                       t = 0.0;
247                     else
248                       t = atan2(nx, ny) / M_PI;
249
250                     if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
251                       ny = 1e4;
252                     else
253                       ny = sqrt(nx * nx + ny * ny) - 1.0;
254                     nx = t;
255                   }
256                   break;
257                 case 6: /* broken */
258                   if (nx > 1.0)
259                     nx = nx - 1.0;
260                   if (nx < -1.0)
261                     nx = nx + 1.0;
262                   if (ny > 1.0)
263                     ny = ny - 1.0;
264                   if (ny < -1.0)
265                     ny = ny + 1.0;
266                   break;
267                 case 7: /* spherical */
268                   {
269                     double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
270
271                     nx = nx / r;
272                     ny = ny / r;
273                   }
274                   break;
275                 case 8: /*  */
276                   nx = atan(nx) / M_PI_2;
277                   ny = atan(ny) / M_PI_2;
278                   break;
279 /* #if 0 */  /* core dumps on some machines, why not all? */
280                 case 9: /* complex sine */
281                   {
282                     double u = nx;
283                     double v = ny;
284                     double ev = exp(v);
285                     double emv = exp(-v);
286
287                     nx = (ev + emv) * sin(u) / 2.0;
288                     ny = (ev - emv) * cos(u) / 2.0;
289                   }
290                   break;
291                 case 10:        /* polynomial */
292                   if (nx < 0)
293                     nx = -nx * nx;
294                   else
295                     nx = nx * nx;
296                   if (ny < 0)
297                     ny = -ny * ny;
298                   else
299                     ny = ny * ny;
300                   break;
301 /* #endif */
302                 default:
303                   nx = sin(nx);
304                   ny = sin(ny);
305                 }
306             }
307           if (!recurse (nx, ny, l + 1, dpy, win))
308             return 0;
309         }
310     }
311   return 1;
312 }
313
314
315 static void
316 flame (Display *dpy, Window window)
317 {
318   int i, j, k;
319   static int alt = 0;
320
321   if (!(cur_level++ % max_levels))
322     {
323       if (delay2) usleep (delay2);
324       XClearWindow (dpy, window);
325       alt = !alt;
326
327       variation = random() % MAXKINDS;
328     }
329   else
330     {
331       if (ncolors > 2)
332         {
333           XSetForeground (dpy, gc, colors [pixcol].pixel);
334           if (--pixcol < 0)
335             pixcol = ncolors - 1;
336         }
337     }
338
339   /* number of functions */
340   snum = 2 + (cur_level % (MAXLEV - 1));
341
342   /* how many of them are of alternate form */
343   if (alt)
344     anum = 0;
345   else
346     anum = halfrandom (snum) + 2;
347
348   /* 6 coefs per function */
349   for (k = 0; k < snum; k++)
350     {
351       for (i = 0; i < 2; i++)
352         for (j = 0; j < 3; j++)
353           f[i][j][k] = ((double) (random() & 1023) / 512.0 - 1.0);
354     }
355   num_points = 0;
356   total_points = 0;
357   (void) recurse (0.0, 0.0, 0, dpy, window);
358   XDrawPoints (dpy, window, gc, points, num_points, CoordModeOrigin);
359   XSync (dpy, True);
360   if (delay) usleep (delay);
361 }
362
363
364 #ifdef __hpux
365 /* I don't understand why this is necessary, but I'm told that this program
366    does nothing at all on HP-sUX without it.
367  */
368 #undef random
369 #undef srandom
370 #include <math.h>
371 int matherr(x)
372    register struct exception *x;
373 {
374   if (x->type == PLOSS) return 1;
375   else return 0;
376 }
377 #endif /* __hpux */
378
379
380 \f
381 char *progclass = "Flame";
382
383 char *defaults [] = {
384   ".background: black",
385   ".foreground: white",
386   "*colors:     64",
387   "*iterations: 25",
388   "*delay:      50000",
389   "*delay2:     2000000",
390   "*points:     10000",
391   0
392 };
393
394 XrmOptionDescRec options [] = {
395   { "-colors",          ".colors",      XrmoptionSepArg, 0 },
396   { "-iterations",      ".iterations",  XrmoptionSepArg, 0 },
397   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
398   { "-delay2",          ".delay2",      XrmoptionSepArg, 0 },
399   { "-points",          ".points",      XrmoptionSepArg, 0 },
400   { 0, 0, 0, 0 }
401 };
402
403 void
404 screenhack (Display *dpy, Window window)
405 {
406   init_flame (dpy, window);
407   while (1)
408     flame (dpy, window);
409 }