-/* -*- Mode: C; tab-width: 4 -*- */
-/* ifs --- modified iterated functions system */
-
-#if 0
-static const char sccsid[] = "@(#)ifs.c 5.00 2000/11/01 xlockmore";
-#endif
+/* 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 <thefishface@gmail.com>, Feb 2005
+Many improvements by Robby Griffin <rmg@terc.edu>, Mar 2006
+*/
+
+#include <assert.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#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 translate, scale, rotate;
+};
-/*-
- * 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.
- *
- * 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:
- * 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.
- */
+#define getdot(x,y) (st->board[((y)*st->widthb)+((x)>>5)] & (1<<((x) & 31)))
+#define setdot(x,y) (st->board[((y)*st->widthb)+((x)>>5)] |= (1<<((x) & 31)))
-#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: 20000 \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};
+static float
+myrandom(float up)
+{
+ return (((float)random() / RAND_MAX) * up);
+}
+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",
+# ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
+ "*doubleBuffer: False",
+#else
+ "*doubleBuffer: True",
#endif
+ 0
+};
-/*****************************************************/
-
-typedef float DBL;
-typedef int F_PT;
-
-/* typedef float F_PT; */
-
-/*****************************************************/
-
-#define FIX 12
-#define UNIT ( 1<<FIX )
-#define MAX_SIMI 6
-
- /* 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
-
-#define DBL_To_F_PT(x) (F_PT)( (DBL)(UNIT)*(x) )
-
-typedef struct Similitude_Struct SIMI;
-typedef struct Fractal_Struct FRACTAL;
+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" },
+ { "-db", ".doubleBuffer",XrmoptionNoArg, "True" },
+ { "-no-db", ".doubleBuffer",XrmoptionNoArg, "False" },
+ { 0, 0, 0, 0 }
+};
-struct Similitude_Struct {
- DBL c_x, c_y;
- DBL r, r2, A, A2;
- F_PT Ct, St, Ct2, St2;
- F_PT Cx, Cy;
- F_PT R, R2;
-};
+/* 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;
+}
-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;
- GC dbuf_gc;
-};
+/* 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;
-static FRACTAL *Root = (FRACTAL *) NULL, *Cur_F;
-static XPoint *Buf;
-static int Cur_Pt;
+ x >>= 8;
+ y >>= 8;
+ if (getdot(x, y)) return;
+ setdot(x, y);
-/*****************************************************/
+ 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 DBL
-Gauss_Rand(DBL c, DBL A, DBL S)
-{
- DBL y;
+ st->pointbuf[st->npoints].x = x;
+ st->pointbuf[st->npoints].y = y;
+ st->npoints++;
- 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);
+ if (st->npoints >= countof(st->pointbuf)) {
+ drawpoints(st);
+ }
}
-static DBL
-Half_Gauss_Rand(DBL c, DBL A, DBL S)
-{
- DBL y;
- y = (DBL) LRAND() / MAXRAND;
- y = A * (1.0 - exp(-y * y * S)) / (1.0 - exp(-S));
- return (c + y);
+/* 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)
+{
+ 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 void
-Random_Simis(FRACTAL * F, SIMI * Cur, int i)
+CreateLens(struct state *st,
+ float nr,
+ float ns,
+ float nx,
+ float ny,
+ Lens *newlens)
{
- 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++;
- }
+ 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->tx = ny;
+
+ lensmatrix(st, newlens);
}
-
+
static void
-free_ifs_buffers(FRACTAL *Fractal)
+mutate(struct state *st, Lens *l)
{
- if (Fractal->Buffer1 != NULL) {
- (void) free((void *) Fractal->Buffer1);
- Fractal->Buffer1 = (XPoint *) NULL;
- }
- if (Fractal->Buffer2 != NULL) {
- (void) free((void *) Fractal->Buffer2);
- Fractal->Buffer2 = (XPoint *) NULL;
- }
+ 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);
+ }
}
+#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 <lensnum> times - with results from each lens/function. *
+ * After <length> calls to itself, it stops iterating and draws a point. */
static void
-free_ifs(Display *display, FRACTAL *Fractal)
+recurse(struct state *st, int x, int y, int length)
{
- 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;
- }
+ int i;
+ Lens *l;
+
+ if (length == 0) {
+ sp(st, 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);
+ }
+ }
}
-/***************************************************************/
-
-void
-init_ifs(ModeInfo * mi)
+/* Performs <count> random lens transformations, drawing a point at each
+ * iteration after the first 10.
+ */
+static void
+iterate(struct state *st, int count)
{
- 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);
-
+ 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();
+ sp(st, x, y);
+ }
+
+# undef STEP
+
+ st->x = x;
+ st->y = y;
}
-
-/***************************************************************/
-
-/* 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)
+/* 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)
{
- 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;
+ struct state *st = (struct state *) closure;
+ int i;
+ int xmin = st->xmin, xmax = st->xmax, ymin = st->ymin, ymax = st->ymax;
+
+ /* 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;
+ XSetForeground(st->dpy, st->gc, st->colours[st->ccolour].pixel);
+
+ /* calculate and draw points for this frame */
+ memset(st->board, 0, st->widthb * st->height * sizeof(*st->board));
+ if (st->recurse)
+ recurse(st, st->width << 7, st->height << 7, st->length);
+ else
+ iterate(st, pow(st->lensnum, st->length));
+ 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(FRACTAL * F, 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 = F->Lx + (x * F->Lx / (UNIT * 2)); */
- /* Buf->y = F->Ly - (y * F->Ly / (UNIT * 2)); */
- Buf->x = (UNIT * 2 + x) * F->Lx / (UNIT * 2);
- Buf->y = (UNIT * 2 - 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++;
- }
- }
+ 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->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(ModeInfo * mi)
+ifs_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
{
- 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;
+ 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;
- 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++;
+ return False;
}
-
-/***************************************************************/
-
-void
-release_ifs(ModeInfo * mi)
+static void
+ifs_free (Display *dpy, Window window, void *closure)
{
- if (Root != NULL) {
- int screen;
-
- for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
- free_ifs(MI_DISPLAY(mi), &Root[screen]);
- (void) free((void *) Root);
- Root = (FRACTAL *) 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);
}
-#endif /* MODE_ifs */
+XSCREENSAVER_MODULE ("IFS", ifs)