xenocara/app/xlockmore/modes/flame.c
2006-11-26 11:07:42 +00:00

357 lines
8.4 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* flame --- recursive fractal cosmic flames */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)flame.c 5.00 2000/11/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:
* 01-Nov-2000: Allocation checks
* 10-May-1997: Compatible with xscreensaver
* 11-Aug-1995: Got rid of polynomial since it was crashing xlock on some
* machines.
* 01-Jun-1995: This should look more like the original with some updates by
* Scott Draves.
* 27-Jun-1991: vary number of functions used.
* 24-Jun-1991: fixed portability problem with integer mod (%).
* 06-Jun-1991: Written, received from Scott Draves <spot@cs.cmu.edu>
*/
#ifdef STANDALONE
#define MODE_flame
#define PROGCLASS "Flame"
#define HACK_INIT init_flame
#define HACK_DRAW draw_flame
#define flame_opts xlockmore_opts
#define DEFAULTS "*delay: 750000 \n" \
"*count: 20 \n" \
"*cycles: 10000 \n" \
"*ncolors: 200 \n"
#define UNIFORM_COLORS
#define BRIGHT_COLORS
#include "xlockmore.h" /* in xscreensaver distribution */
#else /* STANDALONE */
#include "xlock.h" /* in xlockmore distribution */
#endif /* STANDALONE */
#ifdef MODE_flame
ModeSpecOpt flame_opts =
{0, (XrmOptionDescRec *) NULL, 0, (argtype *) NULL, (OptionStruct *) NULL};
#ifdef USE_MODULES
ModStruct flame_description =
{"flame", "init_flame", "draw_flame", "release_flame",
"refresh_flame", "init_flame", (char *) NULL, &flame_opts,
750000, 20, 10000, 1, 64, 1.0, "",
"Shows cosmic flame fractals", 0, NULL};
#endif
#define MAXLEV 4
#define MAXKINDS 9
#define MAXBATCH 12
typedef struct {
double f[2][3][MAXLEV]; /* three non-homogeneous transforms */
int variation;
int max_levels;
int cur_level;
int snum;
int anum;
int width, height;
int num_points;
int total_points;
int pixcol;
int cycles;
int alt;
XPoint pts[MAXBATCH];
short lasthalf;
} flamestruct;
static flamestruct *flames = (flamestruct *) NULL;
static short
halfrandom(flamestruct * fp, int mv)
{
unsigned long r;
if (fp->lasthalf) {
r = fp->lasthalf;
fp->lasthalf = 0;
} else {
r = LRAND();
fp->lasthalf = (short) (r >> 16);
}
return r % mv;
}
static Bool
recurse(ModeInfo * mi, flamestruct * fp,
register double x, register double y, register int l)
{
int i;
double nx, ny;
if (l == fp->max_levels) {
fp->total_points++;
if (fp->total_points > fp->cycles) /* how long each fractal runs */
return False;
if (x > -1.0 && x < 1.0 && y > -1.0 && y < 1.0) {
fp->pts[fp->num_points].x = (int) ((fp->width / 2) * (x + 1.0));
fp->pts[fp->num_points].y = (int) ((fp->height / 2) * (y + 1.0));
fp->num_points++;
if (fp->num_points >= MAXBATCH) { /* point buffer size */
XDrawPoints(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), fp->pts,
fp->num_points, CoordModeOrigin);
fp->num_points = 0;
}
}
} else {
for (i = 0; i < fp->snum; i++) {
nx = fp->f[0][0][i] * x + fp->f[0][1][i] * y + fp->f[0][2][i];
ny = fp->f[1][0][i] * x + fp->f[1][1][i] * y + fp->f[1][2][i];
if (i < fp->anum) {
switch (fp->variation) {
case 0: /* sinusoidal */
nx = sin(nx);
ny = sin(ny);
break;
case 1: /* complex */
{
double r2 = nx * nx + ny * ny + 1e-6;
nx = nx / r2;
ny = ny / r2;
}
break;
case 2: /* bent */
if (nx < 0.0)
nx = nx * 2.0;
if (ny < 0.0)
ny = ny / 2.0;
break;
case 3: /* 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 4: /* 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 5: /* 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;
case 6: /* 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;
case 7: /* spherical */
{
double r = 0.5 + sqrt(nx * nx + ny * ny + 1e-6);
nx = nx / r;
ny = ny / r;
}
break;
case 8: /* */
nx = atan(nx) / M_PI_2;
ny = atan(ny) / M_PI_2;
break;
#if 0
/* core dumps on some machines, why not all? */
case 9: /* 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;
}
break;
case 10: /* polynomial */
if (nx < 0)
nx = -nx * nx;
else
nx = nx * nx;
if (ny < 0)
ny = -ny * ny;
else
ny = ny * ny;
break;
#endif
default:
nx = sin(nx);
ny = sin(ny);
}
}
if (!recurse(mi, fp, nx, ny, l + 1))
return False;
}
}
return True;
}
void
init_flame(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
GC gc = MI_GC(mi);
flamestruct *fp;
if (flames == NULL) {
if ((flames = (flamestruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (flamestruct))) == NULL)
return;
}
fp = &flames[MI_SCREEN(mi)];
fp->width = MI_WIDTH(mi);
fp->height = MI_HEIGHT(mi);
if (MI_COUNT(mi) < 1)
fp->max_levels = 1;
else
fp->max_levels = MI_COUNT(mi);
fp->cycles = MI_CYCLES(mi);
MI_CLEARWINDOW(mi);
if (MI_NPIXELS(mi) > 2) {
fp->pixcol = halfrandom(fp, MI_NPIXELS(mi));
XSetForeground(display, gc, MI_PIXEL(mi, fp->pixcol));
} else {
XSetForeground(display, gc, MI_WHITE_PIXEL(mi));
}
fp->variation = NRAND(MAXKINDS);
}
void
draw_flame(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
int i, j, k;
flamestruct *fp;
if (flames == NULL)
return;
fp = &flames[MI_SCREEN(mi)];
if (!(fp->cur_level++ % fp->max_levels)) {
MI_CLEARWINDOW(mi);
if (MI_NPIXELS(mi) <= 2)
XSetForeground(display, MI_GC(mi), MI_WHITE_PIXEL(mi));
fp->alt = !fp->alt;
} else {
if (MI_NPIXELS(mi) > 2) {
XSetForeground(display, MI_GC(mi), MI_PIXEL(mi, fp->pixcol));
if (--fp->pixcol < 0)
fp->pixcol = MI_NPIXELS(mi) - 1;
}
}
MI_IS_DRAWN(mi) = True;
/* number of functions */
fp->snum = 2 + (fp->cur_level % (MAXLEV - 1));
/* how many of them are of alternate form */
if (fp->alt)
fp->anum = 0;
else
fp->anum = halfrandom(fp, fp->snum) + 2;
/* 6 coefs per function */
for (k = 0; k < fp->snum; k++) {
for (i = 0; i < 2; i++)
for (j = 0; j < 3; j++)
fp->f[i][j][k] = ((double) (LRAND() & 1023) / 512.0 - 1.0);
}
fp->num_points = 0;
fp->total_points = 0;
(void) recurse(mi, fp, 0.0, 0.0, 0);
XDrawPoints(display, MI_WINDOW(mi), MI_GC(mi),
fp->pts, fp->num_points, CoordModeOrigin);
}
void
release_flame(ModeInfo * mi)
{
if (flames != NULL) {
free(flames);
flames = (flamestruct *) NULL;
}
}
void
refresh_flame(ModeInfo * mi)
{
MI_CLEARWINDOW(mi);
}
#endif /* MODE_flame */