1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* ifs --- modified iterated functions system */
5 static const char sccsid[] = "@(#)ifs.c 5.00 2000/11/01 xlockmore";
9 * Copyright (c) 1997 by Massimino Pascal <Pascal.Massimon@ens.fr>
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.
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.
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.
26 * When shown ifs, Diana Rose (4 years old) said, "It looks like dancing."
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.
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" \
44 #include "xlockmore.h" /* in xscreensaver distribution */
45 #else /* STANDALONE */
46 #include "xlock.h" /* in xlockmore distribution */
47 #endif /* STANDALONE */
51 ModeSpecOpt ifs_opts =
52 {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
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};
63 /*****************************************************/
68 /* typedef float F_PT; */
70 /*****************************************************/
73 #define UNIT ( 1<<FIX )
76 /* settings for a PC 120Mhz... */
77 #define MAX_DEPTH_2 10
82 #define DBL_To_F_PT(x) (F_PT)( (DBL)(UNIT)*(x) )
84 typedef struct Similitude_Struct SIMI;
85 typedef struct Fractal_Struct FRACTAL;
87 struct Similitude_Struct {
91 F_PT Ct, St, Ct2, St2;
96 struct Fractal_Struct {
99 SIMI Components[5 * MAX_SIMI];
102 int Width, Height, Lx, Ly;
103 DBL r_mean, dr_mean, dr2_mean;
105 XPoint *Buffer1, *Buffer2;
110 static FRACTAL *Root = (FRACTAL *) NULL, *Cur_F;
115 /*****************************************************/
118 Gauss_Rand(DBL c, DBL A, DBL S)
122 y = (DBL) LRAND() / MAXRAND;
123 y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
130 Half_Gauss_Rand(DBL c, DBL A, DBL S)
134 y = (DBL) LRAND() / MAXRAND;
135 y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
140 Random_Simis(FRACTAL * F, SIMI * Cur, int 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);
154 free_ifs_buffers(FRACTAL *Fractal)
156 if (Fractal->Buffer1 != NULL) {
157 (void) free((void *) Fractal->Buffer1);
158 Fractal->Buffer1 = (XPoint *) NULL;
160 if (Fractal->Buffer2 != NULL) {
161 (void) free((void *) Fractal->Buffer2);
162 Fractal->Buffer2 = (XPoint *) NULL;
168 free_ifs(Display *display, FRACTAL *Fractal)
170 free_ifs_buffers(Fractal);
171 if (Fractal->dbuf != None) {
172 XFreePixmap(display, Fractal->dbuf);
173 Fractal->dbuf = None;
175 if (Fractal->dbuf_gc != None) {
176 XFreeGC(display, Fractal->dbuf_gc);
177 Fractal->dbuf_gc = None;
181 /***************************************************************/
184 init_ifs(ModeInfo * mi)
186 Display *display = MI_DISPLAY(mi);
187 Window window = MI_WINDOW(mi);
193 Root = (FRACTAL *) calloc(
194 MI_NUM_SCREENS(mi), sizeof (FRACTAL));
198 Fractal = &Root[MI_SCREEN(mi)];
200 free_ifs_buffers(Fractal);
201 i = (NRAND(4)) + 2; /* Number of centers */
204 Fractal->Depth = MAX_DEPTH_3;
205 Fractal->r_mean = .6;
206 Fractal->dr_mean = .4;
207 Fractal->dr2_mean = .3;
211 Fractal->Depth = MAX_DEPTH_4;
212 Fractal->r_mean = .5;
213 Fractal->dr_mean = .4;
214 Fractal->dr2_mean = .3;
218 Fractal->Depth = MAX_DEPTH_5;
219 Fractal->r_mean = .5;
220 Fractal->dr_mean = .4;
221 Fractal->dr2_mean = .3;
226 Fractal->Depth = MAX_DEPTH_2;
227 Fractal->r_mean = .7;
228 Fractal->dr_mean = .3;
229 Fractal->dr2_mean = .4;
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;
238 if ((Fractal->Buffer1 = (XPoint *) calloc(Fractal->Max_Pt,
239 sizeof (XPoint))) == NULL) {
240 free_ifs(display, Fractal);
243 if ((Fractal->Buffer2 = (XPoint *) calloc(Fractal->Max_Pt,
244 sizeof (XPoint))) == NULL) {
245 free_ifs(display, Fractal);
249 Fractal->Width = MI_WIDTH(mi);
250 Fractal->Height = MI_HEIGHT(mi);
253 Fractal->Lx = (Fractal->Width - 1) / 2;
254 Fractal->Ly = (Fractal->Height - 1) / 2;
255 Fractal->Col = NRAND(MI_NPIXELS(mi) - 1) + 1;
257 Random_Simis(Fractal, Fractal->Components, 5 * MAX_SIMI);
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) {
270 gcv.graphics_exposures = False;
271 gcv.function = GXcopy;
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,
278 XFreePixmap(display, Fractal->dbuf);
279 Fractal->dbuf = None;
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);
290 /* don't want any exposure events from XCopyPlane */
291 XSetGraphicsExposures(display, gc, False);
296 /***************************************************************/
298 /* Should be taken care of already... but just in case */
299 #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus)
304 Transform(SIMI * Simi, F_PT xo, F_PT yo, F_PT * x, F_PT * y)
309 xo = (xo * Simi->R) / UNIT;
311 yo = (yo * Simi->R) / UNIT;
314 xx = (xx * Simi->R2) / UNIT;
316 yy = (yy * Simi->R2) / UNIT;
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;
322 /***************************************************************/
325 Trace(FRACTAL * F, F_PT xo, F_PT yo)
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);
340 if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) {
349 Draw_Fractal(ModeInfo * mi)
351 Display *display = MI_DISPLAY(mi);
352 Window window = MI_WINDOW(mi);
354 FRACTAL *F = &Root[MI_SCREEN(mi)];
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);
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));
368 Cur->R = DBL_To_F_PT(Cur->r);
369 Cur->R2 = DBL_To_F_PT(Cur->r2);
376 for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) {
379 for (Simi = F->Components, j = F->Nb_Simi; j; --j, Simi++) {
382 Transform(Simi, xo, yo, &x, &y);
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,
394 XFillRectangle(display, F->dbuf, F->dbuf_gc, 0, 0,
395 F->Width, F->Height);
397 XDrawPoints(display, window, gc, F->Buffer1, F->Cur_Pt, CoordModeOrigin);
399 if (MI_NPIXELS(mi) < 2)
400 XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
402 XSetForeground(display, gc, MI_PIXEL(mi, F->Col % MI_NPIXELS(mi)));
404 if (F->dbuf != None) {
405 XSetForeground(display, F->dbuf_gc, 1);
406 XDrawPoints(display, F->dbuf, F->dbuf_gc, F->Buffer2, Cur_Pt,
409 XDrawPoints(display, window, gc, F->Buffer2, Cur_Pt, CoordModeOrigin);
412 XCopyPlane(display, F->dbuf, window, gc, 0, 0, F->Width, F->Height, 0, 0, 1);
416 F->Buffer1 = F->Buffer2;
422 draw_ifs(ModeInfo * mi)
425 DBL u, uu, v, vv, u0, u1, u2, u3;
426 SIMI *S, *S1, *S2, *S3, *S4;
431 F = &Root[MI_SCREEN(mi)];
432 if (F->Buffer1 == NULL)
435 u = (DBL) (F->Count) * (DBL) (F->Speed) / 1000.0;
446 S2 = S1 + F->Nb_Simi;
447 S3 = S2 + F->Nb_Simi;
448 S4 = S3 + F->Nb_Simi;
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;
459 MI_IS_DRAWN(mi) = True;
463 if (F->Count >= 1000 / F->Speed) {
466 S2 = S1 + F->Nb_Simi;
467 S3 = S2 + F->Nb_Simi;
468 S4 = S3 + F->Nb_Simi;
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;
480 Random_Simis(F, F->Components + 3 * F->Nb_Simi, F->Nb_Simi);
482 Random_Simis(F, F->Components + 4 * F->Nb_Simi, F->Nb_Simi);
492 /***************************************************************/
495 release_ifs(ModeInfo * mi)
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;
507 #endif /* MODE_ifs */