1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* discrete --- chaotic mappings */
3 
4 #if 0
5 static const char sccsid[] = "@(#)discrete.c	5.00 2000/11/01 xlockmore";
6 
7 #endif
8 
9 /*-
10  * Copyright (c) 1996 by Tim Auckland <tda10.geo@yahoo.com>
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  * "discrete" shows a number of fractals based on the "discrete map"
25  * type of dynamical systems.  They include a different way of looking
26  * at the HOPALONG system, an inverse julia-set iteration, the "Standard
27  * Map" and the "Bird in a Thornbush" fractal.
28  *
29  * Revision History:
30  * 01-Nov-2000: Allocation checks
31  * 31-Jul-1997: Ported to xlockmore-4
32  * 08-Aug-1996: Adapted from hop.c Copyright (c) 1991 by Patrick J. Naughton.
33  */
34 
35 #ifdef STANDALONE
36 #define MODE_discrete
37 #define DEFAULTS "*delay: 1000 \n" \
38 	"*count: 4096 \n" \
39 	"*cycles: 2500 \n" \
40 	"*ncolors: 100 \n" \
41 
42 # define free_discrete 0
43 # define reshape_discrete 0
44 # define discrete_handle_event 0
45 #define SMOOTH_COLORS
46 #include "xlockmore.h"		/* in xscreensaver distribution */
47 #else /* STANDALONE */
48 #include "xlock.h"		/* in xlockmore distribution */
49 #endif /* STANDALONE */
50 
51 #ifdef MODE_discrete
52 
53 ENTRYPOINT ModeSpecOpt discrete_opts =
54 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
55 
56 #ifdef USE_MODULES
57 ModStruct   discrete_description =
58 {"discrete", "init_discrete", "draw_discrete", "release_discrete",
59  "refresh_discrete", "init_discrete", (char *) NULL, &discrete_opts,
60  1000, 4096, 2500, 1, 64, 1.0, "",
61  "Shows various discrete maps", 0, NULL};
62 
63 #endif
64 
65 enum ftypes {
66 	SQRT, BIRDIE, STANDARD, TRIG, CUBIC, HENON, AILUJ, HSHOE, DELOG
67 };
68 
69 /*#define TEST STANDARD */
70 
71 #define BIASES 18
72 static enum ftypes bias[BIASES] =
73 {
74 	STANDARD, STANDARD, STANDARD, STANDARD,
75 	SQRT, SQRT, SQRT, SQRT,
76 	BIRDIE, BIRDIE, BIRDIE,
77 	AILUJ, AILUJ, AILUJ,
78 	TRIG, TRIG,
79 	CUBIC,
80 	HENON,
81 };
82 
83 typedef struct {
84 	int         maxx;
85 	int         maxy;	/* max of the screen */
86 	double      a;
87 	double      b;
88 	double      c;
89 	double      d;
90 	double      e;
91 	double      i;
92 	double      j;		/* discrete parameters */
93 	double      ic;
94 	double      jc;
95 	double      is;
96 	double      js;
97 	int         inc;
98 	int         pix;
99 	enum ftypes op;
100 	int         count;
101 	XPoint     *pointBuffer;	/* pointer for XDrawPoints */
102 } discretestruct;
103 
104 static discretestruct *discretes = (discretestruct *) NULL;
105 
106 static void
free_discrete_screen(discretestruct * hp)107 free_discrete_screen(discretestruct *hp)
108 {
109 	if (hp == NULL) {
110 		return;
111 	}
112 	if (hp->pointBuffer != NULL) {
113 		free(hp->pointBuffer);
114 		/* hp->pointBuffer = NULL; */
115 	}
116 	hp = NULL;
117 }
118 
119 ENTRYPOINT void
init_discrete(ModeInfo * mi)120 init_discrete(ModeInfo * mi)
121 {
122 	double      range;
123 	discretestruct *hp;
124 
125 	MI_INIT(mi, discretes);
126 	hp = &discretes[MI_SCREEN(mi)];
127 
128 	hp->maxx = MI_WIDTH(mi);
129 	hp->maxy = MI_HEIGHT(mi);
130 #ifdef TEST
131 	hp->op = TEST;
132 #else
133 	hp->op = bias[LRAND() % BIASES];
134 #endif
135 	switch (hp->op) {
136 		case HSHOE:
137 			hp->ic = 0;
138 			hp->jc = 0;
139 			hp->is = hp->maxx / (4);
140 			hp->js = hp->maxy / (4);
141 			hp->a = 0.5;
142 			hp->b = 0.5;
143 			hp->c = 0.2;
144 			hp->d = -1.25;
145 			hp->e = 1;
146 			hp->i = hp->j = 0.0;
147 			break;
148 		case DELOG:
149 			hp->ic = 0.5;
150 			hp->jc = 0.3;
151 			hp->is = hp->maxx / 1.5;
152 			hp->js = hp->maxy / 1.5;
153 			hp->a = 2.176399;
154 			hp->i = hp->j = 0.01;
155 			break;
156 		case HENON:
157 			hp->jc = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.4;
158 			hp->ic = 1.3 * (1 - (hp->jc * hp->jc) / (0.4 * 0.4));
159 			hp->is = hp->maxx;
160 			hp->js = hp->maxy * 1.5;
161 			hp->a = 1;
162 			hp->b = 1.4;
163 			hp->c = 0.3;
164 			hp->i = hp->j = 0;
165 			break;
166 		case SQRT:
167 			hp->ic = 0;
168 			hp->jc = 0;
169 			hp->is = 1;
170 			hp->js = 1;
171 			range = sqrt((double) hp->maxx * 2 * hp->maxx * 2 +
172 				     (double) hp->maxy * 2 * hp->maxy * 2) /
173 				(10.0 + LRAND() % 10);
174 
175 			hp->a = (LRAND() / MAXRAND) * range - range / 2.0;
176 			hp->b = (LRAND() / MAXRAND) * range - range / 2.0;
177 			hp->c = (LRAND() / MAXRAND) * range - range / 2.0;
178 			if (!(LRAND() % 2))
179 				hp->c = 0.0;
180 			hp->i = hp->j = 0.0;
181 			break;
182 		case STANDARD:
183 			hp->ic = M_PI;
184 			hp->jc = M_PI;
185 			hp->is = hp->maxx / (M_PI * 2);
186 			hp->js = hp->maxy / (M_PI * 2);
187 			hp->a = 0;	/* decay */
188 			hp->b = (LRAND() / MAXRAND) * 2.0;
189 			hp->c = 0;
190 			hp->i = M_PI;
191 			hp->j = M_PI;
192 			break;
193 		case BIRDIE:
194 			hp->ic = 0;
195 			hp->jc = 0;
196 			hp->is = hp->maxx / 2;
197 			hp->js = hp->maxy / 2;
198 			hp->a = 1.99 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.2;
199 			hp->b = 0;
200 			hp->c = 0.8 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.1;
201 			hp->i = hp->j = 0;
202 			break;
203 		case TRIG:
204 			hp->a = 5;
205 			hp->b = 0.5 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.3;
206 			hp->ic = hp->a;
207 			hp->jc = 0;
208 			hp->is = hp->maxx / (hp->b * 20);
209 			hp->js = hp->maxy / (hp->b * 20);
210 			hp->i = hp->j = 0;
211 			break;
212 		case CUBIC:
213 			hp->a = 2.77;
214 			hp->b = 0.1 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.1;
215 			hp->ic = 0;
216 			hp->jc = 0;
217 			hp->is = hp->maxx / 4;
218 			hp->js = hp->maxy / 4;
219 			hp->i = hp->j = 0.1;
220 			break;
221 		case AILUJ:
222 			{
223 				int         i;
224 				double      x, y, xtemp, ytemp;
225 
226 				hp->ic = 0;
227 				hp->jc = 0;
228 				hp->is = hp->maxx / 4;
229 				hp->js = hp->maxx / 4;
230 				do {
231 					hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 1.5 - 0.5;
232 					hp->b = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 1.5;
233 					x = y = 0;
234 #define MAXITER 10
235 					for (i = 0; i < MAXITER && x * x + y * y < 13; i++) {	/* 'Brot calc */
236 						xtemp = x * x - y * y + hp->a;
237 						ytemp = 2 * x * y + hp->b;
238 						x = xtemp;
239 						y = ytemp;
240 					}
241 				} while (i < MAXITER);	/* wait for a connected set */
242 				hp->i = hp->j = 0.1;
243 				break;
244 			}
245 	}
246 	hp->pix = 0;
247 	hp->inc = 0;
248 
249 	if (hp->pointBuffer == NULL) {
250 		hp->pointBuffer = (XPoint *) malloc(sizeof (XPoint) * MI_COUNT(mi));
251 		/* if fails will check later */
252 	}
253 
254 	/* Clear the background. */
255 	MI_CLEARWINDOW(mi);
256 
257 	XSetForeground(MI_DISPLAY(mi), MI_GC(mi), MI_WHITE_PIXEL(mi));
258 	hp->count = 0;
259 }
260 
261 
262 ENTRYPOINT void
draw_discrete(ModeInfo * mi)263 draw_discrete(ModeInfo * mi)
264 {
265 	Display    *dsp = MI_DISPLAY(mi);
266 	Window      win = MI_WINDOW(mi);
267 	double      oldj, oldi;
268 	int         count = MI_COUNT(mi);
269 	int         cycles = MI_CYCLES(mi);
270 	int         k;
271 	XPoint     *xp;
272 	GC          gc = MI_GC(mi);
273 	discretestruct *hp;
274 
275 	if (discretes == NULL)
276 		return;
277 	hp = &discretes[MI_SCREEN(mi)];
278 	if (hp->pointBuffer == NULL)
279 		return;
280 
281 	k = count;
282 	xp = hp->pointBuffer;
283 
284 	hp->inc++;
285 
286 	MI_IS_DRAWN(mi) = True;
287 
288 	if (MI_NPIXELS(mi) > 2) {
289 		XSetForeground(dsp, gc, MI_PIXEL(mi, hp->pix));
290 		if (++hp->pix >= MI_NPIXELS(mi))
291 			hp->pix = 0;
292 	}
293 	while (k--) {
294 		oldj = hp->j;
295 		oldi = hp->i;
296 		switch (hp->op) {
297 			case HSHOE:
298 				{
299 					int         i;
300 
301 #if 0
302 					if (!k) {
303 						XSetForeground(dsp, gc, MI_BLACK_PIXEL(mi));
304 						XFillRectangle(dsp, win, gc, 0, 0, hp->maxx, hp->maxy);
305 						XSetForeground(dsp, gc, MI_PIXEL(mi, hp->pix));
306 					} else
307 #endif
308 #define HD
309 #ifdef HD
310 					if (k < count / 4) {
311 						hp->i = ((double) k / count) * 8 - 1;
312 						hp->j = 1;
313 					} else if (k < count / 2) {
314 						hp->i = 1;
315 						hp->j = 3 - ((double) k / count) * 8;
316 					} else if (k < 3 * count / 4) {
317 						hp->i = 5 - ((double) k / count) * 8;
318 						hp->j = -1;
319 					} else {
320 						hp->i = -1;
321 						hp->j = ((double) k / count) * 8 - 7;
322 					}
323 					for (i = 1; i < (hp->inc % 15); i++) {
324 						oldj = hp->j;
325 						oldi = hp->i;
326 #endif
327 						hp->i = (hp->a * oldi + hp->b) * oldj;
328 						hp->j = (hp->e - hp->d + hp->c * oldi) * oldj * oldj - hp->c * oldi + hp->d;
329 #ifdef HD
330 					}
331 #endif
332 					break;
333 				}
334 			case DELOG:
335 				hp->j = oldi;
336 				hp->i = hp->a * oldi * (1 - oldj);
337 				break;
338 			case HENON:
339 				hp->i = oldj + hp->a - hp->b * oldi * oldi;
340 				hp->j = hp->c * oldi;
341 				break;
342 			case SQRT:
343 				if (k) {
344 					hp->j = hp->a + hp->i;
345 					hp->i = -oldj + (hp->i < 0
346 					? sqrt(fabs(hp->b * (hp->i - hp->c)))
347 							 : -sqrt(fabs(hp->b * (hp->i - hp->c))));
348 				} else {
349 					static int  s = 1;
350 
351 					hp->i = s * hp->inc * hp->maxx / cycles / 2;
352 					hp->j = hp->a + hp->i;
353 					s = -s;
354 				}
355 				break;
356 			case STANDARD:
357 				if (k) {
358 					hp->j = (1 - hp->a) * oldj + hp->b * sin(oldi) + hp->a * hp->c;
359 					hp->j = fmod(hp->j + 2 * M_PI, 2 * M_PI);
360 					hp->i = oldi + hp->j;
361 					hp->i = fmod(hp->i + 2 * M_PI, 2 * M_PI);
362 				} else {
363 					static int  s = 1;
364 
365 					hp->j = M_PI + fmod(s * hp->inc * 2 * M_PI / (cycles - 0.5), M_PI);
366 					hp->i = M_PI;
367 					s = -s;
368 				}
369 				break;
370 			case BIRDIE:
371 				hp->j = oldi;
372 				hp->i = (1 - hp->c) * cos(M_PI * hp->a * oldj) + hp->c * hp->b;
373 				hp->b = oldj;
374 				break;
375 			case TRIG:
376 				{
377 					double      r2 = oldi * oldi + oldj * oldj;
378 
379 					hp->i = hp->a + hp->b * (oldi * cos(r2) - oldj * sin(r2));
380 					hp->j = hp->b * (oldj * cos(r2) + oldi * sin(r2));
381 				}
382 				break;
383 			case CUBIC:
384 				hp->i = oldj;
385 				hp->j = hp->a * oldj - oldj * oldj * oldj - hp->b * oldi;
386 				break;
387 			case AILUJ:
388 				hp->i = ((LRAND() < MAXRAND / 2) ? -1 : 1) *
389 					sqrt(((oldi - hp->a) +
390 					      sqrt((oldi - hp->a) * (oldi - hp->a) + (oldj - hp->b) * (oldj - hp->b))) / 2);
391 				if (hp->i < 0.00000001 && hp->i > -0.00000001)
392 					hp->i = (hp->i > 0.0) ? 0.00000001 : -0.00000001;
393 				hp->j = (oldj - hp->b) / (2 * hp->i);
394 				break;
395 		}
396 		xp->x = hp->maxx / 2 + (int) ((hp->i - hp->ic) * hp->is);
397 		xp->y = hp->maxy / 2 - (int) ((hp->j - hp->jc) * hp->js);
398 		xp++;
399 	}
400 	XDrawPoints(dsp, win, gc, hp->pointBuffer, count, CoordModeOrigin);
401 	if (++hp->count > cycles) {
402 		init_discrete(mi);
403 	}
404 }
405 
406 ENTRYPOINT void
release_discrete(ModeInfo * mi)407 release_discrete(ModeInfo * mi)
408 {
409 	if (discretes != NULL) {
410 		int         screen;
411 
412 		for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
413 			free_discrete_screen(&discretes[screen]);
414 		}
415 		free(discretes);
416 		discretes = (discretestruct *) NULL;
417 	}
418 }
419 
420 #ifndef STANDALONE
421 ENTRYPOINT void
refresh_discrete(ModeInfo * mi)422 refresh_discrete(ModeInfo * mi)
423 {
424 	MI_CLEARWINDOW(mi);
425 }
426 #endif
427 
428 XSCREENSAVER_MODULE ("Discrete", discrete)
429 
430 #endif /* MODE_discrete */
431