summaryrefslogtreecommitdiffstats
path: root/hacks/swirl.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/swirl.c')
-rw-r--r--hacks/swirl.c1445
1 files changed, 1445 insertions, 0 deletions
diff --git a/hacks/swirl.c b/hacks/swirl.c
new file mode 100644
index 0000000..ae72820
--- /dev/null
+++ b/hacks/swirl.c
@@ -0,0 +1,1445 @@
+/* -*- Mode: C; tab-width: 4 -*-
+ * swirl --- swirly color-cycling patterns.
+ */
+#if 0
+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.
+ *
+ * 09-Oct-2016: dmo2118@gmail.com: Updated for new xshm.c.
+ * 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 DEFAULTS "*count: 5 \n" \
+ "*delay: 10000 \n" \
+ "*ncolors: 200 \n" \
+ "*useSHM: True \n" \
+ "*fpsSolid: true \n" \
+ "*ignoreRotation: True \n" \
+ ".lowrez: True \n" \
+
+# define SMOOTH_COLORS
+# define WRITABLE_COLORS
+# define release_swirl 0
+# define reshape_swirl 0
+# define swirl_handle_event 0
+# include "xlockmore.h" /* from the xscreensaver distribution */
+# include "xshm.h"
+#else /* !STANDALONE */
+# include "xlock.h" /* from the xlockmore distribution */
+# undef HAVE_XSHM_EXTENSION
+#endif /* !STANDALONE */
+
+ENTRYPOINT 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;
+ XShmSegmentInfo shm_info;
+
+ /* 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 */
+
+
+#ifndef 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)
+ destroy_xshm_image(dpy, swirl->ximage, &swirl->shm_info);
+
+ swirl->ximage = create_xshm_image(dpy, swirl->visual, swirl->rdepth,
+ ZPixmap, &swirl->shm_info,
+ swirl->width, swirl->height);
+}
+
+/****************************************************************/
+
+#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 */
+
+ put_xshm_image(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->ximage,
+ x, y, x, y, r, r, &swirl->shm_info);
+}
+
+/****************************************************************/
+
+/*
+ * 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
+ */
+ENTRYPOINT void
+init_swirl(ModeInfo * mi)
+{
+ Display *display = MI_DISPLAY(mi);
+ Window window = MI_WINDOW(mi);
+ SWIRL_P swirl;
+
+ MI_INIT (mi, swirls);
+ swirl = &(swirls[MI_SCREEN(mi)]);
+ initialise_swirl(mi, swirl);
+
+ /* 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
+ */
+ENTRYPOINT 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->xgwa.screen, 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->xgwa.screen, 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->xgwa.screen, MI_COLORMAP(mi),
+ mi->colors, mi->npixels);
+ make_smooth_colormap (mi->xgwa.screen, 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--;
+ }
+ }
+ }
+}
+
+/****************************************************************/
+
+ENTRYPOINT void
+free_swirl (ModeInfo * mi)
+{
+ SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]);
+
+#ifndef STANDALONE
+ if (swirl->cmap != (Colormap) NULL)
+ XFreeColormap(MI_DISPLAY(mi), swirl->cmap);
+#endif /* STANDALONE */
+#ifndef STANDALONE
+ if (swirl->rgb_values != NULL)
+ XFree((void *) swirl->rgb_values);
+#endif /* !STANDALONE */
+ if (swirl->ximage != NULL)
+ destroy_xshm_image(MI_DISPLAY(mi), swirl->ximage,
+ &swirl->shm_info);
+ if (swirl->knots)
+ (void) free((void *) swirl->knots);
+}
+
+/****************************************************************/
+
+#ifndef STANDALONE
+ENTRYPOINT 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;
+ }
+}
+#endif
+
+XSCREENSAVER_MODULE ("Swirl", swirl)