ftp://ftp.smr.ru/pub/0/FreeBSD/releases/distfiles/xscreensaver-3.16.tar.gz
[xscreensaver] / hacks / flame.c
1 /* xscreensaver, Copyright (c) 1993, 1995, 1996, 1998
2  *  Jamie Zawinski <jwz@jwz.org>
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 #include <signal.h>             /* so we can ignore SIGFPE */
56
57 #define POINT_BUFFER_SIZE 10
58 #define MAXLEV 4
59 #define MAXKINDS  10
60
61 static double f[2][3][MAXLEV];  /* three non-homogeneous transforms */
62 static int max_total;
63 static int max_levels;
64 static int max_points;
65 static int cur_level;
66 static int variation;
67 static int snum;
68 static int anum;
69 static int num_points;
70 static int total_points;
71 static int pixcol;
72 static int ncolors;
73 static XColor *colors;
74 static XPoint points [POINT_BUFFER_SIZE];
75 static GC gc;
76
77 static int delay, delay2;
78 static int width, height;
79
80 static short
81 halfrandom (int mv)
82 {
83   static short lasthalf = 0;
84   unsigned long r;
85
86   if (lasthalf)
87     {
88       r = lasthalf;
89       lasthalf = 0;
90     }
91   else
92     {
93       r = random ();
94       lasthalf = r >> 16;
95     }
96   return (r % mv);
97 }
98
99 static void
100 init_flame (Display *dpy, Window window)
101 {
102   XGCValues gcv;
103   XWindowAttributes xgwa;
104   Colormap cmap;
105
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
110      core by default. */
111   signal (SIGFPE, SIG_IGN);
112 #endif
113
114   XGetWindowAttributes (dpy, window, &xgwa);
115   width = xgwa.width;
116   height = xgwa.height;
117   cmap = xgwa.colormap;
118
119   max_points = get_integer_resource ("iterations", "Integer");
120   if (max_points <= 0) max_points = 100;
121
122   max_levels = max_points;
123
124   max_total = get_integer_resource ("points", "Integer");
125   if (max_total <= 0) max_total = 10000;
126
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;
131
132   variation = random() % MAXKINDS;
133
134   if (mono_p)
135     ncolors = 0;
136   else
137     {
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,
142                             True, 0, True);
143       if (ncolors <= 2)
144         mono_p = True, ncolors = 0;
145     }
146
147   gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
148   gcv.background = get_pixel_resource ("background", "Background", dpy, cmap);
149
150   if (! mono_p)
151     {
152       pixcol = halfrandom (ncolors);
153       gcv.foreground = (colors [pixcol].pixel);
154     }
155
156   gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
157 }
158
159 static int
160 recurse (double x, double y, int l, Display *dpy, Window win)
161 {
162   int xp, yp, i;
163   double nx, ny;
164
165   if (l == max_levels)
166     {
167       total_points++;
168       if (total_points > max_total) /* how long each fractal runs */
169         return 0;
170
171       if (x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0)
172         {
173           xp = points[num_points].x = (int) ((width / 2) * (x + 1.0));
174           yp = points[num_points].y = (int) ((height / 2) * (y + 1.0));
175           num_points++;
176           if (num_points >= POINT_BUFFER_SIZE)
177             {
178               XDrawPoints (dpy, win, gc, points, num_points, CoordModeOrigin);
179               num_points = 0;
180               /* if (delay) usleep (delay); */
181               /* XSync (dpy, False); */
182             }
183         }
184     }
185   else
186     {
187       for (i = 0; i < snum; i++)
188         {
189
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."
193            */
194           if ((abs(x) > 1.0E5) || (abs(y) > 1.0E5))
195             x = x / y;
196
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];
199           if (i < anum)
200             {
201               switch (variation)
202                 {
203                 case 0: /* sinusoidal */
204                   nx = sin(nx);
205                   ny = sin(ny);
206                   break;
207                 case 1: /* complex */
208                   {
209                     double r2 = nx * nx + ny * ny + 1e-6;
210                     nx = nx / r2;
211                     ny = ny / r2;
212                   }
213                   break;
214                 case 2: /* bent */
215                   if (nx < 0.0)
216                     nx = nx * 2.0;
217                   if (ny < 0.0)
218                     ny = ny / 2.0;
219                   break;
220                 case 3: /* swirl */
221                   {
222                     double r = (nx * nx + ny * ny);     /* times k here is fun */
223                     double c1 = sin(r);
224                     double c2 = cos(r);
225                     double t = nx;
226
227                     if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
228                       ny = 1e4;
229                     else
230                       ny = c2 * t + c1 * ny;
231                     nx = c1 * nx - c2 * ny;
232                   }
233                   break;
234                 case 4: /* horseshoe */
235                   {
236                     double r, c1, c2, t;
237
238                     /* Avoid atan2: DOMAIN error message */
239                     if (nx == 0.0 && ny == 0.0)
240                       r = 0.0;
241                     else
242                       r = atan2(nx, ny);      /* times k here is fun */
243                     c1 = sin(r);
244                     c2 = cos(r);
245                     t = nx;
246
247                     nx = c1 * nx - c2 * ny;
248                     ny = c2 * t + c1 * ny;
249                   }
250                   break;
251                 case 5: /* drape */
252                   {
253                     double t;
254
255                     /* Avoid atan2: DOMAIN error message */
256                     if (nx == 0.0 && ny == 0.0)
257                       t = 0.0;
258                     else
259                       t = atan2(nx, ny) / M_PI;
260
261                     if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
262                       ny = 1e4;
263                     else
264                       ny = sqrt(nx * nx + ny * ny) - 1.0;
265                     nx = t;
266                   }
267                   break;
268                 case 6: /* broken */
269                   if (nx > 1.0)
270                     nx = nx - 1.0;
271                   if (nx < -1.0)
272                     nx = nx + 1.0;
273                   if (ny > 1.0)
274                     ny = ny - 1.0;
275                   if (ny < -1.0)
276                     ny = ny + 1.0;
277                   break;
278                 case 7: /* spherical */
279                   {
280                     double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
281
282                     nx = nx / r;
283                     ny = ny / r;
284                   }
285                   break;
286                 case 8: /*  */
287                   nx = atan(nx) / M_PI_2;
288                   ny = atan(ny) / M_PI_2;
289                   break;
290 /* #if 0 */  /* core dumps on some machines, why not all? */
291                 case 9: /* complex sine */
292                   {
293                     double u = nx;
294                     double v = ny;
295                     double ev = exp(v);
296                     double emv = exp(-v);
297
298                     nx = (ev + emv) * sin(u) / 2.0;
299                     ny = (ev - emv) * cos(u) / 2.0;
300                   }
301                   break;
302                 case 10:        /* polynomial */
303                   if (nx < 0)
304                     nx = -nx * nx;
305                   else
306                     nx = nx * nx;
307                   if (ny < 0)
308                     ny = -ny * ny;
309                   else
310                     ny = ny * ny;
311                   break;
312 /* #endif */
313                 default:
314                   nx = sin(nx);
315                   ny = sin(ny);
316                 }
317             }
318           if (!recurse (nx, ny, l + 1, dpy, win))
319             return 0;
320         }
321     }
322   return 1;
323 }
324
325
326 static void
327 flame (Display *dpy, Window window)
328 {
329   int i, j, k;
330   static int alt = 0;
331
332   if (!(cur_level++ % max_levels))
333     {
334       if (delay2) usleep (delay2);
335       XClearWindow (dpy, window);
336       alt = !alt;
337
338       variation = random() % MAXKINDS;
339     }
340   else
341     {
342       if (ncolors > 2)
343         {
344           XSetForeground (dpy, gc, colors [pixcol].pixel);
345           if (--pixcol < 0)
346             pixcol = ncolors - 1;
347         }
348     }
349
350   /* number of functions */
351   snum = 2 + (cur_level % (MAXLEV - 1));
352
353   /* how many of them are of alternate form */
354   if (alt)
355     anum = 0;
356   else
357     anum = halfrandom (snum) + 2;
358
359   /* 6 coefs per function */
360   for (k = 0; k < snum; k++)
361     {
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);
365     }
366   num_points = 0;
367   total_points = 0;
368   (void) recurse (0.0, 0.0, 0, dpy, window);
369   XDrawPoints (dpy, window, gc, points, num_points, CoordModeOrigin);
370   XSync (dpy, False);
371   if (delay) usleep (delay);
372 }
373
374
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.
378
379    I'm further told that HPUX 11.0 doesn't define PLOSS, and works ok without
380    this section.  Go figure.
381  */
382 #undef random
383 #undef srandom
384 #include <math.h>
385 int matherr(x)
386    register struct exception *x;
387 {
388   if (x->type == PLOSS) return 1;
389   else return 0;
390 }
391 #endif /* __hpux */
392
393
394 \f
395 char *progclass = "Flame";
396
397 char *defaults [] = {
398   ".background: black",
399   ".foreground: white",
400   "*colors:     64",
401   "*iterations: 25",
402   "*delay:      50000",
403   "*delay2:     2000000",
404   "*points:     10000",
405   0
406 };
407
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 },
414   { 0, 0, 0, 0 }
415 };
416
417 void
418 screenhack (Display *dpy, Window window)
419 {
420   init_flame (dpy, window);
421   while (1)
422     {
423       flame (dpy, window);
424       screenhack_handle_events (dpy);
425     }
426 }