began for maemo
[xscreensaver] / xscreensaver / hacks / swirl.c
1 /* -*- Mode: C; tab-width: 4 -*-
2  * swirl --- swirly color-cycling patterns.
3  */
4 #if 0
5 static const char sccsid[] = "@(#)swirl.c       4.00 97/01/01 xlockmore";
6 #endif
7
8 /* Copyright (c) 1994 M.Dobie <mrd@ecs.soton.ac.uk>
9  *
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.
15  *
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.
21  *
22  * 13-May-97: jwz@jwz.org: 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
30  */
31
32 #ifdef STANDALONE
33 # define DEFAULTS       "*count:                5       \n"                     \
34                                         "*delay:                10000   \n"                     \
35                                         "*ncolors:              200     \n"                     \
36                                         "*useSHM:               True    \n"
37 # define SMOOTH_COLORS
38 # define WRITABLE_COLORS
39 # define reshape_swirl 0
40 # define swirl_handle_event 0
41 # include "xlockmore.h"                         /* from the xscreensaver distribution */
42 # ifdef HAVE_XSHM_EXTENSION
43 #  include "xshm.h"
44 # endif /* HAVE_XSHM_EXTENSION */
45 #else  /* !STANDALONE */
46 # include "xlock.h"                                     /* from the xlockmore distribution */
47 # undef HAVE_XSHM_EXTENSION
48 #endif /* !STANDALONE */
49
50 ENTRYPOINT ModeSpecOpt swirl_opts = {
51   0, NULL, 0, NULL, NULL };
52
53 #include <time.h>
54
55 /****************************************************************/
56
57 #define MASS            4       /* maximum mass of a knot */
58 #define MIN_RES         5       /* minimim resolution (>= MIN_RES) */
59 #define MAX_RES         1       /* maximum resolution (>0) */
60 #define TWO_PLANE_PCNT  30      /* probability for two plane mode (0-100) */
61 #define RESTART         2500    /* number of cycles before restart */
62 #define BATCH_DRAW      100     /* points to draw per iteration */
63
64 /* knot types */
65 typedef enum {
66         NONE = 0,
67         ORBIT = (1 << 0),
68         WHEEL = (1 << 1),
69         PICASSO = (1 << 2),
70         RAY = (1 << 3),
71         HOOK = (1 << 4),
72         ALL = (1 << 5)
73 } KNOT_T;
74
75 /* a knot */
76 typedef struct Knot {
77         int         x, y;       /* position */
78         int         m;          /* mass */
79         KNOT_T      t;          /* type in the first (or only) plane */
80         KNOT_T      T;          /* type in second plane if there is one */
81         int         M;          /* mass in second plane if there is one */
82 } KNOT     , *KNOT_P;
83
84 /* a colour specification */
85 typedef struct Colour {
86         unsigned short r, g, b;
87 } COLOUR   , *COLOUR_P;
88
89 /* drawing direction */
90 typedef enum {
91         DRAW_RIGHT, DRAW_DOWN, DRAW_LEFT, DRAW_UP
92 } DIR_T;
93
94 /****************************************************************/
95
96 /* data associated with a swirl window */
97 typedef struct swirl_data {
98         /* window paramaters */
99         Window      win;        /* the window */
100         int         width, height;      /* window size */
101         int         depth;      /* depth */
102         int         rdepth;     /* real depth (for XImage) */
103         Visual     *visual;     /* visual */
104
105         /* swirl drawing parameters */
106         int         n_knots;    /* number of knots */
107         KNOT_P      knots;      /* knot details */
108         KNOT_T      knot_type;  /* general type of knots */
109         int         resolution; /* drawing resolution, 1..5 */
110         int         max_resolution;     /* maximum resolution, MAX_RES */
111         int         r;          /* pixel step */
112         Bool        two_plane;  /* two plane mode? */
113         Bool        first_plane;        /* doing first plane? */
114         int         start_again;        /* when to restart */
115
116         /* spiral drawing parameters */
117         int         x, y;       /* current point */
118         DIR_T       direction;  /* current direction */
119         int         dir_todo, dir_done;         /* how many points in current direction? */
120         int         batch_todo, batch_done;     /* how many points in this batch */
121         Bool        started, drawing;   /* are we drawing? */
122
123         /* image stuff */
124         unsigned char *image;   /* image data */
125         XImage     *ximage;
126
127         /* colours stuff */
128         int         colours;    /* how many colours possible */
129         int         dcolours;   /* how many colours for shading */
130 #ifndef STANDALONE
131         Bool        fixed_colourmap;    /* fixed colourmap? */
132 #endif /* !STANDALONE */
133         Bool        monochrome; /* monochrome? */
134         Colormap    cmap;       /* colour map for the window */
135         XColor     *rgb_values; /* colour definitions array */
136 #ifndef STANDALONE
137         int         current_map;        /* current colour map, 0..dcolours-1 */
138         unsigned long fg, bg, white, black;     /* black and white pixel values */
139         int         shift;      /* colourmap shift */
140         int         dshift;     /* colourmap shift while drawing */
141         XColor      fgcol, bgcol;       /* foreground and background colour specs */
142 #endif /* !STANDALONE */
143         Bool       off_screen;
144 } SWIRL    , *SWIRL_P;
145
146 #define SWIRLCOLOURS 13
147
148 #ifndef STANDALONE
149 /* basic colours */
150 static COLOUR basic_colours[SWIRLCOLOURS];
151 #endif /* !STANDALONE */
152
153 /* an array of swirls for each screen */
154 static SWIRL_P swirls = NULL;
155
156 /* 
157    random_no
158
159    Return a random integer between 0 and n inclusive
160
161    -      n is the maximum number
162
163    Returns a random integer */
164
165 static int
166 random_no(unsigned int n)
167 {
168         return ((int) ((n + 1) * (double) LRAND() / MAXRAND));
169 }
170
171 /****************************************************************/
172
173 /* 
174    initialise_swirl
175
176    Initialise all the swirl data
177
178    -      swirl is the swirl data */
179
180 static void
181 initialise_swirl(ModeInfo * mi, SWIRL_P swirl)
182 {
183 #ifndef STANDALONE
184         Display    *display = MI_DISPLAY(mi);
185 #endif /* !STANDALONE */
186
187         swirl->width = 0;       /* width and height of window */
188         swirl->height = 0;
189         swirl->depth = 1;
190         swirl->rdepth = 1;
191         swirl->visual = NULL;
192         swirl->resolution = MIN_RES + 1;        /* current resolution */
193         swirl->max_resolution = MAX_RES;        /* maximum resolution */
194         swirl->n_knots = 0;     /* number of knots */
195         swirl->knot_type = ALL; /* general type of knots */
196         swirl->two_plane = False;       /* two plane mode? */
197         swirl->first_plane = False;     /* doing first plane? */
198         swirl->start_again = -1;        /* restart counter */
199
200         /* drawing parameters */
201         swirl->x = 0;
202         swirl->y = 0;
203         swirl->started = False;
204         swirl->drawing = False;
205
206         /* image stuff */
207         swirl->image = NULL;    /* image data */
208         swirl->ximage = NULL;
209
210         /* colours stuff */
211         swirl->colours = 0;     /* how many colours possible */
212         swirl->dcolours = 0;    /* how many colours for shading */
213         swirl->cmap = (Colormap) NULL;
214         swirl->rgb_values = NULL;       /* colour definitions array */
215 #ifndef STANDALONE
216         swirl->current_map = 0; /* current colour map, 0..dcolours-1 */
217
218         /* set up fg fb colour specs */
219         swirl->white = MI_WIN_WHITE_PIXEL(mi);
220         swirl->black = MI_WIN_BLACK_PIXEL(mi);
221 #endif /* !STANDALONE */
222
223
224 #ifndef 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 */
232 }
233
234 /****************************************************************/
235
236 /* 
237  * initialise_image
238  *
239  * Initialise the image for drawing to
240  *
241  * -      swirl is the swirl data
242  */
243 static void
244 initialise_image(ModeInfo * mi, SWIRL_P swirl)
245 {
246   Display *dpy = MI_DISPLAY(mi);
247
248   if (swirl->ximage != NULL)
249         XDestroyImage(swirl->ximage);
250
251   swirl->ximage = 0;
252 #ifdef HAVE_XSHM_EXTENSION
253   if (mi->use_shm)
254         {
255           swirl->ximage = create_xshm_image(dpy, swirl->visual, swirl->rdepth,
256                                                                                 ZPixmap, 0, &mi->shm_info,
257                                                                                 swirl->width, swirl->height);
258           if (!swirl->ximage)
259                 mi->use_shm = False;
260         }
261 #endif /* HAVE_XSHM_EXTENSION */
262
263   if (!swirl->ximage)
264         {
265           swirl->ximage = XCreateImage(dpy, swirl->visual, swirl->rdepth, ZPixmap,
266                                                                    0, 0, swirl->width, swirl->height,
267                                                                    8, 0);
268           swirl->image = (unsigned char *)
269         calloc(swirl->height, swirl->ximage->bytes_per_line);
270       swirl->ximage->data = (char *) swirl->image;
271         }
272 }
273
274 /****************************************************************/
275
276 #ifndef STANDALONE
277 /* 
278  * initialise_colours
279  *
280  * Initialise the list of colours from which the colourmaps are derived
281  *
282  * -      colours is the array to initialise
283  * -      saturation is the saturation value to use 0->grey,
284  *            1.0->full saturation
285  */
286 static void
287 initialise_colours(COLOUR * colours, float saturate)
288 {
289         int         i;
290
291         /* start off fully saturated, medium and bright colours */
292         colours[0].r = 0xA000;
293         colours[0].g = 0x0000;
294         colours[0].b = 0x0000;
295         colours[1].r = 0xD000;
296         colours[1].g = 0x0000;
297         colours[1].b = 0x0000;
298         colours[2].r = 0x0000;
299         colours[2].g = 0x6000;
300         colours[2].b = 0x0000;
301         colours[3].r = 0x0000;
302         colours[3].g = 0x9000;
303         colours[3].b = 0x0000;
304         colours[4].r = 0x0000;
305         colours[4].g = 0x0000;
306         colours[4].b = 0xC000;
307         colours[5].r = 0x0000;
308         colours[5].g = 0x0000;
309         colours[5].b = 0xF000;
310         colours[6].r = 0xA000;
311         colours[6].g = 0x6000;
312         colours[6].b = 0x0000;
313         colours[7].r = 0xD000;
314         colours[7].g = 0x9000;
315         colours[7].b = 0x0000;
316         colours[8].r = 0xA000;
317         colours[8].g = 0x0000;
318         colours[8].b = 0xC000;
319         colours[9].r = 0xD000;
320         colours[9].g = 0x0000;
321         colours[9].b = 0xF000;
322         colours[10].r = 0x0000;
323         colours[10].g = 0x6000;
324         colours[10].b = 0xC000;
325         colours[11].r = 0x0000;
326         colours[11].g = 0x9000;
327         colours[11].b = 0xF000;
328         colours[12].r = 0xA000;
329         colours[12].g = 0xA000;
330         colours[12].b = 0xA000;
331
332         /* add white for low saturation */
333         for (i = 0; i < SWIRLCOLOURS - 1; i++) {
334                 unsigned short max_rg, max;
335
336                 /* what is the max intensity for this colour? */
337                 max_rg = (colours[i].r > colours[i].g) ? colours[i].r : colours[i].g;
338                 max = (max_rg > colours[i].b) ? max_rg : colours[i].b;
339
340                 /* bring elements up to max as saturation approaches 0.0 */
341                 colours[i].r += (unsigned short) ((float) (1.0 - saturate) *
342                                                ((float) max - colours[i].r));
343                 colours[i].g += (unsigned short) ((float) (1.0 - saturate) *
344                                                ((float) max - colours[i].g));
345                 colours[i].b += (unsigned short) ((float) (1.0 - saturate) *
346                                                ((float) max - colours[i].b));
347         }
348 }
349 #endif /* !STANDALONE */
350
351 /****************************************************************/
352
353 #ifndef STANDALONE
354 /* 
355  * set_black_and_white
356  *
357  * Set the entries for foreground & background pixels and
358  * WhitePixel & BlackPixel in an array of colour specifications.
359  *
360  * -      swirl is the swirl data
361  * -      values is the array of specifications 
362  */
363 static void
364 set_black_and_white(SWIRL_P swirl, XColor * values)
365 {
366         unsigned long white, black;
367
368         /* where is black and white? */
369         white = swirl->white;
370         black = swirl->black;
371
372         /* set black and white up */
373         values[white].flags = DoRed | DoGreen | DoBlue;
374         values[white].pixel = white;
375         values[white].red = 0xFFFF;
376         values[white].green = 0xFFFF;
377         values[white].blue = 0xFFFF;
378         values[black].flags = DoRed | DoGreen | DoBlue;
379         values[black].pixel = black;
380         values[black].red = 0;
381         values[black].green = 0;
382         values[black].blue = 0;
383
384         /* copy the colour specs from the original entries */
385         values[swirl->fg] = swirl->fgcol;
386         values[swirl->bg] = swirl->bgcol;
387 }
388
389 /****************************************************************/
390
391 /* 
392  * set_colour
393  *
394  * Set an entry in an array of XColor specifications. The given entry will be
395  * set to the given colour. If the entry corresponds to the foreground,
396  * background, WhitePixel, or BlackPixel it is ignored and the given colour
397  * is is put in the next entry.
398  *
399  * Therefore, the given colour may be placed up to four places after the
400  * specified entry in the array, if foreground, background, white, or black
401  * intervene.
402  *
403  * -      swirl is the swirl data
404  * -      value points to a pointer to the array entry. It gets updated to
405  *            point to the next free entry.
406  * -      pixel points to the current pixel number. It gets updated.
407  * -      c points to the colour to add
408  */
409 static void
410 set_colour(SWIRL_P swirl, XColor ** value, unsigned long *pixel, COLOUR_P c)
411 {
412         Bool        done;
413         unsigned long fg, bg, white, black;
414
415         /* where are foreground, background, white, and black? */
416         fg = swirl->fg;
417         bg = swirl->bg;
418         white = swirl->white;
419         black = swirl->black;
420
421         /* haven't set it yet */
422         done = False;
423
424         /* try and set the colour */
425         while (!done) {
426                 (**value).flags = DoRed | DoGreen | DoBlue;
427                 (**value).pixel = *pixel;
428
429                 /* white, black, fg, bg, or a colour? */
430                 if ((*pixel != fg) && (*pixel != bg) &&
431                     (*pixel != white) && (*pixel != black)) {
432                         (**value).red = c->r;
433                         (**value).green = c->g;
434                         (**value).blue = c->b;
435
436                         /* now we've done it */
437                         done = True;
438                 }
439                 /* next pixel */
440                 (*value)++;
441                 (*pixel)++;
442         }
443 }
444
445 /****************************************************************/
446
447 /* 
448  * get_colour
449  *
450  * Get an entry from an array of XColor specifications. The next colour from
451  * the array will be returned. Foreground, background, WhitePixel, or
452  * BlackPixel will be ignored.
453  *
454  * -      swirl is the swirl data
455  * -      value points the array entry. It is updated to point to the entry
456  *            following the one returned.
457  * -      c is set to the colour found
458  */
459 static void
460 get_colour(SWIRL_P swirl, XColor ** value, COLOUR_P c)
461 {
462         Bool        done;
463         unsigned long fg, bg, white, black;
464
465         /* where is white and black? */
466         fg = swirl->fg;
467         bg = swirl->bg;
468         white = swirl->white;
469         black = swirl->black;
470
471         /* haven't set it yet */
472         done = False;
473
474         /* try and set the colour */
475         while (!done) {
476                 /* black, white or a colour? */
477                 if (((*value)->pixel != fg) && ((*value)->pixel != bg) &&
478                   ((*value)->pixel != white) && ((*value)->pixel != black)) {
479                         c->r = (*value)->red;
480                         c->g = (*value)->green;
481                         c->b = (*value)->blue;
482
483                         /* now we've done it */
484                         done = True;
485                 }
486                 /* next value */
487                 (*value)++;
488         }
489 }
490 #endif /* !STANDALONE */
491
492 /****************************************************************/
493
494 #ifndef STANDALONE
495 /* 
496  *  interpolate
497  *
498  * Generate n colours between c1 and c2.  n XColors at *value are set up with
499  * ascending pixel values.
500  *
501  * If the pixel range includes BlackPixel or WhitePixel they are set to black
502  * and white respectively but otherwise ignored. Therefore, up to n+2 colours
503  * may actually be set by this function.
504  *
505  * -      swirl is the swirl data
506  * -      values points a pointer to an array of XColors to update
507  * -      pixel points to the pixel number to start at
508  * -      k n is the number of colours to generate
509  * -      c1, c2 are the colours to interpolate between
510  */
511 static void
512 interpolate(SWIRL_P swirl, XColor ** values, unsigned long *pixel, int n, COLOUR_P c1, COLOUR_P c2)
513 {
514         int         i, r, g, b;
515         COLOUR      c;
516         unsigned short maxv;
517
518         /* maximum value */
519         maxv = (255 << 8);
520
521         for (i = 0; i < n / 2 && (int) *pixel < swirl->colours; i++) {
522                 /* work out the colour */
523                 r = c1->r + 2 * i * ((int) c2->r) / n;
524                 c.r = (r > (int) maxv) ? maxv : r;
525                 g = c1->g + 2 * i * ((int) c2->g) / n;
526                 c.g = (g > (int) maxv) ? maxv : g;
527                 b = c1->b + 2 * i * ((int) c2->b) / n;
528                 c.b = (b > (int) maxv) ? maxv : b;
529
530                 /* set it up */
531                 set_colour(swirl, values, pixel, &c);
532         }
533         for (i = n / 2; i >= 0 && (int) *pixel < swirl->colours; i--) {
534                 r = c2->r + 2 * i * ((int) c1->r) / n;
535                 c.r = (r > (int) maxv) ? maxv : r;
536                 g = c2->g + 2 * i * ((int) c1->g) / n;
537                 c.g = (g > (int) maxv) ? maxv : g;
538                 b = c2->b + 2 * i * ((int) c1->b) / n;
539                 c.b = (b > (int) maxv) ? maxv : b;
540
541                 /* set it up */
542                 set_colour(swirl, values, pixel, &c);
543         }
544 }
545
546 /****************************************************************/
547
548 /* 
549  * basic_map
550  *
551  * Generate a `random' closed loop colourmap that occupies the whole colour
552  * map.
553  *
554  * -      swirl is the swirl data
555  * -      values is the array of colour definitions to set up
556  */
557 static void
558 basic_map(SWIRL_P swirl, XColor * values)
559 {
560         COLOUR      c[3];
561         int         i;
562         unsigned short r1, g1, b1, r2, g2, b2, r3, g3, b3;
563         int         L1, L2, L3, L;
564         unsigned long pixel;
565         XColor     *value;
566
567         /* start at the beginning of the colour map */
568         pixel = 0;
569         value = values;
570
571         /* choose 3 different basic colours at random */
572         for (i = 0; i < 3;) {
573                 int         j;
574                 Bool        same;
575
576                 /* choose colour i */
577                 c[i] = basic_colours[random_no(SWIRLCOLOURS - 1)];
578
579                 /* assume different */
580                 same = False;
581
582                 /* different from the rest? */
583                 for (j = 0; j < i; j++)
584                         if ((c[i].r == c[j].r) &&
585                             (c[i].g == c[j].g) &&
586                             (c[i].b == c[j].b))
587                                 same = True;
588
589                 /* ready for the next colour? */
590                 if (!same)
591                         i++;
592         }
593
594         /* extract components into variables */
595         r1 = c[0].r;
596         g1 = c[0].g;
597         b1 = c[0].b;
598         r2 = c[1].r;
599         g2 = c[1].g;
600         b2 = c[1].b;
601         r3 = c[2].r;
602         g3 = c[2].g;
603         b3 = c[2].b;
604
605         /* work out the lengths of each side of the triangle */
606         L1 = (int) sqrt((((double) r1 - r2) * ((double) r1 - r2) +
607                          ((double) g1 - g2) * ((double) g1 - g2) +
608                          ((double) b1 - b2) * ((double) b1 - b2)));
609
610         L2 = (int) sqrt((((double) r3 - r2) * ((double) r3 - r2) +
611                          ((double) g3 - g2) * ((double) g3 - g2) +
612                          ((double) b3 - b2) * ((double) b3 - b2)));
613
614         L3 = (int) sqrt((((double) r1 - r3) * ((double) r1 - r3) +
615                          ((double) g1 - g3) * ((double) g1 - g3) +
616                          ((double) b1 - b3) * ((double) b1 - b3)));
617
618         L = L1 + L2 + L3;
619
620         /* allocate colours in proportion to the lengths of the sides */
621         interpolate(swirl, &value, &pixel,
622                     (int) ((double) swirl->dcolours * ((double) L1 / (double) L)) + 1, c, c + 1);
623         interpolate(swirl, &value, &pixel,
624                     (int) ((double) swirl->dcolours * ((double) L2 / (double) L)) + 1, c + 1, c + 2);
625         interpolate(swirl, &value, &pixel,
626                     (int) ((double) swirl->dcolours * ((double) L3 / (double) L)) + 1, c + 2, c);
627
628         /* fill up any remaining slots (due to rounding) */
629         while ((int) pixel < swirl->colours) {
630                 /* repeat the last colour */
631                 set_colour(swirl, &value, &pixel, c);
632         }
633
634         /* ensure black and white are correct */
635         if (!swirl->fixed_colourmap)
636                 set_black_and_white(swirl, values);
637 }
638
639 /****************************************************************/
640
641 /* 
642  * pre_rotate
643  *
644  * Generate pre-rotated versions of the colour specifications
645  *
646  * -      swirl is the swirl data
647  * -      values is an array of colour specifications
648  */
649 static void
650 pre_rotate(SWIRL_P swirl, XColor * values)
651 {
652         int         i, j;
653         XColor     *src, *dest;
654         int         dcolours;
655         unsigned long pixel;
656
657         /* how many colours to display? */
658         dcolours = swirl->dcolours;
659
660         /* start at the first map */
661         src = values;
662         dest = values + swirl->colours;
663
664         /* generate dcolours-1 rotated maps */
665         for (i = 0; i < dcolours - 1; i++) {
666                 COLOUR      first;
667
668                 /* start at the first pixel */
669                 pixel = 0;
670
671                 /* remember the first one and skip it */
672                 get_colour(swirl, &src, &first);
673
674                 /* put a rotated version of src at dest */
675                 for (j = 0; j < dcolours - 1; j++) {
676                         COLOUR      c;
677
678                         /* get the source colour */
679                         get_colour(swirl, &src, &c);
680
681                         /* set the colour */
682                         set_colour(swirl, &dest, &pixel, &c);
683                 }
684
685                 /* put the first one at the end */
686                 set_colour(swirl, &dest, &pixel, &first);
687
688                 /* NB: src and dest should now be ready for the next table */
689
690                 /* ensure black and white are properly set */
691                 set_black_and_white(swirl, src);
692         }
693 }
694
695 /****************************************************************/
696
697 /* 
698  * create_colourmap
699  *
700  * Create a read/write colourmap to use
701  *
702  * -      swirl is the swirl data
703  */
704
705 static void
706 create_colourmap(ModeInfo * mi, SWIRL_P swirl)
707 {
708         Display    *display = MI_DISPLAY(mi);
709         int         preserve;
710         int         n_rotations;
711         int         i;
712         Bool        truecolor;
713   unsigned long redmask, greenmask, bluemask;
714
715         swirl->fixed_colourmap = !setupColormap(mi, &(swirl->colours),
716     &truecolor, &redmask, &greenmask, &bluemask);
717         preserve = preserveColors(swirl->fg, swirl->bg, swirl->white, swirl->black);
718
719         /* how many colours should we animate? */
720         swirl->dcolours = (swirl->colours > preserve + 1) ?
721                 swirl->colours - preserve : swirl->colours;
722
723         if (MI_NPIXELS(mi) < 2)
724                 return;
725
726         /* how fast to shift the colourmap? */
727         swirl->shift = (swirl->colours > 64) ? swirl->colours / 64 : 1;
728         swirl->dshift = (swirl->shift > 1) ? swirl->shift * 2 : 1;
729
730         /* how may colour map rotations are there? */
731         n_rotations = (swirl->fixed_colourmap) ? 1 : swirl->dcolours;
732
733         /* allocate space for colour definitions (if not already there) */
734         if (swirl->rgb_values == NULL) {
735                 swirl->rgb_values = (XColor *) calloc((swirl->colours + 3) * n_rotations,
736                                                       sizeof (XColor));
737
738                 /* create a colour map */
739                 if (!swirl->fixed_colourmap)
740                         swirl->cmap =
741                                 XCreateColormap(display, swirl->win, swirl->visual, AllocAll);
742         }
743         /* select a set of colours for the colour map */
744         basic_map(swirl, swirl->rgb_values);
745
746         /* are we rotating them? */
747         if (!swirl->fixed_colourmap) {
748                 /* generate rotations of the colour maps */
749                 pre_rotate(swirl, swirl->rgb_values);
750
751                 /* store the colours in the colour map */
752                 XStoreColors(display, swirl->cmap, swirl->rgb_values, swirl->colours);
753         } else {
754                 if (truecolor) {
755                         int         rsh, gsh, bsh;
756                         unsigned long int t;
757
758                         t = redmask;
759                         for (i = 0; (int) t > 0; i++, t >>= 1);
760                         rsh = 16 - i;
761                         t = greenmask;
762                         for (i = 0; (int) t > 0; i++, t >>= 1);
763                         gsh = 16 - i;
764                         t = bluemask;
765                         for (i = 0; (int) t > 0; i++, t >>= 1);
766                         bsh = 16 - i;
767                         for (i = 0; i < swirl->colours; i++)
768                                 swirl->rgb_values[i].pixel =
769                                         ((rsh > 0 ? (swirl->rgb_values[i].red) >> rsh :
770                                           (swirl->rgb_values[i].red) << (-rsh)) & redmask) |
771                                         ((gsh > 0 ? (swirl->rgb_values[i].green) >> gsh :
772                                           (swirl->rgb_values[i].green) << (-gsh)) & greenmask) |
773                                         ((bsh > 0 ? (swirl->rgb_values[i].blue) >> bsh :
774                                           (swirl->rgb_values[i].blue) << (-bsh)) & bluemask);
775                 } else {
776                         /* lookup the colours in the fixed colour map */
777                         for (i = 0; i < swirl->colours; i++)
778                                 (void) XAllocColor(display, MI_COLORMAP(mi),
779                                                    &(swirl->rgb_values[i]));
780                 }
781         }
782 }
783
784 /****************************************************************/
785
786 /* 
787  * install_map
788  *
789  * Install a new set of colours into the colour map
790  *
791  * -      dpy is the display
792  * -      swirl is the swirl data
793  * -      shift is the amount to rotate the colour map by
794  */
795 static void
796 install_map(Display * dpy, SWIRL_P swirl, int shift)
797 {
798         if (!swirl->fixed_colourmap) {
799                 /* shift the colour map */
800                 swirl->current_map = (swirl->current_map + shift) %
801                         swirl->dcolours;
802
803                 /* store it */
804                 XStoreColors(dpy, swirl->cmap,
805                              swirl->rgb_values +
806                              swirl->current_map * swirl->colours,
807                              swirl->colours);
808         }
809 }
810 #endif /* !STANDALONE */
811
812 /****************************************************************/
813
814 /* 
815  * create_knots
816  *
817  * Initialise the array of knot
818  *
819  * swirl is the swirl data
820  */
821 static void
822 create_knots(SWIRL_P swirl)
823 {
824         int         k;
825         Bool        orbit, wheel, picasso, ray, hook;
826         KNOT_P      knot;
827
828         /* create array for knots */
829         if (swirl->knots)
830                 (void) free((void *) swirl->knots);
831         swirl->knots = (KNOT_P) calloc(swirl->n_knots, sizeof (KNOT));
832
833         /* no knots yet */
834         orbit = wheel = picasso = ray = hook = False;
835
836         /* what types do we have? */
837         if ((int) swirl->knot_type & (int) ALL) {
838                 orbit = wheel = ray = hook = True;
839         } else {
840                 if ((int) swirl->knot_type & (int) ORBIT)
841                         orbit = True;
842                 if ((int) swirl->knot_type & (int) WHEEL)
843                         wheel = True;
844                 if ((int) swirl->knot_type & (int) PICASSO)
845                         picasso = True;
846                 if ((int) swirl->knot_type & (int) RAY)
847                         ray = True;
848                 if ((int) swirl->knot_type & (int) HOOK)
849                         hook = True;
850         }
851
852         /* initialise each knot */
853         knot = swirl->knots;
854         for (k = 0; k < swirl->n_knots; k++) {
855                 /* position */
856                 knot->x = random_no((unsigned int) swirl->width);
857                 knot->y = random_no((unsigned int) swirl->height);
858
859                 /* mass */
860                 knot->m = random_no(MASS) + 1;
861
862                 /* can be negative */
863                 if (random_no(100) > 50)
864                         knot->m *= -1;
865
866                 /* type */
867                 knot->t = NONE;
868                 while (knot->t == NONE) {
869                         /* choose a random one from the types available */
870                         switch (random_no(4)) {
871                                 case 0:
872                                         if (orbit)
873                                                 knot->t = ORBIT;
874                                         break;
875                                 case 1:
876                                         if (wheel)
877                                                 knot->t = WHEEL;
878                                         break;
879                                 case 2:
880                                         if (picasso)
881                                                 knot->t = PICASSO;
882                                         break;
883                                 case 3:
884                                         if (ray)
885                                                 knot->t = RAY;
886                                         break;
887                                 case 4:
888                                         if (hook)
889                                                 knot->t = HOOK;
890                                         break;
891                         }
892                 }
893
894                 /* if two planes, do same for second plane */
895                 if (swirl->two_plane) {
896                         knot->T = NONE;
897                         while (knot->T == NONE || knot->T == knot->t) {
898                                 /* choose a different type */
899                                 switch (random_no(4)) {
900                                         case 0:
901                                                 if (orbit)
902                                                         knot->T = ORBIT;
903                                                 break;
904                                         case 1:
905                                                 if (wheel)
906                                                         knot->T = WHEEL;
907                                                 break;
908                                         case 2:
909                                                 if (picasso)
910                                                         knot->T = PICASSO;
911                                                 break;
912                                         case 3:
913                                                 if (ray)
914                                                         knot->T = RAY;
915                                                 break;
916                                         case 4:
917                                                 if (hook)
918                                                         knot->T = HOOK;
919                                                 break;
920                                 }
921                         }
922                 }
923                 /* next knot */
924                 knot++;
925         }
926 }
927
928 /****************************************************************/
929
930 /* 
931  * do_point
932  *
933  * Work out the pixel value at i, j. Ensure it does not clash with BlackPixel
934  * or WhitePixel.
935  *
936  * -      swirl is the swirl data
937  * -      i, j is the point to calculate
938  *
939  * Returns the value of the point
940  */
941 static unsigned long
942 do_point(SWIRL_P swirl, int i, int j)
943 {
944         int         tT, k, value, add;
945         double      dx, dy, theta, dist;
946         int         dcolours, qcolours;
947         double      rads;
948         KNOT_P      knot;
949
950         /* how many colours? */
951         dcolours = swirl->dcolours;
952         qcolours = dcolours / 4;
953
954         /* colour step round a circle */
955         rads = (double) dcolours / (2.0 * M_PI);
956
957         /* start at zero */
958         value = 0;
959
960         /* go through all the knots */
961         knot = swirl->knots;
962         for (k = 0; k < swirl->n_knots; k++) {
963                 dx = i - knot->x;
964                 dy = j - knot->y;
965
966                 /* in two_plane mode get the appropriate knot type */
967                 if (swirl->two_plane)
968                         tT = (int) ((swirl->first_plane) ? knot->t : knot->T);
969                 else
970                         tT = (int) knot->t;
971
972                 /* distance from knot */
973                 dist = sqrt(dx * dx + dy * dy);
974
975                 /* nothing to add at first */
976                 add = 0;
977
978                 /* work out the contribution (if close enough) */
979                 if (dist > 0.1)
980                         switch (tT) {
981                                 case ORBIT:
982                                         add = (int) (dcolours / (1.0 + 0.01 * abs(knot->m) * dist));
983                                         break;
984                                 case WHEEL:
985                                         /* Avoid atan2: DOMAIN error message */
986                                         if (dy == 0.0 && dx == 0.0)
987                                                 theta = 1.0;
988                                         else
989                                                 theta = (atan2(dy, dx) + M_PI) / M_PI;
990                                         if (theta < 1.0)
991                                                 add = (int) (dcolours * theta +
992                                                   sin(0.1 * knot->m * dist) *
993                                                 qcolours * exp(-0.01 * dist));
994                                         else
995                                                 add = (int) (dcolours * (theta - 1.0) +
996                                                   sin(0.1 * knot->m * dist) *
997                                                 qcolours * exp(-0.01 * dist));
998                                         break;
999                                 case PICASSO:
1000                                         add = (int) (dcolours *
1001                                           fabs(cos(0.002 * knot->m * dist)));
1002                                         break;
1003                                 case RAY:
1004                                         /* Avoid atan2: DOMAIN error message */
1005                                         if (dy == 0.0 && dx == 0.0)
1006                                                 add = 0;
1007                                         else
1008                                                 add = (int) (dcolours * fabs(sin(2.0 * atan2(dy, dx))));
1009
1010                                         break;
1011                                 case HOOK:
1012                                         /* Avoid atan2: DOMAIN error message */
1013                                         if (dy == 0.0 && dx == 0.0)
1014                                                 add = (int) (0.05 * (abs(knot->m) - 1) * dist);
1015                                         else
1016                                                 add = (int) (rads * atan2(dy, dx) +
1017                                                              0.05 * (abs(knot->m) - 1) * dist);
1018                                         break;
1019                         }
1020                 /* for a +ve mass add on the contribution else take it off */
1021                 if (knot->m > 0)
1022                         value += add;
1023                 else
1024                         value -= add;
1025
1026                 /* next knot */
1027                 knot++;
1028         }
1029
1030         /* toggle plane */
1031         swirl->first_plane = (!swirl->first_plane);
1032
1033         /* make sure we handle -ve values properly */
1034         if (value >= 0)
1035                 value = (value % dcolours) + 2;
1036         else
1037                 value = dcolours - (abs(value) % (dcolours - 1));
1038
1039 #ifndef STANDALONE
1040         /* if fg and bg are 1 and 0 we should be OK, but just in case */
1041         while ((dcolours > 2) &&
1042                (((value % swirl->colours) == (int) swirl->fg) ||
1043                 ((value % swirl->colours) == (int) swirl->bg) ||
1044                 ((value % swirl->colours) == (int) swirl->white) ||
1045                 ((value % swirl->colours) == (int) swirl->black))) {
1046                 value++;
1047         }
1048 #endif /* !STANDALONE */
1049
1050         /* definitely make sure it is in range */
1051         value = value % swirl->colours;
1052
1053         /* lookup the pixel value if necessary */
1054 #ifndef STANDALONE
1055         if (swirl->fixed_colourmap && swirl->dcolours > 2)
1056 #endif
1057                 value = swirl->rgb_values[value].pixel;
1058
1059         /* return it */
1060         return ((unsigned long) value);
1061 }
1062
1063 /****************************************************************/
1064
1065 /* 
1066  * draw_block
1067  *
1068  * Draw a square block of points with the same value.
1069  *
1070  * -      ximage is the XImage to draw on.
1071  * -      x, y is the top left corner
1072  * -      s is the length of each side
1073  * -      v is the value
1074  */
1075 static void
1076 draw_block(XImage * ximage, int x, int y, int s, unsigned long v)
1077 {
1078         int         a, b;
1079
1080         for (a = 0; a < s; a++)
1081                 for (b = 0; b < s; b++) {
1082                         XPutPixel(ximage, x + b, y + a, v);
1083                 }
1084 }
1085
1086 /****************************************************************/
1087
1088 /* 
1089  * draw_point  Draw the current point in a swirl pattern onto the XImage
1090  *
1091  * -    swirl is the swirl
1092  * -    win is the window to update
1093  */
1094 static void
1095 draw_point(ModeInfo * mi, SWIRL_P swirl)
1096 {
1097         int         r;
1098         int         x, y;
1099
1100         /* get current point coordinates and resolution */
1101         x = swirl->x;
1102         y = swirl->y;
1103         r = swirl->r;
1104
1105         /* check we are within the window */
1106         if ((x < 0) || (x > swirl->width - r) || (y < 0) || (y > swirl->height - r))
1107                 return;
1108
1109         /* what style are we drawing? */
1110         if (swirl->two_plane) {
1111                 int         r2;
1112
1113                 /* halve the block size */
1114                 r2 = r / 2;
1115
1116                 /* interleave blocks at half r */
1117                 draw_block(swirl->ximage, x, y, r2, do_point(swirl, x, y));
1118                 draw_block(swirl->ximage, x + r2, y, r2, do_point(swirl, x + r2, y));
1119                 draw_block(swirl->ximage, x + r2, y + r2, r2, do_point(swirl,
1120                         x + r2, y + r2));
1121                 draw_block(swirl->ximage, x, y + r2, r2, do_point(swirl, x, y + r2));
1122         } else
1123                 draw_block(swirl->ximage, x, y, r, do_point(swirl, x, y));
1124
1125         /* update the screen */
1126
1127 #ifdef HAVE_XSHM_EXTENSION
1128         if (mi->use_shm)
1129           XShmPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->ximage,
1130                                    x, y, x, y, r, r, False);
1131         else
1132 #endif /* !HAVE_XSHM_EXTENSION */
1133           /* PURIFY 4.0.1 on SunOS4 and on Solaris 2 reports a 256 byte memory
1134                  leak on the next line. */
1135           XPutImage(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->ximage,
1136                                 x, y, x, y, r, r);
1137 }
1138
1139 /****************************************************************/
1140
1141 /* 
1142  * next_point  Move to the next point in the spiral pattern
1143  *  -    swirl is the swirl
1144  *  -    win is the window to update
1145  */
1146 static void
1147 next_point(SWIRL_P swirl)
1148 {
1149         /* more to do in this direction? */
1150         if (swirl->dir_done < swirl->dir_todo) {
1151                 /* move in the current direction */
1152                 switch (swirl->direction) {
1153                         case DRAW_RIGHT:
1154                                 swirl->x += swirl->r;
1155                                 break;
1156                         case DRAW_DOWN:
1157                                 swirl->y += swirl->r;
1158                                 break;
1159                         case DRAW_LEFT:
1160                                 swirl->x -= swirl->r;
1161                                 break;
1162                         case DRAW_UP:
1163                                 swirl->y -= swirl->r;
1164                                 break;
1165                 }
1166
1167                 /* done another point */
1168                 swirl->dir_done++;
1169         } else {
1170                 /* none drawn yet */
1171                 swirl->dir_done = 0;
1172
1173                 /* change direction - check and record if off screen */
1174                 switch (swirl->direction) {
1175                         case DRAW_RIGHT:
1176                                 swirl->direction = DRAW_DOWN;
1177                                 if (swirl->x > swirl->width - swirl->r) {
1178                                         /* skip these points */
1179                                         swirl->dir_done = swirl->dir_todo;
1180                                         swirl->y += (swirl->dir_todo * swirl->r);
1181
1182                                         /* check for finish */
1183                                         if (swirl->off_screen)
1184                                                 swirl->drawing = False;
1185                                         swirl->off_screen = True;
1186                                 } else
1187                                         swirl->off_screen = False;
1188                                 break;
1189                         case DRAW_DOWN:
1190                                 swirl->direction = DRAW_LEFT;
1191                                 swirl->dir_todo++;
1192                                 if (swirl->y > swirl->height - swirl->r) {
1193                                         /* skip these points */
1194                                         swirl->dir_done = swirl->dir_todo;
1195                                         swirl->x -= (swirl->dir_todo * swirl->r);
1196
1197                                         /* check for finish */
1198                                         if (swirl->off_screen)
1199                                                 swirl->drawing = False;
1200                                         swirl->off_screen = True;
1201                                 } else
1202                                         swirl->off_screen = False;
1203                                 break;
1204                         case DRAW_LEFT:
1205                                 swirl->direction = DRAW_UP;
1206                                 if (swirl->x < 0) {
1207                                         /* skip these points */
1208                                         swirl->dir_done = swirl->dir_todo;
1209                                         swirl->y -= (swirl->dir_todo * swirl->r);
1210
1211                                         /* check for finish */
1212                                         if (swirl->off_screen)
1213                                                 swirl->drawing = False;
1214                                         swirl->off_screen = True;
1215                                 } else
1216                                         swirl->off_screen = False;
1217                                 break;
1218                         case DRAW_UP:
1219                                 swirl->direction = DRAW_RIGHT;
1220                                 swirl->dir_todo++;
1221                                 if (swirl->y < 0) {
1222                                         /* skip these points */
1223                                         swirl->dir_done = swirl->dir_todo;
1224                                         swirl->x += (swirl->dir_todo * swirl->r);
1225
1226                                         /* check for finish */
1227                                         if (swirl->off_screen)
1228                                                 swirl->drawing = False;
1229                                         swirl->off_screen = True;
1230                                 } else
1231                                         swirl->off_screen = False;
1232                                 break;
1233                 }
1234         }
1235 }
1236
1237 /****************************************************************/
1238
1239 /* 
1240  * init_swirl
1241  *
1242  * Initialise things for swirling
1243  *
1244  * -      win is the window to draw in
1245  */
1246 ENTRYPOINT void
1247 init_swirl(ModeInfo * mi)
1248 {
1249         Display    *display = MI_DISPLAY(mi);
1250         Window      window = MI_WINDOW(mi);
1251         SWIRL_P     swirl;
1252
1253         /* does the swirls array exist? */
1254         if (swirls == NULL) {
1255                 /* allocate an array, one entry for each screen */
1256                 swirls = (SWIRL_P) calloc(MI_NUM_SCREENS(mi), sizeof (SWIRL));
1257         }
1258         /* get a pointer to this swirl */
1259         swirl = &(swirls[MI_SCREEN(mi)]);
1260         initialise_swirl(mi, swirl);
1261                 
1262         /* get window parameters */
1263         swirl->win = window;
1264         swirl->width = MI_WIN_WIDTH(mi);
1265         swirl->height = MI_WIN_HEIGHT(mi);
1266         swirl->depth = MI_WIN_DEPTH(mi);
1267         swirl->rdepth = swirl->depth;
1268         swirl->visual = MI_VISUAL(mi);
1269
1270         if (swirl->depth > 16)
1271                 swirl->depth = 16;
1272
1273         /* initialise image for speeding up drawing */
1274         initialise_image(mi, swirl);
1275
1276         /* clear the window (before setting the colourmap) */
1277         XClearWindow(display, MI_WINDOW(mi));
1278
1279 #ifdef STANDALONE
1280
1281         swirl->rgb_values = mi->colors;
1282         swirl->colours = mi->npixels;
1283         swirl->dcolours = swirl->colours;
1284 /*      swirl->fixed_colourmap = !mi->writable_p;*/
1285
1286 #else /* !STANDALONE */
1287
1288         /* initialise the colours from which the colourmap is derived */
1289         initialise_colours(basic_colours, MI_SATURATION(mi));
1290
1291         /* set up the colour map */
1292         create_colourmap(mi, swirl);
1293
1294         /* attach the colour map to the window (if we have one) */
1295         if (!swirl->fixed_colourmap) {
1296 #if 1
1297                 setColormap(display, window, swirl->cmap, MI_WIN_IS_INWINDOW(mi));
1298 #else
1299                 XSetWindowColormap(display, window, swirl->cmap);
1300                 (void) XSetWMColormapWindows(display, window, &window, 1);
1301                 XInstallColormap(display, swirl->cmap);
1302 #endif
1303         }
1304 #endif /* STANDALONE */
1305
1306         /* resolution starts off chunky */
1307         swirl->resolution = MIN_RES + 1;
1308
1309         /* calculate the pixel step for this resulution */
1310         swirl->r = (1 << (swirl->resolution - 1));
1311
1312         /* how many knots? */
1313         swirl->n_knots = random_no((unsigned int) MI_BATCHCOUNT(mi) / 2) +
1314                 MI_BATCHCOUNT(mi) + 1;
1315
1316         /* what type of knots? */
1317         swirl->knot_type = ALL; /* for now */
1318
1319         /* use two_plane mode occaisionally */
1320         if (random_no(100) <= TWO_PLANE_PCNT) {
1321                 swirl->two_plane = swirl->first_plane = True;
1322                 swirl->max_resolution = 2;
1323         } else
1324                 swirl->two_plane = False;
1325
1326         /* fix the knot values */
1327         create_knots(swirl);
1328
1329         /* we are off */
1330         swirl->started = True;
1331         swirl->drawing = False;
1332 }
1333
1334 /****************************************************************/
1335
1336 /* 
1337  * draw_swirl
1338  *
1339  * Draw one iteration of swirling
1340  *
1341  * -      win is the window to draw in
1342  */
1343 ENTRYPOINT void
1344 draw_swirl(ModeInfo * mi)
1345 {
1346         SWIRL_P     swirl = &(swirls[MI_SCREEN(mi)]);
1347
1348         /* are we going? */
1349         if (swirl->started) {
1350                 /* in the middle of drawing? */
1351                 if (swirl->drawing) {
1352 #ifdef STANDALONE
1353                   if (mi->writable_p)
1354                         rotate_colors(MI_DISPLAY(mi), MI_COLORMAP(mi),
1355                                                   swirl->rgb_values, swirl->colours, 1);
1356 #else  /* !STANDALONE */
1357                         /* rotate the colours */
1358                         install_map(MI_DISPLAY(mi), swirl, swirl->dshift);
1359 #endif /* !STANDALONE */
1360
1361                         /* draw a batch of points */
1362                         swirl->batch_todo = BATCH_DRAW;
1363                         while ((swirl->batch_todo > 0) && swirl->drawing) {
1364                                 /* draw a point */
1365                                 draw_point(mi, swirl);
1366
1367                                 /* move to the next point */
1368                                 next_point(swirl);
1369
1370                                 /* done a point */
1371                                 swirl->batch_todo--;
1372                         }
1373                 } else {
1374 #ifdef STANDALONE
1375                   if (mi->writable_p)
1376                         rotate_colors(MI_DISPLAY(mi), MI_COLORMAP(mi),
1377                                                   swirl->rgb_values, swirl->colours, 1);
1378 #else  /* !STANDALONE */
1379                         /* rotate the colours */
1380                         install_map(MI_DISPLAY(mi), swirl, swirl->shift);
1381 #endif /* !STANDALONE */
1382
1383                         /* time for a higher resolution? */
1384                         if (swirl->resolution > swirl->max_resolution) {
1385                                 /* move to higher resolution */
1386                                 swirl->resolution--;
1387
1388                                 /* calculate the pixel step for this resulution */
1389                                 swirl->r = (1 << (swirl->resolution - 1));
1390
1391                                 /* start drawing again */
1392                                 swirl->drawing = True;
1393
1394                                 /* start in the middle of the screen */
1395                                 swirl->x = (swirl->width - swirl->r) / 2;
1396                                 swirl->y = (swirl->height - swirl->r) / 2;
1397
1398                                 /* initialise spiral drawing parameters */
1399                                 swirl->direction = DRAW_RIGHT;
1400                                 swirl->dir_todo = 1;
1401                                 swirl->dir_done = 0;
1402                         } else {
1403                                 /* all done, decide when to restart */
1404                                 if (swirl->start_again == -1) {
1405                                         /* start the counter */
1406                                         swirl->start_again = RESTART;
1407                                 } else if (swirl->start_again == 0) {
1408                                         /* reset the counter */
1409                                         swirl->start_again = -1;
1410
1411 #ifdef STANDALONE
1412                                         /* Pick a new colormap! */
1413                                         XClearWindow (MI_DISPLAY(mi), MI_WINDOW(mi));
1414                                         free_colors (MI_DISPLAY(mi), MI_COLORMAP(mi),
1415                                                                  mi->colors, mi->npixels);
1416                                         make_smooth_colormap (MI_DISPLAY(mi),
1417                                                                                   MI_VISUAL(mi),
1418                                                                                   MI_COLORMAP(mi),
1419                                                                                   mi->colors, &mi->npixels, True,
1420                                                                                   &mi->writable_p, True);
1421                                         swirl->colours = mi->npixels;
1422 #endif /* STANDALONE */
1423
1424                                         /* start again */
1425                                         init_swirl(mi);
1426                                 } else
1427                                         /* decrement the counter */
1428                                         swirl->start_again--;
1429                         }
1430                 }
1431         }
1432 }
1433
1434 /****************************************************************/
1435
1436 ENTRYPOINT void
1437 release_swirl (ModeInfo * mi)
1438 {
1439         /* does the swirls array exist? */
1440         if (swirls != NULL) {
1441                 int         i;
1442
1443                 /* free them all */
1444                 for (i = 0; i < MI_NUM_SCREENS(mi); i++) {
1445                         SWIRL_P     swirl = &(swirls[i]);
1446
1447 #ifndef STANDALONE
1448                         if (swirl->cmap != (Colormap) NULL)
1449                                 XFreeColormap(MI_DISPLAY(mi), swirl->cmap);
1450 #endif /* STANDALONE */
1451 #ifndef STANDALONE
1452                         if (swirl->rgb_values != NULL)
1453                                 XFree((void *) swirl->rgb_values);
1454 #endif /* !STANDALONE */
1455                         if (swirl->ximage != NULL)
1456                                 XDestroyImage(swirl->ximage);
1457                         if (swirl->knots)
1458                                 (void) free((void *) swirl->knots);
1459                 }
1460                 /* deallocate an array, one entry for each screen */
1461                 (void) free((void *) swirls);
1462                 swirls = NULL;
1463         }
1464 }
1465
1466 /****************************************************************/
1467
1468 ENTRYPOINT void
1469 refresh_swirl (ModeInfo * mi)
1470 {
1471         SWIRL_P     swirl = &(swirls[MI_SCREEN(mi)]);
1472
1473         if (swirl->started) {
1474                 if (swirl->drawing)
1475                         swirl->resolution = swirl->resolution + 1;
1476                 swirl->drawing = False;
1477         }
1478 }
1479
1480 XSCREENSAVER_MODULE ("Swirl", swirl)