X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Fifs.c;h=d79f0f32c9f9b23272a50817a920e629bd69fdd0;hb=c494fd2e6b3b25582375d62e40f4f5cc984ca424;hp=3bccf872073170a619a1d67f8d570a63a0da3b97;hpb=df7adbee81405e2849728a24b498ad2117784b1f;p=xscreensaver diff --git a/hacks/ifs.c b/hacks/ifs.c index 3bccf872..d79f0f32 100644 --- a/hacks/ifs.c +++ b/hacks/ifs.c @@ -1,479 +1,531 @@ -/* -*- Mode: C; tab-width: 4 -*- - * ifs --- Modified iterated functions system. - */ -#if !defined( lint ) && !defined( SABER ) -static const char sccsid[] = "@(#)ifs.c 4.02 97/04/01 xlockmore"; -#endif - -/* Copyright (c) 1997 by Massimino Pascal (Pascal.Massimon@ens.fr) - * - * - * 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. - * - * Revision History: - * 10-May-97: 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 PROGCLASS "IFS" -# define HACK_INIT init_ifs -# define HACK_DRAW draw_ifs -# define ifs_opts xlockmore_opts -# define DEFAULTS "*delay: 20000 \n" \ - "*ncolors: 100 \n" -# define SMOOTH_COLORS -# include "xlockmore.h" /* from the xscreensaver distribution */ -#else /* !STANDALONE */ -# include "xlock.h" /* from the xlockmore distribution */ -#endif /* !STANDALONE */ - -ModeSpecOpt ifs_opts = { - 0, NULL, 0, NULL, NULL }; - -/*****************************************************/ -/*****************************************************/ - -typedef float DBL; -typedef short int F_PT; - -/* typedef float F_PT; */ - -/*****************************************************/ +/* Copyright © Chris Le Sueur and Robby Griffin, 2005-2006 + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +Ultimate thanks go to Massimino Pascal, who created the original +xscreensaver hack, and inspired me with it's swirly goodness. This +version adds things like variable quality, number of functions and also +a groovier colouring mode. + +This version by Chris Le Sueur , Feb 2005 +Many improvements by Robby Griffin , Mar 2006 +Multi-coloured mode added by Jack Grahl , Jan 2007 +*/ + +#include +#include +#include +#include +#include + +#include "screenhack.h" + +#undef countof +#define countof(x) (sizeof((x)) / sizeof(*(x))) + +typedef struct { + float r, s, tx, ty; /* Rotation, Scale, Translation X & Y */ + float ro, rt, rc; /* Old Rotation, Rotation Target, Rotation Counter */ + float so, st, sc; /* Old Scale, Scale Target, Scale Counter */ + float sa, txa, tya; /* Scale change, Translation change */ + + int ua, ub, utx; /* Precomputed combined r,s,t values */ + int uc, ud, uty; /* Precomputed combined r,s,t values */ + +} Lens; + +struct state { + Display *dpy; + Window window; + GC gc; + Drawable backbuffer; + XColor *colours; + int ncolours; + int ccolour; + int blackColor, whiteColor; + + int width, widthb, height; + int width8, height8; + unsigned int *board; + XPoint pointbuf[1000]; + int npoints; + int xmin, xmax, ymin, ymax; + int x, y; + + int delay; + + int lensnum; + Lens *lenses; + int length; + int mode; + Bool recurse; + Bool multi; + Bool translate, scale, rotate; +}; -#define FIX 12 -#define UNIT ( 1<board[((y)*st->widthb)+((x)>>5)] & (1<<((x) & 31))) +#define setdot(x,y) (st->board[((y)*st->widthb)+((x)>>5)] |= (1<<((x) & 31))) - /* settings for a PC 120Mhz... */ -#define MAX_DEPTH_2 10 -#define MAX_DEPTH_3 6 -#define MAX_DEPTH_4 4 -#define MAX_DEPTH_5 3 +static float +myrandom(float up) +{ + return (((float)random() / RAND_MAX) * up); +} -#define DBL_To_F_PT(x) (F_PT)( (DBL)(UNIT)*(x) ) +static const char *ifs_defaults [] = { + ".background: Black", + "*lensnum: 3", + "*length: 9", + "*mode: 0", + "*colors: 200", + "*delay: 20000", + "*translate: True", + "*scale: True", + "*rotate: True", + "*recurse: False", + "*multi: True", +# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */ + "*doubleBuffer: False", +#else + "*doubleBuffer: True", +#endif + 0 +}; -/*****************************************************/ +static XrmOptionDescRec ifs_options [] = { + { "-detail", ".length", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-mode", ".mode", XrmoptionSepArg, 0 }, + { "-colors", ".colors", XrmoptionSepArg, 0 }, + { "-functions", ".lensnum", XrmoptionSepArg, 0 }, + { "-no-translate", ".translate", XrmoptionNoArg, "False" }, + { "-no-scale", ".scale", XrmoptionNoArg, "False" }, + { "-no-rotate", ".rotate", XrmoptionNoArg, "False" }, + { "-recurse", ".recurse", XrmoptionNoArg, "True" }, + { "-iterate", ".recurse", XrmoptionNoArg, "False" }, + { "-multi", ".multi", XrmoptionNoArg, "True" }, + { "-no-multi", ".multi", XrmoptionNoArg, "False" }, + { "-db", ".doubleBuffer",XrmoptionNoArg, "True" }, + { "-no-db", ".doubleBuffer",XrmoptionNoArg, "False" }, + { 0, 0, 0, 0 } +}; -static int Max_Colors; -static ModeInfo *The_MI; -static F_PT Lx, Ly; -static int D; -static Display *display; -static GC gc; -static Window window; -/*****************************************************/ +/* Draw all the queued points on the backbuffer */ +static void +drawpoints(struct state *st) +{ + XDrawPoints(st->dpy, st->backbuffer, st->gc, st->pointbuf, st->npoints, + CoordModeOrigin); + st->npoints = 0; +} -typedef struct Similitude_Struct SIMI; -typedef struct Fractal_Struct FRACTAL; +/* Set a point to be drawn, if it hasn't been already. + * Expects coordinates in 256ths of a pixel. */ +static void +sp(struct state *st, int x, int y) +{ + if (x < 0 || x >= st->width8 || y < 0 || y >= st->height8) + return; -struct Similitude_Struct { + x >>= 8; + y >>= 8; - DBL c_x, c_y; - DBL r, r2, A, A2; - F_PT Ct, St, Ct2, St2; - F_PT Cx, Cy; - F_PT R, R2; -}; + if (getdot(x, y)) return; + setdot(x, y); -struct Fractal_Struct { - - int Nb_Simi; - SIMI Components[5 * MAX_SIMI]; - int Depth, Col; - int Count, Speed; - int Width, Height, Lx, Ly; - DBL r_mean, dr_mean, dr2_mean; - int Cur_Pt, Max_Pt; - XPoint *Buffer1, *Buffer2; - Pixmap dbuf; /* jwz */ - GC dbuf_gc; -}; + if (x < st->xmin) st->xmin = x; + if (x > st->xmax) st->xmax = x; + if (y < st->ymin) st->ymin = y; + if (y > st->ymax) st->ymax = y; -static FRACTAL *Root = NULL, *Cur_F; -static XPoint *Buf; -static int Cur_Pt; + st->pointbuf[st->npoints].x = x; + st->pointbuf[st->npoints].y = y; + st->npoints++; + if (st->npoints >= countof(st->pointbuf)) { + drawpoints(st); + } +} -/*****************************************************/ -/*****************************************************/ -static DBL -Gauss_Rand(DBL c, DBL A, DBL S) +/* Precompute integer values for matrix multiplication and vector + * addition. The matrix multiplication will go like this (see iterate()): + * |x2| |ua ub| |x| |utx| + * | | = | | * | | + | | + * |y2| |uc ud| |y| |uty| + * + * There is an extra factor of 2^10 in these values, and an extra factor of + * 2^8 in the coordinates, in order to implement fixed-point arithmetic. + */ +static void +lensmatrix(struct state *st, Lens *l) { - DBL y; - - y = (DBL) LRAND() / MAXRAND; - y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S)); - if (NRAND(2)) - return (c + y); - return (c - y); + l->ua = 1024.0 * l->s * cos(l->r); + l->ub = -1024.0 * l->s * sin(l->r); + l->uc = -l->ub; + l->ud = l->ua; + l->utx = 131072.0 * st->width * (l->s * (sin(l->r) - cos(l->r)) + + l->tx / 16 + 1); + l->uty = -131072.0 * st->height * (l->s * (sin(l->r) + cos(l->r)) + + l->ty / 16 - 1); } -static DBL -Half_Gauss_Rand(DBL c, DBL A, DBL S) +static void +CreateLens(struct state *st, + float nr, + float ns, + float nx, + float ny, + Lens *newlens) { - DBL y; - - y = (DBL) LRAND() / MAXRAND; - y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S)); - return (c + y); + newlens->sa = newlens->txa = newlens->tya = 0; + if (st->rotate) { + newlens->r = newlens->ro = newlens->rt = nr; + newlens->rc = 1; + } + else newlens->r = 0; + + if (st->scale) { + newlens->s = newlens->so = newlens->st = ns; + newlens->sc = 1; + } + else newlens->s = 0.5; + + newlens->tx = nx; + newlens->ty = ny; + + lensmatrix(st, newlens); } - + static void -Random_Simis(FRACTAL * F, SIMI * Cur, int i) +mutate(struct state *st, Lens *l) { - 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++; - } + if (st->rotate) { + float factor; + if(l->rc >= 1) { + l->rc = 0; + l->ro = l->rt; + l->rt = myrandom(4) - 2; + } + factor = (sin((-M_PI / 2.0) + M_PI * l->rc) + 1.0) / 2.0; + l->r = l->ro + (l->rt - l->ro) * factor; + l->rc += 0.01; + } + if (st->scale) { + float factor; + if (l->sc >= 1) { + /* Reset counter, obtain new target value */ + l->sc = 0; + l->so = l->st; + l->st = myrandom(2) - 1; + } + factor = (sin((-M_PI / 2.0) + M_PI * l->sc) + 1.0) / 2.0; + /* Take average of old target and new target, using factor to * + * weight. It's computed sinusoidally, resulting in smooth, * + * rhythmic transitions. */ + l->s = l->so + (l->st - l->so) * factor; + l->sc += 0.01; + } + if (st->translate) { + l->txa += myrandom(0.004) - 0.002; + l->tya += myrandom(0.004) - 0.002; + l->tx += l->txa; + l->ty += l->tya; + if (l->tx > 6) l->txa -= 0.004; + if (l->ty > 6) l->tya -= 0.004; + if (l->tx < -6) l->txa += 0.004; + if (l->ty < -6) l->tya += 0.004; + if (l->txa > 0.05 || l->txa < -0.05) l->txa /= 1.7; + if (l->tya > 0.05 || l->tya < -0.05) l->tya /= 1.7; + } + if (st->rotate || st->scale || st->translate) { + lensmatrix(st, l); + } } -/***************************************************************/ -void -init_ifs(ModeInfo * mi) +#define STEPX(l,x,y) (((l)->ua * (x) + (l)->ub * (y) + (l)->utx) >> 10) +#define STEPY(l,x,y) (((l)->uc * (x) + (l)->ud * (y) + (l)->uty) >> 10) +/*#define STEPY(l,x,y) (((l)->ua * (y) - (l)->ub * (x) + (l)->uty) >> 10)*/ + +/* Calls itself times - with results from each lens/function. * + * After calls to itself, it stops iterating and draws a point. */ +static void +recurse(struct state *st, int x, int y, int length, int p) { - 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)]; - - if (Fractal->Max_Pt) { - free(Fractal->Buffer1); - free(Fractal->Buffer2); - } - 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; - - Fractal->Buffer1 = (XPoint *) calloc(Fractal->Max_Pt, sizeof (XPoint)); - if (Fractal->Buffer1 == NULL) - goto Abort; - Fractal->Buffer2 = (XPoint *) calloc(Fractal->Max_Pt, sizeof (XPoint)); - if (Fractal->Buffer2 == NULL) - goto Abort; - - Fractal->Speed = 6; - Fractal->Width = MI_WIN_WIDTH(mi); - Fractal->Height = MI_WIN_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); - - Fractal->dbuf = XCreatePixmap(MI_DISPLAY(mi), MI_WINDOW(mi), - Fractal->Width, Fractal->Height, 1); - if (Fractal->dbuf) - { - XGCValues gcv; - gcv.foreground = 0; - gcv.background = 0; - gcv.function = GXcopy; - Fractal->dbuf_gc = XCreateGC(MI_DISPLAY(mi), Fractal->dbuf, - GCForeground|GCBackground|GCFunction, - &gcv); - XFillRectangle(MI_DISPLAY(mi), Fractal->dbuf, - Fractal->dbuf_gc, 0,0, Fractal->Width, Fractal->Height); - - XSetBackground(MI_DISPLAY(mi), MI_GC(mi), MI_WIN_BLACK_PIXEL(mi)); - XSetFunction(MI_DISPLAY(mi), MI_GC(mi), GXcopy); - } - - XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi)); - return; - - Abort: - if (Fractal->Buffer1 != NULL) - free(Fractal->Buffer1); - if (Fractal->Buffer2 != NULL) - free(Fractal->Buffer2); - Fractal->Buffer1 = NULL; - Fractal->Buffer2 = NULL; - Fractal->Max_Pt = 0; - return; + int i; + Lens *l; + + if (length == 0) { + if (p == 0) + sp(st, x, y); + else { + l = &st->lenses[p]; + sp(st, STEPX(l, x, y), STEPY(l, x, y)); + } + } + else { + for (i = 0; i < st->lensnum; i++) { + l = &st->lenses[i]; + recurse(st, STEPX(l, x, y), STEPY(l, x, y), length - 1, p); + } + } } - -/***************************************************************/ - -#ifndef __GNUC__ -# undef inline -# define inline /* */ -#endif - -static inline void -Transform(SIMI * Simi, F_PT xo, F_PT yo, F_PT * x, F_PT * y) +/* Performs random lens transformations, drawing a point at each + * iteration after the first 10. + */ +static void +iterate(struct state *st, int count, int p) { - 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; + int i; + Lens *l; + int x = st->x; + int y = st->y; + int tx; + +# define STEP() \ + l = &st->lenses[random() % st->lensnum]; \ + tx = STEPX(l, x, y); \ + y = STEPY(l, x, y); \ + x = tx + + for (i = 0; i < 10; i++) { + STEP(); + } + + for ( ; i < count; i++) { + STEP(); + if (p == 0) + sp(st, x, y); + else + { + l = &st->lenses[p]; + sp(st, STEPX(l, x, y), STEPY(l, x, y)); + } + } + +# undef STEP + + st->x = x; + st->y = y; } -/***************************************************************/ +/* Come on and iterate, iterate, iterate and sing... * + * Yeah, this function just calls iterate, mutate, * + * and then draws everything. */ +static unsigned long +ifs_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int i; + int xmin = st->xmin, xmax = st->xmax, ymin = st->ymin, ymax = st->ymax; + int partcolor, x, y; + + + /* erase whatever was drawn in the previous frame */ + if (xmin <= xmax && ymin <= ymax) { + XSetForeground(st->dpy, st->gc, st->blackColor); + XFillRectangle(st->dpy, st->backbuffer, st->gc, + xmin, ymin, + xmax - xmin + 1, ymax - ymin + 1); + st->xmin = st->width + 1; + st->xmax = st->ymax = -1; + st->ymin = st->height + 1; + } + + st->ccolour++; + st->ccolour %= st->ncolours; + + /* calculate and draw points for this frame */ + x = st->width << 7; + y = st->height << 7; + + if (st->multi) { + for (i = 0; i < st->lensnum; i++) { + partcolor = st->ccolour * (i+1); + partcolor %= st->ncolours; + XSetForeground(st->dpy, st->gc, st->colours[partcolor].pixel); + memset(st->board, 0, st->widthb * st->height * sizeof(*st->board)); + if (st->recurse) + recurse(st, x, y, st->length - 1, i); + else + iterate(st, pow(st->lensnum, st->length - 1), i); + if (st->npoints) + drawpoints(st); + } + } + else { + + XSetForeground(st->dpy, st->gc, st->colours[st->ccolour].pixel); + memset(st->board, 0, st->widthb * st->height * sizeof(*st->board)); + if (st->recurse) + recurse(st, x, y, st->length, 0); + else + iterate(st, pow(st->lensnum, st->length), 0); + if (st->npoints) + drawpoints(st); + } + + /* if we just drew into a buffer, copy the changed area (including + * erased area) to screen */ + if (st->backbuffer != st->window + && ((st->xmin <= st->xmax && st->ymin <= st->ymax) + || (xmin <= xmax && ymin <= ymax))) { + if (st->xmin < xmin) xmin = st->xmin; + if (st->xmax > xmax) xmax = st->xmax; + if (st->ymin < ymin) ymin = st->ymin; + if (st->ymax > ymax) ymax = st->ymax; + XCopyArea(st->dpy, st->backbuffer, st->window, st->gc, + xmin, ymin, + xmax - xmin + 1, ymax - ymin + 1, + xmin, ymin); + } + + for(i = 0; i < st->lensnum; i++) { + mutate(st, &st->lenses[i]); + } + + return st->delay; +} static void -Trace(F_PT xo, F_PT yo) +ifs_reshape (Display *, Window, void *, unsigned int, unsigned int); + +static void * +ifs_init (Display *d_arg, Window w_arg) { - 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 = Lx + (x * Lx / (UNIT * 2)); - Buf->y = Ly - (y * Ly / (UNIT * 2)); - Buf++; - Cur_Pt++; - - if (D && ((x - xo) >> 4) && ((y - yo) >> 4)) { - D--; - Trace(x, y); - D++; - } - } + struct state *st = (struct state *) calloc (1, sizeof(*st)); + int i; + XWindowAttributes xgwa; + + /* Initialise all this X shizzle */ + st->dpy = d_arg; + st->window = w_arg; + + st->blackColor = BlackPixel(st->dpy, DefaultScreen(st->dpy)); + st->whiteColor = WhitePixel(st->dpy, DefaultScreen(st->dpy)); + st->gc = XCreateGC(st->dpy, st->window, 0, NULL); + + XGetWindowAttributes (st->dpy, st->window, &xgwa); + ifs_reshape(st->dpy, st->window, st, xgwa.width, xgwa.height); + + st->ncolours = get_integer_resource(st->dpy, "colors", "Colors"); + if (st->ncolours < st->lensnum) + st->ncolours = st->lensnum; + if (st->colours) free(st->colours); + st->colours = (XColor *)calloc(st->ncolours, sizeof(XColor)); + if (!st->colours) exit(1); + make_smooth_colormap (st->dpy, xgwa.visual, xgwa.colormap, + st->colours, &st->ncolours, + True, 0, False); + + /* Initialize IFS data */ + + st->delay = get_integer_resource(st->dpy, "delay", "Delay"); + st->length = get_integer_resource(st->dpy, "length", "Detail"); + if (st->length < 0) st->length = 0; + st->mode = get_integer_resource(st->dpy, "mode", "Mode"); + + st->rotate = get_boolean_resource(st->dpy, "rotate", "Boolean"); + st->scale = get_boolean_resource(st->dpy, "scale", "Boolean"); + st->translate = get_boolean_resource(st->dpy, "translate", "Boolean"); + st->recurse = get_boolean_resource(st->dpy, "recurse", "Boolean"); + st->multi = get_boolean_resource(st->dpy, "multi", "Boolean"); + + st->lensnum = get_integer_resource(st->dpy, "lensnum", "Functions"); + if (st->lenses) free (st->lenses); + st->lenses = (Lens *)calloc(st->lensnum, sizeof(Lens)); + if (!st->lenses) exit(1); + for (i = 0; i < st->lensnum; i++) { + CreateLens(st, + myrandom(1)-0.5, + myrandom(1), + myrandom(4)-2, + myrandom(4)+2, + &st->lenses[i]); + } + + return st; } static void -Draw_Fractal(FRACTAL * F) +ifs_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) { - 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; - Lx = F->Lx; - Ly = F->Ly; - D = F->Depth; - 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(x, y); - } - } - - /* Erase previous */ - - if (F->Cur_Pt) { - XSetForeground(display, gc, MI_WIN_BLACK_PIXEL(The_MI)); - if (F->dbuf) /* jwz */ - { - 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 (Max_Colors < 2) - XSetForeground(display, gc, MI_WIN_WHITE_PIXEL(The_MI)); - else - XSetForeground(display, gc, MI_PIXEL(The_MI, F->Col % Max_Colors)); - if (Cur_Pt) { - if (F->dbuf) - { - 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) - 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; + struct state *st = (struct state *)closure; + XWindowAttributes xgwa; + + /* oh well, we need the screen depth anyway */ + XGetWindowAttributes (st->dpy, st->window, &xgwa); + + st->width = xgwa.width; + st->widthb = ((xgwa.width + 31) >> 5); + st->height = xgwa.height; + st->width8 = xgwa.width << 8; + st->height8 = xgwa.height << 8; + + if (!st->xmax && !st->ymax && !st->xmin && !st->ymin) { + st->xmin = xgwa.width + 1; + st->xmax = st->ymax = -1; + st->ymin = xgwa.height + 1; + } + + if (st->backbuffer != None && st->backbuffer != st->window) { + XFreePixmap(st->dpy, st->backbuffer); + st->backbuffer = None; + } + + if (get_boolean_resource (st->dpy, "doubleBuffer", "Boolean")) { + st->backbuffer = XCreatePixmap(st->dpy, st->window, st->width, st->height, xgwa.depth); + XSetForeground(st->dpy, st->gc, st->blackColor); + XFillRectangle(st->dpy, st->backbuffer, st->gc, + 0, 0, st->width, st->height); + } else { + st->backbuffer = st->window; + XClearWindow(st->dpy, st->window); + } + + if (st->board) free(st->board); + st->board = (unsigned int *)calloc(st->widthb * st->height, sizeof(unsigned int)); + if (!st->board) exit(1); } - -void -draw_ifs(ModeInfo * mi) +static Bool +ifs_event (Display *dpy, Window window, void *closure, XEvent *event) { - int i; - FRACTAL *F; - DBL u, uu, v, vv, u0, u1, u2, u3; - SIMI *S, *S1, *S2, *S3, *S4; - - The_MI = mi; - display = MI_DISPLAY(mi); - window = MI_WINDOW(mi); - gc = MI_GC(mi); - Max_Colors = MI_NPIXELS(mi); - - F = &Root[MI_SCREEN(mi)]; - - 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; - } - - Draw_Fractal(F); - - 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++; + return False; } - -/***************************************************************/ - -void -release_ifs(ModeInfo * mi) +static void +ifs_free (Display *dpy, Window window, void *closure) { - int i; - - if (Root == NULL) - return; - - for (i = 0; i < MI_NUM_SCREENS(mi); ++i) { - if (Root[i].Buffer1 != NULL) - free(Root[i].Buffer1); - if (Root[i].Buffer2 != NULL) - free(Root[i].Buffer2); - if (Root[i].dbuf) - XFreePixmap(MI_DISPLAY(mi), Root[i].dbuf); - if (Root[i].dbuf_gc) - XFreeGC(MI_DISPLAY(mi), Root[i].dbuf_gc); - } - free(Root); - Root = NULL; + struct state *st = (struct state *) closure; + + if (st->board) free(st->board); + if (st->lenses) free(st->lenses); + if (st->colours) free(st->colours); + if (st->backbuffer != None && st->backbuffer != st->window) + XFreePixmap(st->dpy, st->backbuffer); + free(st); } + +XSCREENSAVER_MODULE ("IFS", ifs)