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