source: trunk/third/xscreensaver/hacks/ifs.c @ 20148

Revision 20148, 12.4 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 4 -*- */
2/* ifs --- modified iterated functions system */
3
4#if 0
5static 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
51ModeSpecOpt ifs_opts =
52{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
53
54#ifdef USE_MODULES
55ModStruct   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
65typedef float DBL;
66typedef 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
84typedef struct Similitude_Struct SIMI;
85typedef struct Fractal_Struct FRACTAL;
86
87struct 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
96struct 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
110static FRACTAL *Root = (FRACTAL *) NULL, *Cur_F;
111static XPoint *Buf;
112static int  Cur_Pt;
113
114
115/*****************************************************/
116
117static      DBL
118Gauss_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
129static      DBL
130Half_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
139static void
140Random_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
153static void
154free_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
167static void
168free_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
183void
184init_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
303static inline void
304Transform(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
324static void
325Trace(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
348static void
349Draw_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
421void
422draw_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
494void
495release_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 */
Note: See TracBrowser for help on using the repository browser.