1077 lines
26 KiB
C
1077 lines
26 KiB
C
/* -*- Mode: C; tab-width: 4 -*- */
|
|
/* swirl --- swirly patterns */
|
|
|
|
#if !defined( lint ) && !defined( SABER )
|
|
static const char sccsid[] = "@(#)swirl.c 5.09 2003/06/30 xlockmore";
|
|
|
|
#endif
|
|
|
|
/*-
|
|
* Copyright (c) 1994 M.Dobie <mrd@ecs.soton.ac.uk>
|
|
*
|
|
* 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:
|
|
* 30-Jun-2003: Changed writeable mode to be more consistent with
|
|
* xscreensaver's starfish, looks like I am not going to
|
|
* port the variable speed colormapping when done drawing.
|
|
* 01-Nov-2000: Allocation checks
|
|
* 13-May-1997: jwz@jwz.org: turned into a standalone program.
|
|
* 21-Apr-1995: improved startup time for TrueColour displays
|
|
* (limited to 16bpp to save memory) S.Early <sde1000@cam.ac.uk>
|
|
* 09-Jan-1995: fixed colour maps (more colourful) and the image now spirals
|
|
* outwards from the centre with a fixed number of points drawn
|
|
* every iteration. Thanks to M.Dobie <mrd@ecs.soton.ac.uk>.
|
|
* 1994: written. Copyright (c) 1994 M.Dobie <mrd@ecs.soton.ac.uk>
|
|
* based on original code by R.Taylor
|
|
*/
|
|
|
|
#ifdef STANDALONE
|
|
#define MODE_swirl
|
|
#define PROGCLASS "Swirl"
|
|
#define HACK_INIT init_swirl
|
|
#define HACK_DRAW draw_swirl
|
|
#define swirl_opts xlockmore_opts
|
|
#define DEFAULTS "*delay: 5000 \n" \
|
|
"*count: 5 \n" \
|
|
"*ncolors: 200 \n"
|
|
#define SMOOTH_COLORS
|
|
#define WRITABLE_COLORS
|
|
#include "xlockmore.h" /* from the xscreensaver distribution */
|
|
#else /* !STANDALONE */
|
|
#include "xlock.h" /* from the xlockmore distribution */
|
|
#include "color.h"
|
|
#endif /* !STANDALONE */
|
|
|
|
#ifdef MODE_swirl
|
|
|
|
#define DEF_CYCLE "True"
|
|
|
|
static Bool cycle_p;
|
|
|
|
static XrmOptionDescRec opts[] =
|
|
{
|
|
{(char *) "-cycle", (char *) ".swirl.cycle", XrmoptionNoArg, (caddr_t) "on"},
|
|
{(char *) "+cycle", (char *) ".swirl.cycle", XrmoptionNoArg, (caddr_t) "off"}
|
|
};
|
|
|
|
static argtype vars[] =
|
|
{
|
|
{(void *) & cycle_p, (char *) "cycle", (char *) "Cycle", (char *) DEF_CYCLE, t_Bool}
|
|
};
|
|
|
|
static OptionStruct desc[] =
|
|
{
|
|
{(char *) "-/+cycle", (char *) "turn on/off colour cycling"}
|
|
};
|
|
|
|
ModeSpecOpt swirl_opts =
|
|
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
|
|
|
|
#ifdef USE_MODULES
|
|
ModStruct swirl_description =
|
|
{"swirl", "init_swirl", "draw_swirl", "release_swirl",
|
|
"refresh_swirl", "init_swirl", (char *) NULL, &swirl_opts,
|
|
5000, 5, 1, 1, 64, 1.0, "",
|
|
"Shows animated swirling patterns", 0, NULL};
|
|
|
|
#endif
|
|
|
|
#include <time.h>
|
|
|
|
#define MASS 4 /* maximum mass of a knot */
|
|
#define MIN_RES 5 /* minimim resolution (>= MIN_RES) */
|
|
#define MAX_RES 1 /* maximum resolution (>0) */
|
|
#define TWO_PLANE_PCNT 30 /* probability for two plane mode (0-100) */
|
|
#define RESTART 2500 /* number of cycles before restart */
|
|
#define BATCH_DRAW 100 /* points to draw per iteration */
|
|
|
|
/* knot types */
|
|
typedef enum {
|
|
NONE = 0,
|
|
ORBIT = (1 << 0),
|
|
WHEEL = (1 << 1),
|
|
PICASSO = (1 << 2),
|
|
RAY = (1 << 3),
|
|
HOOK = (1 << 4),
|
|
ALL = (1 << 5)
|
|
} KNOT_T;
|
|
|
|
/* a knot */
|
|
typedef struct Knot {
|
|
int x, y; /* position */
|
|
int m; /* mass */
|
|
KNOT_T t; /* type in the first (or only) plane */
|
|
KNOT_T T; /* type in second plane if there is one */
|
|
int M; /* mass in second plane if there is one */
|
|
} KNOT , *KNOT_P;
|
|
|
|
/* drawing direction */
|
|
typedef enum {
|
|
DRAW_RIGHT, DRAW_DOWN, DRAW_LEFT, DRAW_UP
|
|
} DIR_T;
|
|
|
|
/****************************************************************/
|
|
|
|
/* data associated with a swirl window */
|
|
typedef struct swirl_data {
|
|
/* window paramaters */
|
|
int width, height; /* window size */
|
|
int depth; /* depth */
|
|
int rdepth; /* real depth (for XImage) */
|
|
Visual *visual; /* visual */
|
|
|
|
/* swirl drawing parameters */
|
|
int n_knots; /* number of knots */
|
|
KNOT_P knots; /* knot details */
|
|
KNOT_T knot_type; /* general type of knots */
|
|
int resolution; /* drawing resolution, 1..5 */
|
|
int max_resolution; /* maximum resolution, MAX_RES */
|
|
int r; /* pixel step */
|
|
Bool two_plane; /* two plane mode? */
|
|
Bool first_plane; /* doing first plane? */
|
|
int start_again; /* when to restart */
|
|
|
|
/* spiral drawing parameters */
|
|
int x, y; /* current point */
|
|
DIR_T dir; /* current direction */
|
|
int dir_todo, dir_done; /* how many points in current direction? */
|
|
int batch_todo, batch_done; /* how many points in this batch */
|
|
Bool started, drawing; /* are we drawing? */
|
|
Bool off_screen;
|
|
|
|
/* image stuff */
|
|
XImage *ximage;
|
|
|
|
/* colours stuff */
|
|
int shift; /* colourmap shift */
|
|
int dshift; /* colourmap shift while drawing */
|
|
unsigned int cur_color;
|
|
GC gc;
|
|
Colormap cmap;
|
|
unsigned long blackpixel, whitepixel, fg, bg;
|
|
int direction;
|
|
XColor *colors;
|
|
int ncolors;
|
|
Bool cycle_p, mono_p, no_colors, reverse;
|
|
ModeInfo *mi;
|
|
} swirlstruct;
|
|
|
|
/* an array of swirls for each screen */
|
|
static swirlstruct *swirls = (swirlstruct *) NULL;
|
|
|
|
/*-
|
|
random_no
|
|
|
|
Return a random integer between 0 and n inclusive
|
|
|
|
- n is the maximum number
|
|
|
|
Returns a random integer */
|
|
|
|
static int
|
|
random_no(unsigned int n)
|
|
{
|
|
return ((int) ((n + 1) * (double) LRAND() / MAXRAND));
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
static void
|
|
free_swirl(Display *display, swirlstruct *sp)
|
|
{
|
|
ModeInfo *mi = sp->mi;
|
|
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
MI_WHITE_PIXEL(mi) = sp->whitepixel;
|
|
MI_BLACK_PIXEL(mi) = sp->blackpixel;
|
|
#ifndef STANDALONE
|
|
MI_FG_PIXEL(mi) = sp->fg;
|
|
MI_BG_PIXEL(mi) = sp->bg;
|
|
#endif
|
|
if (sp->colors != NULL) {
|
|
if (sp->ncolors && !sp->no_colors)
|
|
free_colors(display, sp->cmap, sp->colors,
|
|
sp->ncolors);
|
|
free(sp->colors);
|
|
sp->colors = (XColor *) NULL;
|
|
}
|
|
if (sp->cmap != None) {
|
|
XFreeColormap(display, sp->cmap);
|
|
sp->cmap = None;
|
|
}
|
|
}
|
|
if (sp->gc != None) {
|
|
XFreeGC(display, sp->gc);
|
|
sp->gc = None;
|
|
}
|
|
if (sp->ximage != None) {
|
|
(void) XDestroyImage(sp->ximage);
|
|
sp->ximage = None;
|
|
}
|
|
if (sp->knots != NULL) {
|
|
free(sp->knots);
|
|
sp->knots = (KNOT_P) NULL;
|
|
}
|
|
}
|
|
|
|
#ifndef STANDALONE
|
|
extern char *background;
|
|
extern char *foreground;
|
|
#endif
|
|
|
|
/*-
|
|
initialise_swirl
|
|
|
|
Initialise all the swirl data
|
|
|
|
- swirl is the swirl data */
|
|
|
|
static void
|
|
initialise_swirl(swirlstruct *sp)
|
|
{
|
|
sp->width = 0; /* width and height of window */
|
|
sp->height = 0;
|
|
sp->depth = 1;
|
|
sp->rdepth = 1;
|
|
sp->visual = (Visual *) NULL;
|
|
sp->resolution = MIN_RES + 1; /* current resolution */
|
|
sp->max_resolution = MAX_RES; /* maximum resolution */
|
|
sp->n_knots = 0; /* number of knots */
|
|
sp->knot_type = ALL; /* general type of knots */
|
|
sp->two_plane = False; /* two plane mode? */
|
|
sp->first_plane = False; /* doing first plane? */
|
|
sp->start_again = -1; /* restart counter */
|
|
|
|
/* drawing parameters */
|
|
sp->x = 0;
|
|
sp->y = 0;
|
|
sp->started = False;
|
|
sp->drawing = False;
|
|
|
|
/* image stuff */
|
|
sp->ximage = None;
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
/*-
|
|
* initialise_image
|
|
*
|
|
* Initialise the image for drawing to
|
|
*
|
|
* - swirl is the swirl data
|
|
*/
|
|
static Bool
|
|
initialise_image(Display * dpy, swirlstruct *sp)
|
|
{
|
|
unsigned int pad;
|
|
int bytes_per_line;
|
|
int image_depth = sp->rdepth;
|
|
int data_depth = image_depth;
|
|
unsigned char *image; /* image data */
|
|
|
|
/* On SGIs at least, using an XImage of depth 24 on a Visual of depth 24
|
|
* requires the XImage data to use 32 bits per pixel. I don't understand
|
|
* how one is supposed to determine this -- maybe XListPixmapFormats?
|
|
* But on systems that don't work this way, allocating 32 bpp instead of
|
|
* 24 will be wasteful but non-fatal. -- jwz, 16-May-97.
|
|
*/
|
|
if (data_depth >= 24 && data_depth < 32)
|
|
data_depth = 32;
|
|
|
|
/* get the bitmap pad */
|
|
pad = BitmapPad(dpy);
|
|
/* destroy the old image (destroy XImage and data) */
|
|
if (sp->ximage != NULL)
|
|
(void) XDestroyImage(sp->ximage);
|
|
|
|
/* how many bytes per line? (bits rounded up to pad) */
|
|
bytes_per_line = ((sp->width * data_depth + pad - 1) / pad) * (pad / 8);
|
|
|
|
/* allocate space for the image */
|
|
if ((image = (unsigned char *) calloc(bytes_per_line *
|
|
sp->height, 1)) == NULL) {
|
|
return False;
|
|
}
|
|
|
|
/* create an ximage with this */
|
|
if ((sp->ximage = XCreateImage(dpy, sp->visual, image_depth, ZPixmap,
|
|
0, (char *) image, sp->width,
|
|
sp->height, pad, bytes_per_line)) == None) {
|
|
free(image);
|
|
return False;
|
|
}
|
|
return True;
|
|
}
|
|
|
|
/*-
|
|
* create_knots
|
|
*
|
|
* Initialise the array of knot
|
|
*
|
|
* swirl is the swirl data
|
|
*/
|
|
static Bool
|
|
create_knots(swirlstruct *sp)
|
|
{
|
|
int k;
|
|
Bool orbit, wheel, picasso, ray, hook;
|
|
KNOT_P knot;
|
|
|
|
/* create array for knots */
|
|
if (sp->knots)
|
|
free(sp->knots);
|
|
if ((sp->knots = (KNOT_P) calloc(sp->n_knots,
|
|
sizeof (KNOT))) == NULL) {
|
|
return False;
|
|
}
|
|
|
|
/* no knots yet */
|
|
orbit = wheel = picasso = ray = hook = False;
|
|
|
|
/* what types do we have? */
|
|
if ((int) sp->knot_type & (int) ALL) {
|
|
orbit = wheel = ray = hook = True;
|
|
} else {
|
|
if ((int) sp->knot_type & (int) ORBIT)
|
|
orbit = True;
|
|
if ((int) sp->knot_type & (int) WHEEL)
|
|
wheel = True;
|
|
if ((int) sp->knot_type & (int) PICASSO)
|
|
picasso = True;
|
|
if ((int) sp->knot_type & (int) RAY)
|
|
ray = True;
|
|
if ((int) sp->knot_type & (int) HOOK)
|
|
hook = True;
|
|
}
|
|
|
|
/* initialise each knot */
|
|
knot = sp->knots;
|
|
for (k = 0; k < sp->n_knots; k++) {
|
|
/* position */
|
|
knot->x = random_no((unsigned int) sp->width);
|
|
knot->y = random_no((unsigned int) sp->height);
|
|
|
|
/* mass */
|
|
knot->m = random_no(MASS) + 1;
|
|
|
|
/* can be negative */
|
|
if (random_no(100) > 50)
|
|
knot->m *= -1;
|
|
|
|
/* type */
|
|
knot->t = NONE;
|
|
while (knot->t == NONE) {
|
|
/* choose a random one from the types available */
|
|
switch (random_no(4)) {
|
|
case 0:
|
|
if (orbit)
|
|
knot->t = ORBIT;
|
|
break;
|
|
case 1:
|
|
if (wheel)
|
|
knot->t = WHEEL;
|
|
break;
|
|
case 2:
|
|
if (picasso)
|
|
knot->t = PICASSO;
|
|
break;
|
|
case 3:
|
|
if (ray)
|
|
knot->t = RAY;
|
|
break;
|
|
case 4:
|
|
if (hook)
|
|
knot->t = HOOK;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* if two planes, do same for second plane */
|
|
if (sp->two_plane) {
|
|
knot->T = NONE;
|
|
while (knot->T == NONE || knot->T == knot->t) {
|
|
/* choose a different type */
|
|
switch (random_no(4)) {
|
|
case 0:
|
|
if (orbit)
|
|
knot->T = ORBIT;
|
|
break;
|
|
case 1:
|
|
if (wheel)
|
|
knot->T = WHEEL;
|
|
break;
|
|
case 2:
|
|
if (picasso)
|
|
knot->T = PICASSO;
|
|
break;
|
|
case 3:
|
|
if (ray)
|
|
knot->T = RAY;
|
|
break;
|
|
case 4:
|
|
if (hook)
|
|
knot->T = HOOK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/* next knot */
|
|
knot++;
|
|
}
|
|
return True;
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
/*-
|
|
* do_point
|
|
*
|
|
* Work out the pixel value at i, j. Ensure it does not clash with BlackPixel
|
|
* or WhitePixel.
|
|
*
|
|
* - swirl is the swirl data
|
|
* - i, j is the point to calculate
|
|
*
|
|
* Returns the value of the point
|
|
*/
|
|
static unsigned long
|
|
do_point(swirlstruct *sp, int i, int j)
|
|
{
|
|
int tT, k, add, value;
|
|
unsigned long colour_value;
|
|
double dx, dy, theta, dist;
|
|
int ncolours, qcolours;
|
|
double rads;
|
|
KNOT_P knot;
|
|
ModeInfo *mi = sp->mi;
|
|
|
|
/* how many colours? */
|
|
ncolours = sp->ncolors;
|
|
qcolours = ncolours / 4;
|
|
|
|
/* colour step round a circle */
|
|
rads = (double) ncolours / (2.0 * M_PI);
|
|
|
|
/* start at zero */
|
|
value = 0;
|
|
|
|
/* go through all the knots */
|
|
knot = sp->knots;
|
|
for (k = 0; k < sp->n_knots; k++) {
|
|
dx = i - knot->x;
|
|
dy = j - knot->y;
|
|
|
|
/* in two_plane mode get the appropriate knot type */
|
|
if (sp->two_plane)
|
|
tT = (int) ((sp->first_plane) ? knot->t : knot->T);
|
|
else
|
|
tT = (int) knot->t;
|
|
|
|
/* distance from knot */
|
|
dist = sqrt(dx * dx + dy * dy);
|
|
|
|
/* nothing to add at first */
|
|
add = 0;
|
|
|
|
/* work out the contribution (if close enough) */
|
|
if (dist > 0.1)
|
|
switch (tT) {
|
|
case ORBIT:
|
|
add = (int) (ncolours / (1.0 + 0.01 * abs(knot->m) * dist));
|
|
break;
|
|
case WHEEL:
|
|
/* Avoid atan2: DOMAIN error message */
|
|
if (dy == 0.0 && dx == 0.0)
|
|
theta = 1.0;
|
|
else
|
|
theta = (atan2(dy, dx) + M_PI) / M_PI;
|
|
if (theta < 1.0)
|
|
add = (int) (ncolours * theta +
|
|
sin(0.1 * knot->m * dist) *
|
|
qcolours * exp(-0.01 * dist));
|
|
else
|
|
add = (int) (ncolours * (theta - 1.0) +
|
|
sin(0.1 * knot->m * dist) *
|
|
qcolours * exp(-0.01 * dist));
|
|
break;
|
|
case PICASSO:
|
|
add = (int) (ncolours *
|
|
fabs(cos(0.002 * knot->m * dist)));
|
|
break;
|
|
case RAY:
|
|
/* Avoid atan2: DOMAIN error message */
|
|
if (dy == 0.0 && dx == 0.0)
|
|
add = 0;
|
|
else
|
|
add = (int) (ncolours * fabs(sin(2.0 * atan2(dy, dx))));
|
|
|
|
break;
|
|
case HOOK:
|
|
/* Avoid atan2: DOMAIN error message */
|
|
if (dy == 0.0 && dx == 0.0)
|
|
add = (int) (0.05 * (abs(knot->m) - 1) * dist);
|
|
else
|
|
add = (int) (rads * atan2(dy, dx) +
|
|
0.05 * (abs(knot->m) - 1) * dist);
|
|
break;
|
|
}
|
|
/* for a positive mass add on the contribution else take it off */
|
|
if (knot->m > 0)
|
|
value += add;
|
|
else
|
|
value -= add;
|
|
|
|
/* next knot */
|
|
knot++;
|
|
}
|
|
|
|
/* toggle plane */
|
|
sp->first_plane = (!sp->first_plane);
|
|
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
if (ncolours < 2) {
|
|
ncolours = 2;
|
|
}
|
|
/* make sure we handle negative values properly */
|
|
if (value >= 0)
|
|
colour_value = (value % ncolours) + 2;
|
|
else
|
|
colour_value = ncolours - (abs((int) value) % (ncolours - 1));
|
|
|
|
/* definitely make sure it is in range */
|
|
colour_value = colour_value % ncolours;
|
|
|
|
if (sp->mono_p) {
|
|
return colour_value;
|
|
} else {
|
|
return sp->colors[colour_value].pixel;
|
|
}
|
|
} else {
|
|
if (value >= 0)
|
|
colour_value = (value % MI_NPIXELS(mi)) + 2;
|
|
else
|
|
colour_value = MI_NPIXELS(mi) - (abs((int) value) % (MI_NPIXELS(mi) - 1));
|
|
/* definitely make sure it is in range */
|
|
colour_value = colour_value % MI_NPIXELS(mi);
|
|
if (MI_NPIXELS(mi) > 2) {
|
|
return MI_PIXEL(mi, colour_value);
|
|
} else if (colour_value % 2)
|
|
return MI_BLACK_PIXEL(mi);
|
|
else
|
|
return MI_WHITE_PIXEL(mi);
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
/*-
|
|
* draw_block
|
|
*
|
|
* Draw a square block of points with the same value.
|
|
*
|
|
* - ximage is the XImage to draw on.
|
|
* - x, y is the top left corner
|
|
* - s is the length of each side
|
|
* - v is the value
|
|
*/
|
|
static void
|
|
draw_block(XImage * ximage, int x, int y, int s, unsigned long v)
|
|
{
|
|
int a, b;
|
|
|
|
for (a = 0; a < s; a++)
|
|
for (b = 0; b < s; b++) {
|
|
XPutPixel(ximage, x + b, y + a, v);
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
/*-
|
|
* draw_point Draw the current point in a swirl pattern onto the XImage
|
|
*
|
|
* - swirl is the swirl
|
|
* - win is the window to update
|
|
*/
|
|
static void
|
|
draw_point(ModeInfo * mi, swirlstruct *sp)
|
|
{
|
|
int r;
|
|
int x, y;
|
|
|
|
/* get current point coordinates and resolution */
|
|
x = sp->x;
|
|
y = sp->y;
|
|
r = sp->r;
|
|
|
|
/* check we are within the window */
|
|
if ((x < 0) || (x > sp->width - r) || (y < 0) || (y > sp->height - r))
|
|
return;
|
|
|
|
/* what style are we drawing? */
|
|
if (sp->two_plane) {
|
|
int r2;
|
|
|
|
/* halve the block size */
|
|
r2 = r / 2;
|
|
|
|
/* interleave blocks at half r */
|
|
draw_block(sp->ximage, x, y, r2, do_point(sp, x, y));
|
|
draw_block(sp->ximage, x + r2, y, r2, do_point(sp, x + r2, y));
|
|
draw_block(sp->ximage, x + r2, y + r2, r2, do_point(sp,
|
|
x + r2, y + r2));
|
|
draw_block(sp->ximage, x, y + r2, r2, do_point(sp, x, y + r2));
|
|
} else
|
|
draw_block(sp->ximage, x, y, r, do_point(sp, x, y));
|
|
|
|
/* update the screen */
|
|
/*-
|
|
* PURIFY 4.0.1 on SunOS4 and on Solaris 2 reports a 256 byte memory leak on
|
|
* the next line. */
|
|
(void) XPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), sp->ximage,
|
|
x, y, x, y, r, r);
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
/*-
|
|
* next_point Move to the next point in the spiral pattern
|
|
* - swirl is the swirl
|
|
* - win is the window to update
|
|
*/
|
|
static void
|
|
next_point(swirlstruct *sp)
|
|
{
|
|
/* more to do in this direction? */
|
|
if (sp->dir_done < sp->dir_todo) {
|
|
/* move in the current direction */
|
|
switch (sp->dir) {
|
|
case DRAW_RIGHT:
|
|
sp->x += sp->r;
|
|
break;
|
|
case DRAW_DOWN:
|
|
sp->y += sp->r;
|
|
break;
|
|
case DRAW_LEFT:
|
|
sp->x -= sp->r;
|
|
break;
|
|
case DRAW_UP:
|
|
sp->y -= sp->r;
|
|
break;
|
|
}
|
|
|
|
/* done another point */
|
|
sp->dir_done++;
|
|
} else {
|
|
/* none drawn yet */
|
|
sp->dir_done = 0;
|
|
|
|
/* change direction - check and record if off screen */
|
|
switch (sp->dir) {
|
|
case DRAW_RIGHT:
|
|
sp->dir = DRAW_DOWN;
|
|
if (sp->x > sp->width - sp->r) {
|
|
/* skip these points */
|
|
sp->dir_done = sp->dir_todo;
|
|
sp->y += (sp->dir_todo * sp->r);
|
|
|
|
/* check for finish */
|
|
if (sp->off_screen)
|
|
sp->drawing = False;
|
|
sp->off_screen = True;
|
|
} else
|
|
sp->off_screen = False;
|
|
break;
|
|
case DRAW_DOWN:
|
|
sp->dir = DRAW_LEFT;
|
|
sp->dir_todo++;
|
|
if (sp->y > sp->height - sp->r) {
|
|
/* skip these points */
|
|
sp->dir_done = sp->dir_todo;
|
|
sp->x -= (sp->dir_todo * sp->r);
|
|
|
|
/* check for finish */
|
|
if (sp->off_screen)
|
|
sp->drawing = False;
|
|
sp->off_screen = True;
|
|
} else
|
|
sp->off_screen = False;
|
|
break;
|
|
case DRAW_LEFT:
|
|
sp->dir = DRAW_UP;
|
|
if (sp->x < 0) {
|
|
/* skip these points */
|
|
sp->dir_done = sp->dir_todo;
|
|
sp->y -= (sp->dir_todo * sp->r);
|
|
|
|
/* check for finish */
|
|
if (sp->off_screen)
|
|
sp->drawing = False;
|
|
sp->off_screen = True;
|
|
} else
|
|
sp->off_screen = False;
|
|
break;
|
|
case DRAW_UP:
|
|
sp->dir = DRAW_RIGHT;
|
|
sp->dir_todo++;
|
|
if (sp->y < 0) {
|
|
/* skip these points */
|
|
sp->dir_done = sp->dir_todo;
|
|
sp->x += (sp->dir_todo * sp->r);
|
|
|
|
/* check for finish */
|
|
if (sp->off_screen)
|
|
sp->drawing = False;
|
|
sp->off_screen = True;
|
|
} else
|
|
sp->off_screen = False;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
/*-
|
|
* init_swirl
|
|
*
|
|
* Initialise things for swirling
|
|
*
|
|
* - win is the window to draw in
|
|
*/
|
|
void
|
|
init_swirl(ModeInfo * mi)
|
|
{
|
|
Display *display = MI_DISPLAY(mi);
|
|
Window window = MI_WINDOW(mi);
|
|
swirlstruct *sp;
|
|
|
|
/* does the swirls array exist? */
|
|
if (swirls == NULL) {
|
|
int i;
|
|
|
|
/* allocate an array, one entry for each screen */
|
|
if ((swirls = (swirlstruct *) calloc(MI_NUM_SCREENS(mi),
|
|
sizeof (swirlstruct))) == NULL)
|
|
return;
|
|
|
|
/* initialise them all */
|
|
for (i = 0; i < MI_NUM_SCREENS(mi); i++)
|
|
initialise_swirl(&swirls[i]);
|
|
}
|
|
/* get a pointer to this swirl */
|
|
sp = &(swirls[MI_SCREEN(mi)]);
|
|
sp->mi = mi;
|
|
|
|
/* get window parameters */
|
|
sp->width = MI_WIDTH(mi);
|
|
sp->height = MI_HEIGHT(mi);
|
|
sp->depth = MI_DEPTH(mi);
|
|
sp->rdepth = sp->depth;
|
|
sp->visual = MI_VISUAL(mi);
|
|
|
|
if (sp->depth > 16)
|
|
sp->depth = 16;
|
|
|
|
/* initialise image for speeding up drawing */
|
|
if (!initialise_image(display, sp)) {
|
|
free_swirl(display, sp);
|
|
return;
|
|
}
|
|
MI_CLEARWINDOW(mi);
|
|
|
|
if (!sp->gc) {
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
XColor color;
|
|
|
|
#ifndef STANDALONE
|
|
sp->fg = MI_FG_PIXEL(mi);
|
|
sp->bg = MI_BG_PIXEL(mi);
|
|
#endif
|
|
sp->blackpixel = MI_BLACK_PIXEL(mi);
|
|
sp->whitepixel = MI_WHITE_PIXEL(mi);
|
|
if ((sp->cmap = XCreateColormap(display, window,
|
|
MI_VISUAL(mi), AllocNone)) == None) {
|
|
free_swirl(display, sp);
|
|
return;
|
|
}
|
|
XSetWindowColormap(display, window, sp->cmap);
|
|
(void) XParseColor(display, sp->cmap, "black", &color);
|
|
(void) XAllocColor(display, sp->cmap, &color);
|
|
MI_BLACK_PIXEL(mi) = color.pixel;
|
|
(void) XParseColor(display, sp->cmap, "white", &color);
|
|
(void) XAllocColor(display, sp->cmap, &color);
|
|
MI_WHITE_PIXEL(mi) = color.pixel;
|
|
#ifndef STANDALONE
|
|
(void) XParseColor(display, sp->cmap, background, &color);
|
|
(void) XAllocColor(display, sp->cmap, &color);
|
|
MI_BG_PIXEL(mi) = color.pixel;
|
|
(void) XParseColor(display, sp->cmap, foreground, &color);
|
|
(void) XAllocColor(display, sp->cmap, &color);
|
|
MI_FG_PIXEL(mi) = color.pixel;
|
|
#endif
|
|
sp->colors = (XColor *) NULL;
|
|
sp->ncolors = 0;
|
|
}
|
|
if ((sp->gc = XCreateGC(display, MI_WINDOW(mi),
|
|
(unsigned long) 0, (XGCValues *) NULL)) == None) {
|
|
free_swirl(display, sp);
|
|
return;
|
|
}
|
|
}
|
|
MI_CLEARWINDOW(mi);
|
|
|
|
/* Set up colour map */
|
|
sp->direction = (LRAND() & 1) ? 1 : -1;
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
if (sp->colors != NULL) {
|
|
if (sp->ncolors && !sp->no_colors)
|
|
free_colors(display, sp->cmap, sp->colors, sp->ncolors);
|
|
free(sp->colors);
|
|
sp->colors = (XColor *) NULL;
|
|
}
|
|
sp->ncolors = MI_NCOLORS(mi);
|
|
if (sp->ncolors < 2)
|
|
sp->ncolors = 2;
|
|
if (sp->ncolors <= 2)
|
|
sp->mono_p = True;
|
|
else
|
|
sp->mono_p = False;
|
|
|
|
if (sp->mono_p)
|
|
sp->colors = (XColor *) NULL;
|
|
else
|
|
if ((sp->colors = (XColor *) malloc(sizeof (*sp->colors) *
|
|
(sp->ncolors + 1))) == NULL) {
|
|
free_swirl(display, sp);
|
|
return;
|
|
}
|
|
sp->cycle_p = has_writable_cells(mi);
|
|
if (sp->cycle_p) {
|
|
if (MI_IS_FULLRANDOM(mi)) {
|
|
if (!NRAND(8))
|
|
sp->cycle_p = False;
|
|
else
|
|
sp->cycle_p = True;
|
|
} else {
|
|
sp->cycle_p = cycle_p;
|
|
}
|
|
}
|
|
if (!sp->mono_p) {
|
|
if (!(LRAND() % 10))
|
|
make_random_colormap(
|
|
#if STANDALONE
|
|
display, MI_WINDOW(mi),
|
|
#else
|
|
mi,
|
|
#endif
|
|
sp->cmap, sp->colors, &sp->ncolors,
|
|
True, True, &sp->cycle_p);
|
|
else if (!(LRAND() % 2))
|
|
make_uniform_colormap(
|
|
#if STANDALONE
|
|
display, MI_WINDOW(mi),
|
|
#else
|
|
mi,
|
|
#endif
|
|
sp->cmap, sp->colors, &sp->ncolors,
|
|
True, &sp->cycle_p);
|
|
else
|
|
make_smooth_colormap(
|
|
#if STANDALONE
|
|
display, MI_WINDOW(mi),
|
|
#else
|
|
mi,
|
|
#endif
|
|
sp->cmap, sp->colors, &sp->ncolors,
|
|
True, &sp->cycle_p);
|
|
}
|
|
XInstallColormap(display, sp->cmap);
|
|
if (sp->ncolors < 2) {
|
|
sp->ncolors = 2;
|
|
sp->no_colors = True;
|
|
} else
|
|
sp->no_colors = False;
|
|
if (sp->ncolors <= 2)
|
|
sp->mono_p = True;
|
|
|
|
if (sp->mono_p)
|
|
sp->cycle_p = False;
|
|
|
|
}
|
|
if (MI_IS_INSTALL(mi) && MI_NPIXELS(mi) > 2) {
|
|
if (sp->mono_p) {
|
|
sp->cur_color = MI_BLACK_PIXEL(mi);
|
|
}
|
|
}
|
|
|
|
/* resolution starts off chunky */
|
|
sp->resolution = MIN_RES + 1;
|
|
|
|
/* calculate the pixel step for this resulution */
|
|
sp->r = (1 << (sp->resolution - 1));
|
|
|
|
/* how many knots? */
|
|
sp->n_knots = random_no((unsigned int) MI_COUNT(mi) / 2) +
|
|
MI_COUNT(mi) + 1;
|
|
|
|
/* what type of knots? */
|
|
sp->knot_type = ALL; /* for now */
|
|
|
|
/* use two_plane mode occaisionally */
|
|
if (random_no(100) <= TWO_PLANE_PCNT) {
|
|
sp->two_plane = sp->first_plane = True;
|
|
sp->max_resolution = 2;
|
|
} else
|
|
sp->two_plane = False;
|
|
|
|
/* fix the knot values */
|
|
if (!create_knots(sp)) {
|
|
free_swirl(display, sp);
|
|
return;
|
|
}
|
|
|
|
/* we are off */
|
|
sp->started = True;
|
|
sp->drawing = False;
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
/*-
|
|
* draw_swirl
|
|
*
|
|
* Draw one iteration of swirling
|
|
*
|
|
* - win is the window to draw in
|
|
*/
|
|
void
|
|
draw_swirl(ModeInfo * mi)
|
|
{
|
|
swirlstruct *sp;
|
|
|
|
if (swirls == NULL)
|
|
return;
|
|
sp = &(swirls[MI_SCREEN(mi)]);
|
|
if (sp->knots == NULL)
|
|
return;
|
|
|
|
MI_IS_DRAWN(mi) = True;
|
|
|
|
/* are we going? */
|
|
if (sp->started) {
|
|
/* in the middle of drawing? */
|
|
if (sp->drawing) {
|
|
if(sp->cycle_p) {
|
|
rotate_colors(MI_DISPLAY(mi), sp->cmap, sp->colors, sp->ncolors, sp->direction);
|
|
if (!(LRAND() % 1000))
|
|
sp->direction = -sp->direction;
|
|
}
|
|
/* draw a batch of points */
|
|
sp->batch_todo = BATCH_DRAW;
|
|
while ((sp->batch_todo > 0) && sp->drawing) {
|
|
/* draw a point */
|
|
draw_point(mi, sp);
|
|
|
|
/* move to the next point */
|
|
next_point(sp);
|
|
|
|
/* done a point */
|
|
sp->batch_todo--;
|
|
}
|
|
} else {
|
|
if(sp->cycle_p) {
|
|
rotate_colors(MI_DISPLAY(mi), sp->cmap, sp->colors, sp->ncolors, sp->direction);
|
|
if (!(LRAND() % 1000))
|
|
sp->direction = -sp->direction;
|
|
}
|
|
|
|
/* time for a higher resolution? */
|
|
if (sp->resolution > sp->max_resolution) {
|
|
/* move to higher resolution */
|
|
sp->resolution--;
|
|
|
|
/* calculate the pixel step for this resulution */
|
|
sp->r = (1 << (sp->resolution - 1));
|
|
|
|
/* start drawing again */
|
|
sp->drawing = True;
|
|
|
|
/* start in the middle of the screen */
|
|
sp->x = (sp->width - sp->r) / 2;
|
|
sp->y = (sp->height - sp->r) / 2;
|
|
|
|
/* initialise spiral drawing parameters */
|
|
sp->dir = DRAW_RIGHT;
|
|
sp->dir_todo = 1;
|
|
sp->dir_done = 0;
|
|
} else {
|
|
/* all done, decide when to restart */
|
|
if (sp->start_again == -1) {
|
|
/* start the counter */
|
|
sp->start_again = RESTART;
|
|
} else if (sp->start_again == 0) {
|
|
/* reset the counter */
|
|
sp->start_again = -1;
|
|
|
|
/* start again */
|
|
init_swirl(mi);
|
|
} else
|
|
/* decrement the counter */
|
|
sp->start_again--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
void
|
|
release_swirl(ModeInfo * mi)
|
|
{
|
|
/* does the swirls array exist? */
|
|
if (swirls != NULL) {
|
|
int screen;
|
|
|
|
/* free them all */
|
|
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
|
|
free_swirl(MI_DISPLAY(mi), &swirls[screen]);
|
|
/* deallocate an array, one entry for each screen */
|
|
free(swirls);
|
|
swirls = (swirlstruct *) NULL;
|
|
}
|
|
}
|
|
|
|
/****************************************************************/
|
|
|
|
void
|
|
refresh_swirl(ModeInfo * mi)
|
|
{
|
|
swirlstruct *sp;
|
|
|
|
if (swirls == NULL)
|
|
return;
|
|
sp = &swirls[MI_SCREEN(mi)];
|
|
|
|
if (sp->started) {
|
|
MI_CLEARWINDOW(mi);
|
|
if (sp->drawing)
|
|
sp->resolution = sp->resolution + 1;
|
|
sp->drawing = False;
|
|
}
|
|
}
|
|
|
|
#endif /* MODE_swirl */
|