1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* ifs --- modified iterated functions system */
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)ifs.c 5.00 2000/11/01 xlockmore";
10 * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
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.
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.
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.
27 * When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
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.
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" \
45 #include "xlockmore.h" /* in xscreensaver distribution */
46 #else /* STANDALONE */
47 #include "xlock.h" /* in xlockmore distribution */
48 #endif /* STANDALONE */
52 ModeSpecOpt ifs_opts =
53 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
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};
64 /*****************************************************/
69 /* typedef float F_PT; */
71 /*****************************************************/
74 #define UNIT ( 1<<FIX )
77 /* settings for a PC 120Mhz... */
78 #define MAX_DEPTH_2 10
83 #define DBL_To_F_PT(x) (F_PT)( (DBL)(UNIT)*(x) )
85 typedef struct Similitude_Struct SIMI;
86 typedef struct Fractal_Struct FRACTAL;
88 struct Similitude_Struct {
92 F_PT Ct, St, Ct2, St2;
97 struct Fractal_Struct {
100 SIMI Components[5 * MAX_SIMI];
103 int Width, Height, Lx, Ly;
104 DBL r_mean, dr_mean, dr2_mean;
106 XPoint *Buffer1, *Buffer2;
111 static FRACTAL *Root = (FRACTAL *) NULL, *Cur_F;
116 /*****************************************************/
119 Gauss_Rand(DBL c, DBL A, DBL S)
123 y = (DBL) LRAND() / MAXRAND;
124 y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
131 Half_Gauss_Rand(DBL c, DBL A, DBL S)
135 y = (DBL) LRAND() / MAXRAND;
136 y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
141 Random_Simis(FRACTAL * F, SIMI * Cur, int 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);
155 free_ifs_buffers(FRACTAL *Fractal)
157 if (Fractal->Buffer1 != NULL) {
158 (void) free((void *) Fractal->Buffer1);
159 Fractal->Buffer1 = (XPoint *) NULL;
161 if (Fractal->Buffer2 != NULL) {
162 (void) free((void *) Fractal->Buffer2);
163 Fractal->Buffer2 = (XPoint *) NULL;
169 free_ifs(Display *display, FRACTAL *Fractal)
171 free_ifs_buffers(Fractal);
172 if (Fractal->dbuf != None) {
173 XFreePixmap(display, Fractal->dbuf);
174 Fractal->dbuf = None;
176 if (Fractal->dbuf_gc != None) {
177 XFreeGC(display, Fractal->dbuf_gc);
178 Fractal->dbuf_gc = None;
182 /***************************************************************/
185 init_ifs(ModeInfo * mi)
187 Display *display = MI_DISPLAY(mi);
188 Window window = MI_WINDOW(mi);
194 Root = (FRACTAL *) calloc(
195 MI_NUM_SCREENS(mi), sizeof (FRACTAL));
199 Fractal = &Root[MI_SCREEN(mi)];
201 free_ifs_buffers(Fractal);
202 i = (NRAND(4)) + 2; /* Number of centers */
205 Fractal->Depth = MAX_DEPTH_3;
206 Fractal->r_mean = .6;
207 Fractal->dr_mean = .4;
208 Fractal->dr2_mean = .3;
212 Fractal->Depth = MAX_DEPTH_4;
213 Fractal->r_mean = .5;
214 Fractal->dr_mean = .4;
215 Fractal->dr2_mean = .3;
219 Fractal->Depth = MAX_DEPTH_5;
220 Fractal->r_mean = .5;
221 Fractal->dr_mean = .4;
222 Fractal->dr2_mean = .3;
227 Fractal->Depth = MAX_DEPTH_2;
228 Fractal->r_mean = .7;
229 Fractal->dr_mean = .3;
230 Fractal->dr2_mean = .4;
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;
239 if ((Fractal->Buffer1 = (XPoint *) calloc(Fractal->Max_Pt,
240 sizeof (XPoint))) == NULL) {
241 free_ifs(display, Fractal);
244 if ((Fractal->Buffer2 = (XPoint *) calloc(Fractal->Max_Pt,
245 sizeof (XPoint))) == NULL) {
246 free_ifs(display, Fractal);
250 Fractal->Width = MI_WIDTH(mi);
251 Fractal->Height = MI_HEIGHT(mi);
254 Fractal->Lx = (Fractal->Width - 1) / 2;
255 Fractal->Ly = (Fractal->Height - 1) / 2;
256 Fractal->Col = NRAND(MI_NPIXELS(mi) - 1) + 1;
258 Random_Simis(Fractal, Fractal->Components, 5 * MAX_SIMI);
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) {
271 gcv.graphics_exposures = False;
272 gcv.function = GXcopy;
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,
279 XFreePixmap(display, Fractal->dbuf);
280 Fractal->dbuf = None;
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);
291 /* don't want any exposure events from XCopyPlane */
292 XSetGraphicsExposures(display, gc, False);
297 /***************************************************************/
299 /* Should be taken care of already... but just in case */
300 #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
305 Transform(SIMI * Simi, F_PT xo, F_PT yo, F_PT * x, F_PT * y)
310 xo = (xo * Simi->R) / UNIT;
312 yo = (yo * Simi->R) / UNIT;
315 xx = (xx * Simi->R2) / UNIT;
317 yy = (yy * Simi->R2) / UNIT;
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;
323 /***************************************************************/
326 Trace(FRACTAL * F, F_PT xo, F_PT yo)
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));
339 if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) {
348 Draw_Fractal(ModeInfo * mi)
350 Display *display = MI_DISPLAY(mi);
351 Window window = MI_WINDOW(mi);
353 FRACTAL *F = &Root[MI_SCREEN(mi)];
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);
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));
367 Cur->R = DBL_To_F_PT(Cur->r);
368 Cur->R2 = DBL_To_F_PT(Cur->r2);
375 for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
378 for (Simi = F->Components, j = F->Nb_Simi; j; --j, Simi++) {
381 Transform(Simi, xo, yo, &x, &y);
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,
393 XFillRectangle(display, F->dbuf, F->dbuf_gc, 0, 0,
394 F->Width, F->Height);
396 XDrawPoints(display, window, gc, F->Buffer1, F->Cur_Pt, CoordModeOrigin);
398 if (MI_NPIXELS(mi) < 2)
399 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
401 XSetForeground(display, gc, MI_PIXEL(mi, F->Col % MI_NPIXELS(mi)));
403 if (F->dbuf != None) {
404 XSetForeground(display, F->dbuf_gc, 1);
405 XDrawPoints(display, F->dbuf, F->dbuf_gc, F->Buffer2, Cur_Pt,
408 XDrawPoints(display, window, gc, F->Buffer2, Cur_Pt, CoordModeOrigin);
411 XCopyPlane(display, F->dbuf, window, gc, 0, 0, F->Width, F->Height, 0, 0, 1);
415 F->Buffer1 = F->Buffer2;
421 draw_ifs(ModeInfo * mi)
424 DBL u, uu, v, vv, u0, u1, u2, u3;
425 SIMI *S, *S1, *S2, *S3, *S4;
430 F = &Root[MI_SCREEN(mi)];
431 if (F->Buffer1 == NULL)
434 u = (DBL) (F->Count) * (DBL) (F->Speed) / 1000.0;
445 S2 = S1 + F->Nb_Simi;
446 S3 = S2 + F->Nb_Simi;
447 S4 = S3 + F->Nb_Simi;
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;
458 MI_IS_DRAWN(mi) = True;
462 if (F->Count >= 1000 / F->Speed) {
465 S2 = S1 + F->Nb_Simi;
466 S3 = S2 + F->Nb_Simi;
467 S4 = S3 + F->Nb_Simi;
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;
479 Random_Simis(F, F->Components + 3 * F->Nb_Simi, F->Nb_Simi);
481 Random_Simis(F, F->Components + 4 * F->Nb_Simi, F->Nb_Simi);
491 /***************************************************************/
494 release_ifs(ModeInfo * mi)
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;
506 #endif /* MODE_ifs */