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