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