1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* strange --- strange attractors */
5 static const char sccsid[] = "@(#)strange.c 5.00 2000/11/01 xlockmore";
9 * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
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.
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.
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.
29 * strange attractors are not so hard to find...
34 # define DEFAULTS "*delay: 2000 \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 */
47 ENTRYPOINT ModeSpecOpt strange_opts =
48 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
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};
68 /* #define UNIT2 (3140*UNIT/1000) */
70 #define SKIP_FIRST 100
71 #define MAX_POINTS 5500
72 #define DBL_To_PRM(x) (PRM)( (DBL)(UNIT)*(x) )
75 #define DO_FOLD(a) (a)<0 ? -A->Fold[ (-(a))&(UNIT2-1) ] : A->Fold[ (a)&(UNIT2-1) ]
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 ) )
85 /******************************************************************/
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;
95 int Col, Count, Speed;
97 Pixmap dbuf; /* jwz */
101 static ATTRACTOR *Root = (ATTRACTOR *) NULL;
103 static DBL Amp_Prm[MAX_PRM] =
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
109 static DBL Mid_Prm[MAX_PRM] =
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,
117 Gauss_Rand(DBL c, DBL A, DBL S)
121 y = (DBL) LRAND() / MAXRAND;
122 y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
130 Random_Prm(DBL * Prm)
134 for (i = 0; i < MAX_PRM; ++i)
135 Prm[i] = Gauss_Rand(Mid_Prm[i], Amp_Prm[i], 4.0);
138 /***************************************************************/
140 /* 2 examples of non-linear map */
143 Iterate_X2(ATTRACTOR * A, PRM x, PRM y, PRM * xo, PRM * yo)
145 PRM xx, yy, xy, x2y, y2x, Tmp;
148 x2y = (xx * y) / UNIT;
150 y2x = (yy * x) / UNIT;
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);
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);
162 Iterate_X3(ATTRACTOR * A, PRM x, PRM y, PRM * xo, PRM * yo)
164 PRM xx, yy, xy, x2y, y2x, Tmp_x, Tmp_y, Tmp_z;
167 x2y = (xx * y) / UNIT;
169 y2x = (yy * x) / UNIT;
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);
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);
179 Tmp_y = DO_FOLD(Tmp_y);
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;
185 *xo = (Tmp_x * UNIT) / Tmp_z;
186 *yo = (Tmp_y * UNIT) / Tmp_z;
189 static void (*Funcs[2]) (ATTRACTOR *, PRM, PRM, PRM *, PRM *) = {
190 Iterate_X2, Iterate_X3
193 /***************************************************************/
196 free_strange(Display *display, ATTRACTOR *A)
198 if (A->Buffer1 != NULL) {
199 (void) free((void *) A->Buffer1);
200 A->Buffer1 = (XPoint *) NULL;
202 if (A->Buffer2 != NULL) {
203 (void) free((void *) A->Buffer2);
204 A->Buffer2 = (XPoint *) NULL;
207 XFreePixmap(display, A->dbuf);
211 XFreeGC(display, A->dbuf_gc);
214 if (A->Fold != NULL) {
215 (void) free((void *) A->Fold);
216 A->Fold = (PRM *) NULL;
221 draw_strange(ModeInfo * mi)
227 Display *display = MI_DISPLAY(mi);
228 Window window = MI_WINDOW(mi);
231 void (*Iterate) (ATTRACTOR *, PRM, PRM, PRM *, PRM *);
232 PRM xmin, xmax, ymin, ymax;
237 A = &Root[MI_SCREEN(mi)];
242 Iterate = A->Iterate;
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]);
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;
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 ); */
278 x = xo + NRAND(8) - 4;
279 y = yo + NRAND(8) - 4;
282 MI_IS_DRAWN(mi) = True;
284 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
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);
292 XDrawPoints(display, window, gc, A->Buffer1, Cur_Pt, CoordModeOrigin);
294 if (MI_NPIXELS(mi) < 2)
295 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
297 XSetForeground(display, gc, MI_PIXEL(mi, A->Col % MI_NPIXELS(mi)));
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,
303 XCopyPlane(display, A->dbuf, window, gc, 0, 0, A->Width, A->Height, 0, 0, 1);
305 XDrawPoints(display, window, gc, A->Buffer2, A->Cur_Pt, CoordModeOrigin);
308 A->Buffer1 = A->Buffer2;
311 if ((xmax - xmin < DBL_To_PRM(.2)) && (ymax - ymin < DBL_To_PRM(.2)))
312 A->Count += 4 * A->Speed;
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];
325 /***************************************************************/
328 init_strange(ModeInfo * mi)
330 Display *display = MI_DISPLAY(mi);
332 Window window = MI_WINDOW(mi);
335 ATTRACTOR *Attractor;
338 if ((Root = (ATTRACTOR *) calloc(MI_NUM_SCREENS(mi),
339 sizeof (ATTRACTOR))) == NULL)
342 Attractor = &Root[MI_SCREEN(mi)];
344 if (Attractor->Fold == NULL) {
347 if ((Attractor->Fold = (PRM *) calloc(UNIT2 + 1,
348 sizeof (PRM))) == NULL) {
349 free_strange(display, Attractor);
352 for (i = 0; i <= UNIT2; ++i) {
355 /* x = ( DBL )(i)/UNIT2; */
356 /* x = sin( M_PI/2.0*x ); */
359 /* x = x*(1.0-x)*4.0; */
360 x = (DBL) (i) / UNIT;
362 Attractor->Fold[i] = DBL_To_PRM(x);
365 if (Attractor->Buffer1 == NULL)
366 if ((Attractor->Buffer1 = (XPoint *) calloc(MAX_POINTS,
367 sizeof (XPoint))) == NULL) {
368 free_strange(display, Attractor);
371 if (Attractor->Buffer2 == NULL)
372 if ((Attractor->Buffer2 = (XPoint *) calloc(MAX_POINTS,
373 sizeof (XPoint))) == NULL) {
374 free_strange(display, Attractor);
377 Attractor->Max_Pt = MAX_POINTS;
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;
386 Attractor->Iterate = Funcs[NRAND(2)];
387 Random_Prm(Attractor->Prm1);
388 Random_Prm(Attractor->Prm2);
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) {
401 gcv.graphics_exposures = False;
402 #endif /* HAVE_COCOA */
403 gcv.function = GXcopy;
405 if (Attractor->dbuf_gc != None)
406 XFreeGC(display, Attractor->dbuf_gc);
408 if ((Attractor->dbuf_gc = XCreateGC(display, Attractor->dbuf,
410 GCGraphicsExposures |
411 #endif /* HAVE_COCOA */
412 GCFunction | GCForeground | GCBackground,
414 XFreePixmap(display, Attractor->dbuf);
415 Attractor->dbuf = None;
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);
427 /* Do not want any exposure events from XCopyPlane */
428 XSetGraphicsExposures(display, MI_GC(mi), False);
431 /***************************************************************/
434 release_strange(ModeInfo * mi)
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;
446 XSCREENSAVER_MODULE ("Strange", strange)
448 #endif /* MODE_strange */