1 /* -*- Mode: C; tab-width: 4 -*-
2 * swirl --- swirly color-cycling patterns.
5 static const char sccsid[] = "@(#)swirl.c 4.00 97/01/01 xlockmore";
8 /* Copyright (c) 1994 M.Dobie <mrd@ecs.soton.ac.uk>
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.
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.
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
34 # define DEFAULTS "*count: 5 \n" \
38 "*fpsSolid: true \n" \
39 "*ignoreRotation: True \n" \
41 # define SMOOTH_COLORS
42 # define WRITABLE_COLORS
43 # define release_swirl 0
44 # include "xlockmore.h" /* from the xscreensaver distribution */
46 #else /* !STANDALONE */
47 # include "xlock.h" /* from the xlockmore distribution */
48 # undef HAVE_XSHM_EXTENSION
49 #endif /* !STANDALONE */
51 ENTRYPOINT ModeSpecOpt swirl_opts = {
52 0, NULL, 0, NULL, NULL };
56 /****************************************************************/
58 #define MASS 4 /* maximum mass of a knot */
59 #define MIN_RES 5 /* minimim resolution (>= MIN_RES) */
60 #define MAX_RES 1 /* maximum resolution (>0) */
61 #define TWO_PLANE_PCNT 30 /* probability for two plane mode (0-100) */
62 #define RESTART 2500 /* number of cycles before restart */
63 #define BATCH_DRAW 100 /* points to draw per iteration */
78 int x, y; /* position */
80 KNOT_T t; /* type in the first (or only) plane */
81 KNOT_T T; /* type in second plane if there is one */
82 int M; /* mass in second plane if there is one */
85 /* a colour specification */
86 typedef struct Colour {
87 unsigned short r, g, b;
90 /* drawing direction */
92 DRAW_RIGHT, DRAW_DOWN, DRAW_LEFT, DRAW_UP
95 /****************************************************************/
97 /* data associated with a swirl window */
98 typedef struct swirl_data {
99 /* window paramaters */
100 Window win; /* the window */
101 int width, height; /* window size */
102 int depth; /* depth */
103 int rdepth; /* real depth (for XImage) */
104 Visual *visual; /* visual */
106 /* swirl drawing parameters */
107 int n_knots; /* number of knots */
108 KNOT_P knots; /* knot details */
109 KNOT_T knot_type; /* general type of knots */
110 int resolution; /* drawing resolution, 1..5 */
111 int max_resolution; /* maximum resolution, MAX_RES */
112 int r; /* pixel step */
113 Bool two_plane; /* two plane mode? */
114 Bool first_plane; /* doing first plane? */
115 int start_again; /* when to restart */
117 /* spiral drawing parameters */
118 int x, y; /* current point */
119 DIR_T direction; /* current direction */
120 int dir_todo, dir_done; /* how many points in current direction? */
121 int batch_todo, batch_done; /* how many points in this batch */
122 Bool started, drawing; /* are we drawing? */
125 unsigned char *image; /* image data */
127 XShmSegmentInfo shm_info;
130 int colours; /* how many colours possible */
131 int dcolours; /* how many colours for shading */
133 Bool fixed_colourmap; /* fixed colourmap? */
134 #endif /* !STANDALONE */
135 Bool monochrome; /* monochrome? */
136 Colormap cmap; /* colour map for the window */
137 XColor *rgb_values; /* colour definitions array */
139 int current_map; /* current colour map, 0..dcolours-1 */
140 unsigned long fg, bg, white, black; /* black and white pixel values */
141 int shift; /* colourmap shift */
142 int dshift; /* colourmap shift while drawing */
143 XColor fgcol, bgcol; /* foreground and background colour specs */
144 #endif /* !STANDALONE */
148 #define SWIRLCOLOURS 13
152 static COLOUR basic_colours[SWIRLCOLOURS];
153 #endif /* !STANDALONE */
155 /* an array of swirls for each screen */
156 static SWIRL_P swirls = NULL;
161 Return a random integer between 0 and n inclusive
163 - n is the maximum number
165 Returns a random integer */
168 random_no(unsigned int n)
170 return ((int) ((n + 1) * (double) LRAND() / MAXRAND));
173 /****************************************************************/
178 Initialise all the swirl data
180 - swirl is the swirl data */
183 initialise_swirl(ModeInfo * mi, SWIRL_P swirl)
186 Display *display = MI_DISPLAY(mi);
187 #endif /* !STANDALONE */
189 swirl->width = 0; /* width and height of window */
193 swirl->visual = NULL;
194 swirl->resolution = MIN_RES + 1; /* current resolution */
195 swirl->max_resolution = MAX_RES; /* maximum resolution */
196 swirl->n_knots = 0; /* number of knots */
197 swirl->knot_type = ALL; /* general type of knots */
198 swirl->two_plane = False; /* two plane mode? */
199 swirl->first_plane = False; /* doing first plane? */
200 swirl->start_again = -1; /* restart counter */
202 /* drawing parameters */
205 swirl->started = False;
206 swirl->drawing = False;
209 swirl->image = NULL; /* image data */
210 swirl->ximage = NULL;
213 swirl->colours = 0; /* how many colours possible */
214 swirl->dcolours = 0; /* how many colours for shading */
215 swirl->cmap = (Colormap) NULL;
216 swirl->rgb_values = NULL; /* colour definitions array */
218 swirl->current_map = 0; /* current colour map, 0..dcolours-1 */
220 /* set up fg fb colour specs */
221 swirl->white = MI_WIN_WHITE_PIXEL(mi);
222 swirl->black = MI_WIN_BLACK_PIXEL(mi);
223 #endif /* !STANDALONE */
227 swirl->fg = MI_FG_COLOR(mi);
228 swirl->bg = MI_BG_COLOR(mi);
229 swirl->fgcol.pixel = swirl->fg;
230 swirl->bgcol.pixel = swirl->bg;
231 XQueryColor(display, MI_COLORMAP(mi), &(swirl->fgcol));
232 XQueryColor(display, MI_COLORMAP(mi), &(swirl->bgcol));
233 #endif /* !STANDALONE */
236 /****************************************************************/
241 * Initialise the image for drawing to
243 * - swirl is the swirl data
246 initialise_image(ModeInfo * mi, SWIRL_P swirl)
248 Display *dpy = MI_DISPLAY(mi);
250 if (swirl->ximage != NULL)
251 destroy_xshm_image(dpy, swirl->ximage, &swirl->shm_info);
253 swirl->ximage = create_xshm_image(dpy, swirl->visual, swirl->rdepth,
254 ZPixmap, &swirl->shm_info,
255 swirl->width, swirl->height);
258 /****************************************************************/
264 * Initialise the list of colours from which the colourmaps are derived
266 * - colours is the array to initialise
267 * - saturation is the saturation value to use 0->grey,
268 * 1.0->full saturation
271 initialise_colours(COLOUR * colours, float saturate)
275 /* start off fully saturated, medium and bright colours */
276 colours[0].r = 0xA000;
277 colours[0].g = 0x0000;
278 colours[0].b = 0x0000;
279 colours[1].r = 0xD000;
280 colours[1].g = 0x0000;
281 colours[1].b = 0x0000;
282 colours[2].r = 0x0000;
283 colours[2].g = 0x6000;
284 colours[2].b = 0x0000;
285 colours[3].r = 0x0000;
286 colours[3].g = 0x9000;
287 colours[3].b = 0x0000;
288 colours[4].r = 0x0000;
289 colours[4].g = 0x0000;
290 colours[4].b = 0xC000;
291 colours[5].r = 0x0000;
292 colours[5].g = 0x0000;
293 colours[5].b = 0xF000;
294 colours[6].r = 0xA000;
295 colours[6].g = 0x6000;
296 colours[6].b = 0x0000;
297 colours[7].r = 0xD000;
298 colours[7].g = 0x9000;
299 colours[7].b = 0x0000;
300 colours[8].r = 0xA000;
301 colours[8].g = 0x0000;
302 colours[8].b = 0xC000;
303 colours[9].r = 0xD000;
304 colours[9].g = 0x0000;
305 colours[9].b = 0xF000;
306 colours[10].r = 0x0000;
307 colours[10].g = 0x6000;
308 colours[10].b = 0xC000;
309 colours[11].r = 0x0000;
310 colours[11].g = 0x9000;
311 colours[11].b = 0xF000;
312 colours[12].r = 0xA000;
313 colours[12].g = 0xA000;
314 colours[12].b = 0xA000;
316 /* add white for low saturation */
317 for (i = 0; i < SWIRLCOLOURS - 1; i++) {
318 unsigned short max_rg, max;
320 /* what is the max intensity for this colour? */
321 max_rg = (colours[i].r > colours[i].g) ? colours[i].r : colours[i].g;
322 max = (max_rg > colours[i].b) ? max_rg : colours[i].b;
324 /* bring elements up to max as saturation approaches 0.0 */
325 colours[i].r += (unsigned short) ((float) (1.0 - saturate) *
326 ((float) max - colours[i].r));
327 colours[i].g += (unsigned short) ((float) (1.0 - saturate) *
328 ((float) max - colours[i].g));
329 colours[i].b += (unsigned short) ((float) (1.0 - saturate) *
330 ((float) max - colours[i].b));
333 #endif /* !STANDALONE */
335 /****************************************************************/
339 * set_black_and_white
341 * Set the entries for foreground & background pixels and
342 * WhitePixel & BlackPixel in an array of colour specifications.
344 * - swirl is the swirl data
345 * - values is the array of specifications
348 set_black_and_white(SWIRL_P swirl, XColor * values)
350 unsigned long white, black;
352 /* where is black and white? */
353 white = swirl->white;
354 black = swirl->black;
356 /* set black and white up */
357 values[white].flags = DoRed | DoGreen | DoBlue;
358 values[white].pixel = white;
359 values[white].red = 0xFFFF;
360 values[white].green = 0xFFFF;
361 values[white].blue = 0xFFFF;
362 values[black].flags = DoRed | DoGreen | DoBlue;
363 values[black].pixel = black;
364 values[black].red = 0;
365 values[black].green = 0;
366 values[black].blue = 0;
368 /* copy the colour specs from the original entries */
369 values[swirl->fg] = swirl->fgcol;
370 values[swirl->bg] = swirl->bgcol;
373 /****************************************************************/
378 * Set an entry in an array of XColor specifications. The given entry will be
379 * set to the given colour. If the entry corresponds to the foreground,
380 * background, WhitePixel, or BlackPixel it is ignored and the given colour
381 * is is put in the next entry.
383 * Therefore, the given colour may be placed up to four places after the
384 * specified entry in the array, if foreground, background, white, or black
387 * - swirl is the swirl data
388 * - value points to a pointer to the array entry. It gets updated to
389 * point to the next free entry.
390 * - pixel points to the current pixel number. It gets updated.
391 * - c points to the colour to add
394 set_colour(SWIRL_P swirl, XColor ** value, unsigned long *pixel, COLOUR_P c)
397 unsigned long fg, bg, white, black;
399 /* where are foreground, background, white, and black? */
402 white = swirl->white;
403 black = swirl->black;
405 /* haven't set it yet */
408 /* try and set the colour */
410 (**value).flags = DoRed | DoGreen | DoBlue;
411 (**value).pixel = *pixel;
413 /* white, black, fg, bg, or a colour? */
414 if ((*pixel != fg) && (*pixel != bg) &&
415 (*pixel != white) && (*pixel != black)) {
416 (**value).red = c->r;
417 (**value).green = c->g;
418 (**value).blue = c->b;
420 /* now we've done it */
429 /****************************************************************/
434 * Get an entry from an array of XColor specifications. The next colour from
435 * the array will be returned. Foreground, background, WhitePixel, or
436 * BlackPixel will be ignored.
438 * - swirl is the swirl data
439 * - value points the array entry. It is updated to point to the entry
440 * following the one returned.
441 * - c is set to the colour found
444 get_colour(SWIRL_P swirl, XColor ** value, COLOUR_P c)
447 unsigned long fg, bg, white, black;
449 /* where is white and black? */
452 white = swirl->white;
453 black = swirl->black;
455 /* haven't set it yet */
458 /* try and set the colour */
460 /* black, white or a colour? */
461 if (((*value)->pixel != fg) && ((*value)->pixel != bg) &&
462 ((*value)->pixel != white) && ((*value)->pixel != black)) {
463 c->r = (*value)->red;
464 c->g = (*value)->green;
465 c->b = (*value)->blue;
467 /* now we've done it */
474 #endif /* !STANDALONE */
476 /****************************************************************/
482 * Generate n colours between c1 and c2. n XColors at *value are set up with
483 * ascending pixel values.
485 * If the pixel range includes BlackPixel or WhitePixel they are set to black
486 * and white respectively but otherwise ignored. Therefore, up to n+2 colours
487 * may actually be set by this function.
489 * - swirl is the swirl data
490 * - values points a pointer to an array of XColors to update
491 * - pixel points to the pixel number to start at
492 * - k n is the number of colours to generate
493 * - c1, c2 are the colours to interpolate between
496 interpolate(SWIRL_P swirl, XColor ** values, unsigned long *pixel, int n, COLOUR_P c1, COLOUR_P c2)
505 for (i = 0; i < n / 2 && (int) *pixel < swirl->colours; i++) {
506 /* work out the colour */
507 r = c1->r + 2 * i * ((int) c2->r) / n;
508 c.r = (r > (int) maxv) ? maxv : r;
509 g = c1->g + 2 * i * ((int) c2->g) / n;
510 c.g = (g > (int) maxv) ? maxv : g;
511 b = c1->b + 2 * i * ((int) c2->b) / n;
512 c.b = (b > (int) maxv) ? maxv : b;
515 set_colour(swirl, values, pixel, &c);
517 for (i = n / 2; i >= 0 && (int) *pixel < swirl->colours; i--) {
518 r = c2->r + 2 * i * ((int) c1->r) / n;
519 c.r = (r > (int) maxv) ? maxv : r;
520 g = c2->g + 2 * i * ((int) c1->g) / n;
521 c.g = (g > (int) maxv) ? maxv : g;
522 b = c2->b + 2 * i * ((int) c1->b) / n;
523 c.b = (b > (int) maxv) ? maxv : b;
526 set_colour(swirl, values, pixel, &c);
530 /****************************************************************/
535 * Generate a `random' closed loop colourmap that occupies the whole colour
538 * - swirl is the swirl data
539 * - values is the array of colour definitions to set up
542 basic_map(SWIRL_P swirl, XColor * values)
546 unsigned short r1, g1, b1, r2, g2, b2, r3, g3, b3;
551 /* start at the beginning of the colour map */
555 /* choose 3 different basic colours at random */
556 for (i = 0; i < 3;) {
560 /* choose colour i */
561 c[i] = basic_colours[random_no(SWIRLCOLOURS - 1)];
563 /* assume different */
566 /* different from the rest? */
567 for (j = 0; j < i; j++)
568 if ((c[i].r == c[j].r) &&
569 (c[i].g == c[j].g) &&
573 /* ready for the next colour? */
578 /* extract components into variables */
589 /* work out the lengths of each side of the triangle */
590 L1 = (int) sqrt((((double) r1 - r2) * ((double) r1 - r2) +
591 ((double) g1 - g2) * ((double) g1 - g2) +
592 ((double) b1 - b2) * ((double) b1 - b2)));
594 L2 = (int) sqrt((((double) r3 - r2) * ((double) r3 - r2) +
595 ((double) g3 - g2) * ((double) g3 - g2) +
596 ((double) b3 - b2) * ((double) b3 - b2)));
598 L3 = (int) sqrt((((double) r1 - r3) * ((double) r1 - r3) +
599 ((double) g1 - g3) * ((double) g1 - g3) +
600 ((double) b1 - b3) * ((double) b1 - b3)));
604 /* allocate colours in proportion to the lengths of the sides */
605 interpolate(swirl, &value, &pixel,
606 (int) ((double) swirl->dcolours * ((double) L1 / (double) L)) + 1, c, c + 1);
607 interpolate(swirl, &value, &pixel,
608 (int) ((double) swirl->dcolours * ((double) L2 / (double) L)) + 1, c + 1, c + 2);
609 interpolate(swirl, &value, &pixel,
610 (int) ((double) swirl->dcolours * ((double) L3 / (double) L)) + 1, c + 2, c);
612 /* fill up any remaining slots (due to rounding) */
613 while ((int) pixel < swirl->colours) {
614 /* repeat the last colour */
615 set_colour(swirl, &value, &pixel, c);
618 /* ensure black and white are correct */
619 if (!swirl->fixed_colourmap)
620 set_black_and_white(swirl, values);
623 /****************************************************************/
628 * Generate pre-rotated versions of the colour specifications
630 * - swirl is the swirl data
631 * - values is an array of colour specifications
634 pre_rotate(SWIRL_P swirl, XColor * values)
641 /* how many colours to display? */
642 dcolours = swirl->dcolours;
644 /* start at the first map */
646 dest = values + swirl->colours;
648 /* generate dcolours-1 rotated maps */
649 for (i = 0; i < dcolours - 1; i++) {
652 /* start at the first pixel */
655 /* remember the first one and skip it */
656 get_colour(swirl, &src, &first);
658 /* put a rotated version of src at dest */
659 for (j = 0; j < dcolours - 1; j++) {
662 /* get the source colour */
663 get_colour(swirl, &src, &c);
666 set_colour(swirl, &dest, &pixel, &c);
669 /* put the first one at the end */
670 set_colour(swirl, &dest, &pixel, &first);
672 /* NB: src and dest should now be ready for the next table */
674 /* ensure black and white are properly set */
675 set_black_and_white(swirl, src);
679 /****************************************************************/
684 * Create a read/write colourmap to use
686 * - swirl is the swirl data
690 create_colourmap(ModeInfo * mi, SWIRL_P swirl)
692 Display *display = MI_DISPLAY(mi);
697 unsigned long redmask, greenmask, bluemask;
699 swirl->fixed_colourmap = !setupColormap(mi, &(swirl->colours),
700 &truecolor, &redmask, &greenmask, &bluemask);
701 preserve = preserveColors(swirl->fg, swirl->bg, swirl->white, swirl->black);
703 /* how many colours should we animate? */
704 swirl->dcolours = (swirl->colours > preserve + 1) ?
705 swirl->colours - preserve : swirl->colours;
707 if (MI_NPIXELS(mi) < 2)
710 /* how fast to shift the colourmap? */
711 swirl->shift = (swirl->colours > 64) ? swirl->colours / 64 : 1;
712 swirl->dshift = (swirl->shift > 1) ? swirl->shift * 2 : 1;
714 /* how may colour map rotations are there? */
715 n_rotations = (swirl->fixed_colourmap) ? 1 : swirl->dcolours;
717 /* allocate space for colour definitions (if not already there) */
718 if (swirl->rgb_values == NULL) {
719 swirl->rgb_values = (XColor *) calloc((swirl->colours + 3) * n_rotations,
722 /* create a colour map */
723 if (!swirl->fixed_colourmap)
725 XCreateColormap(display, swirl->win, swirl->visual, AllocAll);
727 /* select a set of colours for the colour map */
728 basic_map(swirl, swirl->rgb_values);
730 /* are we rotating them? */
731 if (!swirl->fixed_colourmap) {
732 /* generate rotations of the colour maps */
733 pre_rotate(swirl, swirl->rgb_values);
735 /* store the colours in the colour map */
736 XStoreColors(display, swirl->cmap, swirl->rgb_values, swirl->colours);
743 for (i = 0; (int) t > 0; i++, t >>= 1);
746 for (i = 0; (int) t > 0; i++, t >>= 1);
749 for (i = 0; (int) t > 0; i++, t >>= 1);
751 for (i = 0; i < swirl->colours; i++)
752 swirl->rgb_values[i].pixel =
753 ((rsh > 0 ? (swirl->rgb_values[i].red) >> rsh :
754 (swirl->rgb_values[i].red) << (-rsh)) & redmask) |
755 ((gsh > 0 ? (swirl->rgb_values[i].green) >> gsh :
756 (swirl->rgb_values[i].green) << (-gsh)) & greenmask) |
757 ((bsh > 0 ? (swirl->rgb_values[i].blue) >> bsh :
758 (swirl->rgb_values[i].blue) << (-bsh)) & bluemask);
760 /* lookup the colours in the fixed colour map */
761 for (i = 0; i < swirl->colours; i++)
762 (void) XAllocColor(display, MI_COLORMAP(mi),
763 &(swirl->rgb_values[i]));
768 /****************************************************************/
773 * Install a new set of colours into the colour map
775 * - dpy is the display
776 * - swirl is the swirl data
777 * - shift is the amount to rotate the colour map by
780 install_map(Display * dpy, SWIRL_P swirl, int shift)
782 if (!swirl->fixed_colourmap) {
783 /* shift the colour map */
784 swirl->current_map = (swirl->current_map + shift) %
788 XStoreColors(dpy, swirl->cmap,
790 swirl->current_map * swirl->colours,
794 #endif /* !STANDALONE */
796 /****************************************************************/
801 * Initialise the array of knot
803 * swirl is the swirl data
806 create_knots(SWIRL_P swirl)
809 Bool orbit, wheel, picasso, ray, hook;
812 /* create array for knots */
814 (void) free((void *) swirl->knots);
815 swirl->knots = (KNOT_P) calloc(swirl->n_knots, sizeof (KNOT));
818 orbit = wheel = picasso = ray = hook = False;
820 /* what types do we have? */
821 if ((int) swirl->knot_type & (int) ALL) {
822 orbit = wheel = ray = hook = True;
824 if ((int) swirl->knot_type & (int) ORBIT)
826 if ((int) swirl->knot_type & (int) WHEEL)
828 if ((int) swirl->knot_type & (int) PICASSO)
830 if ((int) swirl->knot_type & (int) RAY)
832 if ((int) swirl->knot_type & (int) HOOK)
836 /* initialise each knot */
838 for (k = 0; k < swirl->n_knots; k++) {
840 knot->x = random_no((unsigned int) swirl->width);
841 knot->y = random_no((unsigned int) swirl->height);
844 knot->m = random_no(MASS) + 1;
846 /* can be negative */
847 if (random_no(100) > 50)
852 while (knot->t == NONE) {
853 /* choose a random one from the types available */
854 switch (random_no(4)) {
878 /* if two planes, do same for second plane */
879 if (swirl->two_plane) {
881 while (knot->T == NONE || knot->T == knot->t) {
882 /* choose a different type */
883 switch (random_no(4)) {
912 /****************************************************************/
917 * Work out the pixel value at i, j. Ensure it does not clash with BlackPixel
920 * - swirl is the swirl data
921 * - i, j is the point to calculate
923 * Returns the value of the point
926 do_point(SWIRL_P swirl, int i, int j)
928 int tT, k, value, add;
929 double dx, dy, theta, dist;
930 int dcolours, qcolours;
934 /* how many colours? */
935 dcolours = swirl->dcolours;
936 qcolours = dcolours / 4;
938 /* colour step round a circle */
939 rads = (double) dcolours / (2.0 * M_PI);
944 /* go through all the knots */
946 for (k = 0; k < swirl->n_knots; k++) {
950 /* in two_plane mode get the appropriate knot type */
951 if (swirl->two_plane)
952 tT = (int) ((swirl->first_plane) ? knot->t : knot->T);
956 /* distance from knot */
957 dist = sqrt(dx * dx + dy * dy);
959 /* nothing to add at first */
962 /* work out the contribution (if close enough) */
966 add = (int) (dcolours / (1.0 + 0.01 * abs(knot->m) * dist));
969 /* Avoid atan2: DOMAIN error message */
970 if (dy == 0.0 && dx == 0.0)
973 theta = (atan2(dy, dx) + M_PI) / M_PI;
975 add = (int) (dcolours * theta +
976 sin(0.1 * knot->m * dist) *
977 qcolours * exp(-0.01 * dist));
979 add = (int) (dcolours * (theta - 1.0) +
980 sin(0.1 * knot->m * dist) *
981 qcolours * exp(-0.01 * dist));
984 add = (int) (dcolours *
985 fabs(cos(0.002 * knot->m * dist)));
988 /* Avoid atan2: DOMAIN error message */
989 if (dy == 0.0 && dx == 0.0)
992 add = (int) (dcolours * fabs(sin(2.0 * atan2(dy, dx))));
996 /* Avoid atan2: DOMAIN error message */
997 if (dy == 0.0 && dx == 0.0)
998 add = (int) (0.05 * (abs(knot->m) - 1) * dist);
1000 add = (int) (rads * atan2(dy, dx) +
1001 0.05 * (abs(knot->m) - 1) * dist);
1004 /* for a +ve mass add on the contribution else take it off */
1015 swirl->first_plane = (!swirl->first_plane);
1017 /* make sure we handle -ve values properly */
1019 value = (value % dcolours) + 2;
1021 value = dcolours - (abs(value) % (dcolours - 1));
1024 /* if fg and bg are 1 and 0 we should be OK, but just in case */
1025 while ((dcolours > 2) &&
1026 (((value % swirl->colours) == (int) swirl->fg) ||
1027 ((value % swirl->colours) == (int) swirl->bg) ||
1028 ((value % swirl->colours) == (int) swirl->white) ||
1029 ((value % swirl->colours) == (int) swirl->black))) {
1032 #endif /* !STANDALONE */
1034 /* definitely make sure it is in range */
1035 value = value % swirl->colours;
1037 /* lookup the pixel value if necessary */
1039 if (swirl->fixed_colourmap && swirl->dcolours > 2)
1041 value = swirl->rgb_values[value].pixel;
1044 return ((unsigned long) value);
1047 /****************************************************************/
1052 * Draw a square block of points with the same value.
1054 * - ximage is the XImage to draw on.
1055 * - x, y is the top left corner
1056 * - s is the length of each side
1060 draw_block(XImage * ximage, int x, int y, int s, unsigned long v)
1064 for (a = 0; a < s; a++)
1065 for (b = 0; b < s; b++) {
1066 XPutPixel(ximage, x + b, y + a, v);
1070 /****************************************************************/
1073 * draw_point Draw the current point in a swirl pattern onto the XImage
1075 * - swirl is the swirl
1076 * - win is the window to update
1079 draw_point(ModeInfo * mi, SWIRL_P swirl)
1084 /* get current point coordinates and resolution */
1089 /* check we are within the window */
1090 if ((x < 0) || (x > swirl->width - r) || (y < 0) || (y > swirl->height - r))
1093 /* what style are we drawing? */
1094 if (swirl->two_plane) {
1097 /* halve the block size */
1100 /* interleave blocks at half r */
1101 draw_block(swirl->ximage, x, y, r2, do_point(swirl, x, y));
1102 draw_block(swirl->ximage, x + r2, y, r2, do_point(swirl, x + r2, y));
1103 draw_block(swirl->ximage, x + r2, y + r2, r2, do_point(swirl,
1105 draw_block(swirl->ximage, x, y + r2, r2, do_point(swirl, x, y + r2));
1107 draw_block(swirl->ximage, x, y, r, do_point(swirl, x, y));
1109 /* update the screen */
1111 put_xshm_image(MI_DISPLAY(mi), MI_WINDOW(mi), MI_GC(mi), swirl->ximage,
1112 x, y, x, y, r, r, &swirl->shm_info);
1115 /****************************************************************/
1118 * next_point Move to the next point in the spiral pattern
1119 * - swirl is the swirl
1120 * - win is the window to update
1123 next_point(SWIRL_P swirl)
1125 /* more to do in this direction? */
1126 if (swirl->dir_done < swirl->dir_todo) {
1127 /* move in the current direction */
1128 switch (swirl->direction) {
1130 swirl->x += swirl->r;
1133 swirl->y += swirl->r;
1136 swirl->x -= swirl->r;
1139 swirl->y -= swirl->r;
1143 /* done another point */
1146 /* none drawn yet */
1147 swirl->dir_done = 0;
1149 /* change direction - check and record if off screen */
1150 switch (swirl->direction) {
1152 swirl->direction = DRAW_DOWN;
1153 if (swirl->x > swirl->width - swirl->r) {
1154 /* skip these points */
1155 swirl->dir_done = swirl->dir_todo;
1156 swirl->y += (swirl->dir_todo * swirl->r);
1158 /* check for finish */
1159 if (swirl->off_screen)
1160 swirl->drawing = False;
1161 swirl->off_screen = True;
1163 swirl->off_screen = False;
1166 swirl->direction = DRAW_LEFT;
1168 if (swirl->y > swirl->height - swirl->r) {
1169 /* skip these points */
1170 swirl->dir_done = swirl->dir_todo;
1171 swirl->x -= (swirl->dir_todo * swirl->r);
1173 /* check for finish */
1174 if (swirl->off_screen)
1175 swirl->drawing = False;
1176 swirl->off_screen = True;
1178 swirl->off_screen = False;
1181 swirl->direction = DRAW_UP;
1183 /* skip these points */
1184 swirl->dir_done = swirl->dir_todo;
1185 swirl->y -= (swirl->dir_todo * swirl->r);
1187 /* check for finish */
1188 if (swirl->off_screen)
1189 swirl->drawing = False;
1190 swirl->off_screen = True;
1192 swirl->off_screen = False;
1195 swirl->direction = DRAW_RIGHT;
1198 /* skip these points */
1199 swirl->dir_done = swirl->dir_todo;
1200 swirl->x += (swirl->dir_todo * swirl->r);
1202 /* check for finish */
1203 if (swirl->off_screen)
1204 swirl->drawing = False;
1205 swirl->off_screen = True;
1207 swirl->off_screen = False;
1213 /****************************************************************/
1215 static void free_swirl (ModeInfo * mi);
1220 * Initialise things for swirling
1222 * - win is the window to draw in
1225 init_swirl(ModeInfo * mi)
1227 Display *display = MI_DISPLAY(mi);
1228 Window window = MI_WINDOW(mi);
1231 MI_INIT (mi, swirls, free_swirl);
1232 swirl = &(swirls[MI_SCREEN(mi)]);
1233 initialise_swirl(mi, swirl);
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);
1243 if (swirl->depth > 16)
1246 /* initialise image for speeding up drawing */
1247 initialise_image(mi, swirl);
1249 /* clear the window (before setting the colourmap) */
1250 XClearWindow(display, MI_WINDOW(mi));
1254 swirl->rgb_values = mi->colors;
1255 swirl->colours = mi->npixels;
1256 swirl->dcolours = swirl->colours;
1257 /* swirl->fixed_colourmap = !mi->writable_p;*/
1259 #else /* !STANDALONE */
1261 /* initialise the colours from which the colourmap is derived */
1262 initialise_colours(basic_colours, MI_SATURATION(mi));
1264 /* set up the colour map */
1265 create_colourmap(mi, swirl);
1267 /* attach the colour map to the window (if we have one) */
1268 if (!swirl->fixed_colourmap) {
1270 setColormap(display, window, swirl->cmap, MI_WIN_IS_INWINDOW(mi));
1272 XSetWindowColormap(display, window, swirl->cmap);
1273 (void) XSetWMColormapWindows(display, window, &window, 1);
1274 XInstallColormap(display, swirl->cmap);
1277 #endif /* STANDALONE */
1279 /* resolution starts off chunky */
1280 swirl->resolution = MIN_RES + 1;
1282 /* calculate the pixel step for this resulution */
1283 swirl->r = (1 << (swirl->resolution - 1));
1285 /* how many knots? */
1286 swirl->n_knots = random_no((unsigned int) MI_BATCHCOUNT(mi) / 2) +
1287 MI_BATCHCOUNT(mi) + 1;
1289 /* what type of knots? */
1290 swirl->knot_type = ALL; /* for now */
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;
1297 swirl->two_plane = False;
1299 /* fix the knot values */
1300 create_knots(swirl);
1303 swirl->started = True;
1304 swirl->drawing = False;
1307 /****************************************************************/
1312 * Draw one iteration of swirling
1314 * - win is the window to draw in
1317 draw_swirl(ModeInfo * mi)
1319 SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]);
1322 if (swirl->started) {
1323 /* in the middle of drawing? */
1324 if (swirl->drawing) {
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 */
1334 /* draw a batch of points */
1335 swirl->batch_todo = BATCH_DRAW;
1336 while ((swirl->batch_todo > 0) && swirl->drawing) {
1338 draw_point(mi, swirl);
1340 /* move to the next point */
1344 swirl->batch_todo--;
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 */
1356 /* time for a higher resolution? */
1357 if (swirl->resolution > swirl->max_resolution) {
1358 /* move to higher resolution */
1359 swirl->resolution--;
1361 /* calculate the pixel step for this resulution */
1362 swirl->r = (1 << (swirl->resolution - 1));
1364 /* start drawing again */
1365 swirl->drawing = True;
1367 /* start in the middle of the screen */
1368 swirl->x = (swirl->width - swirl->r) / 2;
1369 swirl->y = (swirl->height - swirl->r) / 2;
1371 /* initialise spiral drawing parameters */
1372 swirl->direction = DRAW_RIGHT;
1373 swirl->dir_todo = 1;
1374 swirl->dir_done = 0;
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;
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),
1391 mi->colors, &mi->npixels, True,
1392 &mi->writable_p, True);
1393 swirl->colours = mi->npixels;
1394 #endif /* STANDALONE */
1399 /* decrement the counter */
1400 swirl->start_again--;
1407 reshape_swirl(ModeInfo * mi, int width, int height)
1409 XClearWindow (MI_DISPLAY (mi), MI_WINDOW(mi));
1413 /****************************************************************/
1416 free_swirl (ModeInfo * mi)
1418 SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]);
1421 if (swirl->cmap != (Colormap) NULL)
1422 XFreeColormap(MI_DISPLAY(mi), swirl->cmap);
1423 #endif /* STANDALONE */
1425 if (swirl->rgb_values != NULL)
1426 XFree((void *) swirl->rgb_values);
1427 #endif /* !STANDALONE */
1428 if (swirl->ximage != NULL)
1429 destroy_xshm_image(MI_DISPLAY(mi), swirl->ximage,
1432 (void) free((void *) swirl->knots);
1435 /****************************************************************/
1438 refresh_swirl (ModeInfo * mi)
1440 SWIRL_P swirl = &(swirls[MI_SCREEN(mi)]);
1442 if (swirl->started) {
1444 swirl->resolution = swirl->resolution + 1;
1445 swirl->drawing = False;
1450 swirl_handle_event (ModeInfo *mi, XEvent *event)
1452 if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
1454 reshape_swirl (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1460 XSCREENSAVER_MODULE ("Swirl", swirl)