1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* flame --- recursive fractal cosmic flames */
3
4 #if 0
5 static const char sccsid[] = "@(#)flame.c 5.00 2000/11/01 xlockmore";
6
7 #endif
8
9 /*-
10 * Copyright (c) 1991 by Patrick J. Naughton.
11 *
12 * Permission to use, copy, modify, and distribute this software and its
13 * documentation for any purpose and without fee is hereby granted,
14 * provided that the above copyright notice appear in all copies and that
15 * both that copyright notice and this permission notice appear in
16 * supporting documentation.
17 *
18 * This file is provided AS IS with no warranties of any kind. The author
19 * shall have no liability with respect to the infringement of copyrights,
20 * trade secrets or any patents by this file or any part thereof. In no
21 * event will the author be liable for any lost revenue or profits or
22 * other special, indirect and consequential damages.
23 *
24 * Revision History:
25 * 01-Nov-2000: Allocation checks
26 * 10-May-1997: Compatible with xscreensaver
27 * 11-Aug-1995: Got rid of polynomial since it was crashing xlock on some
28 * machines.
29 * 01-Jun-1995: This should look more like the original with some updates by
30 * Scott Draves.
31 * 27-Jun-1991: vary number of functions used.
32 * 24-Jun-1991: fixed portability problem with integer mod (%).
33 * 06-Jun-1991: Written, received from Scott Draves <spot@cs.cmu.edu>
34 */
35
36 #ifdef STANDALONE
37 #define MODE_flame
38 #define DEFAULTS "*delay: 750000 \n" \
39 "*count: 20 \n" \
40 "*cycles: 10000 \n" \
41 "*ncolors: 200 \n" \
42
43 # define free_flame 0
44 # define reshape_flame 0
45 # define flame_handle_event 0
46 #define UNIFORM_COLORS
47 #define BRIGHT_COLORS
48 #include "xlockmore.h" /* in xscreensaver distribution */
49 #else /* STANDALONE */
50 #include "xlock.h" /* in xlockmore distribution */
51
52 #endif /* STANDALONE */
53
54 #ifdef MODE_flame
55
56 ENTRYPOINT ModeSpecOpt flame_opts =
57 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
58
59 #ifdef USE_MODULES
60 ModStruct flame_description =
61 {"flame", "init_flame", "draw_flame", "release_flame",
62 "refresh_flame", "init_flame", (char *) NULL, &flame_opts,
63 750000, 20, 10000, 1, 64, 1.0, "",
64 "Shows cosmic flame fractals", 0, NULL};
65
66 #endif
67
68 #define MAXLEV 4
69 #define MAXKINDS 9
70 #define MAXBATCH 12
71
72 typedef struct {
73 double f[2][3][MAXLEV]; /* three non-homogeneous transforms */
74 int variation;
75 int max_levels;
76 int cur_level;
77 int snum;
78 int anum;
79 int width, height;
80 int num_points;
81 int total_points;
82 int pixcol;
83 int cycles;
84 int alt;
85 XPoint pts[MAXBATCH];
86 short lasthalf;
87 } flamestruct;
88
89 static flamestruct *flames = (flamestruct *) NULL;
90
91 static short
halfrandom(flamestruct * fp,int mv)92 halfrandom(flamestruct * fp, int mv)
93 {
94 unsigned long r;
95
96 if (fp->lasthalf) {
97 r = fp->lasthalf;
98 fp->lasthalf = 0;
99 } else {
100 r = LRAND();
101 fp->lasthalf = (short) (r >> 16);
102 }
103 return r % mv;
104 }
105
106 static Bool
recurse(ModeInfo * mi,flamestruct * fp,register double x,register double y,register int l)107 recurse(ModeInfo * mi, flamestruct * fp,
108 register double x, register double y, register int l)
109 {
110 int i;
111 double nx, ny;
112
113 if (l == fp->max_levels) {
114 fp->total_points++;
115 if (fp->total_points > fp->cycles) /* how long each fractal runs */
116 return False;
117
118 if (x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0) {
119 fp->pts[fp->num_points].x = (int) ((fp->width / 2) * (x + 1.0));
120 fp->pts[fp->num_points].y = (int) ((fp->height / 2) * (y + 1.0));
121 fp->num_points++;
122 if (fp->num_points >= MAXBATCH) { /* point buffer size */
123 XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), fp->pts,
124 fp->num_points, CoordModeOrigin);
125 fp->num_points = 0;
126 }
127 }
128 } else {
129 for (i = 0; i < fp->snum; i++) {
130 nx = fp->f[0][0][i] * x + fp->f[0][1][i] * y + fp->f[0][2][i];
131 ny = fp->f[1][0][i] * x + fp->f[1][1][i] * y + fp->f[1][2][i];
132 if (i < fp->anum) {
133 switch (fp->variation) {
134 case 0: /* sinusoidal */
135 nx = sin(nx);
136 ny = sin(ny);
137 break;
138 case 1: /* complex */
139 {
140 double r2 = nx * nx + ny * ny + 1e-6;
141
142 nx = nx / r2;
143 ny = ny / r2;
144 }
145 break;
146 case 2: /* bent */
147 if (nx < 0.0)
148 nx = nx * 2.0;
149 if (ny < 0.0)
150 ny = ny / 2.0;
151 break;
152 case 3: /* swirl */
153 {
154 double r = (nx * nx + ny * ny); /* times k here is fun */
155 double c1 = sin(r);
156 double c2 = cos(r);
157 double t = nx;
158
159 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
160 ny = 1e4;
161 else
162 ny = c2 * t + c1 * ny;
163 nx = c1 * nx - c2 * ny;
164 }
165 break;
166 case 4: /* horseshoe */
167 {
168 double r, c1,
169 c2,
170 t;
171
172 /* Avoid atan2: DOMAIN error message */
173 if (nx == 0.0 && ny == 0.0)
174 r = 0.0;
175 else
176 r = atan2(nx, ny); /* times k here is fun */
177 c1 = sin(r);
178 c2 = cos(r);
179 t = nx;
180
181 nx = c1 * nx - c2 * ny;
182 ny = c2 * t + c1 * ny;
183 }
184 break;
185 case 5: /* drape */
186 {
187 double t;
188
189 /* Avoid atan2: DOMAIN error message */
190 if (nx == 0.0 && ny == 0.0)
191 t = 0.0;
192 else
193 t = atan2(nx, ny) / M_PI;
194
195 if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
196 ny = 1e4;
197 else
198 ny = sqrt(nx * nx + ny * ny) - 1.0;
199 nx = t;
200 }
201 break;
202 case 6: /* broken */
203 if (nx > 1.0)
204 nx = nx - 1.0;
205 if (nx < -1.0)
206 nx = nx + 1.0;
207 if (ny > 1.0)
208 ny = ny - 1.0;
209 if (ny < -1.0)
210 ny = ny + 1.0;
211 break;
212 case 7: /* spherical */
213 {
214 double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
215
216 nx = nx / r;
217 ny = ny / r;
218 }
219 break;
220 case 8: /* */
221 nx = atan(nx) / M_PI_2;
222 ny = atan(ny) / M_PI_2;
223 break;
224 #if 0
225 /* core dumps on some machines, why not all? */
226 case 9: /* complex sine */
227 {
228 double u = nx,
229 v = ny;
230 double ev = exp(v);
231 double emv = exp(-v);
232
233 nx = (ev + emv) * sin(u) / 2.0;
234 ny = (ev - emv) * cos(u) / 2.0;
235 }
236 break;
237 case 10: /* polynomial */
238 if (nx < 0)
239 nx = -nx * nx;
240 else
241 nx = nx * nx;
242 if (ny < 0)
243 ny = -ny * ny;
244 else
245 ny = ny * ny;
246 break;
247 #endif
248 default:
249 nx = sin(nx);
250 ny = sin(ny);
251 }
252 }
253 if (!recurse(mi, fp, nx, ny, l + 1))
254 return False;
255 }
256 }
257 return True;
258 }
259
260 ENTRYPOINT void
init_flame(ModeInfo * mi)261 init_flame(ModeInfo * mi)
262 {
263 Display *display = MI_DISPLAY(mi);
264 GC gc = MI_GC(mi);
265 flamestruct *fp;
266
267 MI_INIT(mi, flames);
268 fp = &flames[MI_SCREEN(mi)];
269
270 fp->width = MI_WIDTH(mi);
271 fp->height = MI_HEIGHT(mi);
272 if (MI_COUNT(mi) < 1)
273 fp->max_levels = 1;
274 else
275 fp->max_levels = MI_COUNT(mi);
276 fp->cycles = MI_CYCLES(mi);
277
278 MI_CLEARWINDOW(mi);
279
280 if (MI_NPIXELS(mi) > 2) {
281 fp->pixcol = halfrandom(fp, MI_NPIXELS(mi));
282 XSetForeground(display, gc, MI_PIXEL(mi, fp->pixcol));
283 } else {
284 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
285 }
286 fp->variation = NRAND(MAXKINDS);
287 }
288
289 ENTRYPOINT void
draw_flame(ModeInfo * mi)290 draw_flame(ModeInfo * mi)
291 {
292 Display *display = MI_DISPLAY(mi);
293 int i, j, k;
294 flamestruct *fp;
295
296 if (flames == NULL)
297 return;
298 fp = &flames[MI_SCREEN(mi)];
299
300 if (!(fp->cur_level++ % fp->max_levels)) {
301 MI_CLEARWINDOW(mi);
302 if (MI_NPIXELS(mi) <= 2)
303 XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
304 fp->alt = !fp->alt;
305 } else {
306 if (MI_NPIXELS(mi) > 2) {
307 XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, fp->pixcol));
308 if (--fp->pixcol < 0)
309 fp->pixcol = MI_NPIXELS(mi) - 1;
310 }
311 }
312
313 MI_IS_DRAWN(mi) = True;
314
315 /* number of functions */
316 fp->snum = 2 + (fp->cur_level % (MAXLEV - 1));
317
318 /* how many of them are of alternate form */
319 if (fp->alt)
320 fp->anum = 0;
321 else
322 fp->anum = halfrandom(fp, fp->snum) + 2;
323
324 /* 6 coefs per function */
325 for (k = 0; k < fp->snum; k++) {
326 for (i = 0; i < 2; i++)
327 for (j = 0; j < 3; j++)
328 fp->f[i][j][k] = ((double) (LRAND() & 1023) / 512.0 - 1.0);
329 }
330 fp->num_points = 0;
331 fp->total_points = 0;
332 (void) recurse(mi, fp, 0.0, 0.0, 0);
333 XDrawPoints(display, MI_WINDOW(mi), MI_GC(mi),
334 fp->pts, fp->num_points, CoordModeOrigin);
335 }
336
337 ENTRYPOINT void
release_flame(ModeInfo * mi)338 release_flame(ModeInfo * mi)
339 {
340 if (flames != NULL) {
341 free(flames);
342 flames = (flamestruct *) NULL;
343 }
344 }
345
346 #ifndef STANDALONE
347 ENTRYPOINT void
refresh_flame(ModeInfo * mi)348 refresh_flame(ModeInfo * mi)
349 {
350 MI_CLEARWINDOW(mi);
351 }
352 #endif
353
354 XSCREENSAVER_MODULE ("Flame", flame)
355
356 #endif /* MODE_flame */
357