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