1 /* -*- Mode: C; tab-width: 4 -*-
2 * strange --- Strange attractors are not so hard to find...
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)strange.c 4.02 97/04/01 xlockmore";
8 /* Copyright (c) 1997 by Massimino Pascal (Pascal.Massimon@ens.fr)
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation for any purpose and without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation.
16 * This file is provided AS IS with no warranties of any kind. The author
17 * shall have no liability with respect to the infringement of copyrights,
18 * trade secrets or any patents by this file or any part thereof. In no
19 * event will the author be liable for any lost revenue or profits or
20 * other special, indirect and consequential damages.
23 * 10-May-97: jwz@netscape.com: turned into a standalone program.
24 * Made it render into an offscreen bitmap and then copy
25 * that onto the screen, to reduce flicker.
29 # define PROGCLASS "Strange"
30 # define HACK_INIT init_strange
31 # define HACK_DRAW draw_strange
32 # define strange_opts xlockmore_opts
33 # define DEFAULTS "*delay: 2000 \n" \
35 # define SMOOTH_COLORS
36 # include "xlockmore.h" /* from the xscreensaver distribution */
37 #else /* !STANDALONE */
38 # include "xlock.h" /* from the xlockmore distribution */
39 #endif /* !STANDALONE */
41 ModeSpecOpt strange_opts = {
42 0, NULL, 0, NULL, NULL };
44 /*****************************************************/
45 /*****************************************************/
52 /* #define UNIT2 (3140*UNIT/1000) */
54 #define SKIP_FIRST 100
55 #define MAX_POINTS 5500
56 #define DBL_To_PRM(x) (PRM)( (DBL)(UNIT)*(x) )
59 #define DO_FOLD(a) (a)<0 ? -Fold[ (-(a))&(UNIT2-1) ] : Fold[ (a)&(UNIT2-1) ]
62 #define DO_FOLD(a) (a)<-UNIT2 ? -Fold[(-(a))%UNIT2] : (a)<0 ? -Fold[ -(a) ]
64 : \ (a)>UNIT2 ? Fold[ (a)%UNIT2 ] : Fold[ (a) ] */
65 /* #define DO_FOLD(a) DBL_To_PRM( sin( (DBL)(a)/UNIT ) ) */
67 #define DO_FOLD(a) (a)<0 ? DBL_To_PRM( exp( 16.0*(a)/UNIT2 ) )-1.0 : \
68 DBL_To_PRM( 1.0-exp( -16.0*(a)/UNIT2 ) ) */
70 /******************************************************************/
75 DBL Prm1[MAX_PRM], Prm2[MAX_PRM];
76 void (*Iterate) (PRM, PRM, PRM *, PRM *);
77 XPoint *Buffer1, *Buffer2;
79 int Col, Count, Speed;
81 Pixmap dbuf; /* jwz */
85 static ATTRACTOR *Root;
86 static PRM xmin, xmax, ymin, ymax;
87 static PRM Prm[MAX_PRM];
88 static PRM *Fold = NULL;
90 /******************************************************************/
91 /******************************************************************/
93 static DBL Amp_Prm[MAX_PRM] =
95 1.0, 3.5, 3.5, 2.5, 4.7,
96 1.0, 3.5, 3.6, 2.5, 4.7,
97 1.0, 1.5, 2.2, 2.1, 3.5
99 static DBL Mid_Prm[MAX_PRM] =
101 0.0, 1.5, 0.0, .5, 1.5,
102 0.0, 1.5, 0.0, .5, 1.5,
103 0.0, 1.5, -1.0, -.5, 2.5,
107 Gauss_Rand(DBL c, DBL A, DBL S)
111 y = (DBL) LRAND() / MAXRAND;
112 y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
120 Random_Prm(DBL * Prm)
124 for (i = 0; i < MAX_PRM; ++i)
125 Prm[i] = Gauss_Rand(Mid_Prm[i], Amp_Prm[i], 4.0);
128 /***************************************************************/
130 /* 2 examples of non-linear map */
133 Iterate_X2(PRM x, PRM y, PRM * xo, PRM * yo)
135 PRM xx, yy, xy, x2y, y2x, Tmp;
138 x2y = (xx * y) / UNIT;
140 y2x = (yy * x) / UNIT;
143 Tmp = Prm[1] * xx + Prm[2] * xy + Prm[3] * yy + Prm[4] * x2y;
144 Tmp = Prm[0] - y + (Tmp / UNIT);
146 Tmp = Prm[6] * xx + Prm[7] * xy + Prm[8] * yy + Prm[9] * y2x;
147 Tmp = Prm[5] + x + (Tmp / UNIT);
152 Iterate_X3(PRM x, PRM y, PRM * xo, PRM * yo)
154 PRM xx, yy, xy, x2y, y2x, Tmp_x, Tmp_y, Tmp_z;
157 x2y = (xx * y) / UNIT;
159 y2x = (yy * x) / UNIT;
162 Tmp_x = Prm[1] * xx + Prm[2] * xy + Prm[3] * yy + Prm[4] * x2y;
163 Tmp_x = Prm[0] - y + (Tmp_x / UNIT);
164 Tmp_x = DO_FOLD(Tmp_x);
166 Tmp_y = Prm[6] * xx + Prm[7] * xy + Prm[8] * yy + Prm[9] * y2x;
167 Tmp_y = Prm[5] + x + (Tmp_y / UNIT);
169 Tmp_y = DO_FOLD(Tmp_y);
171 Tmp_z = Prm[11] * xx + Prm[12] * xy + Prm[13] * yy + Prm[14] * y2x;
172 Tmp_z = Prm[10] + x + (Tmp_z / UNIT);
173 Tmp_z = UNIT + Tmp_z * Tmp_z / UNIT;
175 *xo = (Tmp_x * UNIT) / Tmp_z;
176 *yo = (Tmp_y * UNIT) / Tmp_z;
179 static void (*Funcs[2]) (PRM, PRM, PRM *, PRM *) = {
180 Iterate_X2, Iterate_X3
183 /***************************************************************/
186 draw_strange(ModeInfo * mi)
188 int i, j, n, Max_Colors, Cur_Pt;
197 void (*Iterate) (PRM, PRM, PRM *, PRM *);
199 display = MI_DISPLAY(mi);
200 window = MI_WINDOW(mi);
202 Max_Colors = MI_NPIXELS(mi);
204 A = &Root[MI_SCREEN(mi)];
207 Iterate = A->Iterate;
209 u = (DBL) (A->Count) / 1000.0;
210 for (j = MAX_PRM - 1; j >= 0; --j)
211 Prm[j] = DBL_To_PRM((1.0 - u) * A->Prm1[j] + u * A->Prm2[j]);
213 x = y = DBL_To_PRM(.0);
214 for (n = SKIP_FIRST; n; --n) {
215 (*Iterate) (x, y, &xo, &yo);
216 x = xo + NRAND(8) - 4;
217 y = yo + NRAND(8) - 4;
226 Lx = (DBL) A->Width / UNIT / 2.2;
227 Ly = (DBL) A->Height / UNIT / 2.2;
228 for (n = A->Max_Pt; n; --n) {
229 (*Iterate) (x, y, &xo, &yo);
230 Buf->x = (short) (Lx * (x + DBL_To_PRM(1.1)));
231 Buf->y = (short) (Ly * (DBL_To_PRM(1.1) - y));
232 /* (void) fprintf( stderr, "X,Y: %d %d ", Buf->x, Buf->y ); */
243 x = xo + NRAND(8) - 4;
244 y = yo + NRAND(8) - 4;
247 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
249 if (A->dbuf) /* jwz */
251 XSetForeground(display, A->dbuf_gc, 0);
252 /* XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer1,
253 Cur_Pt,CoordModeOrigin);*/
254 XFillRectangle(display, A->dbuf, A->dbuf_gc, 0,0, A->Width, A->Height);
257 XDrawPoints(display, window, gc, A->Buffer1, Cur_Pt, CoordModeOrigin);
260 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
262 XSetForeground(display, gc, MI_PIXEL(mi, A->Col % Max_Colors));
266 XSetForeground(display, A->dbuf_gc, 1);
267 XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer2, A->Cur_Pt,
271 XDrawPoints(display, window, gc, A->Buffer2, A->Cur_Pt, CoordModeOrigin);
274 XCopyPlane(display, A->dbuf, window, gc, 0,0,A->Width,A->Height,0,0, 1);
277 A->Buffer1 = A->Buffer2;
280 if ((xmax - xmin < DBL_To_PRM(.2)) && (ymax - ymin < DBL_To_PRM(.2)))
281 A->Count += 4 * A->Speed;
283 A->Count += A->Speed;
284 if (A->Count >= 1000) {
285 for (i = MAX_PRM - 1; i >= 0; --i)
286 A->Prm1[i] = A->Prm2[i];
294 /***************************************************************/
297 init_strange(ModeInfo * mi)
299 ATTRACTOR *Attractor;
302 Root = (ATTRACTOR *) calloc(
303 MI_NUM_SCREENS(mi), sizeof (ATTRACTOR));
310 Fold = (PRM *) calloc(UNIT2 + 1, sizeof (PRM));
313 for (i = 0; i <= UNIT2; ++i) {
316 /* x = ( DBL )(i)/UNIT2; */
317 /* x = sin( M_PI/2.0*x ); */
320 /* x = x*(1.0-x)*4.0; */
321 x = (DBL) (i) / UNIT;
323 Fold[i] = DBL_To_PRM(x);
326 Attractor = &Root[MI_SCREEN(mi)];
328 Attractor->Buffer1 = (XPoint *) calloc(MAX_POINTS, sizeof (XPoint));
329 if (Attractor->Buffer1 == NULL)
331 Attractor->Buffer2 = (XPoint *) calloc(MAX_POINTS, sizeof (XPoint));
332 if (Attractor->Buffer2 == NULL)
334 Attractor->Max_Pt = MAX_POINTS;
336 Attractor->Width = MI_WIN_WIDTH(mi);
337 Attractor->Height = MI_WIN_HEIGHT(mi);
338 Attractor->Cur_Pt = 0;
339 Attractor->Count = 0;
340 Attractor->Col = NRAND(MI_NPIXELS(mi));
341 Attractor->Speed = 4;
343 Attractor->Iterate = Funcs[NRAND(2)];
344 Random_Prm(Attractor->Prm1);
345 Random_Prm(Attractor->Prm2);
347 Attractor->dbuf = XCreatePixmap(MI_DISPLAY(mi), MI_WINDOW(mi),
348 Attractor->Width, Attractor->Height, 1);
354 gcv.function = GXcopy;
355 Attractor->dbuf_gc = XCreateGC(MI_DISPLAY(mi), Attractor->dbuf,
356 GCForeground|GCBackground|GCFunction,
358 XFillRectangle(MI_DISPLAY(mi), Attractor->dbuf,
359 Attractor->dbuf_gc, 0,0, Attractor->Width,
361 XSetBackground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
362 XSetFunction(MI_DISPLAY(mi), MI_GC(mi), GXcopy);
365 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
369 if (Attractor->Buffer1 != NULL)
370 free(Attractor->Buffer1);
371 if (Attractor->Buffer2 != NULL)
372 free(Attractor->Buffer2);
373 Attractor->Buffer1 = NULL;
374 Attractor->Buffer2 = NULL;
375 Attractor->Cur_Pt = 0;
379 /***************************************************************/
382 release_strange(ModeInfo * mi)
389 for (i = 0; i < MI_NUM_SCREENS(mi); ++i) {
390 if (Root[i].Buffer1 != NULL)
391 free(Root[i].Buffer1);
392 if (Root[i].Buffer2 != NULL)
393 free(Root[i].Buffer2);
395 XFreePixmap(MI_DISPLAY(mi), Root[i].dbuf);
397 XFreeGC(MI_DISPLAY(mi), Root[i].dbuf_gc);