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