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