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