370ab4d7bce8c7a66cef1ee399fbc3b225aa2886
[xscreensaver] / hacks / flame.c
1 /* xscreensaver, Copyright (c) 1993 Jamie Zawinski <jwz@lucid.com>
2  *
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 
9  * implied warranty.
10  */
11
12 /* This file was ported from xlock for use in xscreensaver (and standalone)
13  * by jwz on 18-Oct-93.  Original copyright reads:
14  *
15  *   static char sccsid[] = "@(#)flame.c 1.4 91/09/27 XLOCK";
16  *
17  * flame.c - recursive fractal cosmic flames.
18  *
19  * Copyright (c) 1991 by Patrick J. Naughton.
20  *
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.
26  *
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.
32  *
33  * Comments and additions should be sent to the author:
34  *
35  *                     naughton@eng.sun.com
36  *
37  *                     Patrick J. Naughton
38  *                     MS 21-14
39  *                     Sun Laboritories, Inc.
40  *                     2550 Garcia Ave
41  *                     Mountain View, CA  94043
42  *
43  * Revision History:
44  * 27-Jun-91: vary number of functions used.
45  * 24-Jun-91: fixed portability problem with integer mod (%).
46  * 06-Jun-91: Written. (received from Scott Graves, spot@cs.cmu.edu).
47  */
48
49 #include "screenhack.h"
50
51 /*#include <math.h>*/
52
53 #define POINT_BUFFER_SIZE 10
54 #define MAXLEV 4
55
56 static double f[2][3][MAXLEV];  /* three non-homogeneous transforms */
57 static int max_total;
58 static int max_levels;
59 static int max_points;
60 static int cur_level;
61 static int snum;
62 static int anum;
63 static int num_points;
64 static int total_points;
65 static int pixcol;
66 static int npixels;
67 static unsigned long *pixels;
68 static XPoint points [POINT_BUFFER_SIZE];
69 static GC gc;
70
71 static int delay, delay2;
72 static int width, height;
73
74 static short
75 halfrandom (mv)
76      int mv;
77 {
78   static short lasthalf = 0;
79   unsigned long r;
80
81   if (lasthalf)
82     {
83       r = lasthalf;
84       lasthalf = 0;
85     }
86   else
87     {
88       r = random ();
89       lasthalf = r >> 16;
90     }
91   return (r % mv);
92 }
93
94
95 static void
96 init_flame (dpy, window)
97      Display *dpy;
98      Window window;
99 {
100   int i;
101   XGCValues gcv;
102   XWindowAttributes xgwa;
103   Colormap cmap;
104   XGetWindowAttributes (dpy, window, &xgwa);
105   width = xgwa.width;
106   height = xgwa.height;
107   cmap = xgwa.colormap;
108
109   max_points = get_integer_resource ("iterations", "Integer");
110   if (max_points <= 0) max_points = 100;
111
112   max_levels = max_points;
113
114   max_total = get_integer_resource ("points", "Integer");
115   if (max_total <= 0) max_total = 10000;
116
117   delay = get_integer_resource ("delay", "Integer");
118   if (delay < 0) delay = 0;
119   delay2 = get_integer_resource ("delay2", "Integer");
120   if (delay2 < 0) delay2 = 0;
121
122   if (mono_p)
123     npixels = 0;
124   else
125     {
126       int i = get_integer_resource ("ncolors", "Integer");
127       double saturation = 1.0;
128       double value = 1.0;
129       XColor color;
130       if (i <= 0) i = 128;
131
132       pixels = (unsigned long *) malloc ((i+1) * sizeof (*pixels));
133       for (npixels = 0; npixels < i; npixels++)
134         {
135           hsv_to_rgb ((360*npixels)/i, saturation, value,
136                       &color.red, &color.green, &color.blue);
137           if (! XAllocColor (dpy, cmap, &color))
138             break;
139           pixels [npixels] = color.pixel;
140         }
141     }
142
143   gcv.foreground = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
144   gcv.background = get_pixel_resource ("background", "Background", dpy, cmap);
145
146   if (! mono_p)
147     {
148       pixcol = halfrandom (npixels);
149       gcv.foreground = (pixels [pixcol]);
150     }
151
152   gc = XCreateGC (dpy, window, GCForeground | GCBackground, &gcv);
153 }
154
155 static int
156 recurse (x, y, l, dpy, win)
157      register double x, y;
158      register int l;
159      Display *dpy;
160      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, True); */
182             }
183         }
184     }
185   else
186     {
187       for (i = 0; i < snum; i++)
188         {
189           nx = f[0][0][i] * x + f[0][1][i] * y + f[0][2][i];
190           ny = f[1][0][i] * x + f[1][1][i] * y + f[1][2][i];
191           if (i < anum)
192             {
193               nx = sin(nx);
194               ny = sin(ny);
195             }
196           if (!recurse (nx, ny, l + 1, dpy, win))
197             return 0;
198         }
199     }
200   return 1;
201 }
202
203
204 static void
205 flame (dpy, window)
206      Display *dpy;
207      Window window;
208 {
209   int i, j, k;
210   static int alt = 0;
211
212   if (!(cur_level++ % max_levels))
213     {
214       if (delay2) usleep (delay2);
215       XClearWindow (dpy, window);
216       alt = !alt;
217     }
218   else
219     {
220       if (npixels > 2)
221         {
222           XSetForeground (dpy, gc, pixels [pixcol]);
223           if (--pixcol < 0)
224             pixcol = npixels - 1;
225         }
226     }
227
228   /* number of functions */
229   snum = 2 + (cur_level % (MAXLEV - 1));
230
231   /* how many of them are of alternate form */
232   if (alt)
233     anum = 0;
234   else
235     anum = halfrandom (snum) + 2;
236
237   /* 6 coefs per function */
238   for (k = 0; k < snum; k++)
239     {
240       for (i = 0; i < 2; i++)
241         for (j = 0; j < 3; j++)
242           f[i][j][k] = ((double) (random() & 1023) / 512.0 - 1.0);
243     }
244   num_points = 0;
245   total_points = 0;
246   (void) recurse (0.0, 0.0, 0, dpy, window);
247   XDrawPoints (dpy, window, gc, points, num_points, CoordModeOrigin);
248   XSync (dpy, True);
249   if (delay) usleep (delay);
250 }
251
252 \f
253 char *progclass = "Flame";
254
255 char *defaults [] = {
256   "*background: black",
257   "*foreground: white",
258   "*colors:     128",
259   "*iterations: 25",
260   "*delay:      50000",
261   "*delay2:     2000000",
262   "*points:     10000",
263   0
264 };
265
266 XrmOptionDescRec options [] = {
267   { "-ncolors",         ".colors",      XrmoptionSepArg, 0 },
268   { "-iterations",      ".iterations",  XrmoptionSepArg, 0 },
269   { "-delay",           ".delay",       XrmoptionSepArg, 0 },
270   { "-delay2",          ".delay2",      XrmoptionSepArg, 0 },
271   { "-points",          ".points",      XrmoptionSepArg, 0 }
272 };
273 int options_size = (sizeof (options) / sizeof (options[0]));
274
275 void
276 screenhack (dpy, window)
277      Display *dpy;
278      Window window;
279 {
280   init_flame (dpy, window);
281   while (1)
282     flame (dpy, window);
283 }