1 /* xscreensaver, Copyright (c) 1997, 2002 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 (got_colors > wanted_colors - 10)
81 /* don't bother complaining if we're within ten pixels. */
84 if (wanted_writable && !got_writable)
86 "%s: wanted %d writable colors; got %d read-only colors.\n",
87 progname, wanted_colors, got_colors);
89 fprintf (stderr, "%s: wanted %d%s colors; got %d.\n",
90 progname, wanted_colors, (got_writable ? " writable" : ""),
97 make_color_ramp (Display *dpy, Colormap cmap,
98 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
99 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
100 XColor *colors, int *ncolorsP,
105 Bool verbose_p = True; /* argh. */
107 int total_ncolors = *ncolorsP;
109 Bool wanted_writable = (allocate_p && writable_p);
110 double dh, ds, dv; /* deltas */
112 wanted = total_ncolors;
114 wanted = (wanted / 2) + 1;
117 ncolors = total_ncolors;
119 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
122 ncolors = (ncolors / 2) + 1;
124 /* Note: unlike other routines in this module, this function assumes that
125 if h1 and h2 are more than 180 degrees apart, then the desired direction
126 is always from h1 to h2 (rather than the shorter path.) make_uniform
129 dh = ((double)h2 - (double)h1) / ncolors;
130 ds = (s2 - s1) / ncolors;
131 dv = (v2 - v1) / ncolors;
133 for (i = 0; i < ncolors; i++)
135 colors[i].flags = DoRed|DoGreen|DoBlue;
136 hsv_to_rgb ((int) (h1 + (i*dh)), (s1 + (i*ds)), (v1 + (i*dv)),
137 &colors[i].red, &colors[i].green, &colors[i].blue);
141 for (i = ncolors; i < *ncolorsP; i++)
142 colors[i] = colors[(*ncolorsP)-i];
149 unsigned long *pixels = (unsigned long *)
150 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
152 /* allocate_writable_colors() won't do here, because we need exactly this
153 number of cells, or the color sequence we've chosen won't fit. */
154 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
160 for (i = 0; i < *ncolorsP; i++)
161 colors[i].pixel = pixels[i];
164 XStoreColors (dpy, cmap, colors, *ncolorsP);
168 for (i = 0; i < *ncolorsP; i++)
172 if (XAllocColor (dpy, cmap, &color))
174 colors[i].pixel = color.pixel;
178 free_colors (dpy, cmap, colors, i);
187 /* we weren't able to allocate all the colors we wanted;
188 decrease the requested number and try again.
190 total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
191 total_ncolors > 100 ? total_ncolors - 10 :
192 total_ncolors > 75 ? total_ncolors - 5 :
193 total_ncolors > 25 ? total_ncolors - 3 :
194 total_ncolors > 10 ? total_ncolors - 2 :
195 total_ncolors > 2 ? total_ncolors - 1 :
197 *ncolorsP = total_ncolors;
198 ncolors = total_ncolors;
199 if (total_ncolors > 0)
205 /* don't warn if we got 0 writable colors -- probably TrueColor. */
206 (ncolors != 0 || !wanted_writable))
207 complain (wanted, ncolors, wanted_writable, wanted_writable && writable_p);
211 #define MAXPOINTS 50 /* yeah, so I'm lazy */
215 make_color_path (Display *dpy, Colormap cmap,
216 int npoints, int *h, double *s, double *v,
217 XColor *colors, int *ncolorsP,
222 int total_ncolors = *ncolorsP;
224 int ncolors[MAXPOINTS]; /* number of pixels per edge */
225 double dh[MAXPOINTS]; /* distance between pixels, per edge (0 - 360.0) */
226 double ds[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
227 double dv[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
234 else if (npoints == 2) /* using make_color_ramp() will be faster */
236 make_color_ramp (dpy, cmap,
237 h[0], s[0], v[0], h[1], s[1], v[1],
240 allocate_p, writable_p);
243 else if (npoints >= MAXPOINTS)
245 npoints = MAXPOINTS-1;
251 double DH[MAXPOINTS]; /* Distance between H values in the shortest
252 direction around the circle, that is, the
253 distance between 10 and 350 is 20.
254 (Range is 0 - 360.0.)
256 double edge[MAXPOINTS]; /* lengths of edges in unit HSV space. */
257 double ratio[MAXPOINTS]; /* proportions of the edges (total 1.0) */
259 double one_point_oh = 0; /* (debug) */
261 for (i = 0; i < npoints; i++)
263 int j = (i+1) % npoints;
264 double d = ((double) (h[i] - h[j])) / 360;
266 if (d > 0.5) d = 0.5 - (d - 0.5);
270 for (i = 0; i < npoints; i++)
272 int j = (i+1) % npoints;
273 edge[i] = sqrt((DH[i] * DH[j]) +
274 ((s[j] - s[i]) * (s[j] - s[i])) +
275 ((v[j] - v[i]) * (v[j] - v[i])));
280 fprintf(stderr, "\ncolors:");
281 for (i=0; i < npoints; i++)
282 fprintf(stderr, " (%d, %.3f, %.3f)", h[i], s[i], v[i]);
283 fprintf(stderr, "\nlengths:");
284 for (i=0; i < npoints; i++)
285 fprintf(stderr, " %.3f", edge[i]);
291 for (i = 0; i < npoints; i++)
293 ratio[i] = edge[i] / circum;
294 one_point_oh += ratio[i];
298 fprintf(stderr, "\nratios:");
299 for (i=0; i < npoints; i++)
300 fprintf(stderr, " %.3f", ratio[i]);
303 if (one_point_oh < 0.99999 || one_point_oh > 1.00001)
306 /* space the colors evenly along the circumference -- that means that the
307 number of pixels on a edge is proportional to the length of that edge
308 (relative to the lengths of the other edges.)
310 for (i = 0; i < npoints; i++)
311 ncolors[i] = total_ncolors * ratio[i];
315 fprintf(stderr, "\npixels:");
316 for (i=0; i < npoints; i++)
317 fprintf(stderr, " %d", ncolors[i]);
318 fprintf(stderr, " (%d)\n", total_ncolors);
321 for (i = 0; i < npoints; i++)
323 int j = (i+1) % npoints;
327 dh[i] = 360 * (DH[i] / ncolors[i]);
328 ds[i] = (s[j] - s[i]) / ncolors[i];
329 dv[i] = (v[j] - v[i]) / ncolors[i];
334 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
337 for (i = 0; i < npoints; i++)
339 int distance = h[(i+1) % npoints] - h[i];
340 int direction = (distance >= 0 ? -1 : 1);
342 if (distance <= 180 && distance >= -180)
343 direction = -direction;
346 fprintf (stderr, "point %d: %3d %.2f %.2f\n",
347 i, h[i], s[i], v[i]);
348 fprintf(stderr, " h[i]=%d dh[i]=%.2f ncolors[i]=%d\n",
349 h[i], dh[i], ncolors[i]);
351 for (j = 0; j < ncolors[i]; j++, k++)
353 double hh = (h[i] + (j * dh[i] * direction));
354 if (hh < 0) hh += 360;
355 else if (hh > 360) hh -= 0;
356 colors[k].flags = DoRed|DoGreen|DoBlue;
359 (s[i] + (j * ds[i])),
360 (v[i] + (j * dv[i])),
361 &colors[k].red, &colors[k].green, &colors[k].blue);
363 fprintf (stderr, "point %d+%d: %.2f %.2f %.2f %04X %04X %04X\n",
366 (s[i] + (j * ds[i])),
367 (v[i] + (j * dv[i])),
368 colors[k].red, colors[k].green, colors[k].blue);
373 /* Floating-point round-off can make us decide to use fewer colors. */
386 unsigned long *pixels = (unsigned long *)
387 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
389 /* allocate_writable_colors() won't do here, because we need exactly this
390 number of cells, or the color sequence we've chosen won't fit. */
391 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
397 for (i = 0; i < *ncolorsP; i++)
398 colors[i].pixel = pixels[i];
401 XStoreColors (dpy, cmap, colors, *ncolorsP);
405 for (i = 0; i < *ncolorsP; i++)
409 if (XAllocColor (dpy, cmap, &color))
411 colors[i].pixel = color.pixel;
415 free_colors (dpy, cmap, colors, i);
424 /* we weren't able to allocate all the colors we wanted;
425 decrease the requested number and try again.
427 total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
428 total_ncolors > 100 ? total_ncolors - 10 :
429 total_ncolors > 75 ? total_ncolors - 5 :
430 total_ncolors > 25 ? total_ncolors - 3 :
431 total_ncolors > 10 ? total_ncolors - 2 :
432 total_ncolors > 2 ? total_ncolors - 1 :
434 *ncolorsP = total_ncolors;
435 if (total_ncolors > 0)
441 make_color_loop (Display *dpy, Colormap cmap,
442 int h0, double s0, double v0, /* 0-360, 0-1.0, 0-1.0 */
443 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
444 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
445 XColor *colors, int *ncolorsP,
451 h[0] = h0; h[1] = h1; h[2] = h2;
452 s[0] = s0; s[1] = s1; s[2] = s2;
453 v[0] = v0; v[1] = v1; v[2] = v2;
454 make_color_path(dpy, cmap,
457 allocate_p, writable_p);
462 make_smooth_colormap (Display *dpy, Visual *visual, Colormap cmap,
463 XColor *colors, int *ncolorsP,
469 int ncolors = *ncolorsP;
470 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
477 Screen *screen = (dpy ? DefaultScreenOfDisplay(dpy) : 0); /* #### WRONG! */
480 if (*ncolorsP <= 0) return;
483 int n = random() % 20;
484 if (n <= 5) npoints = 2; /* 30% of the time */
485 else if (n <= 15) npoints = 3; /* 50% of the time */
486 else if (n <= 18) npoints = 4; /* 15% of the time */
487 else npoints = 5; /* 5% of the time */
491 for (i = 0; i < npoints; i++)
494 if (++loop > 10000) abort();
495 h[i] = random() % 360;
497 v[i] = frand(0.8) + 0.2;
499 /* Make sure that no two adjascent colors are *too* close together.
500 If they are, try again.
504 int j = (i+1 == npoints) ? 0 : (i-1);
505 double hi = ((double) h[i]) / 360;
506 double hj = ((double) h[j]) / 360;
509 if (dh < 0) dh = -dh;
510 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
511 distance = sqrt ((dh * dh) +
512 ((s[j] - s[i]) * (s[j] - s[i])) +
513 ((v[j] - v[i]) * (v[j] - v[i])));
515 goto REPICK_THIS_COLOR;
521 /* If the average saturation or intensity are too low, repick the colors,
522 so that we don't end up with a black-and-white or too-dark map.
524 if (total_s / npoints < 0.2)
525 goto REPICK_ALL_COLORS;
526 if (total_v / npoints < 0.3)
527 goto REPICK_ALL_COLORS;
529 /* If this visual doesn't support writable cells, don't bother trying.
531 if (wanted_writable && !has_writable_cells(screen, visual))
532 *writable_pP = False;
535 make_color_path (dpy, cmap, npoints, h, s, v, colors, &ncolors,
536 allocate_p, (writable_pP && *writable_pP));
538 /* If we tried for writable cells and got none, try for non-writable. */
539 if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
541 *writable_pP = False;
542 goto RETRY_NON_WRITABLE;
546 complain(*ncolorsP, ncolors, wanted_writable,
547 wanted_writable && *writable_pP);
554 make_uniform_colormap (Display *dpy, Visual *visual, Colormap cmap,
555 XColor *colors, int *ncolorsP,
560 int ncolors = *ncolorsP;
561 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
562 Screen *screen = (dpy ? DefaultScreenOfDisplay(dpy) : 0); /* #### WRONG! */
564 double S = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
565 double V = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
567 if (*ncolorsP <= 0) return;
569 /* If this visual doesn't support writable cells, don't bother trying. */
570 if (wanted_writable && !has_writable_cells(screen, visual))
571 *writable_pP = False;
574 make_color_ramp(dpy, cmap,
579 (writable_pP && *writable_pP));
581 /* If we tried for writable cells and got none, try for non-writable. */
582 if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
585 *writable_pP = False;
586 goto RETRY_NON_WRITABLE;
590 complain(*ncolorsP, ncolors, wanted_writable,
591 wanted_writable && *writable_pP);
598 make_random_colormap (Display *dpy, Visual *visual, Colormap cmap,
599 XColor *colors, int *ncolorsP,
605 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
606 int ncolors = *ncolorsP;
608 Screen *screen = (dpy ? DefaultScreenOfDisplay(dpy) : 0); /* #### WRONG! */
610 if (*ncolorsP <= 0) return;
612 /* If this visual doesn't support writable cells, don't bother trying. */
613 if (wanted_writable && !has_writable_cells(screen, visual))
614 *writable_pP = False;
616 for (i = 0; i < ncolors; i++)
618 colors[i].flags = DoRed|DoGreen|DoBlue;
621 int H = random() % 360; /* range 0-360 */
622 double S = ((double) (random()%70) + 30)/100.0; /* range 30%-100% */
623 double V = ((double) (random()%34) + 66)/100.0; /* range 66%-100% */
625 &colors[i].red, &colors[i].green, &colors[i].blue);
629 colors[i].red = random() % 0xFFFF;
630 colors[i].green = random() % 0xFFFF;
631 colors[i].blue = random() % 0xFFFF;
639 if (writable_pP && *writable_pP)
641 unsigned long *pixels = (unsigned long *)
642 malloc(sizeof(*pixels) * (ncolors + 1));
644 allocate_writable_colors (dpy, cmap, pixels, &ncolors);
646 for (i = 0; i < ncolors; i++)
647 colors[i].pixel = pixels[i];
650 XStoreColors (dpy, cmap, colors, ncolors);
654 for (i = 0; i < ncolors; i++)
658 if (!XAllocColor (dpy, cmap, &color))
660 colors[i].pixel = color.pixel;
665 /* If we tried for writable cells and got none, try for non-writable. */
666 if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
669 *writable_pP = False;
670 goto RETRY_NON_WRITABLE;
674 complain(*ncolorsP, ncolors, wanted_writable,
675 wanted_writable && *writable_pP);
682 rotate_colors (Display *dpy, Colormap cmap,
683 XColor *colors, int ncolors, int distance)
686 XColor *colors2 = (XColor *) malloc(sizeof(*colors2) * ncolors);
687 if (ncolors < 2) return;
688 distance = distance % ncolors;
689 for (i = 0; i < ncolors; i++)
691 int j = i - distance;
692 if (j >= ncolors) j -= ncolors;
693 if (j < 0) j += ncolors;
694 colors2[i] = colors[j];
695 colors2[i].pixel = colors[i].pixel;
697 XStoreColors (dpy, cmap, colors2, ncolors);
699 memcpy(colors, colors2, sizeof(*colors) * ncolors);