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