/* -*- 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 * * 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 * 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 . * 1994: written. Copyright (c) 1994 M.Dobie * 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 /****************************************************************/ #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)