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