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;
78 make_color_ramp (Display *dpy, Colormap cmap,
79 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
80 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
81 XColor *colors, int *ncolorsP,
87 int ncolors = *ncolorsP;
88 double dh, ds, dv; /* deltas */
92 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
95 ncolors = (ncolors / 2) + 1;
97 /* Note: unlike other routines in this module, this function assumes that
98 if h1 and h2 are more than 180 degrees apart, then the desired direction
99 is always from h1 to h2 (rather than the shorter path.) make_uniform
102 dh = ((double)h2 - (double)h1) / ncolors;
103 ds = (s2 - s1) / ncolors;
104 dv = (v2 - v1) / ncolors;
106 for (i = 0; i < ncolors; i++)
108 colors[i].flags = DoRed|DoGreen|DoBlue;
109 hsv_to_rgb ((int) (h1 + (i*dh)), (s1 + (i*ds)), (v1 + (i*dv)),
110 &colors[i].red, &colors[i].green, &colors[i].blue);
114 for (i = ncolors; i < *ncolorsP; i++)
115 colors[i] = colors[(*ncolorsP)-i];
122 unsigned long *pixels = (unsigned long *)
123 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
125 /* allocate_writable_colors() won't do here, because we need exactly this
126 number of cells, or the color sequence we've chosen won't fit. */
127 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
133 for (i = 0; i < *ncolorsP; i++)
134 colors[i].pixel = pixels[i];
137 XStoreColors (dpy, cmap, colors, *ncolorsP);
141 for (i = 0; i < *ncolorsP; i++)
145 if (XAllocColor (dpy, cmap, &color))
147 colors[i].pixel = color.pixel;
151 free_colors (dpy, cmap, colors, i);
160 /* we weren't able to allocate all the colors we wanted;
161 decrease the requested number and try again.
163 ncolors = (ncolors > 170 ? ncolors - 20 :
164 ncolors > 100 ? ncolors - 10 :
165 ncolors > 75 ? ncolors - 5 :
166 ncolors > 25 ? ncolors - 3 :
167 ncolors > 10 ? ncolors - 2 :
168 ncolors > 2 ? ncolors - 1 :
176 #define MAXPOINTS 50 /* yeah, so I'm lazy */
180 make_color_path (Display *dpy, Colormap cmap,
181 int npoints, int *h, double *s, double *v,
182 XColor *colors, int *ncolorsP,
187 int total_ncolors = *ncolorsP;
189 int ncolors[MAXPOINTS]; /* number of pixels per edge */
190 double dh[MAXPOINTS]; /* distance between pixels, per edge (0 - 360.0) */
191 double ds[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
192 double dv[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
199 else if (npoints == 2) /* using make_color_ramp() will be faster */
201 make_color_ramp (dpy, cmap,
202 h[0], s[0], v[0], h[1], s[1], v[1],
205 allocate_p, writable_p);
208 else if (npoints >= MAXPOINTS)
210 npoints = MAXPOINTS-1;
216 double DH[MAXPOINTS]; /* Distance between H values in the shortest
217 direction around the circle, that is, the
218 distance between 10 and 350 is 20.
219 (Range is 0 - 360.0.)
221 double edge[MAXPOINTS]; /* lengths of edges in unit HSV space. */
222 double ratio[MAXPOINTS]; /* proportions of the edges (total 1.0) */
224 double one_point_oh = 0; /* (debug) */
226 for (i = 0; i < npoints; i++)
228 int j = (i+1) % npoints;
229 double d = ((double) (h[i] - h[j])) / 360;
231 if (d > 0.5) d = 0.5 - (d - 0.5);
235 for (i = 0; i < npoints; i++)
237 int j = (i+1) % npoints;
238 edge[i] = sqrt((DH[i] * DH[j]) +
239 ((s[j] - s[i]) * (s[j] - s[i])) +
240 ((v[j] - v[i]) * (v[j] - v[i])));
245 fprintf(stderr, "\ncolors:");
246 for (i=0; i < npoints; i++)
247 fprintf(stderr, " (%d, %.3f, %.3f)", h[i], s[i], v[i]);
248 fprintf(stderr, "\nlengths:");
249 for (i=0; i < npoints; i++)
250 fprintf(stderr, " %.3f", edge[i]);
256 for (i = 0; i < npoints; i++)
258 ratio[i] = edge[i] / circum;
259 one_point_oh += ratio[i];
263 fprintf(stderr, "\nratios:");
264 for (i=0; i < npoints; i++)
265 fprintf(stderr, " %.3f", ratio[i]);
268 if (one_point_oh < 0.99999 || one_point_oh > 1.00001)
271 /* space the colors evenly along the circumference -- that means that the
272 number of pixels on a edge is proportional to the length of that edge
273 (relative to the lengths of the other edges.)
275 for (i = 0; i < npoints; i++)
276 ncolors[i] = total_ncolors * ratio[i];
280 fprintf(stderr, "\npixels:");
281 for (i=0; i < npoints; i++)
282 fprintf(stderr, " %d", ncolors[i]);
283 fprintf(stderr, " (%d)\n", total_ncolors);
286 for (i = 0; i < npoints; i++)
288 int j = (i+1) % npoints;
292 dh[i] = 360 * (DH[i] / ncolors[i]);
293 ds[i] = (s[j] - s[i]) / ncolors[i];
294 dv[i] = (v[j] - v[i]) / ncolors[i];
299 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
302 for (i = 0; i < npoints; i++)
304 int distance, direction;
305 distance = h[(i+1) % npoints] - h[i];
306 direction = (distance >= 0 ? -1 : 1);
309 distance = 180 - (distance - 180);
310 else if (distance < -180)
311 distance = -(180 - ((-distance) - 180));
313 direction = -direction;
316 fprintf (stderr, "point %d: %3d %.2f %.2f\n",
317 i, h[i], s[i], v[i]);
318 fprintf(stderr, " h[i]=%d dh[i]=%.2f ncolors[i]=%d\n",
319 h[i], dh[i], ncolors[i]);
321 for (j = 0; j < ncolors[i]; j++, k++)
323 double hh = (h[i] + (j * dh[i] * direction));
324 if (hh < 0) hh += 360;
325 else if (hh > 360) hh -= 0;
326 colors[k].flags = DoRed|DoGreen|DoBlue;
329 (s[i] + (j * ds[i])),
330 (v[i] + (j * dv[i])),
331 &colors[k].red, &colors[k].green, &colors[k].blue);
333 fprintf (stderr, "point %d+%d: %.2f %.2f %.2f %04X %04X %04X\n",
336 (s[i] + (j * ds[i])),
337 (v[i] + (j * dv[i])),
338 colors[k].red, colors[k].green, colors[k].blue);
343 /* Floating-point round-off can make us decide to use fewer colors. */
356 unsigned long *pixels = (unsigned long *)
357 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
359 /* allocate_writable_colors() won't do here, because we need exactly this
360 number of cells, or the color sequence we've chosen won't fit. */
361 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
367 for (i = 0; i < *ncolorsP; i++)
368 colors[i].pixel = pixels[i];
371 XStoreColors (dpy, cmap, colors, *ncolorsP);
375 for (i = 0; i < *ncolorsP; i++)
379 if (XAllocColor (dpy, cmap, &color))
381 colors[i].pixel = color.pixel;
385 free_colors (dpy, cmap, colors, i);
394 /* we weren't able to allocate all the colors we wanted;
395 decrease the requested number and try again.
397 total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
398 total_ncolors > 100 ? total_ncolors - 10 :
399 total_ncolors > 75 ? total_ncolors - 5 :
400 total_ncolors > 25 ? total_ncolors - 3 :
401 total_ncolors > 10 ? total_ncolors - 2 :
402 total_ncolors > 2 ? total_ncolors - 1 :
404 *ncolorsP = total_ncolors;
405 if (total_ncolors > 0)
411 make_color_loop (Display *dpy, Colormap cmap,
412 int h0, double s0, double v0, /* 0-360, 0-1.0, 0-1.0 */
413 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
414 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
415 XColor *colors, int *ncolorsP,
421 h[0] = h0; h[1] = h1; h[2] = h2;
422 s[0] = s0; s[1] = s1; s[2] = s2;
423 v[0] = v0; v[1] = v1; v[2] = v2;
424 make_color_path(dpy, cmap,
427 allocate_p, writable_p);
432 complain (int wanted_colors, int got_colors,
433 Bool wanted_writable, Bool got_writable)
435 if (wanted_writable && !got_writable)
437 "%s: wanted %d writable colors; got %d read-only colors.\n",
438 progname, wanted_colors, got_colors);
440 else if (wanted_colors > (got_colors + 10))
441 /* don't bother complaining if we're within ten pixels. */
442 fprintf(stderr, "%s: wanted %d%s colors; got %d.\n",
443 progname, wanted_colors, (got_writable ? " writable" : ""),
449 make_smooth_colormap (Display *dpy, Visual *visual, Colormap cmap,
450 XColor *colors, int *ncolorsP,
456 int ncolors = *ncolorsP;
457 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
464 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
466 if (*ncolorsP <= 0) return;
469 int n = random() % 20;
470 if (n <= 5) npoints = 2; /* 30% of the time */
471 else if (n <= 15) npoints = 3; /* 50% of the time */
472 else if (n <= 18) npoints = 4; /* 15% of the time */
473 else npoints = 5; /* 5% of the time */
477 for (i = 0; i < npoints; i++)
480 h[i] = random() % 360;
482 v[i] = frand(0.8) + 0.2;
484 /* Make sure that no two adjascent colors are *too* close together.
485 If they are, try again.
489 int j = (i+1 == npoints) ? 0 : (i-1);
490 double hi = ((double) h[i]) / 360;
491 double hj = ((double) h[j]) / 360;
494 if (dh < 0) dh = -dh;
495 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
496 distance = sqrt ((dh * dh) +
497 ((s[j] - s[i]) * (s[j] - s[i])) +
498 ((v[j] - v[i]) * (v[j] - v[i])));
500 goto REPICK_THIS_COLOR;
506 /* If the average saturation or intensity are too low, repick the colors,
507 so that we don't end up with a black-and-white or too-dark map.
509 if (total_s / npoints < 0.2)
510 goto REPICK_ALL_COLORS;
511 if (total_v / npoints < 0.3)
512 goto REPICK_ALL_COLORS;
514 /* If this visual doesn't support writable cells, don't bother trying.
516 if (wanted_writable && !has_writable_cells(screen, visual))
517 *writable_pP = False;
520 make_color_path (dpy, cmap, npoints, h, s, v, colors, &ncolors,
521 allocate_p, (writable_pP && *writable_pP));
523 /* If we tried for writable cells and got none, try for non-writable. */
524 if (allocate_p && *ncolorsP == 0 && *writable_pP)
526 *writable_pP = False;
527 goto RETRY_NON_WRITABLE;
531 complain(*ncolorsP, ncolors, wanted_writable,
532 wanted_writable && *writable_pP);
539 make_uniform_colormap (Display *dpy, Visual *visual, Colormap cmap,
540 XColor *colors, int *ncolorsP,
545 int ncolors = *ncolorsP;
546 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
547 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
549 double S = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
550 double V = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
552 if (*ncolorsP <= 0) return;
554 /* If this visual doesn't support writable cells, don't bother trying. */
555 if (wanted_writable && !has_writable_cells(screen, visual))
556 *writable_pP = False;
559 make_color_ramp(dpy, cmap,
564 (writable_pP && *writable_pP));
566 /* If we tried for writable cells and got none, try for non-writable. */
567 if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
570 *writable_pP = False;
571 goto RETRY_NON_WRITABLE;
575 complain(*ncolorsP, ncolors, wanted_writable,
576 wanted_writable && *writable_pP);
583 make_random_colormap (Display *dpy, Visual *visual, Colormap cmap,
584 XColor *colors, int *ncolorsP,
590 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
591 int ncolors = *ncolorsP;
593 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
595 if (*ncolorsP <= 0) return;
597 /* If this visual doesn't support writable cells, don't bother trying. */
598 if (wanted_writable && !has_writable_cells(screen, visual))
599 *writable_pP = False;
601 for (i = 0; i < ncolors; i++)
603 colors[i].flags = DoRed|DoGreen|DoBlue;
606 int H = random() % 360; /* range 0-360 */
607 double S = ((double) (random()%70) + 30)/100.0; /* range 30%-100% */
608 double V = ((double) (random()%34) + 66)/100.0; /* range 66%-100% */
610 &colors[i].red, &colors[i].green, &colors[i].blue);
614 colors[i].red = random() % 0xFFFF;
615 colors[i].green = random() % 0xFFFF;
616 colors[i].blue = random() % 0xFFFF;
624 if (writable_pP && *writable_pP)
626 unsigned long *pixels = (unsigned long *)
627 malloc(sizeof(*pixels) * (ncolors + 1));
629 allocate_writable_colors (dpy, cmap, pixels, &ncolors);
631 for (i = 0; i < ncolors; i++)
632 colors[i].pixel = pixels[i];
635 XStoreColors (dpy, cmap, colors, ncolors);
639 for (i = 0; i < ncolors; i++)
643 if (!XAllocColor (dpy, cmap, &color))
645 colors[i].pixel = color.pixel;
650 /* If we tried for writable cells and got none, try for non-writable. */
651 if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
654 *writable_pP = False;
655 goto RETRY_NON_WRITABLE;
659 complain(*ncolorsP, ncolors, wanted_writable,
660 wanted_writable && *writable_pP);
667 rotate_colors (Display *dpy, Colormap cmap,
668 XColor *colors, int ncolors, int distance)
671 XColor *colors2 = (XColor *) malloc(sizeof(*colors2) * ncolors);
672 if (ncolors < 2) return;
673 distance = distance % ncolors;
674 for (i = 0; i < ncolors; i++)
676 int j = i - distance;
677 if (j >= ncolors) j -= ncolors;
678 if (j < 0) j += ncolors;
679 colors2[i] = colors[j];
680 colors2[i].pixel = colors[i].pixel;
682 XStoreColors (dpy, cmap, colors2, ncolors);
684 memcpy(colors, colors2, sizeof(*colors) * ncolors);