+++ /dev/null
-/* -*- Mode: C; tab-width: 4 -*-
- * swirl --- swirly color-cycling patterns.
- */
-#if !defined( lint ) && !defined( SABER )
-static const char sccsid[] = "@(#)swirl.c 4.00 97/01/01 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.
- *
- * 13-May-97: jwz@jwz.org: turned into a standalone program.
- * 21-Apr-95: improved startup time for TrueColour displays
- * (limited to 16bpp to save memory) S.Early <sde1000@cam.ac.uk>
- * 09-Jan-95: 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 PROGCLASS "Swirl"
-# define HACK_INIT init_swirl
-# define HACK_DRAW draw_swirl
-# define swirl_opts xlockmore_opts
-# define DEFAULTS "*count: 5 \n" \
- "*delay: 10000 \n" \
- "*ncolors: 200 \n" \
- "*useSHM: True \n"
-# define SMOOTH_COLORS
-# define WRITABLE_COLORS
-# include "xlockmore.h" /* from the xscreensaver distribution */
-# include <X11/Xutil.h>
-# ifdef HAVE_XSHM_EXTENSION
-# include "xshm.h"
-# endif /* HAVE_XSHM_EXTENSION */
-#else /* !STANDALONE */
-# include "xlock.h" /* from the xlockmore distribution */
-# undef HAVE_XSHM_EXTENSION
-#endif /* !STANDALONE */
-
-ModeSpecOpt swirl_opts = {
- 0, NULL, 0, NULL, NULL };
-
-#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;
-
-/* a colour specification */
-typedef struct Colour {
- unsigned short r, g, b;
-} COLOUR , *COLOUR_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 */
- Window win; /* the window */
- 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 direction; /* 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? */
-
- /* image stuff */
- unsigned char *image; /* image data */
- XImage *ximage;
-
- /* colours stuff */
- int colours; /* how many colours possible */
- int dcolours; /* how many colours for shading */
-#ifndef STANDALONE
- Bool fixed_colourmap; /* fixed colourmap? */
-#endif /* !STANDALONE */
- Bool monochrome; /* monochrome? */
- Colormap cmap; /* colour map for the window */
- XColor *rgb_values; /* colour definitions array */
-#ifndef STANDALONE
- int current_map; /* current colour map, 0..dcolours-1 */
- unsigned long fg, bg, white, black; /* black and white pixel values */
- int shift; /* colourmap shift */
- int dshift; /* colourmap shift while drawing */
- XColor fgcol, bgcol; /* foreground and background colour specs */
-#endif /* !STANDALONE */
- Bool off_screen;
-} SWIRL , *SWIRL_P;
-
-#define SWIRLCOLOURS 13
-
-#ifndef STANDALONE
-/* basic colours */
-static COLOUR basic_colours[SWIRLCOLOURS];
-#endif /* !STANDALONE */
-
-/* an array of swirls for each screen */
-static SWIRL_P swirls = 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));
-}
-
-/****************************************************************/
-
-/*
- initialise_swirl
-
- Initialise all the swirl data
-
- - swirl is the swirl data */
-
-static void
-initialise_swirl(ModeInfo * mi, SWIRL_P swirl)
-{
-#ifndef STANDALONE
- Display *display = MI_DISPLAY(mi);
-#endif /* !STANDALONE */
-
- swirl->width = 0; /* width and height of window */
- swirl->height = 0;
- swirl->depth = 1;
- swirl->rdepth = 1;
- swirl->visual = NULL;
- swirl->resolution = MIN_RES + 1; /* current resolution */
- swirl->max_resolution = MAX_RES; /* maximum resolution */
- swirl->n_knots = 0; /* number of knots */
- swirl->knot_type = ALL; /* general type of knots */
- swirl->two_plane = False; /* two plane mode? */
- swirl->first_plane = False; /* doing first plane? */
- swirl->start_again = -1; /* restart counter */
-
- /* drawing parameters */
- swirl->x = 0;
- swirl->y = 0;
- swirl->started = False;
- swirl->drawing = False;
-
- /* image stuff */
- swirl->image = NULL; /* image data */
- swirl->ximage = NULL;
-
- /* colours stuff */
- swirl->colours = 0; /* how many colours possible */
- swirl->dcolours = 0; /* how many colours for shading */
- swirl->cmap = (Colormap) NULL;
- swirl->rgb_values = NULL; /* colour definitions array */
-#ifndef STANDALONE
- swirl->current_map = 0; /* current colour map, 0..dcolours-1 */
-
- /* set up fg fb colour specs */
- swirl->white = MI_WIN_WHITE_PIXEL(mi);
- swirl->black = MI_WIN_BLACK_PIXEL(mi);
-#endif /* !STANDALONE */
-
-
-#ifdef STANDALONE
-# define MI_COLORMAP MI_WIN_COLORMAP
-#else /* !STANDALONE */
- swirl->fg = MI_FG_COLOR(mi);
- swirl->bg = MI_BG_COLOR(mi);
- swirl->fgcol.pixel = swirl->fg;
- swirl->bgcol.pixel = swirl->bg;
- XQueryColor(display, MI_COLORMAP(mi), &(swirl->fgcol));
- XQueryColor(display, MI_COLORMAP(mi), &(swirl->bgcol));
-#endif /* !STANDALONE */
-}
-
-/****************************************************************/
-
-/*
- * initialise_image
- *
- * Initialise the image for drawing to
- *
- * - swirl is the swirl data
- */
-static void
-initialise_image(ModeInfo * mi, SWIRL_P swirl)
-{
- Display *dpy = MI_DISPLAY(mi);
-
- if (swirl->ximage != NULL)
- XDestroyImage(swirl->ximage);
-
- swirl->ximage = 0;
-#ifdef HAVE_XSHM_EXTENSION
- if (mi->use_shm)
- {
- swirl->ximage = create_xshm_image(dpy, swirl->visual, swirl->rdepth,
- ZPixmap, 0, &mi->shm_info,
- swirl->width, swirl->height);
- if (!swirl->ximage)
- mi->use_shm = False;
- }
-#endif /* HAVE_XSHM_EXTENSION */
-
- if (!swirl->ximage)
- {
- swirl->ximage = XCreateImage(dpy, swirl->visual, swirl->rdepth, ZPixmap,
- 0, 0, swirl->width, swirl->height,
- 8, 0);
- swirl->image = (unsigned char *)
- calloc(swirl->height, swirl->ximage->bytes_per_line);
- swirl->ximage->data = (char *) swirl->image;
- }
-}
-
-/****************************************************************/
-
-#ifndef STANDALONE
-/*
- * initialise_colours
- *
- * Initialise the list of colours from which the colourmaps are derived
- *
- * - colours is the array to initialise
- * - saturation is the saturation value to use 0->grey,
- * 1.0->full saturation
- */
-static void
-initialise_colours(COLOUR * colours, float saturate)
-{
- int i;
-
- /* start off fully saturated, medium and bright colours */
- colours[0].r = 0xA000;
- colours[0].g = 0x0000;
- colours[0].b = 0x0000;
- colours[1].r = 0xD000;
- colours[1].g = 0x0000;
- colours[1].b = 0x0000;
- colours[2].r = 0x0000;
- colours[2].g = 0x6000;
- colours[2].b = 0x0000;
- colours[3].r = 0x0000;
- colours[3].g = 0x9000;
- colours[3].b = 0x0000;
- colours[4].r = 0x0000;
- colours[4].g = 0x0000;
- colours[4].b = 0xC000;
- colours[5].r = 0x0000;
- colours[5].g = 0x0000;
- colours[5].b = 0xF000;
- colours[6].r = 0xA000;
- colours[6].g = 0x6000;
- colours[6].b = 0x0000;
- colours[7].r = 0xD000;
- colours[7].g = 0x9000;
- colours[7].b = 0x0000;
- colours[8].r = 0xA000;
- colours[8].g = 0x0000;
- colours[8].b = 0xC000;
- colours[9].r = 0xD000;
- colours[9].g = 0x0000;
- colours[9].b = 0xF000;
- colours[10].r = 0x0000;
- colours[10].g = 0x6000;
- colours[10].b = 0xC000;
- colours[11].r = 0x0000;
- colours[11].g = 0x9000;
- colours[11].b = 0xF000;
- colours[12].r = 0xA000;
- colours[12].g = 0xA000;
- colours[12].b = 0xA000;
-
- /* add white for low saturation */
- for (i = 0; i < SWIRLCOLOURS - 1; i++) {
- unsigned short max_rg, max;
-
- /* what is the max intensity for this colour? */
- max_rg = (colours[i].r > colours[i].g) ? colours[i].r : colours[i].g;
- max = (max_rg > colours[i].b) ? max_rg : colours[i].b;
-
- /* bring elements up to max as saturation approaches 0.0 */
- colours[i].r += (unsigned short) ((float) (1.0 - saturate) *
- ((float) max - colours[i].r));
- colours[i].g += (unsigned short) ((float) (1.0 - saturate) *
- ((float) max - colours[i].g));
- colours[i].b += (unsigned short) ((float) (1.0 - saturate) *
- ((float) max - colours[i].b));
- }
-}
-#endif /* !STANDALONE */
-
-/****************************************************************/
-
-#ifndef STANDALONE
-/*
- * set_black_and_white
- *
- * Set the entries for foreground & background pixels and
- * WhitePixel & BlackPixel in an array of colour specifications.
- *
- * - swirl is the swirl data
- * - values is the array of specifications
- */
-static void
-set_black_and_white(SWIRL_P swirl, XColor * values)
-{
- unsigned long white, black;
-
- /* where is black and white? */
- white = swirl->white;
- black = swirl->black;
-
- /* set black and white up */
- values[white].flags = DoRed | DoGreen | DoBlue;
- values[white].pixel = white;
- values[white].red = 0xFFFF;
- values[white].green = 0xFFFF;
- values[white].blue = 0xFFFF;
- values[black].flags = DoRed | DoGreen | DoBlue;
- values[black].pixel = black;
- values[black].red = 0;
- values[black].green = 0;
- values[black].blue = 0;
-
- /* copy the colour specs from the original entries */
- values[swirl->fg] = swirl->fgcol;
- values[swirl->bg] = swirl->bgcol;
-}
-
-/****************************************************************/
-
-/*
- * set_colour
- *
- * Set an entry in an array of XColor specifications. The given entry will be
- * set to the given colour. If the entry corresponds to the foreground,
- * background, WhitePixel, or BlackPixel it is ignored and the given colour
- * is is put in the next entry.
- *
- * Therefore, the given colour may be placed up to four places after the
- * specified entry in the array, if foreground, background, white, or black
- * intervene.
- *
- * - swirl is the swirl data
- * - value points to a pointer to the array entry. It gets updated to
- * point to the next free entry.
- * - pixel points to the current pixel number. It gets updated.
- * - c points to the colour to add
- */
-static void
-set_colour(SWIRL_P swirl, XColor ** value, unsigned long *pixel, COLOUR_P c)
-{
- Bool done;
- unsigned long fg, bg, white, black;
-
- /* where are foreground, background, white, and black? */
- fg = swirl->fg;
- bg = swirl->bg;
- white = swirl->white;
- black = swirl->black;
-
- /* haven't set it yet */
- done = False;
-
- /* try and set the colour */
- while (!done) {
- (**value).flags = DoRed | DoGreen | DoBlue;
- (**value).pixel = *pixel;
-
- /* white, black, fg, bg, or a colour? */
- if ((*pixel != fg) && (*pixel != bg) &&
- (*pixel != white) && (*pixel != black)) {
- (**value).red = c->r;
- (**value).green = c->g;
- (**value).blue = c->b;
-
- /* now we've done it */
- done = True;
- }
- /* next pixel */
- (*value)++;
- (*pixel)++;
- }
-}
-
-/****************************************************************/
-
-/*
- * get_colour
- *
- * Get an entry from an array of XColor specifications. The next colour from
- * the array will be returned. Foreground, background, WhitePixel, or
- * BlackPixel will be ignored.
- *
- * - swirl is the swirl data
- * - value points the array entry. It is updated to point to the entry
- * following the one returned.
- * - c is set to the colour found
- */
-static void
-get_colour(SWIRL_P swirl, XColor ** value, COLOUR_P c)
-{
- Bool done;
- unsigned long fg, bg, white, black;
-
- /* where is white and black? */
- fg = swirl->fg;
- bg = swirl->bg;
- white = swirl->white;
- black = swirl->black;
-
- /* haven't set it yet */
- done = False;
-
- /* try and set the colour */
- while (!done) {
- /* black, white or a colour? */
- if (((*value)->pixel != fg) && ((*value)->pixel != bg) &&
- ((*value)->pixel != white) && ((*value)->pixel != black)) {
- c->r = (*value)->red;
- c->g = (*value)->green;
- c->b = (*value)->blue;
-
- /* now we've done it */
- done = True;
- }
- /* next value */
- (*value)++;
- }
-}
-#endif /* !STANDALONE */
-
-/****************************************************************/
-
-#ifndef STANDALONE
-/*
- * interpolate
- *
- * Generate n colours between c1 and c2. n XColors at *value are set up with
- * ascending pixel values.
- *
- * If the pixel range includes BlackPixel or WhitePixel they are set to black
- * and white respectively but otherwise ignored. Therefore, up to n+2 colours
- * may actually be set by this function.
- *
- * - swirl is the swirl data
- * - values points a pointer to an array of XColors to update
- * - pixel points to the pixel number to start at
- * - k n is the number of colours to generate
- * - c1, c2 are the colours to interpolate between
- */
-static void
-interpolate(SWIRL_P swirl, XColor ** values, unsigned long *pixel, int n, COLOUR_P c1, COLOUR_P c2)
-{
- int i, r, g, b;
- COLOUR c;
- unsigned short maxv;
-
- /* maximum value */
- maxv = (255 << 8);
-
- for (i = 0; i < n / 2 && (int) *pixel < swirl->colours; i++) {
- /* work out the colour */
- r = c1->r + 2 * i * ((int) c2->r) / n;
- c.r = (r > (int) maxv) ? maxv : r;
- g = c1->g + 2 * i * ((int) c2->g) / n;
- c.g = (g > (int) maxv) ? maxv : g;
- b = c1->b + 2 * i * ((int) c2->b) / n;
- c.b = (b > (int) maxv) ? maxv : b;
-
- /* set it up */
- set_colour(swirl, values, pixel, &c);
- }
- for (i = n / 2; i >= 0 && (int) *pixel < swirl->colours; i--) {
- r = c2->r + 2 * i * ((int) c1->r) / n;
- c.r = (r > (int) maxv) ? maxv : r;
- g = c2->g + 2 * i * ((int) c1->g) / n;
- c.g = (g > (int) maxv) ? maxv : g;
- b = c2->b + 2 * i * ((int) c1->b) / n;
- c.b = (b > (int) maxv) ? maxv : b;
-
- /* set it up */
- set_colour(swirl, values, pixel, &c);
- }
-}
-
-/****************************************************************/
-
-/*
- * basic_map
- *
- * Generate a `random' closed loop colourmap that occupies the whole colour
- * map.
- *
- * - swirl is the swirl data
- * - values is the array of colour definitions to set up
- */
-static void
-basic_map(SWIRL_P swirl, XColor * values)
-{
- COLOUR c[3];
- int i;
- unsigned short r1, g1, b1, r2, g2, b2, r3, g3, b3;
- int L1, L2, L3, L;
- unsigned long pixel;
- XColor *value;
-
- /* start at the beginning of the colour map */
- pixel = 0;
- value = values;
-
- /* choose 3 different basic colours at random */
- for (i = 0; i < 3;) {
- int j;
- Bool same;
-
- /* choose colour i */
- c[i] = basic_colours[random_no(SWIRLCOLOURS - 1)];
-
- /* assume different */
- same = False;
-
- /* different from the rest? */
- for (j = 0; j < i; j++)
- if ((c[i].r == c[j].r) &&
- (c[i].g == c[j].g) &&
- (c[i].b == c[j].b))
- same = True;
-
- /* ready for the next colour? */
- if (!same)
- i++;
- }
-
- /* extract components into variables */
- r1 = c[0].r;
- g1 = c[0].g;
- b1 = c[0].b;
- r2 = c[1].r;
- g2 = c[1].g;
- b2 = c[1].b;
- r3 = c[2].r;
- g3 = c[2].g;
- b3 = c[2].b;
-
- /* work out the lengths of each side of the triangle */
- L1 = (int) sqrt((((double) r1 - r2) * ((double) r1 - r2) +
- ((double) g1 - g2) * ((double) g1 - g2) +
- ((double) b1 - b2) * ((double) b1 - b2)));
-
- L2 = (int) sqrt((((double) r3 - r2) * ((double) r3 - r2) +
- ((double) g3 - g2) * ((double) g3 - g2) +
- ((double) b3 - b2) * ((double) b3 - b2)));
-
- L3 = (int) sqrt((((double) r1 - r3) * ((double) r1 - r3) +
- ((double) g1 - g3) * ((double) g1 - g3) +
- ((double) b1 - b3) * ((double) b1 - b3)));
-
- L = L1 + L2 + L3;
-
- /* allocate colours in proportion to the lengths of the sides */
- interpolate(swirl, &value, &pixel,
- (int) ((double) swirl->dcolours * ((double) L1 / (double) L)) + 1, c, c + 1);
- interpolate(swirl, &value, &pixel,
- (int) ((double) swirl->dcolours * ((double) L2 / (double) L)) + 1, c + 1, c + 2);
- interpolate(swirl, &value, &pixel,
- (int) ((double) swirl->dcolours * ((double) L3 / (double) L)) + 1, c + 2, c);
-
- /* fill up any remaining slots (due to rounding) */
- while ((int) pixel < swirl->colours) {
- /* repeat the last colour */
- set_colour(swirl, &value, &pixel, c);
- }
-
- /* ensure black and white are correct */
- if (!swirl->fixed_colourmap)
- set_black_and_white(swirl, values);
-}
-
-/****************************************************************/
-
-/*
- * pre_rotate
- *
- * Generate pre-rotated versions of the colour specifications
- *
- * - swirl is the swirl data
- * - values is an array of colour specifications
- */
-static void
-pre_rotate(SWIRL_P swirl, XColor * values)
-{
- int i, j;
- XColor *src, *dest;
- int dcolours;
- unsigned long pixel;
-
- /* how many colours to display? */
- dcolours = swirl->dcolours;
-
- /* start at the first map */
- src = values;
- dest = values + swirl->colours;
-
- /* generate dcolours-1 rotated maps */
- for (i = 0; i < dcolours - 1; i++) {
- COLOUR first;
-
- /* start at the first pixel */
- pixel = 0;
-
- /* remember the first one and skip it */
- get_colour(swirl, &src, &first);
-
- /* put a rotated version of src at dest */
- for (j = 0; j < dcolours - 1; j++) {
- COLOUR c;
-
- /* get the source colour */
- get_colour(swirl, &src, &c);
-
- /* set the colour */
- set_colour(swirl, &dest, &pixel, &c);
- }
-
- /* put the first one at the end */
- set_colour(swirl, &dest, &pixel, &first);
-
- /* NB: src and dest should now be ready for the next table */
-
- /* ensure black and white are properly set */
- set_black_and_white(swirl, src);
- }
-}
-
-/****************************************************************/
-
-/*
- * create_colourmap
- *
- * Create a read/write colourmap to use
- *
- * - swirl is the swirl data
- */
-
-static void
-create_colourmap(ModeInfo * mi, SWIRL_P swirl)
-{
- Display *display = MI_DISPLAY(mi);
- int preserve;
- int n_rotations;
- int i;
- Bool truecolor;
- unsigned long redmask, greenmask, bluemask;
-
- swirl->fixed_colourmap = !setupColormap(mi, &(swirl->colours),
- &truecolor, &redmask, &greenmask, &bluemask);
- preserve = preserveColors(swirl->fg, swirl->bg, swirl->white, swirl->black);
-
- /* how many colours should we animate? */
- swirl->dcolours = (swirl->colours > preserve + 1) ?
- swirl->colours - preserve : swirl->colours;
-
- if (MI_NPIXELS(mi) < 2)
- return;
-
- /* how fast to shift the colourmap? */
- swirl->shift = (swirl->colours > 64) ? swirl->colours / 64 : 1;
- swirl->dshift = (swirl->shift > 1) ? swirl->shift * 2 : 1;
-
- /* how may colour map rotations are there? */
- n_rotations = (swirl->fixed_colourmap) ? 1 : swirl->dcolours;
-
- /* allocate space for colour definitions (if not already there) */
- if (swirl->rgb_values == NULL) {
- swirl->rgb_values = (XColor *) calloc((swirl->colours + 3) * n_rotations,
- sizeof (XColor));
-
- /* create a colour map */
- if (!swirl->fixed_colourmap)
- swirl->cmap =
- XCreateColormap(display, swirl->win, swirl->visual, AllocAll);
- }
- /* select a set of colours for the colour map */
- basic_map(swirl, swirl->rgb_values);
-
- /* are we rotating them? */
- if (!swirl->fixed_colourmap) {
- /* generate rotations of the colour maps */
- pre_rotate(swirl, swirl->rgb_values);
-
- /* store the colours in the colour map */
- XStoreColors(display, swirl->cmap, swirl->rgb_values, swirl->colours);
- } else {
- if (truecolor) {
- int rsh, gsh, bsh;
- unsigned long int t;
-
- t = redmask;
- for (i = 0; (int) t > 0; i++, t >>= 1);
- rsh = 16 - i;
- t = greenmask;
- for (i = 0; (int) t > 0; i++, t >>= 1);
- gsh = 16 - i;
- t = bluemask;
- for (i = 0; (int) t > 0; i++, t >>= 1);
- bsh = 16 - i;
- for (i = 0; i < swirl->colours; i++)
- swirl->rgb_values[i].pixel =
- ((rsh > 0 ? (swirl->rgb_values[i].red) >> rsh :
- (swirl->rgb_values[i].red) << (-rsh)) & redmask) |
- ((gsh > 0 ? (swirl->rgb_values[i].green) >> gsh :
- (swirl->rgb_values[i].green) << (-gsh)) & greenmask) |
- ((bsh > 0 ? (swirl->rgb_values[i].blue) >> bsh :
- (swirl->rgb_values[i].blue) << (-bsh)) & bluemask);
- } else {
- /* lookup the colours in the fixed colour map */
- for (i = 0; i < swirl->colours; i++)
- (void) XAllocColor(display, MI_COLORMAP(mi),
- &(swirl->rgb_values[i]));
- }
- }
-}
-
-/****************************************************************/
-
-/*
- * install_map
- *
- * Install a new set of colours into the colour map
- *
- * - dpy is the display
- * - swirl is the swirl data
- * - shift is the amount to rotate the colour map by
- */
-static void
-install_map(Display * dpy, SWIRL_P swirl, int shift)
-{
- if (!swirl->fixed_colourmap) {
- /* shift the colour map */
- swirl->current_map = (swirl->current_map + shift) %
- swirl->dcolours;
-
- /* store it */
- XStoreColors(dpy, swirl->cmap,
- swirl->rgb_values +
- swirl->current_map * swirl->colours,
- swirl->colours);
- }
-}
-#endif /* !STANDALONE */
-
-/****************************************************************/
-
-/*
- * create_knots
- *
- * Initialise the array of knot
- *
- * swirl is the swirl data
- */
-static void
-create_knots(SWIRL_P swirl)
-{
- int k;
- Bool orbit, wheel, picasso, ray, hook;
- KNOT_P knot;
-
- /* create array for knots */
- if (swirl->knots)
- (void) free((void *) swirl->knots);
- swirl->knots = (KNOT_P) calloc(swirl->n_knots, sizeof (KNOT));
-
- /* no knots yet */
- orbit = wheel = picasso = ray = hook = False;
-
- /* what types do we have? */
- if ((int) swirl->knot_type & (int) ALL) {
- orbit = wheel = ray = hook = True;
- } else {
- if ((int) swirl->knot_type & (int) ORBIT)
- orbit = True;
- if ((int) swirl->knot_type & (int) WHEEL)
- wheel = True;
- if ((int) swirl->knot_type & (int) PICASSO)
- picasso = True;
- if ((int) swirl->knot_type & (int) RAY)
- ray = True;
- if ((int) swirl->knot_type & (int) HOOK)
- hook = True;
- }
-
- /* initialise each knot */
- knot = swirl->knots;
- for (k = 0; k < swirl->n_knots; k++) {
- /* position */
- knot->x = random_no((unsigned int) swirl->width);
- knot->y = random_no((unsigned int) swirl->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 (swirl->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++;
- }
-}
-
-/****************************************************************/
-
-/*
- * 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(SWIRL_P swirl, int i, int j)
-{
- int tT, k, value, add;
- double dx, dy, theta, dist;
- int dcolours, qcolours;
- double rads;
- KNOT_P knot;
-
- /* how many colours? */
- dcolours = swirl->dcolours;
- qcolours = dcolours / 4;
-
- /* colour step round a circle */
- rads = (double) dcolours / (2.0 * M_PI);
-
- /* start at zero */
- value = 0;
-
- /* go through all the knots */
- knot = swirl->knots;
- for (k = 0; k < swirl->n_knots; k++) {
- dx = i - knot->x;
- dy = j - knot->y;
-
- /* in two_plane mode get the appropriate knot type */
- if (swirl->two_plane)
- tT = (int) ((swirl->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) (dcolours / (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) (dcolours * theta +
- sin(0.1 * knot->m * dist) *
- qcolours * exp(-0.01 * dist));
- else
- add = (int) (dcolours * (theta - 1.0) +
- sin(0.1 * knot->m * dist) *
- qcolours * exp(-0.01 * dist));
- break;
- case PICASSO:
- add = (int) (dcolours *
- 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) (dcolours * 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 +ve mass add on the contribution else take it off */
- if (knot->m > 0)
- value += add;
- else
- value -= add;
-
- /* next knot */
- knot++;
- }
-
- /* toggle plane */
- swirl->first_plane = (!swirl->first_plane);
-
- /* make sure we handle -ve values properly */
- if (value >= 0)
- value = (value % dcolours) + 2;
- else
- value = dcolours - (abs(value) % (dcolours - 1));
-
-#ifndef STANDALONE
- /* if fg and bg are 1 and 0 we should be OK, but just in case */
- while ((dcolours > 2) &&
- (((value % swirl->colours) == (int) swirl->fg) ||
- ((value % swirl->colours) == (int) swirl->bg) ||
- ((value % swirl->colours) == (int) swirl->white) ||
- ((value % swirl->colours) == (int) swirl->black))) {
- value++;
- }
-#endif /* !STANDALONE */
-
- /* definitely make sure it is in range */
- value = value % swirl->colours;
-
- /* lookup the pixel value if necessary */
-#ifndef STANDALONE
- if (swirl->fixed_colourmap && swirl->dcolours > 2)
-#endif
- value = swirl->rgb_values[value].pixel;
-
- /* return it */
- return ((unsigned long) value);
-}
-
-/****************************************************************/
-
-/*
- * 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, SWIRL_P swirl)
-{
- int r;
- int x, y;
-
- /* get current point coordinates and resolution */
- x = swirl->x;
- y = swirl->y;
- r = swirl->r;
-
- /* check we are within the window */
- if ((x < 0) || (x > swirl->width - r) || (y < 0) || (y > swirl->height - r))
- return;
-
- /* what style are we drawing? */
- if (swirl->two_plane) {
- int r2;
-
- /* halve the block size */
- r2 = r / 2;
-
- /* interleave blocks at half r */
- draw_block(swirl->ximage, x, y, r2, do_point(swirl, x, y));
- draw_block(swirl->ximage, x + r2, y, r2, do_point(swirl, x + r2, y));
- draw_block(swirl->ximage, x + r2, y + r2, r2, do_point(swirl,
- x + r2, y + r2));
- draw_block(swirl->ximage, x, y + r2, r2, do_point(swirl, x, y + r2));
- } else
- draw_block(swirl->ximage, x, y, r, do_point(swirl, x, y));
-
- /* update the screen */
-
-#ifdef HAVE_XSHM_EXTENSION
- if (mi->use_shm)
- XShmPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->ximage,
- x, y, x, y, r, r, False);
- else
-#endif /* !HAVE_XSHM_EXTENSION */
- /* PURIFY 4.0.1 on SunOS4 and on Solaris 2 reports a 256 byte memory
- leak on the next line. */
- XPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->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(SWIRL_P swirl)
-{
- /* more to do in this direction? */
- if (swirl->dir_done < swirl->dir_todo) {
- /* move in the current direction */
- switch (swirl->direction) {
- case DRAW_RIGHT:
- swirl->x += swirl->r;
- break;
- case DRAW_DOWN:
- swirl->y += swirl->r;
- break;
- case DRAW_LEFT:
- swirl->x -= swirl->r;
- break;
- case DRAW_UP:
- swirl->y -= swirl->r;
- break;
- }
-
- /* done another point */
- swirl->dir_done++;
- } else {
- /* none drawn yet */
- swirl->dir_done = 0;
-
- /* change direction - check and record if off screen */
- switch (swirl->direction) {
- case DRAW_RIGHT:
- swirl->direction = DRAW_DOWN;
- if (swirl->x > swirl->width - swirl->r) {
- /* skip these points */
- swirl->dir_done = swirl->dir_todo;
- swirl->y += (swirl->dir_todo * swirl->r);
-
- /* check for finish */
- if (swirl->off_screen)
- swirl->drawing = False;
- swirl->off_screen = True;
- } else
- swirl->off_screen = False;
- break;
- case DRAW_DOWN:
- swirl->direction = DRAW_LEFT;
- swirl->dir_todo++;
- if (swirl->y > swirl->height - swirl->r) {
- /* skip these points */
- swirl->dir_done = swirl->dir_todo;
- swirl->x -= (swirl->dir_todo * swirl->r);
-
- /* check for finish */
- if (swirl->off_screen)
- swirl->drawing = False;
- swirl->off_screen = True;
- } else
- swirl->off_screen = False;
- break;
- case DRAW_LEFT:
- swirl->direction = DRAW_UP;
- if (swirl->x < 0) {
- /* skip these points */
- swirl->dir_done = swirl->dir_todo;
- swirl->y -= (swirl->dir_todo * swirl->r);
-
- /* check for finish */
- if (swirl->off_screen)
- swirl->drawing = False;
- swirl->off_screen = True;
- } else
- swirl->off_screen = False;
- break;
- case DRAW_UP:
- swirl->direction = DRAW_RIGHT;
- swirl->dir_todo++;
- if (swirl->y < 0) {
- /* skip these points */
- swirl->dir_done = swirl->dir_todo;
- swirl->x += (swirl->dir_todo * swirl->r);
-
- /* check for finish */
- if (swirl->off_screen)
- swirl->drawing = False;
- swirl->off_screen = True;
- } else
- swirl->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);
- SWIRL_P swirl;
-
- /* does the swirls array exist? */
- if (swirls == NULL) {
- int i;
-
- /* allocate an array, one entry for each screen */
- swirls = (SWIRL_P) calloc(ScreenCount(display), sizeof (SWIRL));
-
- /* initialise them all */
- for (i = 0; i < ScreenCount(display); i++)
- initialise_swirl(mi, &swirls[i]);
- }
- /* get a pointer to this swirl */
- swirl = &(swirls[MI_SCREEN(mi)]);
-
- /* get window parameters */
- swirl->win = window;
- swirl->width = MI_WIN_WIDTH(mi);
- swirl->height = MI_WIN_HEIGHT(mi);
- swirl->depth = MI_WIN_DEPTH(mi);
- swirl->rdepth = swirl->depth;
- swirl->visual = MI_VISUAL(mi);
-
- if (swirl->depth > 16)
- swirl->depth = 16;
-
- /* initialise image for speeding up drawing */
- initialise_image(mi, swirl);
-
- /* clear the window (before setting the colourmap) */
- XClearWindow(display, MI_WINDOW(mi));
-
-#ifdef STANDALONE
-
- swirl->rgb_values = mi->colors;
- swirl->colours = mi->npixels;
- swirl->dcolours = swirl->colours;
-/* swirl->fixed_colourmap = !mi->writable_p;*/
-
-#else /* !STANDALONE */
-
- /* initialise the colours from which the colourmap is derived */
- initialise_colours(basic_colours, MI_SATURATION(mi));
-
- /* set up the colour map */
- create_colourmap(mi, swirl);
-
- /* attach the colour map to the window (if we have one) */
- if (!swirl->fixed_colourmap) {
-#if 1
- setColormap(display, window, swirl->cmap, MI_WIN_IS_INWINDOW(mi));
-#else
- XSetWindowColormap(display, window, swirl->cmap);
- (void) XSetWMColormapWindows(display, window, &window, 1);
- XInstallColormap(display, swirl->cmap);
-#endif
- }
-#endif /* STANDALONE */
-
- /* resolution starts off chunky */
- swirl->resolution = MIN_RES + 1;
-
- /* calculate the pixel step for this resulution */
- swirl->r = (1 << (swirl->resolution - 1));
-
- /* how many knots? */
- swirl->n_knots = random_no((unsigned int) MI_BATCHCOUNT(mi) / 2) +
- MI_BATCHCOUNT(mi) + 1;
-
- /* what type of knots? */
- swirl->knot_type = ALL; /* for now */
-
- /* use two_plane mode occaisionally */
- if (random_no(100) <= TWO_PLANE_PCNT) {
- swirl->two_plane = swirl->first_plane = True;
- swirl->max_resolution = 2;
- } else
- swirl->two_plane = False;
-
- /* fix the knot values */
- create_knots(swirl);
-
- /* we are off */
- swirl->started = True;
- swirl->drawing = False;
-}
-
-/****************************************************************/
-
-/*
- * draw_swirl
- *
- * Draw one iteration of swirling
- *
- * - win is the window to draw in
- */
-void
-draw_swirl(ModeInfo * mi)
-{
- SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]);
-
- /* are we going? */
- if (swirl->started) {
- /* in the middle of drawing? */
- if (swirl->drawing) {
-#ifdef STANDALONE
- if (mi->writable_p)
- rotate_colors(MI_DISPLAY(mi), MI_COLORMAP(mi),
- swirl->rgb_values, swirl->colours, 1);
-#else /* !STANDALONE */
- /* rotate the colours */
- install_map(MI_DISPLAY(mi), swirl, swirl->dshift);
-#endif /* !STANDALONE */
-
- /* draw a batch of points */
- swirl->batch_todo = BATCH_DRAW;
- while ((swirl->batch_todo > 0) && swirl->drawing) {
- /* draw a point */
- draw_point(mi, swirl);
-
- /* move to the next point */
- next_point(swirl);
-
- /* done a point */
- swirl->batch_todo--;
- }
- } else {
-#ifdef STANDALONE
- if (mi->writable_p)
- rotate_colors(MI_DISPLAY(mi), MI_COLORMAP(mi),
- swirl->rgb_values, swirl->colours, 1);
-#else /* !STANDALONE */
- /* rotate the colours */
- install_map(MI_DISPLAY(mi), swirl, swirl->shift);
-#endif /* !STANDALONE */
-
- /* time for a higher resolution? */
- if (swirl->resolution > swirl->max_resolution) {
- /* move to higher resolution */
- swirl->resolution--;
-
- /* calculate the pixel step for this resulution */
- swirl->r = (1 << (swirl->resolution - 1));
-
- /* start drawing again */
- swirl->drawing = True;
-
- /* start in the middle of the screen */
- swirl->x = (swirl->width - swirl->r) / 2;
- swirl->y = (swirl->height - swirl->r) / 2;
-
- /* initialise spiral drawing parameters */
- swirl->direction = DRAW_RIGHT;
- swirl->dir_todo = 1;
- swirl->dir_done = 0;
- } else {
- /* all done, decide when to restart */
- if (swirl->start_again == -1) {
- /* start the counter */
- swirl->start_again = RESTART;
- } else if (swirl->start_again == 0) {
- /* reset the counter */
- swirl->start_again = -1;
-
-#ifdef STANDALONE
- /* Pick a new colormap! */
- XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi));
- free_colors (MI_DISPLAY(mi), MI_COLORMAP(mi),
- mi->colors, mi->npixels);
- make_smooth_colormap (MI_DISPLAY(mi),
- MI_VISUAL(mi),
- MI_COLORMAP(mi),
- mi->colors, &mi->npixels, True,
- &mi->writable_p, True);
- swirl->colours = mi->npixels;
-#endif /* STANDALONE */
-
- /* start again */
- init_swirl(mi);
- } else
- /* decrement the counter */
- swirl->start_again--;
- }
- }
- }
-}
-
-/****************************************************************/
-
-void
-release_swirl(ModeInfo * mi)
-{
- /* does the swirls array exist? */
- if (swirls != NULL) {
- int i;
-
- /* free them all */
- for (i = 0; i < MI_NUM_SCREENS(mi); i++) {
- SWIRL_P swirl = &(swirls[i]);
-
- if (swirl->cmap != (Colormap) NULL)
- XFreeColormap(MI_DISPLAY(mi), swirl->cmap);
- if (swirl->rgb_values != NULL)
- XFree((void *) swirl->rgb_values);
- if (swirl->ximage != NULL)
- XDestroyImage(swirl->ximage);
- if (swirl->knots)
- (void) free((void *) swirl->knots);
- }
- /* deallocate an array, one entry for each screen */
- (void) free((void *) swirls);
- swirls = NULL;
- }
-}
-
-/****************************************************************/
-
-void
-refresh_swirl(ModeInfo * mi)
-{
- SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]);
-
- if (swirl->started) {
- if (swirl->drawing)
- swirl->resolution = swirl->resolution + 1;
- swirl->drawing = False;
- }
-}