http://packetstormsecurity.org/UNIX/admin/xscreensaver-4.14.tar.gz
[xscreensaver] / hacks / ifs.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* ifs --- modified iterated functions system */
3
4 #if 0
5 static const char sccsid[] = "@(#)ifs.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  * If this mode is weird and you have an old MetroX server, it is buggy.
24  * There is a free SuSE-enhanced MetroX X server that is fine.
25  *
26  * When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
27  *
28  * Revision History:
29  * 01-Nov-2000: Allocation checks
30  * 10-May-1997: jwz@jwz.org: turned into a standalone program.
31  *              Made it render into an offscreen bitmap and then copy
32  *              that onto the screen, to reduce flicker.
33  */
34
35 #ifdef STANDALONE
36 #define MODE_ifs
37 #define PROGCLASS "IFS"
38 #define HACK_INIT init_ifs
39 #define HACK_DRAW draw_ifs
40 #define ifs_opts xlockmore_opts
41 #define DEFAULTS "*delay: 20000 \n" \
42  "*ncolors: 100 \n"
43 #define SMOOTH_COLORS
44 #include "xlockmore.h"          /* in xscreensaver distribution */
45 #else /* STANDALONE */
46 #include "xlock.h"              /* in xlockmore distribution */
47 #endif /* STANDALONE */
48
49 #ifdef MODE_ifs
50
51 ModeSpecOpt ifs_opts =
52 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
53
54 #ifdef USE_MODULES
55 ModStruct   ifs_description =
56 {"ifs", "init_ifs", "draw_ifs", "release_ifs",
57  "init_ifs", "init_ifs", (char *) NULL, &ifs_opts,
58  1000, 1, 1, 1, 64, 1.0, "",
59  "Shows a modified iterated function system", 0, NULL};
60
61 #endif
62
63 /*****************************************************/
64
65 typedef float DBL;
66 typedef int F_PT;
67
68 /* typedef float               F_PT; */
69
70 /*****************************************************/
71
72 #define FIX 12
73 #define UNIT   ( 1<<FIX )
74 #define MAX_SIMI  6
75
76    /* settings for a PC 120Mhz... */
77 #define MAX_DEPTH_2  10
78 #define MAX_DEPTH_3  6
79 #define MAX_DEPTH_4  4
80 #define MAX_DEPTH_5  3
81
82 #define DBL_To_F_PT(x)  (F_PT)( (DBL)(UNIT)*(x) )
83
84 typedef struct Similitude_Struct SIMI;
85 typedef struct Fractal_Struct FRACTAL;
86
87 struct Similitude_Struct {
88
89         DBL         c_x, c_y;
90         DBL         r, r2, A, A2;
91         F_PT        Ct, St, Ct2, St2;
92         F_PT        Cx, Cy;
93         F_PT        R, R2;
94 };
95
96 struct Fractal_Struct {
97
98         int         Nb_Simi;
99         SIMI        Components[5 * MAX_SIMI];
100         int         Depth, Col;
101         int         Count, Speed;
102         int         Width, Height, Lx, Ly;
103         DBL         r_mean, dr_mean, dr2_mean;
104         int         Cur_Pt, Max_Pt;
105         XPoint     *Buffer1, *Buffer2;
106         Pixmap      dbuf;
107         GC          dbuf_gc;
108 };
109
110 static FRACTAL *Root = (FRACTAL *) NULL, *Cur_F;
111 static XPoint *Buf;
112 static int  Cur_Pt;
113
114
115 /*****************************************************/
116
117 static      DBL
118 Gauss_Rand(DBL c, DBL A, DBL S)
119 {
120         DBL         y;
121
122         y = (DBL) LRAND() / MAXRAND;
123         y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
124         if (NRAND(2))
125                 return (c + y);
126         return (c - y);
127 }
128
129 static      DBL
130 Half_Gauss_Rand(DBL c, DBL A, DBL S)
131 {
132         DBL         y;
133
134         y = (DBL) LRAND() / MAXRAND;
135         y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
136         return (c + y);
137 }
138
139 static void
140 Random_Simis(FRACTAL * F, SIMI * Cur, int i)
141 {
142         while (i--) {
143                 Cur->c_x = Gauss_Rand(0.0, .8, 4.0);
144                 Cur->c_y = Gauss_Rand(0.0, .8, 4.0);
145                 Cur->r = Gauss_Rand(F->r_mean, F->dr_mean, 3.0);
146                 Cur->r2 = Half_Gauss_Rand(0.0, F->dr2_mean, 2.0);
147                 Cur->A = Gauss_Rand(0.0, 360.0, 4.0) * (M_PI / 180.0);
148                 Cur->A2 = Gauss_Rand(0.0, 360.0, 4.0) * (M_PI / 180.0);
149                 Cur++;
150         }
151 }
152
153 static void
154 free_ifs_buffers(FRACTAL *Fractal)
155 {
156         if (Fractal->Buffer1 != NULL) {
157                 (void) free((void *) Fractal->Buffer1);
158                 Fractal->Buffer1 = (XPoint *) NULL;
159         }
160         if (Fractal->Buffer2 != NULL) {
161                 (void) free((void *) Fractal->Buffer2);
162                 Fractal->Buffer2 = (XPoint *) NULL;
163         }
164 }
165
166
167 static void
168 free_ifs(Display *display, FRACTAL *Fractal)
169 {
170         free_ifs_buffers(Fractal);
171         if (Fractal->dbuf != None) {
172                 XFreePixmap(display, Fractal->dbuf);
173                 Fractal->dbuf = None;
174         }
175         if (Fractal->dbuf_gc != None) {
176                 XFreeGC(display, Fractal->dbuf_gc);
177                 Fractal->dbuf_gc = None;
178         }
179 }
180
181 /***************************************************************/
182
183 void
184 init_ifs(ModeInfo * mi)
185 {
186         Display    *display = MI_DISPLAY(mi);
187         Window      window = MI_WINDOW(mi);
188         GC          gc = MI_GC(mi);
189         int         i;
190         FRACTAL    *Fractal;
191
192         if (Root == NULL) {
193                 Root = (FRACTAL *) calloc(
194                                        MI_NUM_SCREENS(mi), sizeof (FRACTAL));
195                 if (Root == NULL)
196                         return;
197         }
198         Fractal = &Root[MI_SCREEN(mi)];
199
200         free_ifs_buffers(Fractal);
201         i = (NRAND(4)) + 2;     /* Number of centers */
202         switch (i) {
203                 case 3:
204                         Fractal->Depth = MAX_DEPTH_3;
205                         Fractal->r_mean = .6;
206                         Fractal->dr_mean = .4;
207                         Fractal->dr2_mean = .3;
208                         break;
209
210                 case 4:
211                         Fractal->Depth = MAX_DEPTH_4;
212                         Fractal->r_mean = .5;
213                         Fractal->dr_mean = .4;
214                         Fractal->dr2_mean = .3;
215                         break;
216
217                 case 5:
218                         Fractal->Depth = MAX_DEPTH_5;
219                         Fractal->r_mean = .5;
220                         Fractal->dr_mean = .4;
221                         Fractal->dr2_mean = .3;
222                         break;
223
224                 default:
225                 case 2:
226                         Fractal->Depth = MAX_DEPTH_2;
227                         Fractal->r_mean = .7;
228                         Fractal->dr_mean = .3;
229                         Fractal->dr2_mean = .4;
230                         break;
231         }
232         /* (void) fprintf( stderr, "N=%d\n", i ); */
233         Fractal->Nb_Simi = i;
234         Fractal->Max_Pt = Fractal->Nb_Simi - 1;
235         for (i = 0; i <= Fractal->Depth + 2; ++i)
236                 Fractal->Max_Pt *= Fractal->Nb_Simi;
237
238         if ((Fractal->Buffer1 = (XPoint *) calloc(Fractal->Max_Pt,
239                         sizeof (XPoint))) == NULL) {
240                 free_ifs(display, Fractal);
241                 return;
242         }
243         if ((Fractal->Buffer2 = (XPoint *) calloc(Fractal->Max_Pt,
244                         sizeof (XPoint))) == NULL) {
245                 free_ifs(display, Fractal);
246                 return;
247         }
248         Fractal->Speed = 6;
249         Fractal->Width = MI_WIDTH(mi);
250         Fractal->Height = MI_HEIGHT(mi);
251         Fractal->Cur_Pt = 0;
252         Fractal->Count = 0;
253         Fractal->Lx = (Fractal->Width - 1) / 2;
254         Fractal->Ly = (Fractal->Height - 1) / 2;
255         Fractal->Col = NRAND(MI_NPIXELS(mi) - 1) + 1;
256
257         Random_Simis(Fractal, Fractal->Components, 5 * MAX_SIMI);
258
259 #ifndef NO_DBUF
260         if (Fractal->dbuf != None)
261                 XFreePixmap(display, Fractal->dbuf);
262         Fractal->dbuf = XCreatePixmap(display, window,
263                                       Fractal->Width, Fractal->Height, 1);
264         /* Allocation checked */
265         if (Fractal->dbuf != None) {
266                 XGCValues   gcv;
267
268                 gcv.foreground = 0;
269                 gcv.background = 0;
270                 gcv.graphics_exposures = False;
271                 gcv.function = GXcopy;
272
273                 if (Fractal->dbuf_gc != None)
274                         XFreeGC(display, Fractal->dbuf_gc);
275                 if ((Fractal->dbuf_gc = XCreateGC(display, Fractal->dbuf,
276                                 GCForeground | GCBackground | GCGraphicsExposures | GCFunction,
277                                 &gcv)) == None) {
278                         XFreePixmap(display, Fractal->dbuf);
279                         Fractal->dbuf = None;
280                 } else {
281                         XFillRectangle(display, Fractal->dbuf,
282                             Fractal->dbuf_gc, 0, 0, Fractal->Width, Fractal->Height);
283                         XSetBackground(display, gc, MI_BLACK_PIXEL(mi));
284                         XSetFunction(display, gc, GXcopy);
285                 }
286         }
287 #endif
288         MI_CLEARWINDOW(mi);
289
290         /* don't want any exposure events from XCopyPlane */
291         XSetGraphicsExposures(display, gc, False);
292
293 }
294
295
296 /***************************************************************/
297
298 /* Should be taken care of already... but just in case */
299 #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
300 #undef inline
301 #define inline                  /* */
302 #endif
303 static inline void
304 Transform(SIMI * Simi, F_PT xo, F_PT yo, F_PT * x, F_PT * y)
305 {
306         F_PT        xx, yy;
307
308         xo = xo - Simi->Cx;
309         xo = (xo * Simi->R) / UNIT;
310         yo = yo - Simi->Cy;
311         yo = (yo * Simi->R) / UNIT;
312
313         xx = xo - Simi->Cx;
314         xx = (xx * Simi->R2) / UNIT;
315         yy = -yo - Simi->Cy;
316         yy = (yy * Simi->R2) / UNIT;
317
318         *x = ((xo * Simi->Ct - yo * Simi->St + xx * Simi->Ct2 - yy * Simi->St2) / UNIT) + Simi->Cx;
319         *y = ((xo * Simi->St + yo * Simi->Ct + xx * Simi->St2 + yy * Simi->Ct2) / UNIT) + Simi->Cy;
320 }
321
322 /***************************************************************/
323
324 static void
325 Trace(FRACTAL * F, F_PT xo, F_PT yo)
326 {
327         F_PT        x, y, i;
328         SIMI       *Cur;
329
330         Cur = Cur_F->Components;
331         for (i = Cur_F->Nb_Simi; i; --i, Cur++) {
332                 Transform(Cur, xo, yo, &x, &y);
333                 /* Buf->x = F->Lx + (x * F->Lx / (UNIT * 2)); */
334                 /* Buf->y = F->Ly - (y * F->Ly / (UNIT * 2)); */
335         Buf->x = (UNIT * 2 + x) * F->Lx / (UNIT * 2);
336         Buf->y = (UNIT * 2 - y) * F->Ly / (UNIT * 2);
337                 Buf++;
338                 Cur_Pt++;
339
340                 if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) {
341                         F->Depth--;
342                         Trace(F, x, y);
343                         F->Depth++;
344                 }
345         }
346 }
347
348 static void
349 Draw_Fractal(ModeInfo * mi)
350 {
351         Display    *display = MI_DISPLAY(mi);
352         Window      window = MI_WINDOW(mi);
353         GC          gc = MI_GC(mi);
354         FRACTAL    *F = &Root[MI_SCREEN(mi)];
355         int         i, j;
356         F_PT        x, y, xo, yo;
357         SIMI       *Cur, *Simi;
358
359         for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
360                 Cur->Cx = DBL_To_F_PT(Cur->c_x);
361                 Cur->Cy = DBL_To_F_PT(Cur->c_y);
362
363                 Cur->Ct = DBL_To_F_PT(cos(Cur->A));
364                 Cur->St = DBL_To_F_PT(sin(Cur->A));
365                 Cur->Ct2 = DBL_To_F_PT(cos(Cur->A2));
366                 Cur->St2 = DBL_To_F_PT(sin(Cur->A2));
367
368                 Cur->R = DBL_To_F_PT(Cur->r);
369                 Cur->R2 = DBL_To_F_PT(Cur->r2);
370         }
371
372
373         Cur_Pt = 0;
374         Cur_F = F;
375         Buf = F->Buffer2;
376         for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
377                 xo = Cur->Cx;
378                 yo = Cur->Cy;
379                 for (Simi = F->Components, j = F->Nb_Simi; j; --j, Simi++) {
380                         if (Simi == Cur)
381                                 continue;
382                         Transform(Simi, xo, yo, &x, &y);
383                         Trace(F, x, y);
384                 }
385         }
386
387         /* Erase previous */
388         if (F->Cur_Pt) {
389                 XSetForeground(display, gc, MI_BLACK_PIXEL(mi));
390                 if (F->dbuf != None) {
391                         XSetForeground(display, F->dbuf_gc, 0);
392                         /* XDrawPoints(display, F->dbuf, F->dbuf_gc, F->Buffer1, F->Cur_Pt,
393                                 CoordModeOrigin); */
394                         XFillRectangle(display, F->dbuf, F->dbuf_gc, 0, 0,
395                                        F->Width, F->Height);
396                 } else
397                         XDrawPoints(display, window, gc, F->Buffer1, F->Cur_Pt, CoordModeOrigin);
398         }
399         if (MI_NPIXELS(mi) < 2)
400                 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
401         else
402                 XSetForeground(display, gc, MI_PIXEL(mi, F->Col % MI_NPIXELS(mi)));
403         if (Cur_Pt) {
404                 if (F->dbuf != None) {
405                         XSetForeground(display, F->dbuf_gc, 1);
406                         XDrawPoints(display, F->dbuf, F->dbuf_gc, F->Buffer2, Cur_Pt,
407                                     CoordModeOrigin);
408                 } else
409                         XDrawPoints(display, window, gc, F->Buffer2, Cur_Pt, CoordModeOrigin);
410         }
411         if (F->dbuf != None)
412                 XCopyPlane(display, F->dbuf, window, gc, 0, 0, F->Width, F->Height, 0, 0, 1);
413
414         F->Cur_Pt = Cur_Pt;
415         Buf = F->Buffer1;
416         F->Buffer1 = F->Buffer2;
417         F->Buffer2 = Buf;
418 }
419
420
421 void
422 draw_ifs(ModeInfo * mi)
423 {
424         int         i;
425         DBL         u, uu, v, vv, u0, u1, u2, u3;
426         SIMI       *S, *S1, *S2, *S3, *S4;
427         FRACTAL    *F;
428
429         if (Root == NULL)
430                 return;
431         F = &Root[MI_SCREEN(mi)];
432         if (F->Buffer1 == NULL)
433                 return;
434
435         u = (DBL) (F->Count) * (DBL) (F->Speed) / 1000.0;
436         uu = u * u;
437         v = 1.0 - u;
438         vv = v * v;
439         u0 = vv * v;
440         u1 = 3.0 * vv * u;
441         u2 = 3.0 * v * uu;
442         u3 = u * uu;
443
444         S = F->Components;
445         S1 = S + F->Nb_Simi;
446         S2 = S1 + F->Nb_Simi;
447         S3 = S2 + F->Nb_Simi;
448         S4 = S3 + F->Nb_Simi;
449
450         for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) {
451                 S->c_x = u0 * S1->c_x + u1 * S2->c_x + u2 * S3->c_x + u3 * S4->c_x;
452                 S->c_y = u0 * S1->c_y + u1 * S2->c_y + u2 * S3->c_y + u3 * S4->c_y;
453                 S->r = u0 * S1->r + u1 * S2->r + u2 * S3->r + u3 * S4->r;
454                 S->r2 = u0 * S1->r2 + u1 * S2->r2 + u2 * S3->r2 + u3 * S4->r2;
455                 S->A = u0 * S1->A + u1 * S2->A + u2 * S3->A + u3 * S4->A;
456                 S->A2 = u0 * S1->A2 + u1 * S2->A2 + u2 * S3->A2 + u3 * S4->A2;
457         }
458
459         MI_IS_DRAWN(mi) = True;
460
461         Draw_Fractal(mi);
462
463         if (F->Count >= 1000 / F->Speed) {
464                 S = F->Components;
465                 S1 = S + F->Nb_Simi;
466                 S2 = S1 + F->Nb_Simi;
467                 S3 = S2 + F->Nb_Simi;
468                 S4 = S3 + F->Nb_Simi;
469
470                 for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) {
471                         S2->c_x = 2.0 * S4->c_x - S3->c_x;
472                         S2->c_y = 2.0 * S4->c_y - S3->c_y;
473                         S2->r = 2.0 * S4->r - S3->r;
474                         S2->r2 = 2.0 * S4->r2 - S3->r2;
475                         S2->A = 2.0 * S4->A - S3->A;
476                         S2->A2 = 2.0 * S4->A2 - S3->A2;
477
478                         *S1 = *S4;
479                 }
480                 Random_Simis(F, F->Components + 3 * F->Nb_Simi, F->Nb_Simi);
481
482                 Random_Simis(F, F->Components + 4 * F->Nb_Simi, F->Nb_Simi);
483
484                 F->Count = 0;
485         } else
486                 F->Count++;
487
488         F->Col++;
489 }
490
491
492 /***************************************************************/
493
494 void
495 release_ifs(ModeInfo * mi)
496 {
497         if (Root != NULL) {
498                 int         screen;
499
500                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
501                         free_ifs(MI_DISPLAY(mi), &Root[screen]);
502                 (void) free((void *) Root);
503                 Root = (FRACTAL *) NULL;
504         }
505 }
506
507 #endif /* MODE_ifs */