/* -*- Mode: C; tab-width: 4 -*- */ /* ifs --- modified iterated functions system */ #if !defined( lint ) && !defined( SABER ) static const char sccsid[] = "@(#)ifs.c 5.00 2000/11/01 xlockmore"; #endif /*- * Copyright (c) 1997 by Massimino Pascal * * Permission to use, copy, modify, and distribute this software and its * documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appear in all copies and that * both that copyright notice and this permission notice appear in * supporting documentation. * * This file is provided AS IS with no warranties of any kind. The author * shall have no liability with respect to the infringement of copyrights, * trade secrets or any patents by this file or any part thereof. In no * event will the author be liable for any lost revenue or profits or * other special, indirect and consequential damages. * * If this mode is weird and you have an old MetroX server, it is buggy. * There is a free SuSE-enhanced MetroX X server that is fine. * * When shown ifs, Diana Rose (4 years old) said, "It looks like dancing." * * Revision History: * 22-Dec-2004: TDA: Replace Gauss_Rand with a real Gaussian. Fix * glitches where x=0 or y=0. * 01-Nov-2000: Allocation checks * 10-May-1997: jwz@jwz.org: turned into a standalone program. * Made it render into an offscreen bitmap and then copy * that onto the screen, to reduce flicker. */ #ifdef STANDALONE #define MODE_ifs #define PROGCLASS "IFS" #define HACK_INIT init_ifs #define HACK_DRAW draw_ifs #define ifs_opts xlockmore_opts #define DEFAULTS "*delay: 1000 \n" \ "*ncolors: 100 \n" #define SMOOTH_COLORS #include "xlockmore.h" /* in xscreensaver distribution */ #else /* STANDALONE */ #include "xlock.h" /* in xlockmore distribution */ #endif /* STANDALONE */ #ifdef MODE_ifs ModeSpecOpt ifs_opts = {0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL}; #ifdef USE_MODULES ModStruct ifs_description = {"ifs", "init_ifs", "draw_ifs", "release_ifs", "init_ifs", "init_ifs", (char *) NULL, &ifs_opts, 1000, 1, 1, 1, 64, 1.0, "", "Shows a modified iterated function system", 0, NULL}; #endif /*****************************************************/ typedef float DBL; typedef int F_PT; /* typedef float F_PT; */ /*****************************************************/ #define FIX 12 #define UNIT ( 1<= 1.0); w = sqrt((-2 * log(w))/w); ready = 1; d = x * w; return c + A/3 * y * w; } } static double Half_Gauss_Rand(DBL c, DBL A, DBL S) { static double d; static Bool ready = 0; if(ready) { ready = 0; return c + A/3 * d; } else { double x, y, w; do { x = (double)LRAND() / MAXRAND; y = (double)LRAND() / MAXRAND; w = x*x + y*y; } while(w >= 1.0); w = sqrt((-2 * log(w))/w); ready = 1; d = x * w; return c + A/3 * y * w; } } #endif static void Random_Simis(FRACTAL * F, SIMI * Cur, int i) { while (i--) { Cur->c_x = Gauss_Rand(0.0, .8, 4.0); Cur->c_y = Gauss_Rand(0.0, .8, 4.0); Cur->r = Gauss_Rand(F->r_mean, F->dr_mean, 3.0); Cur->r2 = Half_Gauss_Rand(0.0, F->dr2_mean, 2.0); Cur->A = Gauss_Rand(0.0, 360.0, 4.0) * (M_PI / 180.0); Cur->A2 = Gauss_Rand(0.0, 360.0, 4.0) * (M_PI / 180.0); Cur++; } } static void free_ifs_buffers(FRACTAL *Fractal) { if (Fractal->Buffer1 != NULL) { free(Fractal->Buffer1); Fractal->Buffer1 = (XPoint *) NULL; } if (Fractal->Buffer2 != NULL) { free(Fractal->Buffer2); Fractal->Buffer2 = (XPoint *) NULL; } } static void free_ifs(Display *display, FRACTAL *Fractal) { free_ifs_buffers(Fractal); if (Fractal->dbuf != None) { XFreePixmap(display, Fractal->dbuf); Fractal->dbuf = None; } if (Fractal->dbuf_gc != None) { XFreeGC(display, Fractal->dbuf_gc); Fractal->dbuf_gc = None; } } /***************************************************************/ void init_ifs(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = MI_GC(mi); int i; FRACTAL *Fractal; if (Root == NULL) { Root = (FRACTAL *) calloc( MI_NUM_SCREENS(mi), sizeof (FRACTAL)); if (Root == NULL) return; } Fractal = &Root[MI_SCREEN(mi)]; free_ifs_buffers(Fractal); i = (NRAND(4)) + 2; /* Number of centers */ switch (i) { case 3: Fractal->Depth = MAX_DEPTH_3; Fractal->r_mean = .6; Fractal->dr_mean = .4; Fractal->dr2_mean = .3; break; case 4: Fractal->Depth = MAX_DEPTH_4; Fractal->r_mean = .5; Fractal->dr_mean = .4; Fractal->dr2_mean = .3; break; case 5: Fractal->Depth = MAX_DEPTH_5; Fractal->r_mean = .5; Fractal->dr_mean = .4; Fractal->dr2_mean = .3; break; default: case 2: Fractal->Depth = MAX_DEPTH_2; Fractal->r_mean = .7; Fractal->dr_mean = .3; Fractal->dr2_mean = .4; break; } /* (void) fprintf( stderr, "N=%d\n", i ); */ Fractal->Nb_Simi = i; Fractal->Max_Pt = Fractal->Nb_Simi - 1; for (i = 0; i <= Fractal->Depth + 2; ++i) Fractal->Max_Pt *= Fractal->Nb_Simi; if ((Fractal->Buffer1 = (XPoint *) calloc(Fractal->Max_Pt, sizeof (XPoint))) == NULL) { free_ifs(display, Fractal); return; } if ((Fractal->Buffer2 = (XPoint *) calloc(Fractal->Max_Pt, sizeof (XPoint))) == NULL) { free_ifs(display, Fractal); return; } Fractal->Speed = 6; Fractal->Width = MI_WIDTH(mi); Fractal->Height = MI_HEIGHT(mi); Fractal->Cur_Pt = 0; Fractal->Count = 0; Fractal->Lx = (Fractal->Width - 1) / 2; Fractal->Ly = (Fractal->Height - 1) / 2; Fractal->Col = NRAND(MI_NPIXELS(mi) - 1) + 1; Random_Simis(Fractal, Fractal->Components, 5 * MAX_SIMI); #ifndef NO_DBUF if (Fractal->dbuf != None) XFreePixmap(display, Fractal->dbuf); Fractal->dbuf = XCreatePixmap(display, window, Fractal->Width, Fractal->Height, 1); /* Allocation checked */ if (Fractal->dbuf != None) { XGCValues gcv; gcv.foreground = 0; gcv.background = 0; gcv.graphics_exposures = False; gcv.function = GXcopy; if (Fractal->dbuf_gc != None) XFreeGC(display, Fractal->dbuf_gc); if ((Fractal->dbuf_gc = XCreateGC(display, Fractal->dbuf, GCForeground | GCBackground | GCGraphicsExposures | GCFunction, &gcv)) == None) { XFreePixmap(display, Fractal->dbuf); Fractal->dbuf = None; } else { XFillRectangle(display, Fractal->dbuf, Fractal->dbuf_gc, 0, 0, Fractal->Width, Fractal->Height); XSetBackground(display, gc, MI_BLACK_PIXEL(mi)); XSetFunction(display, gc, GXcopy); } } #endif MI_CLEARWINDOW(mi); /* don't want any exposure events from XCopyPlane */ XSetGraphicsExposures(display, gc, False); } /***************************************************************/ /* Should be taken care of already... but just in case */ #if !defined( __GNUC__ ) && !defined(__cplusplus) && !defined(c_plusplus) #undef inline #define inline /* */ #endif static inline void Transform(SIMI * Simi, F_PT xo, F_PT yo, F_PT * x, F_PT * y) { F_PT xx, yy; xo = xo - Simi->Cx; xo = (xo * Simi->R) / UNIT; yo = yo - Simi->Cy; yo = (yo * Simi->R) / UNIT; xx = xo - Simi->Cx; xx = (xx * Simi->R2) / UNIT; yy = -yo - Simi->Cy; yy = (yy * Simi->R2) / UNIT; *x = ((xo * Simi->Ct - yo * Simi->St + xx * Simi->Ct2 - yy * Simi->St2) / UNIT) + Simi->Cx; *y = ((xo * Simi->St + yo * Simi->Ct + xx * Simi->St2 + yy * Simi->Ct2) / UNIT) + Simi->Cy; } /***************************************************************/ static void Trace(FRACTAL * F, F_PT xo, F_PT yo) { F_PT x, y, i; SIMI *Cur; Cur = Cur_F->Components; for (i = Cur_F->Nb_Simi; i; --i, Cur++) { Transform(Cur, xo, yo, &x, &y); Buf->x = (short) (F->Lx + ((double)x * F->Lx / (UNIT * 2))); Buf->y = (short) (F->Ly - ((double)y * F->Ly / (UNIT * 2))); Buf++; Cur_Pt++; if (F->Depth && ((x - xo) >> 4) && ((y - yo) >> 4)) { F->Depth--; Trace(F, x, y); F->Depth++; } } } static void Draw_Fractal(ModeInfo * mi) { Display *display = MI_DISPLAY(mi); Window window = MI_WINDOW(mi); GC gc = MI_GC(mi); FRACTAL *F = &Root[MI_SCREEN(mi)]; int i, j; F_PT x, y, xo, yo; SIMI *Cur, *Simi; for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) { Cur->Cx = DBL_To_F_PT(Cur->c_x); Cur->Cy = DBL_To_F_PT(Cur->c_y); Cur->Ct = DBL_To_F_PT(cos(Cur->A)); Cur->St = DBL_To_F_PT(sin(Cur->A)); Cur->Ct2 = DBL_To_F_PT(cos(Cur->A2)); Cur->St2 = DBL_To_F_PT(sin(Cur->A2)); Cur->R = DBL_To_F_PT(Cur->r); Cur->R2 = DBL_To_F_PT(Cur->r2); } Cur_Pt = 0; Cur_F = F; Buf = F->Buffer2; for (Cur = F->Components, i = F->Nb_Simi; i; --i, Cur++) { xo = Cur->Cx; yo = Cur->Cy; for (Simi = F->Components, j = F->Nb_Simi; j; --j, Simi++) { if (Simi == Cur) continue; Transform(Simi, xo, yo, &x, &y); Trace(F, x, y); } } /* Erase previous */ if (F->Cur_Pt) { XSetForeground(display, gc, MI_BLACK_PIXEL(mi)); if (F->dbuf != None) { XSetForeground(display, F->dbuf_gc, 0); /* XDrawPoints(display, F->dbuf, F->dbuf_gc, F->Buffer1, F->Cur_Pt, CoordModeOrigin); */ XFillRectangle(display, F->dbuf, F->dbuf_gc, 0, 0, F->Width, F->Height); } else XDrawPoints(display, window, gc, F->Buffer1, F->Cur_Pt, CoordModeOrigin); } if (MI_NPIXELS(mi) < 2) XSetForeground(display, gc, MI_WHITE_PIXEL(mi)); else XSetForeground(display, gc, MI_PIXEL(mi, F->Col % MI_NPIXELS(mi))); if (Cur_Pt) { if (F->dbuf != None) { XSetForeground(display, F->dbuf_gc, 1); XDrawPoints(display, F->dbuf, F->dbuf_gc, F->Buffer2, Cur_Pt, CoordModeOrigin); } else XDrawPoints(display, window, gc, F->Buffer2, Cur_Pt, CoordModeOrigin); } if (F->dbuf != None) XCopyPlane(display, F->dbuf, window, gc, 0, 0, F->Width, F->Height, 0, 0, 1); F->Cur_Pt = Cur_Pt; Buf = F->Buffer1; F->Buffer1 = F->Buffer2; F->Buffer2 = Buf; } void draw_ifs(ModeInfo * mi) { int i; DBL u, uu, v, vv, u0, u1, u2, u3; SIMI *S, *S1, *S2, *S3, *S4; FRACTAL *F; if (Root == NULL) return; F = &Root[MI_SCREEN(mi)]; if (F->Buffer1 == NULL) return; u = (DBL) (F->Count) * (DBL) (F->Speed) / 1000.0; uu = u * u; v = 1.0 - u; vv = v * v; u0 = vv * v; u1 = 3.0 * vv * u; u2 = 3.0 * v * uu; u3 = u * uu; S = F->Components; S1 = S + F->Nb_Simi; S2 = S1 + F->Nb_Simi; S3 = S2 + F->Nb_Simi; S4 = S3 + F->Nb_Simi; for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) { S->c_x = u0 * S1->c_x + u1 * S2->c_x + u2 * S3->c_x + u3 * S4->c_x; S->c_y = u0 * S1->c_y + u1 * S2->c_y + u2 * S3->c_y + u3 * S4->c_y; S->r = u0 * S1->r + u1 * S2->r + u2 * S3->r + u3 * S4->r; S->r2 = u0 * S1->r2 + u1 * S2->r2 + u2 * S3->r2 + u3 * S4->r2; S->A = u0 * S1->A + u1 * S2->A + u2 * S3->A + u3 * S4->A; S->A2 = u0 * S1->A2 + u1 * S2->A2 + u2 * S3->A2 + u3 * S4->A2; } MI_IS_DRAWN(mi) = True; Draw_Fractal(mi); if (F->Count >= 1000 / F->Speed) { S = F->Components; S1 = S + F->Nb_Simi; S2 = S1 + F->Nb_Simi; S3 = S2 + F->Nb_Simi; S4 = S3 + F->Nb_Simi; for (i = F->Nb_Simi; i; --i, S++, S1++, S2++, S3++, S4++) { S2->c_x = 2.0 * S4->c_x - S3->c_x; S2->c_y = 2.0 * S4->c_y - S3->c_y; S2->r = 2.0 * S4->r - S3->r; S2->r2 = 2.0 * S4->r2 - S3->r2; S2->A = 2.0 * S4->A - S3->A; S2->A2 = 2.0 * S4->A2 - S3->A2; *S1 = *S4; } Random_Simis(F, F->Components + 3 * F->Nb_Simi, F->Nb_Simi); Random_Simis(F, F->Components + 4 * F->Nb_Simi, F->Nb_Simi); F->Count = 0; } else F->Count++; F->Col++; } /***************************************************************/ void release_ifs(ModeInfo * mi) { if (Root != NULL) { int screen; for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) free_ifs(MI_DISPLAY(mi), &Root[screen]); free(Root); Root = (FRACTAL *) NULL; } } #endif /* MODE_ifs */