http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / strange.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* strange --- strange attractors */
3
4 #if 0
5 static const char sccsid[] = "@(#)strange.c     5.00 2000/11/01 xlockmore";
6 #endif
7
8 /*-
9  * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
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  * Revision History:
24  * 01-Nov-2000: Allocation checks
25  * 10-May-1997: jwz@jwz.org: turned into a standalone program.
26  *              Made it render into an offscreen bitmap and then copy
27  *              that onto the screen, to reduce flicker.
28  *
29  * strange attractors are not so hard to find...
30  */
31
32 #ifdef STANDALONE
33 #define MODE_strange
34 #define PROGCLASS "Strange"
35 #define HACK_INIT init_strange
36 #define HACK_DRAW draw_strange
37 #define strange_opts xlockmore_opts
38 #define DEFAULTS "*delay: 2000 \n" \
39  "*ncolors: 100 \n"
40 #define SMOOTH_COLORS
41 #include "xlockmore.h"          /* from the xscreensaver distribution */
42 #else /* !STANDALONE */
43 #include "xlock.h"              /* from the xlockmore distribution */
44 #endif /* !STANDALONE */
45
46 #ifdef MODE_strange
47
48 ModeSpecOpt strange_opts =
49 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
50
51 #ifdef USE_MODULES
52 ModStruct   strange_description =
53 {"strange", "init_strange", "draw_strange", "release_strange",
54  "init_strange", "init_strange", (char *) NULL, &strange_opts,
55  1000, 1, 1, 1, 64, 1.0, "",
56  "Shows strange attractors", 0, NULL};
57
58 #endif
59
60 typedef float DBL;
61 typedef int PRM;
62
63 #define UNIT (1<<12)
64 #define UNIT2 (1<<14)
65 /* #define UNIT2 (3140*UNIT/1000) */
66
67 #define SKIP_FIRST      100
68 #define MAX_POINTS      5500
69 #define DBL_To_PRM(x)  (PRM)( (DBL)(UNIT)*(x) )
70
71
72 #define DO_FOLD(a) (a)<0 ? -A->Fold[ (-(a))&(UNIT2-1) ] : A->Fold[ (a)&(UNIT2-1) ]
73
74 #if 0
75 #define DO_FOLD(a) (a)<-UNIT2 ? -A->Fold[(-(a))%UNIT2] : (a)<0 ? -A->Fold[ -(a) ] :\
76 (a)>UNIT2 ? A->Fold[ (a)%UNIT2 ] : A->Fold[ (a) ]
77 #define DO_FOLD(a) DBL_To_PRM( sin( (DBL)(a)/UNIT ) )
78 #define DO_FOLD(a) (a)<0 ? DBL_To_PRM( exp( 16.0*(a)/UNIT2 ) )-1.0 : \
79 DBL_To_PRM( 1.0-exp( -16.0*(a)/UNIT2 ) )
80 #endif
81
82 /******************************************************************/
83
84 #define MAX_PRM 3*5
85
86 typedef struct _ATTRACTOR {
87         DBL         Prm1[MAX_PRM], Prm2[MAX_PRM];
88         PRM         Prm[MAX_PRM], *Fold;
89         void        (*Iterate) (struct _ATTRACTOR *, PRM, PRM, PRM *, PRM *);
90         XPoint     *Buffer1, *Buffer2;
91         int         Cur_Pt, Max_Pt;
92         int         Col, Count, Speed;
93         int         Width, Height;
94         Pixmap      dbuf;       /* jwz */
95         GC          dbuf_gc;
96 } ATTRACTOR;
97
98 static ATTRACTOR *Root = (ATTRACTOR *) NULL; 
99
100 static DBL  Amp_Prm[MAX_PRM] =
101 {
102         1.0, 3.5, 3.5, 2.5, 4.7,
103         1.0, 3.5, 3.6, 2.5, 4.7,
104         1.0, 1.5, 2.2, 2.1, 3.5
105 };
106 static DBL  Mid_Prm[MAX_PRM] =
107 {
108         0.0, 1.5, 0.0, .5, 1.5,
109         0.0, 1.5, 0.0, .5, 1.5,
110         0.0, 1.5, -1.0, -.5, 2.5,
111 };
112
113 static      DBL
114 Gauss_Rand(DBL c, DBL A, DBL S)
115 {
116         DBL         y;
117
118         y = (DBL) LRAND() / MAXRAND;
119         y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
120         if (NRAND(2))
121                 return (c + y);
122         else
123                 return (c - y);
124 }
125
126 static void
127 Random_Prm(DBL * Prm)
128 {
129         int         i;
130
131         for (i = 0; i < MAX_PRM; ++i)
132                 Prm[i] = Gauss_Rand(Mid_Prm[i], Amp_Prm[i], 4.0);
133 }
134
135 /***************************************************************/
136
137    /* 2 examples of non-linear map */
138
139 static void
140 Iterate_X2(ATTRACTOR * A, PRM x, PRM y, PRM * xo, PRM * yo)
141 {
142         PRM         xx, yy, xy, x2y, y2x, Tmp;
143
144         xx = (x * x) / UNIT;
145         x2y = (xx * y) / UNIT;
146         yy = (y * y) / UNIT;
147         y2x = (yy * x) / UNIT;
148         xy = (x * y) / UNIT;
149
150         Tmp = A->Prm[1] * xx + A->Prm[2] * xy + A->Prm[3] * yy + A->Prm[4] * x2y;
151         Tmp = A->Prm[0] - y + (Tmp / UNIT);
152         *xo = DO_FOLD(Tmp);
153         Tmp = A->Prm[6] * xx + A->Prm[7] * xy + A->Prm[8] * yy + A->Prm[9] * y2x;
154         Tmp = A->Prm[5] + x + (Tmp / UNIT);
155         *yo = DO_FOLD(Tmp);
156 }
157
158 static void
159 Iterate_X3(ATTRACTOR * A, PRM x, PRM y, PRM * xo, PRM * yo)
160 {
161         PRM         xx, yy, xy, x2y, y2x, Tmp_x, Tmp_y, Tmp_z;
162
163         xx = (x * x) / UNIT;
164         x2y = (xx * y) / UNIT;
165         yy = (y * y) / UNIT;
166         y2x = (yy * x) / UNIT;
167         xy = (x * y) / UNIT;
168
169         Tmp_x = A->Prm[1] * xx + A->Prm[2] * xy + A->Prm[3] * yy + A->Prm[4] * x2y;
170         Tmp_x = A->Prm[0] - y + (Tmp_x / UNIT);
171         Tmp_x = DO_FOLD(Tmp_x);
172
173         Tmp_y = A->Prm[6] * xx + A->Prm[7] * xy + A->Prm[8] * yy + A->Prm[9] * y2x;
174         Tmp_y = A->Prm[5] + x + (Tmp_y / UNIT);
175
176         Tmp_y = DO_FOLD(Tmp_y);
177
178         Tmp_z = A->Prm[11] * xx + A->Prm[12] * xy + A->Prm[13] * yy + A->Prm[14] * y2x;
179         Tmp_z = A->Prm[10] + x + (Tmp_z / UNIT);
180         Tmp_z = UNIT + Tmp_z * Tmp_z / UNIT;
181
182         *xo = (Tmp_x * UNIT) / Tmp_z;
183         *yo = (Tmp_y * UNIT) / Tmp_z;
184 }
185
186 static void (*Funcs[2]) (ATTRACTOR *, PRM, PRM, PRM *, PRM *) = {
187         Iterate_X2, Iterate_X3
188 };
189
190 /***************************************************************/
191
192 static void
193 free_strange(Display *display, ATTRACTOR *A)
194 {
195         if (A->Buffer1 != NULL) {
196                 (void) free((void *) A->Buffer1);
197                 A->Buffer1 = (XPoint *) NULL;
198         }
199         if (A->Buffer2 != NULL) {
200                 (void) free((void *) A->Buffer2);
201                 A->Buffer2 = (XPoint *) NULL;
202         }
203         if (A->dbuf) {
204                 XFreePixmap(display, A->dbuf);
205                 A->dbuf = None;
206         }
207         if (A->dbuf_gc) {
208                 XFreeGC(display, A->dbuf_gc);
209                 A->dbuf_gc = None;
210         }
211         if (A->Fold != NULL) {
212                 (void) free((void *) A->Fold);
213                 A->Fold = (PRM *) NULL;
214         }
215 }
216
217 void
218 draw_strange(ModeInfo * mi)
219 {
220         int         i, j, n, Cur_Pt;
221         PRM         x, y, xo, yo;
222         DBL         u;
223         XPoint     *Buf;
224         Display    *display = MI_DISPLAY(mi);
225         Window      window = MI_WINDOW(mi);
226         GC          gc = MI_GC(mi);
227         DBL         Lx, Ly;
228         void        (*Iterate) (ATTRACTOR *, PRM, PRM, PRM *, PRM *);
229         PRM         xmin, xmax, ymin, ymax;
230         ATTRACTOR  *A;
231
232         if (Root == NULL)
233                 return;
234         A = &Root[MI_SCREEN(mi)];
235         if (A->Fold == NULL)
236                 return;
237
238         Cur_Pt = A->Cur_Pt;
239         Iterate = A->Iterate;
240
241         u = (DBL) (A->Count) / 1000.0;
242         for (j = MAX_PRM - 1; j >= 0; --j)
243                 A->Prm[j] = DBL_To_PRM((1.0 - u) * A->Prm1[j] + u * A->Prm2[j]);
244
245         x = y = DBL_To_PRM(.0);
246         for (n = SKIP_FIRST; n; --n) {
247                 (*Iterate) (A, x, y, &xo, &yo);
248                 x = xo + NRAND(8) - 4;
249                 y = yo + NRAND(8) - 4;
250         }
251
252         xmax = 0;
253         xmin = UNIT * 4;
254         ymax = 0;
255         ymin = UNIT * 4;
256         A->Cur_Pt = 0;
257         Buf = A->Buffer2;
258         Lx = (DBL) A->Width / UNIT / 2.2;
259         Ly = (DBL) A->Height / UNIT / 2.2;
260         for (n = A->Max_Pt; n; --n) {
261                 (*Iterate) (A, x, y, &xo, &yo);
262                 Buf->x = (int) (Lx * (x + DBL_To_PRM(1.1)));
263                 Buf->y = (int) (Ly * (DBL_To_PRM(1.1) - y));
264                 /* (void) fprintf( stderr, "X,Y: %d %d    ", Buf->x, Buf->y ); */
265                 Buf++;
266                 A->Cur_Pt++;
267                 if (xo > xmax)
268                         xmax = xo;
269                 else if (xo < xmin)
270                         xmin = xo;
271                 if (yo > ymax)
272                         ymax = yo;
273                 else if (yo < ymin)
274                         ymin = yo;
275                 x = xo + NRAND(8) - 4;
276                 y = yo + NRAND(8) - 4;
277         }
278
279         MI_IS_DRAWN(mi) = True;
280
281         XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
282
283         if (A->dbuf != None) {          /* jwz */
284                 XSetForeground(display, A->dbuf_gc, 0);
285 /* XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer1,
286    Cur_Pt,CoordModeOrigin); */
287                 XFillRectangle(display, A->dbuf, A->dbuf_gc, 0, 0, A->Width, A->Height);
288         } else
289                 XDrawPoints(display, window, gc, A->Buffer1, Cur_Pt, CoordModeOrigin);
290
291         if (MI_NPIXELS(mi) < 2)
292                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
293         else
294                 XSetForeground(display, gc, MI_PIXEL(mi, A->Col % MI_NPIXELS(mi)));
295
296         if (A->dbuf != None) {
297                 XSetForeground(display, A->dbuf_gc, 1);
298                 XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer2, A->Cur_Pt,
299                             CoordModeOrigin);
300                 XCopyPlane(display, A->dbuf, window, gc, 0, 0, A->Width, A->Height, 0, 0, 1);
301         } else
302                 XDrawPoints(display, window, gc, A->Buffer2, A->Cur_Pt, CoordModeOrigin);
303
304         Buf = A->Buffer1;
305         A->Buffer1 = A->Buffer2;
306         A->Buffer2 = Buf;
307
308         if ((xmax - xmin < DBL_To_PRM(.2)) && (ymax - ymin < DBL_To_PRM(.2)))
309                 A->Count += 4 * A->Speed;
310         else
311                 A->Count += A->Speed;
312         if (A->Count >= 1000) {
313                 for (i = MAX_PRM - 1; i >= 0; --i)
314                         A->Prm1[i] = A->Prm2[i];
315                 Random_Prm(A->Prm2);
316                 A->Count = 0;
317         }
318         A->Col++;
319 }
320
321
322 /***************************************************************/
323
324 void
325 init_strange(ModeInfo * mi)
326 {
327         Display    *display = MI_DISPLAY(mi);
328         Window      window = MI_WINDOW(mi);
329         GC          gc = MI_GC(mi);
330         ATTRACTOR  *Attractor;
331
332         if (Root == NULL) {
333                 if ((Root = (ATTRACTOR *) calloc(MI_NUM_SCREENS(mi),
334                                 sizeof (ATTRACTOR))) == NULL)
335                         return;
336         }
337         Attractor = &Root[MI_SCREEN(mi)];
338
339         if (Attractor->Fold == NULL) {
340                 int         i;
341
342                 if ((Attractor->Fold = (PRM *) calloc(UNIT2 + 1,
343                                 sizeof (PRM))) == NULL) {
344                         free_strange(display, Attractor);
345                         return;
346                 }
347                 for (i = 0; i <= UNIT2; ++i) {
348                         DBL         x;
349
350                         /* x = ( DBL )(i)/UNIT2; */
351                         /* x = sin( M_PI/2.0*x ); */
352                         /* x = sqrt( x ); */
353                         /* x = x*x; */
354                         /* x = x*(1.0-x)*4.0; */
355                         x = (DBL) (i) / UNIT;
356                         x = sin(x);
357                         Attractor->Fold[i] = DBL_To_PRM(x);
358                 }
359         }
360         if (Attractor->Buffer1 == NULL)
361                 if ((Attractor->Buffer1 = (XPoint *) calloc(MAX_POINTS,
362                                 sizeof (XPoint))) == NULL) {
363                         free_strange(display, Attractor);
364                         return;
365                 }
366         if (Attractor->Buffer2 == NULL)
367                 if ((Attractor->Buffer2 = (XPoint *) calloc(MAX_POINTS,
368                                 sizeof (XPoint))) == NULL) {
369                         free_strange(display, Attractor);
370                         return;
371                 }
372         Attractor->Max_Pt = MAX_POINTS;
373
374         Attractor->Width = MI_WIDTH(mi);
375         Attractor->Height = MI_HEIGHT(mi);
376         Attractor->Cur_Pt = 0;
377         Attractor->Count = 0;
378         Attractor->Col = NRAND(MI_NPIXELS(mi));
379         Attractor->Speed = 4;
380
381         Attractor->Iterate = Funcs[NRAND(2)];
382         Random_Prm(Attractor->Prm1);
383         Random_Prm(Attractor->Prm2);
384 #ifndef NO_DBUF
385         if (Attractor->dbuf != None)
386                 XFreePixmap(display, Attractor->dbuf);
387         Attractor->dbuf = XCreatePixmap(display, window,
388              Attractor->Width, Attractor->Height, 1);
389         /* Allocation checked */
390         if (Attractor->dbuf != None) {
391                 XGCValues   gcv;
392
393                 gcv.foreground = 0;
394                 gcv.background = 0;
395                 gcv.graphics_exposures = False;
396                 gcv.function = GXcopy;
397
398                 if (Attractor->dbuf_gc != None)
399                         XFreeGC(display, Attractor->dbuf_gc);
400
401                 if ((Attractor->dbuf_gc = XCreateGC(display, Attractor->dbuf,
402                                 GCForeground | GCBackground | GCGraphicsExposures | GCFunction,
403                                 &gcv)) == None) {
404                         XFreePixmap(display, Attractor->dbuf);
405                         Attractor->dbuf = None;
406                 } else {
407                         XFillRectangle(display, Attractor->dbuf, Attractor->dbuf_gc,
408                                 0, 0, Attractor->Width, Attractor->Height);
409                         XSetBackground(display, gc, MI_BLACK_PIXEL(mi));
410                         XSetFunction(display, gc, GXcopy);
411                 }
412         }
413 #endif
414
415         MI_CLEARWINDOW(mi);
416
417         /* Do not want any exposure events from XCopyPlane */
418         XSetGraphicsExposures(display, MI_GC(mi), False);
419 }
420
421 /***************************************************************/
422
423 void
424 release_strange(ModeInfo * mi)
425 {
426         if (Root != NULL) {
427                 int         screen;
428
429                 for (screen = 0; screen < MI_NUM_SCREENS(mi); ++screen)
430                         free_strange(MI_DISPLAY(mi), &Root[screen]);
431                 (void) free((void *) Root);
432                 Root = (ATTRACTOR *) NULL; 
433         }
434 }
435
436 #endif /* MODE_strange */