1 /* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* This file contains some utility routines for randomly picking the colors
13 to hack the screen with.
22 extern char *progname;
25 free_colors(Display *dpy, Colormap cmap, XColor *colors, int ncolors)
30 unsigned long *pixels = (unsigned long *)
31 malloc(sizeof(*pixels) * ncolors);
32 for (i = 0; i < ncolors; i++)
33 pixels[i] = colors[i].pixel;
34 XFreeColors (dpy, cmap, pixels, ncolors, 0L);
41 allocate_writable_colors (Display *dpy, Colormap cmap,
42 unsigned long *pixels, int *ncolorsP)
44 int desired = *ncolorsP;
46 int requested = desired;
47 unsigned long *new_pixels = pixels;
53 if (desired - got < requested)
54 requested = desired - got;
56 if (XAllocColorCells (dpy, cmap, False, 0, 0, new_pixels, requested))
58 /* Got all the pixels we asked for. */
59 new_pixels += requested;
64 /* We didn't get all/any of the pixels we asked for. This time, ask
65 for half as many. (If we do get all that we ask for, we ask for
66 the same number again next time, so we only do O(log(n)) server
69 requested = requested / 2;
77 complain (int wanted_colors, int got_colors,
78 Bool wanted_writable, Bool got_writable)
80 if (wanted_writable && !got_writable)
82 "%s: wanted %d writable colors; got %d read-only colors.\n",
83 progname, wanted_colors, got_colors);
85 else if (wanted_colors > (got_colors + 10))
86 /* don't bother complaining if we're within ten pixels. */
87 fprintf(stderr, "%s: wanted %d%s colors; got %d.\n",
88 progname, wanted_colors, (got_writable ? " writable" : ""),
95 make_color_ramp (Display *dpy, Colormap cmap,
96 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
97 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
98 XColor *colors, int *ncolorsP,
103 Bool verbose_p = True; /* argh. */
105 int ncolors = *ncolorsP;
106 int wanted = ncolors;
107 Bool wanted_writable = (allocate_p && writable_p);
108 double dh, ds, dv; /* deltas */
112 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
115 ncolors = (ncolors / 2) + 1;
117 /* Note: unlike other routines in this module, this function assumes that
118 if h1 and h2 are more than 180 degrees apart, then the desired direction
119 is always from h1 to h2 (rather than the shorter path.) make_uniform
122 dh = ((double)h2 - (double)h1) / ncolors;
123 ds = (s2 - s1) / ncolors;
124 dv = (v2 - v1) / ncolors;
126 for (i = 0; i < ncolors; i++)
128 colors[i].flags = DoRed|DoGreen|DoBlue;
129 hsv_to_rgb ((int) (h1 + (i*dh)), (s1 + (i*ds)), (v1 + (i*dv)),
130 &colors[i].red, &colors[i].green, &colors[i].blue);
134 for (i = ncolors; i < *ncolorsP; i++)
135 colors[i] = colors[(*ncolorsP)-i];
142 unsigned long *pixels = (unsigned long *)
143 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
145 /* allocate_writable_colors() won't do here, because we need exactly this
146 number of cells, or the color sequence we've chosen won't fit. */
147 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
153 for (i = 0; i < *ncolorsP; i++)
154 colors[i].pixel = pixels[i];
157 XStoreColors (dpy, cmap, colors, *ncolorsP);
161 for (i = 0; i < *ncolorsP; i++)
165 if (XAllocColor (dpy, cmap, &color))
167 colors[i].pixel = color.pixel;
171 free_colors (dpy, cmap, colors, i);
180 /* we weren't able to allocate all the colors we wanted;
181 decrease the requested number and try again.
183 ncolors = (ncolors > 170 ? ncolors - 20 :
184 ncolors > 100 ? ncolors - 10 :
185 ncolors > 75 ? ncolors - 5 :
186 ncolors > 25 ? ncolors - 3 :
187 ncolors > 10 ? ncolors - 2 :
188 ncolors > 2 ? ncolors - 1 :
197 complain (wanted, ncolors, wanted_writable, wanted_writable && writable_p);
201 #define MAXPOINTS 50 /* yeah, so I'm lazy */
205 make_color_path (Display *dpy, Colormap cmap,
206 int npoints, int *h, double *s, double *v,
207 XColor *colors, int *ncolorsP,
212 int total_ncolors = *ncolorsP;
214 int ncolors[MAXPOINTS]; /* number of pixels per edge */
215 double dh[MAXPOINTS]; /* distance between pixels, per edge (0 - 360.0) */
216 double ds[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
217 double dv[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
224 else if (npoints == 2) /* using make_color_ramp() will be faster */
226 make_color_ramp (dpy, cmap,
227 h[0], s[0], v[0], h[1], s[1], v[1],
230 allocate_p, writable_p);
233 else if (npoints >= MAXPOINTS)
235 npoints = MAXPOINTS-1;
241 double DH[MAXPOINTS]; /* Distance between H values in the shortest
242 direction around the circle, that is, the
243 distance between 10 and 350 is 20.
244 (Range is 0 - 360.0.)
246 double edge[MAXPOINTS]; /* lengths of edges in unit HSV space. */
247 double ratio[MAXPOINTS]; /* proportions of the edges (total 1.0) */
249 double one_point_oh = 0; /* (debug) */
251 for (i = 0; i < npoints; i++)
253 int j = (i+1) % npoints;
254 double d = ((double) (h[i] - h[j])) / 360;
256 if (d > 0.5) d = 0.5 - (d - 0.5);
260 for (i = 0; i < npoints; i++)
262 int j = (i+1) % npoints;
263 edge[i] = sqrt((DH[i] * DH[j]) +
264 ((s[j] - s[i]) * (s[j] - s[i])) +
265 ((v[j] - v[i]) * (v[j] - v[i])));
270 fprintf(stderr, "\ncolors:");
271 for (i=0; i < npoints; i++)
272 fprintf(stderr, " (%d, %.3f, %.3f)", h[i], s[i], v[i]);
273 fprintf(stderr, "\nlengths:");
274 for (i=0; i < npoints; i++)
275 fprintf(stderr, " %.3f", edge[i]);
281 for (i = 0; i < npoints; i++)
283 ratio[i] = edge[i] / circum;
284 one_point_oh += ratio[i];
288 fprintf(stderr, "\nratios:");
289 for (i=0; i < npoints; i++)
290 fprintf(stderr, " %.3f", ratio[i]);
293 if (one_point_oh < 0.99999 || one_point_oh > 1.00001)
296 /* space the colors evenly along the circumference -- that means that the
297 number of pixels on a edge is proportional to the length of that edge
298 (relative to the lengths of the other edges.)
300 for (i = 0; i < npoints; i++)
301 ncolors[i] = total_ncolors * ratio[i];
305 fprintf(stderr, "\npixels:");
306 for (i=0; i < npoints; i++)
307 fprintf(stderr, " %d", ncolors[i]);
308 fprintf(stderr, " (%d)\n", total_ncolors);
311 for (i = 0; i < npoints; i++)
313 int j = (i+1) % npoints;
317 dh[i] = 360 * (DH[i] / ncolors[i]);
318 ds[i] = (s[j] - s[i]) / ncolors[i];
319 dv[i] = (v[j] - v[i]) / ncolors[i];
324 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
327 for (i = 0; i < npoints; i++)
329 int distance, direction;
330 distance = h[(i+1) % npoints] - h[i];
331 direction = (distance >= 0 ? -1 : 1);
334 distance = 180 - (distance - 180);
335 else if (distance < -180)
336 distance = -(180 - ((-distance) - 180));
338 direction = -direction;
341 fprintf (stderr, "point %d: %3d %.2f %.2f\n",
342 i, h[i], s[i], v[i]);
343 fprintf(stderr, " h[i]=%d dh[i]=%.2f ncolors[i]=%d\n",
344 h[i], dh[i], ncolors[i]);
346 for (j = 0; j < ncolors[i]; j++, k++)
348 double hh = (h[i] + (j * dh[i] * direction));
349 if (hh < 0) hh += 360;
350 else if (hh > 360) hh -= 0;
351 colors[k].flags = DoRed|DoGreen|DoBlue;
354 (s[i] + (j * ds[i])),
355 (v[i] + (j * dv[i])),
356 &colors[k].red, &colors[k].green, &colors[k].blue);
358 fprintf (stderr, "point %d+%d: %.2f %.2f %.2f %04X %04X %04X\n",
361 (s[i] + (j * ds[i])),
362 (v[i] + (j * dv[i])),
363 colors[k].red, colors[k].green, colors[k].blue);
368 /* Floating-point round-off can make us decide to use fewer colors. */
381 unsigned long *pixels = (unsigned long *)
382 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
384 /* allocate_writable_colors() won't do here, because we need exactly this
385 number of cells, or the color sequence we've chosen won't fit. */
386 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
392 for (i = 0; i < *ncolorsP; i++)
393 colors[i].pixel = pixels[i];
396 XStoreColors (dpy, cmap, colors, *ncolorsP);
400 for (i = 0; i < *ncolorsP; i++)
404 if (XAllocColor (dpy, cmap, &color))
406 colors[i].pixel = color.pixel;
410 free_colors (dpy, cmap, colors, i);
419 /* we weren't able to allocate all the colors we wanted;
420 decrease the requested number and try again.
422 total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
423 total_ncolors > 100 ? total_ncolors - 10 :
424 total_ncolors > 75 ? total_ncolors - 5 :
425 total_ncolors > 25 ? total_ncolors - 3 :
426 total_ncolors > 10 ? total_ncolors - 2 :
427 total_ncolors > 2 ? total_ncolors - 1 :
429 *ncolorsP = total_ncolors;
430 if (total_ncolors > 0)
436 make_color_loop (Display *dpy, Colormap cmap,
437 int h0, double s0, double v0, /* 0-360, 0-1.0, 0-1.0 */
438 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
439 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
440 XColor *colors, int *ncolorsP,
446 h[0] = h0; h[1] = h1; h[2] = h2;
447 s[0] = s0; s[1] = s1; s[2] = s2;
448 v[0] = v0; v[1] = v1; v[2] = v2;
449 make_color_path(dpy, cmap,
452 allocate_p, writable_p);
457 make_smooth_colormap (Display *dpy, Visual *visual, Colormap cmap,
458 XColor *colors, int *ncolorsP,
464 int ncolors = *ncolorsP;
465 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
472 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
474 if (*ncolorsP <= 0) return;
477 int n = random() % 20;
478 if (n <= 5) npoints = 2; /* 30% of the time */
479 else if (n <= 15) npoints = 3; /* 50% of the time */
480 else if (n <= 18) npoints = 4; /* 15% of the time */
481 else npoints = 5; /* 5% of the time */
485 for (i = 0; i < npoints; i++)
488 h[i] = random() % 360;
490 v[i] = frand(0.8) + 0.2;
492 /* Make sure that no two adjascent colors are *too* close together.
493 If they are, try again.
497 int j = (i+1 == npoints) ? 0 : (i-1);
498 double hi = ((double) h[i]) / 360;
499 double hj = ((double) h[j]) / 360;
502 if (dh < 0) dh = -dh;
503 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
504 distance = sqrt ((dh * dh) +
505 ((s[j] - s[i]) * (s[j] - s[i])) +
506 ((v[j] - v[i]) * (v[j] - v[i])));
508 goto REPICK_THIS_COLOR;
514 /* If the average saturation or intensity are too low, repick the colors,
515 so that we don't end up with a black-and-white or too-dark map.
517 if (total_s / npoints < 0.2)
518 goto REPICK_ALL_COLORS;
519 if (total_v / npoints < 0.3)
520 goto REPICK_ALL_COLORS;
522 /* If this visual doesn't support writable cells, don't bother trying.
524 if (wanted_writable && !has_writable_cells(screen, visual))
525 *writable_pP = False;
528 make_color_path (dpy, cmap, npoints, h, s, v, colors, &ncolors,
529 allocate_p, (writable_pP && *writable_pP));
531 /* If we tried for writable cells and got none, try for non-writable. */
532 if (allocate_p && *ncolorsP == 0 && *writable_pP)
534 *writable_pP = False;
535 goto RETRY_NON_WRITABLE;
539 complain(*ncolorsP, ncolors, wanted_writable,
540 wanted_writable && *writable_pP);
547 make_uniform_colormap (Display *dpy, Visual *visual, Colormap cmap,
548 XColor *colors, int *ncolorsP,
553 int ncolors = *ncolorsP;
554 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
555 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
557 double S = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
558 double V = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
560 if (*ncolorsP <= 0) return;
562 /* If this visual doesn't support writable cells, don't bother trying. */
563 if (wanted_writable && !has_writable_cells(screen, visual))
564 *writable_pP = False;
567 make_color_ramp(dpy, cmap,
572 (writable_pP && *writable_pP));
574 /* If we tried for writable cells and got none, try for non-writable. */
575 if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
578 *writable_pP = False;
579 goto RETRY_NON_WRITABLE;
583 complain(*ncolorsP, ncolors, wanted_writable,
584 wanted_writable && *writable_pP);
591 make_random_colormap (Display *dpy, Visual *visual, Colormap cmap,
592 XColor *colors, int *ncolorsP,
598 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
599 int ncolors = *ncolorsP;
601 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
603 if (*ncolorsP <= 0) return;
605 /* If this visual doesn't support writable cells, don't bother trying. */
606 if (wanted_writable && !has_writable_cells(screen, visual))
607 *writable_pP = False;
609 for (i = 0; i < ncolors; i++)
611 colors[i].flags = DoRed|DoGreen|DoBlue;
614 int H = random() % 360; /* range 0-360 */
615 double S = ((double) (random()%70) + 30)/100.0; /* range 30%-100% */
616 double V = ((double) (random()%34) + 66)/100.0; /* range 66%-100% */
618 &colors[i].red, &colors[i].green, &colors[i].blue);
622 colors[i].red = random() % 0xFFFF;
623 colors[i].green = random() % 0xFFFF;
624 colors[i].blue = random() % 0xFFFF;
632 if (writable_pP && *writable_pP)
634 unsigned long *pixels = (unsigned long *)
635 malloc(sizeof(*pixels) * (ncolors + 1));
637 allocate_writable_colors (dpy, cmap, pixels, &ncolors);
639 for (i = 0; i < ncolors; i++)
640 colors[i].pixel = pixels[i];
643 XStoreColors (dpy, cmap, colors, ncolors);
647 for (i = 0; i < ncolors; i++)
651 if (!XAllocColor (dpy, cmap, &color))
653 colors[i].pixel = color.pixel;
658 /* If we tried for writable cells and got none, try for non-writable. */
659 if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
662 *writable_pP = False;
663 goto RETRY_NON_WRITABLE;
667 complain(*ncolorsP, ncolors, wanted_writable,
668 wanted_writable && *writable_pP);
675 rotate_colors (Display *dpy, Colormap cmap,
676 XColor *colors, int ncolors, int distance)
679 XColor *colors2 = (XColor *) malloc(sizeof(*colors2) * ncolors);
680 if (ncolors < 2) return;
681 distance = distance % ncolors;
682 for (i = 0; i < ncolors; i++)
684 int j = i - distance;
685 if (j >= ncolors) j -= ncolors;
686 if (j < 0) j += ncolors;
687 colors2[i] = colors[j];
688 colors2[i].pixel = colors[i].pixel;
690 XStoreColors (dpy, cmap, colors2, ncolors);
692 memcpy(colors, colors2, sizeof(*colors) * ncolors);