1 /* xscreensaver, Copyright (c) 1997-2013 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 (Screen *screen, Colormap cmap, XColor *colors, int ncolors)
27 Display *dpy = screen ? DisplayOfScreen (screen) : 0;
31 unsigned long *pixels = (unsigned long *)
32 malloc(sizeof(*pixels) * ncolors);
33 for (i = 0; i < ncolors; i++)
34 pixels[i] = colors[i].pixel;
35 XFreeColors (dpy, cmap, pixels, ncolors, 0L);
42 allocate_writable_colors (Screen *screen, Colormap cmap,
43 unsigned long *pixels, int *ncolorsP)
45 Display *dpy = screen ? DisplayOfScreen (screen) : 0;
46 int desired = *ncolorsP;
48 int requested = desired;
49 unsigned long *new_pixels = pixels;
55 if (desired - got < requested)
56 requested = desired - got;
58 if (XAllocColorCells (dpy, cmap, False, 0, 0, new_pixels, requested))
60 /* Got all the pixels we asked for. */
61 new_pixels += requested;
66 /* We didn't get all/any of the pixels we asked for. This time, ask
67 for half as many. (If we do get all that we ask for, we ask for
68 the same number again next time, so we only do O(log(n)) server
71 requested = requested / 2;
79 complain (int wanted_colors, int got_colors,
80 Bool wanted_writable, Bool got_writable)
82 if (got_colors > wanted_colors - 10)
83 /* don't bother complaining if we're within ten pixels. */
86 if (wanted_writable && !got_writable)
88 "%s: wanted %d writable colors; got %d read-only colors.\n",
89 progname, wanted_colors, got_colors);
91 fprintf (stderr, "%s: wanted %d%s colors; got %d.\n",
92 progname, wanted_colors, (got_writable ? " writable" : ""),
99 make_color_ramp (Screen *screen, Visual *visual, Colormap cmap,
100 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
101 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
102 XColor *colors, int *ncolorsP,
107 Display *dpy = screen ? DisplayOfScreen (screen) : 0;
108 Bool verbose_p = True; /* argh. */
110 int total_ncolors = *ncolorsP;
112 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
113 double dh, ds, dv; /* deltas */
115 wanted = total_ncolors;
117 wanted = (wanted / 2) + 1;
119 /* If this visual doesn't support writable cells, don't bother trying.
121 if (wanted_writable && !has_writable_cells(screen, visual))
122 *writable_pP = False;
125 ncolors = total_ncolors;
127 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
130 ncolors = (ncolors / 2) + 1;
132 /* Note: unlike other routines in this module, this function assumes that
133 if h1 and h2 are more than 180 degrees apart, then the desired direction
134 is always from h1 to h2 (rather than the shorter path.) make_uniform
137 dh = ((double)h2 - (double)h1) / ncolors;
138 ds = (s2 - s1) / ncolors;
139 dv = (v2 - v1) / ncolors;
141 for (i = 0; i < ncolors; i++)
143 colors[i].flags = DoRed|DoGreen|DoBlue;
144 hsv_to_rgb ((int) (h1 + (i*dh)), (s1 + (i*ds)), (v1 + (i*dv)),
145 &colors[i].red, &colors[i].green, &colors[i].blue);
149 for (i = ncolors; i < *ncolorsP; i++)
150 colors[i] = colors[(*ncolorsP)-i];
155 if (writable_pP && *writable_pP)
157 unsigned long *pixels = (unsigned long *)
158 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
160 /* allocate_writable_colors() won't do here, because we need exactly this
161 number of cells, or the color sequence we've chosen won't fit. */
162 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
168 for (i = 0; i < *ncolorsP; i++)
169 colors[i].pixel = pixels[i];
172 XStoreColors (dpy, cmap, colors, *ncolorsP);
176 for (i = 0; i < *ncolorsP; i++)
180 if (XAllocColor (dpy, cmap, &color))
182 colors[i].pixel = color.pixel;
186 free_colors (screen, cmap, colors, i);
195 /* we weren't able to allocate all the colors we wanted;
196 decrease the requested number and try again.
198 total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
199 total_ncolors > 100 ? total_ncolors - 10 :
200 total_ncolors > 75 ? total_ncolors - 5 :
201 total_ncolors > 25 ? total_ncolors - 3 :
202 total_ncolors > 10 ? total_ncolors - 2 :
203 total_ncolors > 2 ? total_ncolors - 1 :
205 *ncolorsP = total_ncolors;
206 ncolors = total_ncolors;
207 if (total_ncolors > 0)
213 /* don't warn if we got 0 writable colors -- probably TrueColor. */
214 (ncolors != 0 || !wanted_writable))
215 complain (wanted, ncolors, wanted_writable,
216 (wanted_writable && writable_pP && *writable_pP));
220 #define MAXPOINTS 50 /* yeah, so I'm lazy */
224 make_color_path (Screen *screen, Visual *visual, Colormap cmap,
225 int npoints, int *h, double *s, double *v,
226 XColor *colors, int *ncolorsP,
230 Display *dpy = screen ? DisplayOfScreen (screen) : 0;
232 int total_ncolors = *ncolorsP;
234 int ncolors[MAXPOINTS]; /* number of pixels per edge */
235 double dh[MAXPOINTS]; /* distance between pixels, per edge (0 - 360.0) */
236 double ds[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
237 double dv[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
244 else if (npoints == 2) /* using make_color_ramp() will be faster */
246 make_color_ramp (screen, visual, cmap,
247 h[0], s[0], v[0], h[1], s[1], v[1],
250 allocate_p, writable_pP);
253 else if (npoints >= MAXPOINTS)
255 npoints = MAXPOINTS-1;
261 double DH[MAXPOINTS]; /* Distance between H values in the shortest
262 direction around the circle, that is, the
263 distance between 10 and 350 is 20.
264 (Range is 0 - 360.0.)
266 double edge[MAXPOINTS]; /* lengths of edges in unit HSV space. */
267 double ratio[MAXPOINTS]; /* proportions of the edges (total 1.0) */
269 double one_point_oh = 0; /* (debug) */
271 for (i = 0; i < npoints; i++)
273 int j = (i+1) % npoints;
274 double d = ((double) (h[i] - h[j])) / 360;
276 if (d > 0.5) d = 0.5 - (d - 0.5);
280 for (i = 0; i < npoints; i++)
282 int j = (i+1) % npoints;
283 edge[i] = sqrt((DH[i] * DH[j]) +
284 ((s[j] - s[i]) * (s[j] - s[i])) +
285 ((v[j] - v[i]) * (v[j] - v[i])));
290 fprintf(stderr, "\ncolors:");
291 for (i=0; i < npoints; i++)
292 fprintf(stderr, " (%d, %.3f, %.3f)", h[i], s[i], v[i]);
293 fprintf(stderr, "\nlengths:");
294 for (i=0; i < npoints; i++)
295 fprintf(stderr, " %.3f", edge[i]);
301 for (i = 0; i < npoints; i++)
303 ratio[i] = edge[i] / circum;
304 one_point_oh += ratio[i];
308 fprintf(stderr, "\nratios:");
309 for (i=0; i < npoints; i++)
310 fprintf(stderr, " %.3f", ratio[i]);
313 if (one_point_oh < 0.99999 || one_point_oh > 1.00001)
316 /* space the colors evenly along the circumference -- that means that the
317 number of pixels on a edge is proportional to the length of that edge
318 (relative to the lengths of the other edges.)
320 for (i = 0; i < npoints; i++)
321 ncolors[i] = total_ncolors * ratio[i];
325 fprintf(stderr, "\npixels:");
326 for (i=0; i < npoints; i++)
327 fprintf(stderr, " %d", ncolors[i]);
328 fprintf(stderr, " (%d)\n", total_ncolors);
331 for (i = 0; i < npoints; i++)
333 int j = (i+1) % npoints;
337 dh[i] = 360 * (DH[i] / ncolors[i]);
338 ds[i] = (s[j] - s[i]) / ncolors[i];
339 dv[i] = (v[j] - v[i]) / ncolors[i];
344 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
347 for (i = 0; i < npoints; i++)
349 int distance = h[(i+1) % npoints] - h[i];
350 int direction = (distance >= 0 ? -1 : 1);
352 if (distance <= 180 && distance >= -180)
353 direction = -direction;
356 fprintf (stderr, "point %d: %3d %.2f %.2f\n",
357 i, h[i], s[i], v[i]);
358 fprintf(stderr, " h[i]=%d dh[i]=%.2f ncolors[i]=%d\n",
359 h[i], dh[i], ncolors[i]);
361 for (j = 0; j < ncolors[i]; j++, k++)
363 double hh = (h[i] + (j * dh[i] * direction));
364 if (hh < 0) hh += 360;
365 else if (hh > 360) hh -= 0;
366 colors[k].flags = DoRed|DoGreen|DoBlue;
369 (s[i] + (j * ds[i])),
370 (v[i] + (j * dv[i])),
371 &colors[k].red, &colors[k].green, &colors[k].blue);
373 fprintf (stderr, "point %d+%d: %.2f %.2f %.2f %04X %04X %04X\n",
376 (s[i] + (j * ds[i])),
377 (v[i] + (j * dv[i])),
378 colors[k].red, colors[k].green, colors[k].blue);
383 /* Floating-point round-off can make us decide to use fewer colors. */
394 if (writable_pP && *writable_pP)
396 unsigned long *pixels = (unsigned long *)
397 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
399 /* allocate_writable_colors() won't do here, because we need exactly this
400 number of cells, or the color sequence we've chosen won't fit. */
401 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
407 for (i = 0; i < *ncolorsP; i++)
408 colors[i].pixel = pixels[i];
411 XStoreColors (dpy, cmap, colors, *ncolorsP);
415 for (i = 0; i < *ncolorsP; i++)
419 if (XAllocColor (dpy, cmap, &color))
421 colors[i].pixel = color.pixel;
425 free_colors (screen, cmap, colors, i);
434 /* we weren't able to allocate all the colors we wanted;
435 decrease the requested number and try again.
437 total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
438 total_ncolors > 100 ? total_ncolors - 10 :
439 total_ncolors > 75 ? total_ncolors - 5 :
440 total_ncolors > 25 ? total_ncolors - 3 :
441 total_ncolors > 10 ? total_ncolors - 2 :
442 total_ncolors > 2 ? total_ncolors - 1 :
444 *ncolorsP = total_ncolors;
445 if (total_ncolors > 0)
451 make_color_loop (Screen *screen, Visual *visual, Colormap cmap,
452 int h0, double s0, double v0, /* 0-360, 0-1.0, 0-1.0 */
453 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
454 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
455 XColor *colors, int *ncolorsP,
459 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
463 h[0] = h0; h[1] = h1; h[2] = h2;
464 s[0] = s0; s[1] = s1; s[2] = s2;
465 v[0] = v0; v[1] = v1; v[2] = v2;
467 /* If this visual doesn't support writable cells, don't bother trying.
469 if (wanted_writable && !has_writable_cells(screen, visual))
470 *writable_pP = False;
472 make_color_path (screen, visual, cmap,
475 allocate_p, writable_pP);
480 make_smooth_colormap (Screen *screen, Visual *visual, Colormap cmap,
481 XColor *colors, int *ncolorsP,
487 int ncolors = *ncolorsP;
488 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
497 if (*ncolorsP <= 0) return;
500 int n = random() % 20;
501 if (n <= 5) npoints = 2; /* 30% of the time */
502 else if (n <= 15) npoints = 3; /* 50% of the time */
503 else if (n <= 18) npoints = 4; /* 15% of the time */
504 else npoints = 5; /* 5% of the time */
508 for (i = 0; i < npoints; i++)
511 if (++loop > 10000) abort();
512 h[i] = random() % 360;
514 v[i] = frand(0.8) + 0.2;
516 /* Make sure that no two adjascent colors are *too* close together.
517 If they are, try again.
521 int j = (i+1 == npoints) ? 0 : (i-1);
522 double hi = ((double) h[i]) / 360;
523 double hj = ((double) h[j]) / 360;
526 if (dh < 0) dh = -dh;
527 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
528 distance = sqrt ((dh * dh) +
529 ((s[j] - s[i]) * (s[j] - s[i])) +
530 ((v[j] - v[i]) * (v[j] - v[i])));
532 goto REPICK_THIS_COLOR;
538 /* If the average saturation or intensity are too low, repick the colors,
539 so that we don't end up with a black-and-white or too-dark map.
541 if (total_s / npoints < 0.2)
542 goto REPICK_ALL_COLORS;
543 if (total_v / npoints < 0.3)
544 goto REPICK_ALL_COLORS;
546 /* If this visual doesn't support writable cells, don't bother trying.
548 if (wanted_writable && !has_writable_cells(screen, visual))
549 *writable_pP = False;
552 make_color_path (screen, visual, cmap, npoints, h, s, v, colors, &ncolors,
553 allocate_p, writable_pP);
555 /* If we tried for writable cells and got none, try for non-writable. */
556 if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
558 *writable_pP = False;
559 goto RETRY_NON_WRITABLE;
563 complain(*ncolorsP, ncolors, wanted_writable,
564 wanted_writable && *writable_pP);
571 make_uniform_colormap (Screen *screen, Visual *visual, Colormap cmap,
572 XColor *colors, int *ncolorsP,
577 int ncolors = *ncolorsP;
578 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
580 double S = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
581 double V = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
583 if (*ncolorsP <= 0) return;
585 /* If this visual doesn't support writable cells, don't bother trying. */
586 if (wanted_writable && !has_writable_cells(screen, visual))
587 *writable_pP = False;
590 make_color_ramp(screen, visual, cmap,
594 False, allocate_p, writable_pP);
596 /* If we tried for writable cells and got none, try for non-writable. */
597 if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
600 *writable_pP = False;
601 goto RETRY_NON_WRITABLE;
605 complain(*ncolorsP, ncolors, wanted_writable,
606 wanted_writable && *writable_pP);
613 make_random_colormap (Screen *screen, Visual *visual, Colormap cmap,
614 XColor *colors, int *ncolorsP,
620 Display *dpy = screen ? DisplayOfScreen (screen) : 0;
621 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
622 int ncolors = *ncolorsP;
625 if (*ncolorsP <= 0) return;
627 /* If this visual doesn't support writable cells, don't bother trying. */
628 if (wanted_writable && !has_writable_cells(screen, visual))
629 *writable_pP = False;
632 for (i = 0; i < ncolors; i++)
634 colors[i].flags = DoRed|DoGreen|DoBlue;
637 int H = random() % 360; /* range 0-360 */
638 double S = ((double) (random()%70) + 30)/100.0; /* range 30%-100% */
639 double V = ((double) (random()%34) + 66)/100.0; /* range 66%-100% */
641 &colors[i].red, &colors[i].green, &colors[i].blue);
645 colors[i].red = random() % 0xFFFF;
646 colors[i].green = random() % 0xFFFF;
647 colors[i].blue = random() % 0xFFFF;
651 /* If there are a small number of colors, make sure at least the first
654 if (!bright_p && ncolors <= 4)
657 double s0, s1, v0, v1;
658 rgb_to_hsv (colors[0].red, colors[0].green, colors[0].blue, &h0,&s0,&v0);
659 rgb_to_hsv (colors[1].red, colors[1].green, colors[1].blue, &h1,&s1,&v1);
660 if (fabs (v1-v0) < 0.5)
668 if (writable_pP && *writable_pP)
670 unsigned long *pixels = (unsigned long *)
671 malloc(sizeof(*pixels) * (ncolors + 1));
673 allocate_writable_colors (screen, cmap, pixels, &ncolors);
675 for (i = 0; i < ncolors; i++)
676 colors[i].pixel = pixels[i];
679 XStoreColors (dpy, cmap, colors, ncolors);
683 for (i = 0; i < ncolors; i++)
687 if (!XAllocColor (dpy, cmap, &color))
689 colors[i].pixel = color.pixel;
694 /* If we tried for writable cells and got none, try for non-writable. */
695 if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
698 *writable_pP = False;
699 goto RETRY_NON_WRITABLE;
703 complain(*ncolorsP, ncolors, wanted_writable,
704 wanted_writable && *writable_pP);
711 rotate_colors (Screen *screen, Colormap cmap,
712 XColor *colors, int ncolors, int distance)
714 Display *dpy = screen ? DisplayOfScreen (screen) : 0;
717 if (ncolors < 2) return;
718 colors2 = (XColor *) malloc(sizeof(*colors2) * ncolors);
719 distance = distance % ncolors;
720 for (i = 0; i < ncolors; i++)
722 int j = i - distance;
723 if (j >= ncolors) j -= ncolors;
724 if (j < 0) j += ncolors;
725 colors2[i] = colors[j];
726 colors2[i].pixel = colors[i].pixel;
728 XStoreColors (dpy, cmap, colors2, ncolors);
730 memcpy(colors, colors2, sizeof(*colors) * ncolors);