1 /* -*- Mode: C; tab-width: 4 -*-
2 * swirl --- swirly color-cycling patterns.
4 #if !defined( lint ) && !defined( SABER )
5 static const char sccsid[] = "@(#)swirl.c 4.00 97/01/01 xlockmore";
8 /* Copyright (c) 1994 M.Dobie <mrd@ecs.soton.ac.uk>
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation for any purpose and without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation.
16 * This file is provided AS IS with no warranties of any kind. The author
17 * shall have no liability with respect to the infringement of copyrights,
18 * trade secrets or any patents by this file or any part thereof. In no
19 * event will the author be liable for any lost revenue or profits or
20 * other special, indirect and consequential damages.
22 * 13-May-97: jwz@netscape.com: turned into a standalone program.
23 * 21-Apr-95: improved startup time for TrueColour displays
24 * (limited to 16bpp to save memory) S.Early <sde1000@cam.ac.uk>
25 * 09-Jan-95: fixed colour maps (more colourful) and the image now spirals
26 * outwards from the centre with a fixed number of points drawn
27 * every iteration. Thanks to M.Dobie <mrd@ecs.soton.ac.uk>.
28 * 1994: written. Copyright (c) 1994 M.Dobie <mrd@ecs.soton.ac.uk>
29 * based on original code by R.Taylor
33 # define PROGCLASS "Swirl"
34 # define HACK_INIT init_swirl
35 # define HACK_DRAW draw_swirl
36 # define swirl_opts xlockmore_opts
37 # define DEFAULTS "*count: 5 \n" \
40 # define SMOOTH_COLORS
41 # define WRITABLE_COLORS
42 # include "xlockmore.h" /* from the xscreensaver distribution */
43 # include <X11/Xutil.h>
44 #else /* !STANDALONE */
45 # include "xlock.h" /* from the xlockmore distribution */
46 #endif /* !STANDALONE */
48 ModeSpecOpt swirl_opts = {
49 0, NULL, 0, NULL, NULL };
53 /****************************************************************/
55 #define MASS 4 /* maximum mass of a knot */
56 #define MIN_RES 5 /* minimim resolution (>= MIN_RES) */
57 #define MAX_RES 1 /* maximum resolution (>0) */
58 #define TWO_PLANE_PCNT 30 /* probability for two plane mode (0-100) */
59 #define RESTART 2500 /* number of cycles before restart */
60 #define BATCH_DRAW 100 /* points to draw per iteration */
75 int x, y; /* position */
77 KNOT_T t; /* type in the first (or only) plane */
78 KNOT_T T; /* type in second plane if there is one */
79 int M; /* mass in second plane if there is one */
82 /* a colour specification */
83 typedef struct Colour {
84 unsigned short r, g, b;
87 /* drawing direction */
89 DRAW_RIGHT, DRAW_DOWN, DRAW_LEFT, DRAW_UP
92 /****************************************************************/
94 /* data associated with a swirl window */
95 typedef struct swirl_data {
96 /* window paramaters */
97 Window win; /* the window */
98 int width, height; /* window size */
99 int depth; /* depth */
100 int rdepth; /* real depth (for XImage) */
101 Visual *visual; /* visual */
103 /* swirl drawing parameters */
104 int n_knots; /* number of knots */
105 KNOT_P knots; /* knot details */
106 KNOT_T knot_type; /* general type of knots */
107 int resolution; /* drawing resolution, 1..5 */
108 int max_resolution; /* maximum resolution, MAX_RES */
109 int r; /* pixel step */
110 Bool two_plane; /* two plane mode? */
111 Bool first_plane; /* doing first plane? */
112 int start_again; /* when to restart */
114 /* spiral drawing parameters */
115 int x, y; /* current point */
116 DIR_T direction; /* current direction */
117 int dir_todo, dir_done; /* how many points in current direction? */
118 int batch_todo, batch_done; /* how many points in this batch */
119 Bool started, drawing; /* are we drawing? */
122 unsigned char *image; /* image data */
126 int colours; /* how many colours possible */
127 int dcolours; /* how many colours for shading */
129 Bool fixed_colourmap; /* fixed colourmap? */
130 #endif /* !STANDALONE */
131 Bool monochrome; /* monochrome? */
132 Colormap cmap; /* colour map for the window */
133 XColor *rgb_values; /* colour definitions array */
135 int current_map; /* current colour map, 0..dcolours-1 */
136 unsigned long fg, bg, white, black; /* black and white pixel values */
137 int shift; /* colourmap shift */
138 int dshift; /* colourmap shift while drawing */
139 XColor fgcol, bgcol; /* foreground and background colour specs */
140 #endif /* !STANDALONE */
144 #define SWIRLCOLOURS 13
148 static COLOUR basic_colours[SWIRLCOLOURS];
149 #endif /* !STANDALONE */
151 /* an array of swirls for each screen */
152 static SWIRL_P swirls = NULL;
157 Return a random integer between 0 and n inclusive
159 - n is the maximum number
161 Returns a random integer */
164 random_no(unsigned int n)
166 return ((int) ((n + 1) * (double) LRAND() / MAXRAND));
169 /****************************************************************/
174 Initialise all the swirl data
176 - swirl is the swirl data */
179 initialise_swirl(ModeInfo * mi, SWIRL_P swirl)
182 Display *display = MI_DISPLAY(mi);
183 #endif /* !STANDALONE */
185 swirl->width = 0; /* width and height of window */
189 swirl->visual = NULL;
190 swirl->resolution = MIN_RES + 1; /* current resolution */
191 swirl->max_resolution = MAX_RES; /* maximum resolution */
192 swirl->n_knots = 0; /* number of knots */
193 swirl->knot_type = ALL; /* general type of knots */
194 swirl->two_plane = False; /* two plane mode? */
195 swirl->first_plane = False; /* doing first plane? */
196 swirl->start_again = -1; /* restart counter */
198 /* drawing parameters */
201 swirl->started = False;
202 swirl->drawing = False;
205 swirl->image = NULL; /* image data */
206 swirl->ximage = NULL;
209 swirl->colours = 0; /* how many colours possible */
210 swirl->dcolours = 0; /* how many colours for shading */
211 swirl->cmap = (Colormap) NULL;
212 swirl->rgb_values = NULL; /* colour definitions array */
214 swirl->current_map = 0; /* current colour map, 0..dcolours-1 */
216 /* set up fg fb colour specs */
217 swirl->white = MI_WIN_WHITE_PIXEL(mi);
218 swirl->black = MI_WIN_BLACK_PIXEL(mi);
219 #endif /* !STANDALONE */
223 # define MI_COLORMAP MI_WIN_COLORMAP
224 #else /* !STANDALONE */
225 swirl->fg = MI_FG_COLOR(mi);
226 swirl->bg = MI_BG_COLOR(mi);
227 swirl->fgcol.pixel = swirl->fg;
228 swirl->bgcol.pixel = swirl->bg;
229 XQueryColor(display, MI_COLORMAP(mi), &(swirl->fgcol));
230 XQueryColor(display, MI_COLORMAP(mi), &(swirl->bgcol));
231 #endif /* !STANDALONE */
234 /****************************************************************/
239 * Initialise the image for drawing to
241 * - swirl is the swirl data
244 initialise_image(Display * dpy, SWIRL_P swirl)
248 int image_depth = swirl->rdepth;
249 int data_depth = image_depth;
251 /* On SGIs at least, using an XImage of depth 24 on a Visual of depth 24
252 requires the XImage data to use 32 bits per pixel. I don't understand
253 how one is supposed to determine this -- maybe XListPixmapFormats?
254 But on systems that don't work this way, allocating 32 bpp instead of
255 24 will be wasteful but non-fatal. -- jwz, 16-May-97. */
256 if (data_depth >= 24 && data_depth < 32)
259 /* get the bitmap pad */
260 pad = BitmapPad(dpy);
261 /* destroy the old image (destroy XImage and data) */
262 if (swirl->ximage != NULL)
263 XDestroyImage(swirl->ximage);
265 /* how many bytes per line? (bits rounded up to pad) */
266 bytes_per_line = ((swirl->width * data_depth + pad - 1) / pad) * (pad / 8);
268 /* allocate space for the image */
269 swirl->image = (unsigned char *) calloc(bytes_per_line * swirl->height, 1);
271 /* create an ximage with this */
272 swirl->ximage = XCreateImage(dpy, swirl->visual, image_depth, ZPixmap,
273 0, (char *) swirl->image, swirl->width,
274 swirl->height, pad, bytes_per_line);
277 /****************************************************************/
283 * Initialise the list of colours from which the colourmaps are derived
285 * - colours is the array to initialise
286 * - saturation is the saturation value to use 0->grey,
287 * 1.0->full saturation
290 initialise_colours(COLOUR * colours, float saturate)
294 /* start off fully saturated, medium and bright colours */
295 colours[0].r = 0xA000;
296 colours[0].g = 0x0000;
297 colours[0].b = 0x0000;
298 colours[1].r = 0xD000;
299 colours[1].g = 0x0000;
300 colours[1].b = 0x0000;
301 colours[2].r = 0x0000;
302 colours[2].g = 0x6000;
303 colours[2].b = 0x0000;
304 colours[3].r = 0x0000;
305 colours[3].g = 0x9000;
306 colours[3].b = 0x0000;
307 colours[4].r = 0x0000;
308 colours[4].g = 0x0000;
309 colours[4].b = 0xC000;
310 colours[5].r = 0x0000;
311 colours[5].g = 0x0000;
312 colours[5].b = 0xF000;
313 colours[6].r = 0xA000;
314 colours[6].g = 0x6000;
315 colours[6].b = 0x0000;
316 colours[7].r = 0xD000;
317 colours[7].g = 0x9000;
318 colours[7].b = 0x0000;
319 colours[8].r = 0xA000;
320 colours[8].g = 0x0000;
321 colours[8].b = 0xC000;
322 colours[9].r = 0xD000;
323 colours[9].g = 0x0000;
324 colours[9].b = 0xF000;
325 colours[10].r = 0x0000;
326 colours[10].g = 0x6000;
327 colours[10].b = 0xC000;
328 colours[11].r = 0x0000;
329 colours[11].g = 0x9000;
330 colours[11].b = 0xF000;
331 colours[12].r = 0xA000;
332 colours[12].g = 0xA000;
333 colours[12].b = 0xA000;
335 /* add white for low saturation */
336 for (i = 0; i < SWIRLCOLOURS - 1; i++) {
337 unsigned short max_rg, max;
339 /* what is the max intensity for this colour? */
340 max_rg = (colours[i].r > colours[i].g) ? colours[i].r : colours[i].g;
341 max = (max_rg > colours[i].b) ? max_rg : colours[i].b;
343 /* bring elements up to max as saturation approaches 0.0 */
344 colours[i].r += (unsigned short) ((float) (1.0 - saturate) *
345 ((float) max - colours[i].r));
346 colours[i].g += (unsigned short) ((float) (1.0 - saturate) *
347 ((float) max - colours[i].g));
348 colours[i].b += (unsigned short) ((float) (1.0 - saturate) *
349 ((float) max - colours[i].b));
352 #endif /* !STANDALONE */
354 /****************************************************************/
358 * set_black_and_white
360 * Set the entries for foreground & background pixels and
361 * WhitePixel & BlackPixel in an array of colour specifications.
363 * - swirl is the swirl data
364 * - values is the array of specifications
367 set_black_and_white(SWIRL_P swirl, XColor * values)
369 unsigned long white, black;
371 /* where is black and white? */
372 white = swirl->white;
373 black = swirl->black;
375 /* set black and white up */
376 values[white].flags = DoRed | DoGreen | DoBlue;
377 values[white].pixel = white;
378 values[white].red = 0xFFFF;
379 values[white].green = 0xFFFF;
380 values[white].blue = 0xFFFF;
381 values[black].flags = DoRed | DoGreen | DoBlue;
382 values[black].pixel = black;
383 values[black].red = 0;
384 values[black].green = 0;
385 values[black].blue = 0;
387 /* copy the colour specs from the original entries */
388 values[swirl->fg] = swirl->fgcol;
389 values[swirl->bg] = swirl->bgcol;
392 /****************************************************************/
397 * Set an entry in an array of XColor specifications. The given entry will be
398 * set to the given colour. If the entry corresponds to the foreground,
399 * background, WhitePixel, or BlackPixel it is ignored and the given colour
400 * is is put in the next entry.
402 * Therefore, the given colour may be placed up to four places after the
403 * specified entry in the array, if foreground, background, white, or black
406 * - swirl is the swirl data
407 * - value points to a pointer to the array entry. It gets updated to
408 * point to the next free entry.
409 * - pixel points to the current pixel number. It gets updated.
410 * - c points to the colour to add
413 set_colour(SWIRL_P swirl, XColor ** value, unsigned long *pixel, COLOUR_P c)
416 unsigned long fg, bg, white, black;
418 /* where are foreground, background, white, and black? */
421 white = swirl->white;
422 black = swirl->black;
424 /* haven't set it yet */
427 /* try and set the colour */
429 (**value).flags = DoRed | DoGreen | DoBlue;
430 (**value).pixel = *pixel;
432 /* white, black, fg, bg, or a colour? */
433 if ((*pixel != fg) && (*pixel != bg) &&
434 (*pixel != white) && (*pixel != black)) {
435 (**value).red = c->r;
436 (**value).green = c->g;
437 (**value).blue = c->b;
439 /* now we've done it */
448 /****************************************************************/
453 * Get an entry from an array of XColor specifications. The next colour from
454 * the array will be returned. Foreground, background, WhitePixel, or
455 * BlackPixel will be ignored.
457 * - swirl is the swirl data
458 * - value points the array entry. It is updated to point to the entry
459 * following the one returned.
460 * - c is set to the colour found
463 get_colour(SWIRL_P swirl, XColor ** value, COLOUR_P c)
466 unsigned long fg, bg, white, black;
468 /* where is white and black? */
471 white = swirl->white;
472 black = swirl->black;
474 /* haven't set it yet */
477 /* try and set the colour */
479 /* black, white or a colour? */
480 if (((*value)->pixel != fg) && ((*value)->pixel != bg) &&
481 ((*value)->pixel != white) && ((*value)->pixel != black)) {
482 c->r = (*value)->red;
483 c->g = (*value)->green;
484 c->b = (*value)->blue;
486 /* now we've done it */
493 #endif /* !STANDALONE */
495 /****************************************************************/
501 * Generate n colours between c1 and c2. n XColors at *value are set up with
502 * ascending pixel values.
504 * If the pixel range includes BlackPixel or WhitePixel they are set to black
505 * and white respectively but otherwise ignored. Therefore, up to n+2 colours
506 * may actually be set by this function.
508 * - swirl is the swirl data
509 * - values points a pointer to an array of XColors to update
510 * - pixel points to the pixel number to start at
511 * - k n is the number of colours to generate
512 * - c1, c2 are the colours to interpolate between
515 interpolate(SWIRL_P swirl, XColor ** values, unsigned long *pixel, int n, COLOUR_P c1, COLOUR_P c2)
524 for (i = 0; i < n / 2 && (int) *pixel < swirl->colours; i++) {
525 /* work out the colour */
526 r = c1->r + 2 * i * ((int) c2->r) / n;
527 c.r = (r > (int) maxv) ? maxv : r;
528 g = c1->g + 2 * i * ((int) c2->g) / n;
529 c.g = (g > (int) maxv) ? maxv : g;
530 b = c1->b + 2 * i * ((int) c2->b) / n;
531 c.b = (b > (int) maxv) ? maxv : b;
534 set_colour(swirl, values, pixel, &c);
536 for (i = n / 2; i >= 0 && (int) *pixel < swirl->colours; i--) {
537 r = c2->r + 2 * i * ((int) c1->r) / n;
538 c.r = (r > (int) maxv) ? maxv : r;
539 g = c2->g + 2 * i * ((int) c1->g) / n;
540 c.g = (g > (int) maxv) ? maxv : g;
541 b = c2->b + 2 * i * ((int) c1->b) / n;
542 c.b = (b > (int) maxv) ? maxv : b;
545 set_colour(swirl, values, pixel, &c);
549 /****************************************************************/
554 * Generate a `random' closed loop colourmap that occupies the whole colour
557 * - swirl is the swirl data
558 * - values is the array of colour definitions to set up
561 basic_map(SWIRL_P swirl, XColor * values)
565 unsigned short r1, g1, b1, r2, g2, b2, r3, g3, b3;
570 /* start at the beginning of the colour map */
574 /* choose 3 different basic colours at random */
575 for (i = 0; i < 3;) {
579 /* choose colour i */
580 c[i] = basic_colours[random_no(SWIRLCOLOURS - 1)];
582 /* assume different */
585 /* different from the rest? */
586 for (j = 0; j < i; j++)
587 if ((c[i].r == c[j].r) &&
588 (c[i].g == c[j].g) &&
592 /* ready for the next colour? */
597 /* extract components into variables */
608 /* work out the lengths of each side of the triangle */
609 L1 = (int) sqrt((((double) r1 - r2) * ((double) r1 - r2) +
610 ((double) g1 - g2) * ((double) g1 - g2) +
611 ((double) b1 - b2) * ((double) b1 - b2)));
613 L2 = (int) sqrt((((double) r3 - r2) * ((double) r3 - r2) +
614 ((double) g3 - g2) * ((double) g3 - g2) +
615 ((double) b3 - b2) * ((double) b3 - b2)));
617 L3 = (int) sqrt((((double) r1 - r3) * ((double) r1 - r3) +
618 ((double) g1 - g3) * ((double) g1 - g3) +
619 ((double) b1 - b3) * ((double) b1 - b3)));
623 /* allocate colours in proportion to the lengths of the sides */
624 interpolate(swirl, &value, &pixel,
625 (int) ((double) swirl->dcolours * ((double) L1 / (double) L)) + 1, c, c + 1);
626 interpolate(swirl, &value, &pixel,
627 (int) ((double) swirl->dcolours * ((double) L2 / (double) L)) + 1, c + 1, c + 2);
628 interpolate(swirl, &value, &pixel,
629 (int) ((double) swirl->dcolours * ((double) L3 / (double) L)) + 1, c + 2, c);
631 /* fill up any remaining slots (due to rounding) */
632 while ((int) pixel < swirl->colours) {
633 /* repeat the last colour */
634 set_colour(swirl, &value, &pixel, c);
637 /* ensure black and white are correct */
638 if (!swirl->fixed_colourmap)
639 set_black_and_white(swirl, values);
642 /****************************************************************/
647 * Generate pre-rotated versions of the colour specifications
649 * - swirl is the swirl data
650 * - values is an array of colour specifications
653 pre_rotate(SWIRL_P swirl, XColor * values)
660 /* how many colours to display? */
661 dcolours = swirl->dcolours;
663 /* start at the first map */
665 dest = values + swirl->colours;
667 /* generate dcolours-1 rotated maps */
668 for (i = 0; i < dcolours - 1; i++) {
671 /* start at the first pixel */
674 /* remember the first one and skip it */
675 get_colour(swirl, &src, &first);
677 /* put a rotated version of src at dest */
678 for (j = 0; j < dcolours - 1; j++) {
681 /* get the source colour */
682 get_colour(swirl, &src, &c);
685 set_colour(swirl, &dest, &pixel, &c);
688 /* put the first one at the end */
689 set_colour(swirl, &dest, &pixel, &first);
691 /* NB: src and dest should now be ready for the next table */
693 /* ensure black and white are properly set */
694 set_black_and_white(swirl, src);
698 /****************************************************************/
703 * Create a read/write colourmap to use
705 * - swirl is the swirl data
709 create_colourmap(ModeInfo * mi, SWIRL_P swirl)
711 Display *display = MI_DISPLAY(mi);
716 unsigned long redmask, greenmask, bluemask;
718 swirl->fixed_colourmap = !setupColormap(mi, &(swirl->colours),
719 &truecolor, &redmask, &greenmask, &bluemask);
720 preserve = preserveColors(swirl->fg, swirl->bg, swirl->white, swirl->black);
722 /* how many colours should we animate? */
723 swirl->dcolours = (swirl->colours > preserve + 1) ?
724 swirl->colours - preserve : swirl->colours;
726 if (MI_NPIXELS(mi) < 2)
729 /* how fast to shift the colourmap? */
730 swirl->shift = (swirl->colours > 64) ? swirl->colours / 64 : 1;
731 swirl->dshift = (swirl->shift > 1) ? swirl->shift * 2 : 1;
733 /* how may colour map rotations are there? */
734 n_rotations = (swirl->fixed_colourmap) ? 1 : swirl->dcolours;
736 /* allocate space for colour definitions (if not already there) */
737 if (swirl->rgb_values == NULL) {
738 swirl->rgb_values = (XColor *) calloc((swirl->colours + 3) * n_rotations,
741 /* create a colour map */
742 if (!swirl->fixed_colourmap)
744 XCreateColormap(display, swirl->win, swirl->visual, AllocAll);
746 /* select a set of colours for the colour map */
747 basic_map(swirl, swirl->rgb_values);
749 /* are we rotating them? */
750 if (!swirl->fixed_colourmap) {
751 /* generate rotations of the colour maps */
752 pre_rotate(swirl, swirl->rgb_values);
754 /* store the colours in the colour map */
755 XStoreColors(display, swirl->cmap, swirl->rgb_values, swirl->colours);
762 for (i = 0; (int) t > 0; i++, t >>= 1);
765 for (i = 0; (int) t > 0; i++, t >>= 1);
768 for (i = 0; (int) t > 0; i++, t >>= 1);
770 for (i = 0; i < swirl->colours; i++)
771 swirl->rgb_values[i].pixel =
772 ((rsh > 0 ? (swirl->rgb_values[i].red) >> rsh :
773 (swirl->rgb_values[i].red) << (-rsh)) & redmask) |
774 ((gsh > 0 ? (swirl->rgb_values[i].green) >> gsh :
775 (swirl->rgb_values[i].green) << (-gsh)) & greenmask) |
776 ((bsh > 0 ? (swirl->rgb_values[i].blue) >> bsh :
777 (swirl->rgb_values[i].blue) << (-bsh)) & bluemask);
779 /* lookup the colours in the fixed colour map */
780 for (i = 0; i < swirl->colours; i++)
781 (void) XAllocColor(display, MI_COLORMAP(mi),
782 &(swirl->rgb_values[i]));
787 /****************************************************************/
792 * Install a new set of colours into the colour map
794 * - dpy is the display
795 * - swirl is the swirl data
796 * - shift is the amount to rotate the colour map by
799 install_map(Display * dpy, SWIRL_P swirl, int shift)
801 if (!swirl->fixed_colourmap) {
802 /* shift the colour map */
803 swirl->current_map = (swirl->current_map + shift) %
807 XStoreColors(dpy, swirl->cmap,
809 swirl->current_map * swirl->colours,
813 #endif /* !STANDALONE */
815 /****************************************************************/
820 * Initialise the array of knot
822 * swirl is the swirl data
825 create_knots(SWIRL_P swirl)
828 Bool orbit, wheel, picasso, ray, hook;
831 /* create array for knots */
833 (void) free((void *) swirl->knots);
834 swirl->knots = (KNOT_P) calloc(swirl->n_knots, sizeof (KNOT));
837 orbit = wheel = picasso = ray = hook = False;
839 /* what types do we have? */
840 if ((int) swirl->knot_type & (int) ALL) {
841 orbit = wheel = ray = hook = True;
843 if ((int) swirl->knot_type & (int) ORBIT)
845 if ((int) swirl->knot_type & (int) WHEEL)
847 if ((int) swirl->knot_type & (int) PICASSO)
849 if ((int) swirl->knot_type & (int) RAY)
851 if ((int) swirl->knot_type & (int) HOOK)
855 /* initialise each knot */
857 for (k = 0; k < swirl->n_knots; k++) {
859 knot->x = random_no((unsigned int) swirl->width);
860 knot->y = random_no((unsigned int) swirl->height);
863 knot->m = random_no(MASS) + 1;
865 /* can be negative */
866 if (random_no(100) > 50)
871 while (knot->t == NONE) {
872 /* choose a random one from the types available */
873 switch (random_no(4)) {
897 /* if two planes, do same for second plane */
898 if (swirl->two_plane) {
900 while (knot->T == NONE || knot->T == knot->t) {
901 /* choose a different type */
902 switch (random_no(4)) {
931 /****************************************************************/
936 * Work out the pixel value at i, j. Ensure it does not clash with BlackPixel
939 * - swirl is the swirl data
940 * - i, j is the point to calculate
942 * Returns the value of the point
945 do_point(SWIRL_P swirl, int i, int j)
947 int tT, k, value, add;
948 double dx, dy, theta, dist;
949 int dcolours, qcolours;
953 /* how many colours? */
954 dcolours = swirl->dcolours;
955 qcolours = dcolours / 4;
957 /* colour step round a circle */
958 rads = (double) dcolours / (2.0 * M_PI);
963 /* go through all the knots */
965 for (k = 0; k < swirl->n_knots; k++) {
969 /* in two_plane mode get the appropriate knot type */
970 if (swirl->two_plane)
971 tT = (int) ((swirl->first_plane) ? knot->t : knot->T);
975 /* distance from knot */
976 dist = sqrt(dx * dx + dy * dy);
978 /* nothing to add at first */
981 /* work out the contribution (if close enough) */
985 add = (int) (dcolours / (1.0 + 0.01 * abs(knot->m) * dist));
988 /* Avoid atan2: DOMAIN error message */
989 if (dy == 0.0 && dx == 0.0)
992 theta = (atan2(dy, dx) + M_PI) / M_PI;
994 add = (int) (dcolours * theta +
995 sin(0.1 * knot->m * dist) *
996 qcolours * exp(-0.01 * dist));
998 add = (int) (dcolours * (theta - 1.0) +
999 sin(0.1 * knot->m * dist) *
1000 qcolours * exp(-0.01 * dist));
1003 add = (int) (dcolours *
1004 fabs(cos(0.002 * knot->m * dist)));
1007 /* Avoid atan2: DOMAIN error message */
1008 if (dy == 0.0 && dx == 0.0)
1011 add = (int) (dcolours * fabs(sin(2.0 * atan2(dy, dx))));
1015 /* Avoid atan2: DOMAIN error message */
1016 if (dy == 0.0 && dx == 0.0)
1017 add = (int) (0.05 * (abs(knot->m) - 1) * dist);
1019 add = (int) (rads * atan2(dy, dx) +
1020 0.05 * (abs(knot->m) - 1) * dist);
1023 /* for a +ve mass add on the contribution else take it off */
1034 swirl->first_plane = (!swirl->first_plane);
1036 /* make sure we handle -ve values properly */
1038 value = (value % dcolours) + 2;
1040 value = dcolours - (abs(value) % (dcolours - 1));
1043 /* if fg and bg are 1 and 0 we should be OK, but just in case */
1044 while ((dcolours > 2) &&
1045 (((value % swirl->colours) == (int) swirl->fg) ||
1046 ((value % swirl->colours) == (int) swirl->bg) ||
1047 ((value % swirl->colours) == (int) swirl->white) ||
1048 ((value % swirl->colours) == (int) swirl->black))) {
1051 #endif /* !STANDALONE */
1053 /* definitely make sure it is in range */
1054 value = value % swirl->colours;
1056 /* lookup the pixel value if necessary */
1058 if (swirl->fixed_colourmap && swirl->dcolours > 2)
1060 value = swirl->rgb_values[value].pixel;
1063 return ((unsigned long) value);
1066 /****************************************************************/
1071 * Draw a square block of points with the same value.
1073 * - ximage is the XImage to draw on.
1074 * - x, y is the top left corner
1075 * - s is the length of each side
1079 draw_block(XImage * ximage, int x, int y, int s, unsigned long v)
1083 for (a = 0; a < s; a++)
1084 for (b = 0; b < s; b++) {
1085 XPutPixel(ximage, x + b, y + a, v);
1089 /****************************************************************/
1092 * draw_point Draw the current point in a swirl pattern onto the XImage
1094 * - swirl is the swirl
1095 * - win is the window to update
1098 draw_point(ModeInfo * mi, SWIRL_P swirl)
1103 /* get current point coordinates and resolution */
1108 /* check we are within the window */
1109 if ((x < 0) || (x > swirl->width - r) || (y < 0) || (y > swirl->height - r))
1112 /* what style are we drawing? */
1113 if (swirl->two_plane) {
1116 /* halve the block size */
1119 /* interleave blocks at half r */
1120 draw_block(swirl->ximage, x, y, r2, do_point(swirl, x, y));
1121 draw_block(swirl->ximage, x + r2, y, r2, do_point(swirl, x + r2, y));
1122 draw_block(swirl->ximage, x + r2, y + r2, r2, do_point(swirl,
1124 draw_block(swirl->ximage, x, y + r2, r2, do_point(swirl, x, y + r2));
1126 draw_block(swirl->ximage, x, y, r, do_point(swirl, x, y));
1128 /* update the screen */
1129 /* PURIFY 4.0.1 on SunOS4 and on Solaris 2 reports a 256 byte memory leak on *
1131 XPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->ximage,
1135 /****************************************************************/
1138 * next_point Move to the next point in the spiral pattern
1139 * - swirl is the swirl
1140 * - win is the window to update
1143 next_point(SWIRL_P swirl)
1145 /* more to do in this direction? */
1146 if (swirl->dir_done < swirl->dir_todo) {
1147 /* move in the current direction */
1148 switch (swirl->direction) {
1150 swirl->x += swirl->r;
1153 swirl->y += swirl->r;
1156 swirl->x -= swirl->r;
1159 swirl->y -= swirl->r;
1163 /* done another point */
1166 /* none drawn yet */
1167 swirl->dir_done = 0;
1169 /* change direction - check and record if off screen */
1170 switch (swirl->direction) {
1172 swirl->direction = DRAW_DOWN;
1173 if (swirl->x > swirl->width - swirl->r) {
1174 /* skip these points */
1175 swirl->dir_done = swirl->dir_todo;
1176 swirl->y += (swirl->dir_todo * swirl->r);
1178 /* check for finish */
1179 if (swirl->off_screen)
1180 swirl->drawing = False;
1181 swirl->off_screen = True;
1183 swirl->off_screen = False;
1186 swirl->direction = DRAW_LEFT;
1188 if (swirl->y > swirl->height - swirl->r) {
1189 /* skip these points */
1190 swirl->dir_done = swirl->dir_todo;
1191 swirl->x -= (swirl->dir_todo * swirl->r);
1193 /* check for finish */
1194 if (swirl->off_screen)
1195 swirl->drawing = False;
1196 swirl->off_screen = True;
1198 swirl->off_screen = False;
1201 swirl->direction = DRAW_UP;
1203 /* skip these points */
1204 swirl->dir_done = swirl->dir_todo;
1205 swirl->y -= (swirl->dir_todo * swirl->r);
1207 /* check for finish */
1208 if (swirl->off_screen)
1209 swirl->drawing = False;
1210 swirl->off_screen = True;
1212 swirl->off_screen = False;
1215 swirl->direction = DRAW_RIGHT;
1218 /* skip these points */
1219 swirl->dir_done = swirl->dir_todo;
1220 swirl->x += (swirl->dir_todo * swirl->r);
1222 /* check for finish */
1223 if (swirl->off_screen)
1224 swirl->drawing = False;
1225 swirl->off_screen = True;
1227 swirl->off_screen = False;
1233 /****************************************************************/
1238 * Initialise things for swirling
1240 * - win is the window to draw in
1243 init_swirl(ModeInfo * mi)
1245 Display *display = MI_DISPLAY(mi);
1246 Window window = MI_WINDOW(mi);
1249 /* does the swirls array exist? */
1250 if (swirls == NULL) {
1253 /* allocate an array, one entry for each screen */
1254 swirls = (SWIRL_P) calloc(ScreenCount(display), sizeof (SWIRL));
1256 /* initialise them all */
1257 for (i = 0; i < ScreenCount(display); i++)
1258 initialise_swirl(mi, &swirls[i]);
1260 /* get a pointer to this swirl */
1261 swirl = &(swirls[MI_SCREEN(mi)]);
1263 /* get window parameters */
1264 swirl->win = window;
1265 swirl->width = MI_WIN_WIDTH(mi);
1266 swirl->height = MI_WIN_HEIGHT(mi);
1267 swirl->depth = MI_WIN_DEPTH(mi);
1268 swirl->rdepth = swirl->depth;
1269 swirl->visual = MI_VISUAL(mi);
1271 if (swirl->depth > 16)
1274 /* initialise image for speeding up drawing */
1275 initialise_image(display, swirl);
1277 /* clear the window (before setting the colourmap) */
1278 XClearWindow(display, MI_WINDOW(mi));
1282 swirl->rgb_values = mi->colors;
1283 swirl->colours = mi->npixels;
1284 swirl->dcolours = swirl->colours;
1285 /* swirl->fixed_colourmap = !mi->writable_p;*/
1287 #else /* !STANDALONE */
1289 /* initialise the colours from which the colourmap is derived */
1290 initialise_colours(basic_colours, MI_SATURATION(mi));
1292 /* set up the colour map */
1293 create_colourmap(mi, swirl);
1295 /* attach the colour map to the window (if we have one) */
1296 if (!swirl->fixed_colourmap) {
1298 setColormap(display, window, swirl->cmap, MI_WIN_IS_INWINDOW(mi));
1300 XSetWindowColormap(display, window, swirl->cmap);
1301 (void) XSetWMColormapWindows(display, window, &window, 1);
1302 XInstallColormap(display, swirl->cmap);
1305 #endif /* STANDALONE */
1307 /* resolution starts off chunky */
1308 swirl->resolution = MIN_RES + 1;
1310 /* calculate the pixel step for this resulution */
1311 swirl->r = (1 << (swirl->resolution - 1));
1313 /* how many knots? */
1314 swirl->n_knots = random_no((unsigned int) MI_BATCHCOUNT(mi) / 2) +
1315 MI_BATCHCOUNT(mi) + 1;
1317 /* what type of knots? */
1318 swirl->knot_type = ALL; /* for now */
1320 /* use two_plane mode occaisionally */
1321 if (random_no(100) <= TWO_PLANE_PCNT) {
1322 swirl->two_plane = swirl->first_plane = True;
1323 swirl->max_resolution = 2;
1325 swirl->two_plane = False;
1327 /* fix the knot values */
1328 create_knots(swirl);
1331 swirl->started = True;
1332 swirl->drawing = False;
1335 /****************************************************************/
1340 * Draw one iteration of swirling
1342 * - win is the window to draw in
1345 draw_swirl(ModeInfo * mi)
1347 SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]);
1350 if (swirl->started) {
1351 /* in the middle of drawing? */
1352 if (swirl->drawing) {
1355 rotate_colors(MI_DISPLAY(mi), MI_COLORMAP(mi),
1356 swirl->rgb_values, swirl->colours, 1);
1357 #else /* !STANDALONE */
1358 /* rotate the colours */
1359 install_map(MI_DISPLAY(mi), swirl, swirl->dshift);
1360 #endif /* !STANDALONE */
1362 /* draw a batch of points */
1363 swirl->batch_todo = BATCH_DRAW;
1364 while ((swirl->batch_todo > 0) && swirl->drawing) {
1366 draw_point(mi, swirl);
1368 /* move to the next point */
1372 swirl->batch_todo--;
1377 rotate_colors(MI_DISPLAY(mi), MI_COLORMAP(mi),
1378 swirl->rgb_values, swirl->colours, 1);
1379 #else /* !STANDALONE */
1380 /* rotate the colours */
1381 install_map(MI_DISPLAY(mi), swirl, swirl->shift);
1382 #endif /* !STANDALONE */
1384 /* time for a higher resolution? */
1385 if (swirl->resolution > swirl->max_resolution) {
1386 /* move to higher resolution */
1387 swirl->resolution--;
1389 /* calculate the pixel step for this resulution */
1390 swirl->r = (1 << (swirl->resolution - 1));
1392 /* start drawing again */
1393 swirl->drawing = True;
1395 /* start in the middle of the screen */
1396 swirl->x = (swirl->width - swirl->r) / 2;
1397 swirl->y = (swirl->height - swirl->r) / 2;
1399 /* initialise spiral drawing parameters */
1400 swirl->direction = DRAW_RIGHT;
1401 swirl->dir_todo = 1;
1402 swirl->dir_done = 0;
1404 /* all done, decide when to restart */
1405 if (swirl->start_again == -1) {
1406 /* start the counter */
1407 swirl->start_again = RESTART;
1408 } else if (swirl->start_again == 0) {
1409 /* reset the counter */
1410 swirl->start_again = -1;
1413 /* Pick a new colormap! */
1414 XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi));
1415 free_colors (MI_DISPLAY(mi), MI_COLORMAP(mi),
1416 mi->colors, mi->npixels);
1417 make_smooth_colormap (MI_DISPLAY(mi),
1420 mi->colors, &mi->npixels, True,
1421 &mi->writable_p, True);
1422 swirl->colours = mi->npixels;
1423 #endif /* STANDALONE */
1428 /* decrement the counter */
1429 swirl->start_again--;
1435 /****************************************************************/
1438 release_swirl(ModeInfo * mi)
1440 /* does the swirls array exist? */
1441 if (swirls != NULL) {
1445 for (i = 0; i < MI_NUM_SCREENS(mi); i++) {
1446 SWIRL_P swirl = &(swirls[i]);
1448 if (swirl->cmap != (Colormap) NULL)
1449 XFreeColormap(MI_DISPLAY(mi), swirl->cmap);
1450 if (swirl->rgb_values != NULL)
1451 XFree((void *) swirl->rgb_values);
1452 if (swirl->ximage != NULL)
1453 XDestroyImage(swirl->ximage);
1455 (void) free((void *) swirl->knots);
1457 /* deallocate an array, one entry for each screen */
1458 (void) free((void *) swirls);
1463 /****************************************************************/
1466 refresh_swirl(ModeInfo * mi)
1468 SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]);
1470 if (swirl->started) {
1472 swirl->resolution = swirl->resolution + 1;
1473 swirl->drawing = False;