http://ftp.x.org/contrib/applications/xscreensaver-2.23.tar.gz
[xscreensaver] / hacks / discrete.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* discrete --- chaotic mappings */
3
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)discrete.c 4.10 98/04/24 xlockmore";
6
7 #endif
8
9 /*-
10  * Copyright (c) 1996 by Tim Auckland <Tim.Auckland@Sun.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  * 31-Jul-97: Ported to xlockmore-4
31  * 08-Aug-96: Adapted from hop.c Copyright (c) 1991 by Patrick J. Naughton.
32  */
33
34 #ifdef STANDALONE
35 # define PROGCLASS              "Discrete"
36 # define HACK_INIT              init_discrete
37 # define HACK_DRAW              draw_discrete
38 # define discrete_opts  xlockmore_opts
39 # define SMOOTH_COLORS
40 # define BRIGHT_COLORS
41 # define DEFAULTS               "*delay:  1000 \n" \
42                                                 "*count:  4096 \n" \
43                                                 "*cycles: 2500 \n" \
44                                                 "*ncolors: 100 \n"
45
46 # include "xlockmore.h"         /* in xscreensaver distribution */
47 # include "erase.h"
48
49 #else /* STANDALONE */
50 # include "xlock.h"             /* in xlockmore distribution */
51 #endif /* STANDALONE */
52
53 ModeSpecOpt discrete_opts =
54 {0, NULL, 0, NULL, NULL};
55
56 #ifdef USE_MODULES
57 ModStruct   discrete_description =
58 {"discrete", "init_discrete", "draw_discrete", "release_discrete",
59  "refresh_discrete", "init_discrete", 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 int  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 = NULL;
105
106 void
107 init_discrete(ModeInfo * mi)
108 {
109         double      range;
110         discretestruct *hp;
111
112         if (discretes == NULL) {
113                 if ((discretes =
114                      (discretestruct *) calloc(MI_NUM_SCREENS(mi),
115                                            sizeof (discretestruct))) == NULL)
116                         return;
117         }
118         hp = &discretes[MI_SCREEN(mi)];
119
120
121         hp->maxx = MI_WIDTH(mi);
122         hp->maxy = MI_HEIGHT(mi);
123 #ifdef TEST
124         hp->op = TEST;
125 #else
126         hp->op = bias[LRAND() % BIASES];
127 #endif
128         switch (hp->op) {
129                 case HSHOE:
130                         hp->ic = 0;
131                         hp->jc = 0;
132                         hp->is = hp->maxx / (4);
133                         hp->js = hp->maxy / (4);
134                         hp->a = 0.5;
135                         hp->b = 0.5;
136                         hp->c = 0.2;
137                         hp->d = -1.25;
138                         hp->e = 1;
139                         hp->i = hp->j = 0.0;
140                         break;
141                 case DELOG:
142                         hp->ic = 0.5;
143                         hp->jc = 0.3;
144                         hp->is = hp->maxx / 1.5;
145                         hp->js = hp->maxy / 1.5;
146                         hp->a = 2.176399;
147                         hp->i = hp->j = 0.01;
148                         break;
149                 case HENON:
150                         hp->jc = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.4;
151                         hp->ic = 1.3 * (1 - (hp->jc * hp->jc) / (0.4 * 0.4));
152                         hp->is = hp->maxx;
153                         hp->js = hp->maxy * 1.5;
154                         hp->a = 1;
155                         hp->b = 1.4;
156                         hp->c = 0.3;
157                         hp->i = hp->j = 0;
158                         break;
159                 case SQRT:
160                         hp->ic = 0;
161                         hp->jc = 0;
162                         hp->is = 1;
163                         hp->js = 1;
164                         range = sqrt((double) hp->maxx * 2 * hp->maxx * 2 +
165                                      (double) hp->maxy * 2 * hp->maxy * 2) /
166                                 (10.0 + LRAND() % 10);
167
168                         hp->a = (LRAND() / MAXRAND) * range - range / 2.0;
169                         hp->b = (LRAND() / MAXRAND) * range - range / 2.0;
170                         hp->c = (LRAND() / MAXRAND) * range - range / 2.0;
171                         if (!(LRAND() % 2))
172                                 hp->c = 0.0;
173                         hp->i = hp->j = 0.0;
174                         break;
175                 case STANDARD:
176                         hp->ic = M_PI;
177                         hp->jc = M_PI;
178                         hp->is = hp->maxx / (M_PI * 2);
179                         hp->js = hp->maxy / (M_PI * 2);
180                         hp->a = 0;      /* decay */
181                         hp->b = (LRAND() / MAXRAND) * 2.0;
182                         hp->c = 0;
183                         hp->i = M_PI;
184                         hp->j = M_PI;
185                         break;
186                 case BIRDIE:
187                         hp->ic = 0;
188                         hp->jc = 0;
189                         hp->is = hp->maxx / 2;
190                         hp->js = hp->maxy / 2;
191                         hp->a = 1.99 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.2;
192                         hp->b = 0;
193                         hp->c = 0.8 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.1;
194                         hp->i = hp->j = 0;
195                         break;
196                 case TRIG:
197                         hp->a = 5;
198                         hp->b = 0.5 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.3;
199                         hp->ic = hp->a;
200                         hp->jc = 0;
201                         hp->is = hp->maxx / (hp->b * 20);
202                         hp->js = hp->maxy / (hp->b * 20);
203                         hp->i = hp->j = 0;
204                         break;
205                 case CUBIC:
206                         hp->a = 2.77;
207                         hp->b = 0.1 + ((LRAND() / MAXRAND) * 2.0 - 1.0) * 0.1;
208                         hp->ic = 0;
209                         hp->jc = 0;
210                         hp->is = hp->maxx / 4;
211                         hp->js = hp->maxy / 4;
212                         hp->i = hp->j = 0.1;
213                         break;
214                 case AILUJ:
215                         {
216                                 int         i;
217                                 double      x, y, xn, yn;
218
219                                 hp->ic = 0;
220                                 hp->jc = 0;
221                                 hp->is = hp->maxx / 4;
222                                 hp->js = hp->maxx / 4;
223                                 do {
224                                         hp->a = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 1.5 - 0.5;
225                                         hp->b = ((LRAND() / MAXRAND) * 2.0 - 1.0) * 1.5;
226                                         x = y = 0;
227 #define MAXITER 10
228                                         for (i = 0; i < MAXITER && x * x + y * y < 13; i++) {   /* 'Brot calc */
229                                                 xn = x * x - y * y + hp->a;
230                                                 yn = 2 * x * y + hp->b;
231                                                 x = xn;
232                                                 y = yn;
233                                         }
234                                 } while (i < MAXITER);  /* wait for a connected set */
235                                 hp->i = hp->j = 0.1;
236                                 break;
237                         }
238         }
239         hp->pix = 0;
240         hp->inc = 0;
241
242         if (hp->pointBuffer == NULL)
243                 hp->pointBuffer = (XPoint *) malloc(MI_COUNT(mi) * sizeof (XPoint));
244
245         /* Clear the background. */
246         MI_CLEARWINDOW(mi);
247
248         hp->count = 0;
249 }
250
251
252 void
253 draw_discrete(ModeInfo * mi)
254 {
255         Display    *dsp = MI_DISPLAY(mi);
256         Window      win = MI_WINDOW(mi);
257         double      oldj, oldi;
258         int         batchcount = MI_COUNT(mi);
259         int         cycles = MI_CYCLES(mi);
260         int         k;
261         XPoint     *xp;
262         GC          gc = MI_GC(mi);
263         discretestruct *hp = &discretes[MI_SCREEN(mi)];
264
265         k = batchcount;
266         xp = hp->pointBuffer;
267
268         hp->inc++;
269
270         if (MI_NPIXELS(mi) > 2) {
271                 XSetForeground(dsp, gc, MI_PIXEL(mi, hp->pix));
272                 if (++hp->pix >= MI_NPIXELS(mi))
273                         hp->pix = 0;
274         }
275         while (k--) {
276                 oldj = hp->j;
277                 oldi = hp->i;
278                 switch (hp->op) {
279                         case HSHOE:
280                                 {
281                                         int         i;
282
283 #if 0
284                                         if (!k) {
285                                                 XSetForeground(dsp, gc, MI_BLACK_PIXEL(mi));
286                                                 XFillRectangle(dsp, win, gc, 0, 0, hp->maxx, hp->maxy);
287                                                 XSetForeground(dsp, gc, MI_PIXEL(mi, hp->pix));
288                                         } else
289 #endif
290 #define HD
291 #ifdef HD
292                                         if (k < batchcount / 4) {
293                                                 hp->i = ((double) k / batchcount) * 8 - 1;
294                                                 hp->j = 1;
295                                         } else if (k < batchcount / 2) {
296                                                 hp->i = 1;
297                                                 hp->j = 3 - ((double) k / batchcount) * 8;
298                                         } else if (k < 3 * batchcount / 4) {
299                                                 hp->i = 5 - ((double) k / batchcount) * 8;
300                                                 hp->j = -1;
301                                         } else {
302                                                 hp->i = -1;
303                                                 hp->j = ((double) k / batchcount) * 8 - 7;
304                                         }
305                                         for (i = 1; i < (hp->inc % 15); i++) {
306                                                 oldj = hp->j;
307                                                 oldi = hp->i;
308 #endif
309                                                 hp->i = (hp->a * oldi + hp->b) * oldj;
310                                                 hp->j = (hp->e - hp->d + hp->c * oldi) * oldj * oldj - hp->c * oldi + hp->d;
311 #ifdef HD
312                                         }
313 #endif
314                                         break;
315                                 }
316                         case DELOG:
317                                 hp->j = oldi;
318                                 hp->i = hp->a * oldi * (1 - oldj);
319                                 break;
320                         case HENON:
321                                 hp->i = oldj + hp->a - hp->b * oldi * oldi;
322                                 hp->j = hp->c * oldi;
323                                 break;
324                         case SQRT:
325                                 if (k) {
326                                         hp->j = hp->a + hp->i;
327                                         hp->i = -oldj + (hp->i < 0
328                                         ? sqrt(fabs(hp->b * (hp->i - hp->c)))
329                                                          : -sqrt(fabs(hp->b * (hp->i - hp->c))));
330                                 } else {
331                                         static int  s = 1;
332
333                                         hp->i = s * hp->inc * hp->maxx / cycles / 2;
334                                         hp->j = hp->a + hp->i;
335                                         s = -s;
336                                 }
337                                 break;
338                         case STANDARD:
339                                 if (k) {
340                                         hp->j = (1 - hp->a) * oldj + hp->b * sin(oldi) + hp->a * hp->c;
341                                         hp->j = fmod(hp->j + 2 * M_PI, 2 * M_PI);
342                                         hp->i = oldi + hp->j;
343                                         hp->i = fmod(hp->i + 2 * M_PI, 2 * M_PI);
344                                 } else {
345                                         static int  s = 1;
346
347                                         hp->j = M_PI + fmod(s * hp->inc * 2 * M_PI / (cycles - 0.5), M_PI);
348                                         hp->i = M_PI;
349                                         s = -s;
350                                 }
351                                 break;
352                         case BIRDIE:
353                                 hp->j = oldi;
354                                 hp->i = (1 - hp->c) * cos(M_PI * hp->a * oldj) + hp->c * hp->b;
355                                 hp->b = oldj;
356                                 break;
357                         case TRIG:
358                                 {
359                                         double      r2 = oldi * oldi + oldj * oldj;
360
361                                         hp->i = hp->a + hp->b * (oldi * cos(r2) - oldj * sin(r2));
362                                         hp->j = hp->b * (oldj * cos(r2) + oldi * sin(r2));
363                                 }
364                                 break;
365                         case CUBIC:
366                                 hp->i = oldj;
367                                 hp->j = hp->a * oldj - oldj * oldj * oldj - hp->b * oldi;
368                                 break;
369                         case AILUJ:
370                                 hp->i = ((LRAND() < MAXRAND / 2) ? -1 : 1) *
371                                         sqrt(((oldi - hp->a) +
372                                               sqrt((oldi - hp->a) * (oldi - hp->a) + (oldj - hp->b) * (oldj - hp->b))) / 2);
373                                 hp->j = (oldj - hp->b) / (2 * hp->i);
374                                 break;
375                 }
376                 xp->x = hp->maxx / 2 + (int) ((hp->i - hp->ic) * hp->is);
377                 xp->y = hp->maxy / 2 - (int) ((hp->j - hp->jc) * hp->js);
378                 xp++;
379         }
380         XDrawPoints(dsp, win, gc, hp->pointBuffer, batchcount, CoordModeOrigin);
381         if (++hp->count > cycles) {
382 #ifdef STANDALONE
383                 erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
384 #endif /* STANDALONE */
385                 init_discrete(mi);
386         }
387 }
388
389 void
390 release_discrete(ModeInfo * mi)
391 {
392         if (discretes != NULL) {
393                 int         screen;
394
395                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
396                         discretestruct *hp = &discretes[screen];
397
398                         if (hp->pointBuffer != NULL)
399                                 (void) free((void *) hp->pointBuffer);
400                 }
401                 (void) free((void *) discretes);
402                 discretes = NULL;
403         }
404 }
405
406 void
407 refresh_discrete(ModeInfo * mi)
408 {
409         MI_CLEARWINDOW(mi);
410 }