source: trunk/third/xscreensaver/hacks/flame.c @ 15683

Revision 15683, 10.0 KB checked in by ghudson, 24 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r15682, which included commits to RCS files with non-trunk default branches.
Line 
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
61static double f[2][3][MAXLEV];  /* three non-homogeneous transforms */
62static int max_total;
63static int max_levels;
64static int max_points;
65static int cur_level;
66static int variation;
67static int snum;
68static int anum;
69static int num_points;
70static int total_points;
71static int pixcol;
72static int ncolors;
73static XColor *colors;
74static XPoint points [POINT_BUFFER_SIZE];
75static GC gc;
76
77static int delay, delay2;
78static int width, height;
79
80static short
81halfrandom (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
99static void
100init_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
159static int
160recurse (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
326static void
327flame (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>
385int 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
395char *progclass = "Flame";
396
397char *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
408XrmOptionDescRec 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
417void
418screenhack (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}
Note: See TracBrowser for help on using the repository browser.