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 * 30-Jul-98: sineswiper@resonatorsoft.com: added curve factor (discovered
24 * while experimenting with the Gauss_Rand function).
25 * 10-May-97: 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.
31 # define PROGCLASS "Strange"
32 # define HACK_INIT init_strange
33 # define HACK_DRAW draw_strange
34 # define strange_opts xlockmore_opts
35 # define DEFAULTS "*delay: 2000 \n" \
37 # define SMOOTH_COLORS
38 # include "xlockmore.h" /* from the xscreensaver distribution */
39 #else /* !STANDALONE */
40 # include "xlock.h" /* from the xlockmore distribution */
41 #endif /* !STANDALONE */
43 /*****************************************************/
44 /*****************************************************/
51 /* #define UNIT2 (3140*UNIT/1000) */
53 #define SKIP_FIRST 100
54 #define MAX_POINTS 5500
55 #define DBL_To_PRM(x) (PRM)( (DBL)(UNIT)*(x) )
58 #define DO_FOLD(a) (a)<0 ? -Fold[ (-(a))&(UNIT2-1) ] : Fold[ (a)&(UNIT2-1) ]
61 #define DO_FOLD(a) (a)<-UNIT2 ? -Fold[(-(a))%UNIT2] : (a)<0 ? -Fold[ -(a) ]
63 : \ (a)>UNIT2 ? Fold[ (a)%UNIT2 ] : Fold[ (a) ] */
64 /* #define DO_FOLD(a) DBL_To_PRM( sin( (DBL)(a)/UNIT ) ) */
66 #define DO_FOLD(a) (a)<0 ? DBL_To_PRM( exp( 16.0*(a)/UNIT2 ) )-1.0 : \
67 DBL_To_PRM( 1.0-exp( -16.0*(a)/UNIT2 ) ) */
69 /******************************************************************/
74 DBL Prm1[MAX_PRM], Prm2[MAX_PRM];
75 void (*Iterate) (PRM, PRM, PRM *, PRM *);
76 XPoint *Buffer1, *Buffer2;
78 int Col, Count, Speed;
80 Pixmap dbuf; /* jwz */
84 static ATTRACTOR *Root;
85 static PRM xmin, xmax, ymin, ymax;
86 static PRM Prm[MAX_PRM];
87 static PRM *Fold = NULL;
91 static XrmOptionDescRec opts[] =
93 {"-curve", ".strange.curve", XrmoptionSepArg, (caddr_t) "10"},
95 static OptionStruct desc[] =
97 {"-curve", "set the curve factor of the attractors"},
100 ModeSpecOpt strange_opts = { 1, opts, 0, NULL, desc };
102 /******************************************************************/
103 /******************************************************************/
105 static DBL Amp_Prm[MAX_PRM] =
107 1.0, 3.5, 3.5, 2.5, 4.7,
108 1.0, 3.5, 3.6, 2.5, 4.7,
109 1.0, 1.5, 2.2, 2.1, 3.5
111 static DBL Mid_Prm[MAX_PRM] =
113 0.0, 1.5, 0.0, .5, 1.5,
114 0.0, 1.5, 0.0, .5, 1.5,
115 0.0, 1.5, -1.0, -.5, 2.5,
119 Gauss_Rand(DBL c, DBL A, DBL S)
123 y = (DBL) LRAND() / MAXRAND;
125 y = A * (z - exp(-y * y * S)) / (z - exp(-S));
133 Random_Prm(DBL * Prm)
137 for (i = 0; i < MAX_PRM; ++i)
138 Prm[i] = Gauss_Rand(Mid_Prm[i], Amp_Prm[i], 4.0);
141 /***************************************************************/
143 /* 2 examples of non-linear map */
146 Iterate_X2(PRM x, PRM y, PRM * xo, PRM * yo)
148 PRM xx, yy, xy, x2y, y2x, Tmp;
151 x2y = (xx * y) / UNIT;
153 y2x = (yy * x) / UNIT;
156 Tmp = Prm[1] * xx + Prm[2] * xy + Prm[3] * yy + Prm[4] * x2y;
157 Tmp = Prm[0] - y + (Tmp / UNIT);
159 Tmp = Prm[6] * xx + Prm[7] * xy + Prm[8] * yy + Prm[9] * y2x;
160 Tmp = Prm[5] + x + (Tmp / UNIT);
165 Iterate_X3(PRM x, PRM y, PRM * xo, PRM * yo)
167 PRM xx, yy, xy, x2y, y2x, Tmp_x, Tmp_y, Tmp_z;
170 x2y = (xx * y) / UNIT;
172 y2x = (yy * x) / UNIT;
175 Tmp_x = Prm[1] * xx + Prm[2] * xy + Prm[3] * yy + Prm[4] * x2y;
176 Tmp_x = Prm[0] - y + (Tmp_x / UNIT);
177 Tmp_x = DO_FOLD(Tmp_x);
179 Tmp_y = Prm[6] * xx + Prm[7] * xy + Prm[8] * yy + Prm[9] * y2x;
180 Tmp_y = Prm[5] + x + (Tmp_y / UNIT);
182 Tmp_y = DO_FOLD(Tmp_y);
184 Tmp_z = Prm[11] * xx + Prm[12] * xy + Prm[13] * yy + Prm[14] * y2x;
185 Tmp_z = Prm[10] + x + (Tmp_z / UNIT);
186 Tmp_z = UNIT + Tmp_z * Tmp_z / UNIT;
188 *xo = (Tmp_x * UNIT) / Tmp_z;
189 *yo = (Tmp_y * UNIT) / Tmp_z;
192 static void (*Funcs[2]) (PRM, PRM, PRM *, PRM *) = {
193 Iterate_X2, Iterate_X3
196 /***************************************************************/
199 draw_strange(ModeInfo * mi)
201 int i, j, n, Max_Colors, Cur_Pt;
210 void (*Iterate) (PRM, PRM, PRM *, PRM *);
212 display = MI_DISPLAY(mi);
213 window = MI_WINDOW(mi);
215 Max_Colors = MI_NPIXELS(mi);
217 A = &Root[MI_SCREEN(mi)];
220 Iterate = A->Iterate;
222 u = (DBL) (A->Count) / 1000.0;
223 for (j = MAX_PRM - 1; j >= 0; --j)
224 Prm[j] = DBL_To_PRM((1.0 - u) * A->Prm1[j] + u * A->Prm2[j]);
226 x = y = DBL_To_PRM(.0);
227 for (n = SKIP_FIRST; n; --n) {
228 (*Iterate) (x, y, &xo, &yo);
229 x = xo + NRAND(8) - 4;
230 y = yo + NRAND(8) - 4;
239 Lx = (DBL) A->Width / UNIT / 2.2;
240 Ly = (DBL) A->Height / UNIT / 2.2;
241 for (n = A->Max_Pt; n; --n) {
242 (*Iterate) (x, y, &xo, &yo);
243 Buf->x = (short) (Lx * (x + DBL_To_PRM(1.1)));
244 Buf->y = (short) (Ly * (DBL_To_PRM(1.1) - y));
245 /* (void) fprintf( stderr, "X,Y: %d %d ", Buf->x, Buf->y ); */
256 x = xo + NRAND(8) - 4;
257 y = yo + NRAND(8) - 4;
260 XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(mi));
262 if (A->dbuf) /* jwz */
264 XSetForeground(display, A->dbuf_gc, 0);
265 /* XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer1,
266 Cur_Pt,CoordModeOrigin);*/
267 XFillRectangle(display, A->dbuf, A->dbuf_gc, 0,0, A->Width, A->Height);
270 XDrawPoints(display, window, gc, A->Buffer1, Cur_Pt, CoordModeOrigin);
273 XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(mi));
275 XSetForeground(display, gc, MI_PIXEL(mi, A->Col % Max_Colors));
279 XSetForeground(display, A->dbuf_gc, 1);
280 XDrawPoints(display, A->dbuf, A->dbuf_gc, A->Buffer2, A->Cur_Pt,
284 XDrawPoints(display, window, gc, A->Buffer2, A->Cur_Pt, CoordModeOrigin);
287 XCopyPlane(display, A->dbuf, window, gc, 0,0,A->Width,A->Height,0,0, 1);
290 A->Buffer1 = A->Buffer2;
293 if ((xmax - xmin < DBL_To_PRM(.2)) && (ymax - ymin < DBL_To_PRM(.2)))
294 A->Count += 4 * A->Speed;
296 A->Count += A->Speed;
297 if (A->Count >= 1000) {
298 for (i = MAX_PRM - 1; i >= 0; --i)
299 A->Prm1[i] = A->Prm2[i];
307 /***************************************************************/
310 init_strange(ModeInfo * mi)
312 ATTRACTOR *Attractor;
314 curve = get_integer_resource ("curve", "Integer");
315 if (curve <= 0) curve = 10;
318 Root = (ATTRACTOR *) calloc(
319 MI_NUM_SCREENS(mi), sizeof (ATTRACTOR));
326 Fold = (PRM *) calloc(UNIT2 + 1, sizeof (PRM));
329 for (i = 0; i <= UNIT2; ++i) {
332 /* x = ( DBL )(i)/UNIT2; */
333 /* x = sin( M_PI/2.0*x ); */
336 /* x = x*(1.0-x)*4.0; */
337 x = (DBL) (i) / UNIT;
339 Fold[i] = DBL_To_PRM(x);
342 Attractor = &Root[MI_SCREEN(mi)];
344 Attractor->Buffer1 = (XPoint *) calloc(MAX_POINTS, sizeof (XPoint));
345 if (Attractor->Buffer1 == NULL)
347 Attractor->Buffer2 = (XPoint *) calloc(MAX_POINTS, sizeof (XPoint));
348 if (Attractor->Buffer2 == NULL)
350 Attractor->Max_Pt = MAX_POINTS;
352 Attractor->Width = MI_WIN_WIDTH(mi);
353 Attractor->Height = MI_WIN_HEIGHT(mi);
354 Attractor->Cur_Pt = 0;
355 Attractor->Count = 0;
356 Attractor->Col = NRAND(MI_NPIXELS(mi));
357 Attractor->Speed = 4;
359 Attractor->Iterate = Funcs[NRAND(2)];
360 Random_Prm(Attractor->Prm1);
361 Random_Prm(Attractor->Prm2);
363 Attractor->dbuf = XCreatePixmap(MI_DISPLAY(mi), MI_WINDOW(mi),
364 Attractor->Width, Attractor->Height, 1);
370 gcv.function = GXcopy;
371 Attractor->dbuf_gc = XCreateGC(MI_DISPLAY(mi), Attractor->dbuf,
372 GCForeground|GCBackground|GCFunction,
374 XFillRectangle(MI_DISPLAY(mi), Attractor->dbuf,
375 Attractor->dbuf_gc, 0,0, Attractor->Width,
377 XSetBackground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi));
378 XSetFunction(MI_DISPLAY(mi), MI_GC(mi), GXcopy);
381 XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
385 if (Attractor->Buffer1 != NULL)
386 free(Attractor->Buffer1);
387 if (Attractor->Buffer2 != NULL)
388 free(Attractor->Buffer2);
389 Attractor->Buffer1 = NULL;
390 Attractor->Buffer2 = NULL;
391 Attractor->Cur_Pt = 0;
395 /***************************************************************/
398 release_strange(ModeInfo * mi)
405 for (i = 0; i < MI_NUM_SCREENS(mi); ++i) {
406 if (Root[i].Buffer1 != NULL)
407 free(Root[i].Buffer1);
408 if (Root[i].Buffer2 != NULL)
409 free(Root[i].Buffer2);
411 XFreePixmap(MI_DISPLAY(mi), Root[i].dbuf);
413 XFreeGC(MI_DISPLAY(mi), Root[i].dbuf_gc);