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