+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- * drift --- drifting recursive fractal cosmic flames.
- */
-#if !defined( lint ) && !defined( SABER )
-static const char sccsid[] = "@(#)drift.c 4.02 97/04/01 xlockmore";
-#endif
-
-/* Copyright (c) 1991 by Patrick J. Naughton.
- *
- * 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.
- * 01-Jan-97: Moved new flame to drift. Compile time options now run time.
- * 01-Jun-95: Updated by Scott Draves.
- * 27-Jun-91: vary number of functions used.
- * 24-Jun-91: fixed portability problem with integer mod (%).
- * 06-Jun-91: Written. (received from Scott Draves, spot@cs.cmu.edu).
- */
-
-#ifdef STANDALONE
-# define PROGCLASS "Drift"
-# define HACK_INIT init_drift
-# define HACK_DRAW draw_drift
-# define drift_opts xlockmore_opts
-# define DEFAULTS "*count: 30 \n" \
- "*delay: 10000 \n" \
- "*ncolors: 200 \n"
-# define SMOOTH_COLORS
-# include "xlockmore.h" /* from the xscreensaver distribution */
-# include "erase.h"
-#else /* !STANDALONE */
-# include "xlock.h" /* from the xlockmore distribution */
-#endif /* !STANDALONE */
-
-
-#define MAXBATCH1 200 /* mono */
-#define MAXBATCH2 20 /* color */
-#define FUSE 10 /* discard this many initial iterations */
-#define NMAJORVARS 7
-#define MAXLEV 10
-
-#define DEF_GROW "False" /* Grow fractals instead of animating one at a time,
- would then be like flame */
-#define DEF_LISS "False" /* if this is defined then instead of a point
- bouncing around in a high dimensional sphere, we
- use lissojous figures. Only makes sense if
- grow is false. */
-
-static Bool grow;
-static Bool liss;
-
-static XrmOptionDescRec opts[] =
-{
- {"-grow", ".drift.grow", XrmoptionNoArg, (caddr_t) "on"},
- {"+grow", ".drift.grow", XrmoptionNoArg, (caddr_t) "off"},
- {"-liss", ".drift.trail", XrmoptionNoArg, (caddr_t) "on"},
- {"+liss", ".drift.trail", XrmoptionNoArg, (caddr_t) "off"}
-};
-static argtype vars[] =
-{
- {(caddr_t *) & grow, "grow", "Grow", DEF_GROW, t_Bool},
- {(caddr_t *) & liss, "liss", "Liss", DEF_LISS, t_Bool}
-};
-static OptionStruct desc[] =
-{
- {"-/+grow", "turn on/off growing fractals, else they are animated"},
- {"-/+liss", "turn on/off using lissojous figures to get points"}
-};
-
-ModeSpecOpt drift_opts = { 4, opts, 2, vars, desc };
-
-
-typedef struct {
- /* shape of current flame */
- int nxforms;
- double f[2][3][MAXLEV]; /* a bunch of non-homogeneous xforms */
- int variation[10]; /* for each xform */
-
- /* Animation */
- double df[2][3][MAXLEV];
-
- /* high-level control */
- int mode; /* 0->slow/single 1->fast/many */
- int nfractals; /* draw this many fractals */
- int major_variation;
- int fractal_len; /* pts/fractal */
- int color;
- int rainbow; /* more than one color per fractal
- 1-> computed by adding dimension to fractal */
-
- int width, height; /* of window */
- int timer;
-
- /* draw info about current flame */
- int fuse; /* iterate this many before drawing */
- int total_points; /* draw this many pts before fractal ends */
- int npoints; /* how many we've computed but not drawn */
- XPoint pts[MAXBATCH1]; /* here they are */
- unsigned long pixcol;
- /* when drawing in color, we have a buffer per color */
- int ncpoints[NUMCOLORS];
- XPoint cpts[NUMCOLORS][MAXBATCH2];
-
- double x, y, c;
- int liss_time;
- Bool grow, liss;
-} driftstruct;
-
-static driftstruct *drifts = NULL;
-
-static short
-halfrandom(int mv)
-{
- static short lasthalf = 0;
- unsigned long r;
-
- if (lasthalf) {
- r = lasthalf;
- lasthalf = 0;
- } else {
- r = LRAND();
- lasthalf = r >> 16;
- }
- r = r % mv;
- return r;
-}
-
-static int
-frandom(int n)
-{
- static long saved_random_bits = 0;
- static int nbits = 0;
- int result;
-
- if (3 > nbits) {
- saved_random_bits = LRAND();
- nbits = 31;
- }
- switch (n) {
- case 2:
- result = saved_random_bits & 1;
- saved_random_bits >>= 1;
- nbits -= 1;
- return result;
-
- case 3:
- result = saved_random_bits & 3;
- saved_random_bits >>= 2;
- nbits -= 2;
- if (3 == result)
- return frandom(3);
- return result;
-
- case 4:
- result = saved_random_bits & 3;
- saved_random_bits >>= 2;
- nbits -= 2;
- return result;
-
- case 5:
- result = saved_random_bits & 7;
- saved_random_bits >>= 3;
- nbits -= 3;
- if (4 < result)
- return frandom(5);
- return result;
- default:
- (void) fprintf(stderr, "bad arg to frandom\n");
- exit(1);
- }
- return 0;
-}
-
-#define DISTRIB_A (halfrandom(7000) + 9000)
-#define DISTRIB_B ((frandom(3) + 1) * (frandom(3) + 1) * 120000)
-#define LEN(x) (sizeof(x)/sizeof((x)[0]))
-
-static void
-initmode(ModeInfo * mi, int mode)
-{
- driftstruct *dp = &drifts[MI_SCREEN(mi)];
-
-#define VARIATION_LEN 14
-
- dp->mode = mode;
-
- dp->major_variation = halfrandom(VARIATION_LEN);
- /* 0, 0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 6, 6, 6 */
- dp->major_variation = ((dp->major_variation >= VARIATION_LEN >> 1) &&
- (dp->major_variation < VARIATION_LEN - 1)) ?
- (dp->major_variation + 1) >> 1 : dp->major_variation >> 1;
-
- if (dp->grow) {
- dp->rainbow = 0;
- if (mode) {
- if (!dp->color || halfrandom(8)) {
- dp->nfractals = halfrandom(30) + 5;
- dp->fractal_len = DISTRIB_A;
- } else {
- dp->nfractals = halfrandom(5) + 5;
- dp->fractal_len = DISTRIB_B;
- }
- } else {
- dp->rainbow = dp->color;
- dp->nfractals = 1;
- dp->fractal_len = DISTRIB_B;
- }
- } else {
- dp->nfractals = 1;
- dp->rainbow = dp->color;
- dp->fractal_len = 2000000;
- }
- dp->fractal_len = (dp->fractal_len * MI_BATCHCOUNT(mi)) / 20;
- XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
-}
-
-static void
-pick_df_coefs(ModeInfo * mi)
-{
- driftstruct *dp = &drifts[MI_SCREEN(mi)];
- int i, j, k;
- double r;
-
- for (i = 0; i < dp->nxforms; i++) {
-
- r = 1e-6;
- for (j = 0; j < 2; j++)
- for (k = 0; k < 3; k++) {
- dp->df[j][k][i] = ((double) halfrandom(1000) / 500.0 - 1.0);
- r += dp->df[j][k][i] * dp->df[j][k][i];
- }
- r = (3 + halfrandom(5)) * 0.01 / sqrt(r);
- for (j = 0; j < 2; j++)
- for (k = 0; k < 3; k++)
- dp->df[j][k][i] *= r;
- }
-}
-
-static void
-initfractal(ModeInfo * mi)
-{
- driftstruct *dp = &drifts[MI_SCREEN(mi)];
- int i, j, k;
-
-#define XFORM_LEN 9
-
- dp->fuse = FUSE;
- dp->total_points = 0;
- if (dp->rainbow)
- for (i = 0; i < MI_NPIXELS(mi); i++)
- dp->ncpoints[i] = 0;
- else
- dp->npoints = 0;
- dp->nxforms = halfrandom(XFORM_LEN);
- /* 2, 2, 2, 3, 3, 3, 4, 4, 5 */
- dp->nxforms = (dp->nxforms >= XFORM_LEN - 1) + dp->nxforms / 3 + 2;
-
- dp->c = dp->x = dp->y = 0.0;
- if (dp->liss && !halfrandom(10)) {
- dp->liss_time = 0;
- }
- if (!dp->grow)
- pick_df_coefs(mi);
- for (i = 0; i < dp->nxforms; i++) {
- if (NMAJORVARS == dp->major_variation)
- dp->variation[i] = halfrandom(NMAJORVARS);
- else
- dp->variation[i] = dp->major_variation;
- for (j = 0; j < 2; j++)
- for (k = 0; k < 3; k++) {
- if (dp->liss)
- dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
- else
- dp->f[j][k][i] = ((double) halfrandom(1000) / 500.0 - 1.0);
- }
- }
- if (dp->color)
- dp->pixcol = MI_PIXEL(mi, halfrandom(MI_NPIXELS(mi)));
- else
- dp->pixcol = MI_WIN_WHITE_PIXEL(mi);
-
-}
-
-
-void
-init_drift(ModeInfo * mi)
-{
- driftstruct *dp;
-
- if (drifts == NULL) {
- if ((drifts = (driftstruct *) calloc(MI_NUM_SCREENS(mi),
- sizeof (driftstruct))) == NULL)
- return;
- }
- dp = &drifts[MI_SCREEN(mi)];
-
- dp->width = MI_WIN_WIDTH(mi);
- dp->height = MI_WIN_HEIGHT(mi);
- dp->color = MI_NPIXELS(mi) > 2;
-
- if (MI_WIN_IS_FULLRANDOM(mi)) {
-#if 1 /* jwz: even up the odds */
- switch ((int) (LRAND() % 3)) {
- case 0: dp->grow = True; dp->liss = False; break;
- case 1: dp->grow = False; dp->liss = True; break;
- default: dp->grow = False; dp->liss = False; break;
- /* liss and grow don't work together. */
- }
-#else /* 0 */
- if (LRAND() & 1)
- dp->grow = True;
- else {
- dp->grow = False;
- dp->liss = (Bool) (LRAND() & 1);
- }
-#endif
- } else {
- dp->grow = grow;
- if (dp->grow)
- dp->liss = False;
- else
- dp->liss = liss;
- }
- initmode(mi, 1);
- initfractal(mi);
-}
-
-static void
-iter(driftstruct * dp)
-{
- int i = frandom(dp->nxforms);
- double nx, ny, nc;
-
-
- if (i)
- nc = (dp->c + 1.0) / 2.0;
- else
- nc = dp->c / 2.0;
-
- nx = dp->f[0][0][i] * dp->x + dp->f[0][1][i] * dp->y + dp->f[0][2][i];
- ny = dp->f[1][0][i] * dp->x + dp->f[1][1][i] * dp->y + dp->f[1][2][i];
-
-
- switch (dp->variation[i]) {
- case 1:
- /* sinusoidal */
- nx = sin(nx);
- ny = sin(ny);
- break;
- case 2:
- {
- /* complex */
- double r2 = nx * nx + ny * ny + 1e-6;
-
- nx = nx / r2;
- ny = ny / r2;
- break;
- }
- case 3:
- /* bent */
- if (nx < 0.0)
- nx = nx * 2.0;
- if (ny < 0.0)
- ny = ny / 2.0;
- break;
- case 4:
- {
- /* swirl */
-
- double r = (nx * nx + ny * ny); /* times k here is fun */
- double c1 = sin(r);
- double c2 = cos(r);
- double t = nx;
-
- if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
- ny = 1e4;
- else
- ny = c2 * t + c1 * ny;
- nx = c1 * nx - c2 * ny;
- break;
- }
- case 5:
- {
- /* horseshoe */
- double r, c1, c2, t;
-
- /* Avoid atan2: DOMAIN error message */
- if (nx == 0.0 && ny == 0.0)
- r = 0.0;
- else
- r = atan2(nx, ny); /* times k here is fun */
- c1 = sin(r);
- c2 = cos(r);
- t = nx;
-
- nx = c1 * nx - c2 * ny;
- ny = c2 * t + c1 * ny;
- break;
- }
- case 6:
- {
- /* drape */
- double t;
-
- /* Avoid atan2: DOMAIN error message */
- if (nx == 0.0 && ny == 0.0)
- t = 0.0;
- else
- t = atan2(nx, ny) / M_PI;
-
- if (nx > 1e4 || nx < -1e4 || ny > 1e4 || ny < -1e4)
- ny = 1e4;
- else
- ny = sqrt(nx * nx + ny * ny) - 1.0;
- nx = t;
- break;
- }
- }
-
-#if 0
- /* here are some others */
- {
- /* broken */
- if (nx > 1.0)
- nx = nx - 1.0;
- if (nx < -1.0)
- nx = nx + 1.0;
- if (ny > 1.0)
- ny = ny - 1.0;
- if (ny < -1.0)
- ny = ny + 1.0;
- break;
- }
- {
- /* complex sine */
- double u = nx, v = ny;
- double ev = exp(v);
- double emv = exp(-v);
-
- nx = (ev + emv) * sin(u) / 2.0;
- ny = (ev - emv) * cos(u) / 2.0;
- }
- {
-
- /* polynomial */
- if (nx < 0)
- nx = -nx * nx;
- else
- nx = nx * nx;
-
- if (ny < 0)
- ny = -ny * ny;
- else
- ny = ny * ny;
- }
- {
- /* spherical */
- double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
-
- nx = nx / r;
- ny = ny / r;
- }
- {
- nx = atan(nx) / M_PI_2
- ny = atan(ny) / M_PI_2
- }
-#endif
-
- /* how to check nan too? some machines don't have finite().
- don't need to check ny, it'll propogate */
- if (nx > 1e4 || nx < -1e4) {
- nx = halfrandom(1000) / 500.0 - 1.0;
- ny = halfrandom(1000) / 500.0 - 1.0;
- dp->fuse = FUSE;
- }
- dp->x = nx;
- dp->y = ny;
- dp->c = nc;
-
-}
-
-static void
-draw(ModeInfo * mi, driftstruct * dp, Drawable d)
-{
- Display *display = MI_DISPLAY(mi);
- GC gc = MI_GC(mi);
- double x = dp->x;
- double y = dp->y;
- int fixed_x, fixed_y, npix, c, n;
-
- if (dp->fuse) {
- dp->fuse--;
- return;
- }
- if (!(x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0))
- return;
-
- fixed_x = (int) ((dp->width / 2) * (x + 1.0));
- fixed_y = (int) ((dp->height / 2) * (y + 1.0));
-
- if (!dp->rainbow) {
-
- dp->pts[dp->npoints].x = fixed_x;
- dp->pts[dp->npoints].y = fixed_y;
- dp->npoints++;
- if (dp->npoints == MAXBATCH1) {
- XSetForeground(display, gc, dp->pixcol);
- XDrawPoints(display, d, gc, dp->pts, dp->npoints, CoordModeOrigin);
- dp->npoints = 0;
- }
- } else {
-
- npix = MI_NPIXELS(mi);
- c = (int) (dp->c * npix);
-
- if (c < 0)
- c = 0;
- if (c >= npix)
- c = npix - 1;
- n = dp->ncpoints[c];
- dp->cpts[c][n].x = fixed_x;
- dp->cpts[c][n].y = fixed_y;
- if (++dp->ncpoints[c] == MAXBATCH2) {
- XSetForeground(display, gc, MI_PIXEL(mi, c));
- XDrawPoints(display, d, gc, dp->cpts[c],
- dp->ncpoints[c], CoordModeOrigin);
- dp->ncpoints[c] = 0;
- }
- }
-}
-
-static void
-draw_flush(ModeInfo * mi, driftstruct * dp, Drawable d)
-{
- Display *display = MI_DISPLAY(mi);
- GC gc = MI_GC(mi);
-
- if (dp->rainbow) {
- int npix = MI_NPIXELS(mi);
- int i;
-
- for (i = 0; i < npix; i++) {
- if (dp->ncpoints[i]) {
- XSetForeground(display, gc, MI_PIXEL(mi, i));
- XDrawPoints(display, d, gc, dp->cpts[i],
- dp->ncpoints[i], CoordModeOrigin);
- dp->ncpoints[i] = 0;
- }
- }
- } else {
- if (dp->npoints)
- XSetForeground(display, gc, dp->pixcol);
- XDrawPoints(display, d, gc, dp->pts,
- dp->npoints, CoordModeOrigin);
- dp->npoints = 0;
- }
-}
-
-
-void
-draw_drift(ModeInfo * mi)
-{
- Window window = MI_WINDOW(mi);
- driftstruct *dp = &drifts[MI_SCREEN(mi)];
-
- dp->timer = 3000;
-
- while (dp->timer) {
- iter(dp);
- draw(mi, dp, window);
- if (dp->total_points++ > dp->fractal_len) {
- draw_flush(mi, dp, window);
- if (0 == --dp->nfractals) {
-#ifdef STANDALONE
- XSync(MI_DISPLAY(mi), False);
- sleep(4); /* #### make settable */
- erase_full_window(MI_DISPLAY(mi), MI_WINDOW(mi));
-#endif /* STANDALONE */
- initmode(mi, frandom(2));
- }
- initfractal(mi);
- }
- dp->timer--;
- }
- if (!dp->grow) {
- int i, j, k;
-
- draw_flush(mi, dp, window);
- if (dp->liss)
- dp->liss_time++;
- for (i = 0; i < dp->nxforms; i++)
- for (j = 0; j < 2; j++)
- for (k = 0; k < 3; k++) {
- if (dp->liss)
- dp->f[j][k][i] = sin(dp->liss_time * dp->df[j][k][i]);
- else {
- double t = dp->f[j][k][i] += dp->df[j][k][i];
-
- if (t < -1.0 || 1.0 < t)
- dp->df[j][k][i] *= -1.0;
- }
- }
- }
-}
-
-void
-release_drift(ModeInfo * mi)
-{
- if (drifts != NULL) {
- (void) free((void *) drifts);
- drifts = NULL;
- }
-}
-
-void
-refresh_drift(ModeInfo * mi)
-{
- XClearWindow(MI_DISPLAY(mi), MI_WINDOW(mi));
-}