1 /* xscreensaver, Copyright (c) 1997 Jamie Zawinski <jwz@netscape.com>
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)
28 unsigned long *pixels = (unsigned long *) malloc(sizeof(*pixels) * ncolors);
29 for (i = 0; i < ncolors; i++)
30 pixels[i] = colors[i].pixel;
31 XFreeColors (dpy, cmap, pixels, ncolors, 0L);
37 allocate_writable_colors (Display *dpy, Colormap cmap,
38 unsigned long *pixels, int *ncolorsP)
40 int desired = *ncolorsP;
42 int requested = desired;
43 unsigned long *new_pixels = pixels;
49 if (desired - got > requested)
50 requested = desired - got;
52 if (XAllocColorCells (dpy, cmap, False, 0, 0, new_pixels, requested))
54 /* Got all the pixels we asked for. */
55 new_pixels += requested;
60 /* We didn't get all/any of the pixels we asked for. This time, ask
61 for half as many. (If we do get all that we ask for, we ask for
62 the same number again next time, so we only do O(log(n)) server
65 requested = requested / 2;
74 make_color_ramp (Display *dpy, Colormap cmap,
75 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
76 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
77 XColor *colors, int *ncolorsP,
83 int ncolors = *ncolorsP;
84 double dh, ds, dv; /* deltas */
88 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
91 ncolors = (ncolors / 2) + 1;
93 /* Note: unlike other routines in this module, this function assumes that
94 if h1 and h2 are more than 180 degrees apart, then the desired direction
95 is always from h1 to h2 (rather than the shorter path.) make_uniform
98 dh = ((double)h2 - (double)h1) / ncolors;
99 ds = (s2 - s1) / ncolors;
100 dv = (v2 - v1) / ncolors;
102 for (i = 0; i < ncolors; i++)
104 colors[i].flags = DoRed|DoGreen|DoBlue;
105 hsv_to_rgb ((int) (h1 + (i*dh)), (s1 + (i*ds)), (v1 + (i*dv)),
106 &colors[i].red, &colors[i].green, &colors[i].blue);
110 for (i = ncolors; i < *ncolorsP; i++)
111 colors[i] = colors[(*ncolorsP)-i];
118 unsigned long *pixels = (unsigned long *)
119 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
121 /* allocate_writable_colors() won't do here, because we need exactly this
122 number of cells, or the color sequence we've chosen won't fit. */
123 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
129 for (i = 0; i < *ncolorsP; i++)
130 colors[i].pixel = pixels[i];
133 XStoreColors (dpy, cmap, colors, *ncolorsP);
137 for (i = 0; i < *ncolorsP; i++)
141 if (XAllocColor (dpy, cmap, &color))
143 colors[i].pixel = color.pixel;
147 free_colors (dpy, cmap, colors, i);
156 /* we weren't able to allocate all the colors we wanted;
157 decrease the requested number and try again.
159 ncolors = (ncolors > 170 ? ncolors - 20 :
160 ncolors > 100 ? ncolors - 10 :
161 ncolors > 75 ? ncolors - 5 :
162 ncolors > 25 ? ncolors - 3 :
163 ncolors > 10 ? ncolors - 2 :
164 ncolors > 2 ? ncolors - 1 :
172 #define MAXPOINTS 50 /* yeah, so I'm lazy */
176 make_color_path (Display *dpy, Colormap cmap,
177 int npoints, int *h, double *s, double *v,
178 XColor *colors, int *ncolorsP,
183 int total_ncolors = *ncolorsP;
185 int ncolors[MAXPOINTS]; /* number of pixels per edge */
186 double dh[MAXPOINTS]; /* distance between pixels, per edge (0 - 360.0) */
187 double ds[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
188 double dv[MAXPOINTS]; /* distance between pixels, per edge (0 - 1.0) */
195 else if (npoints == 2) /* using make_color_ramp() will be faster */
197 make_color_ramp (dpy, cmap,
198 h[0], s[0], v[0], h[1], s[1], v[1],
201 allocate_p, writable_p);
204 else if (npoints >= MAXPOINTS)
206 npoints = MAXPOINTS-1;
212 double DH[MAXPOINTS]; /* Distance between H values in the shortest
213 direction around the circle, that is, the
214 distance between 10 and 350 is 20.
215 (Range is 0 - 360.0.)
217 double edge[MAXPOINTS]; /* lengths of edges in unit HSV space. */
218 double ratio[MAXPOINTS]; /* proportions of the edges (total 1.0) */
220 double one_point_oh = 0; /* (debug) */
222 for (i = 0; i < npoints; i++)
224 int j = (i+1) % npoints;
225 double d = ((double) (h[i] - h[j])) / 360;
227 if (d > 0.5) d = 0.5 - (d - 0.5);
231 for (i = 0; i < npoints; i++)
233 int j = (i+1) % npoints;
234 edge[i] = sqrt((DH[i] * DH[j]) +
235 ((s[j] - s[i]) * (s[j] - s[i])) +
236 ((v[j] - v[i]) * (v[j] - v[i])));
241 fprintf(stderr, "\ncolors:");
242 for (i=0; i < npoints; i++)
243 fprintf(stderr, " (%d, %.3f, %.3f)", h[i], s[i], v[i]);
244 fprintf(stderr, "\nlengths:");
245 for (i=0; i < npoints; i++)
246 fprintf(stderr, " %.3f", edge[i]);
252 for (i = 0; i < npoints; i++)
254 ratio[i] = edge[i] / circum;
255 one_point_oh += ratio[i];
259 fprintf(stderr, "\nratios:");
260 for (i=0; i < npoints; i++)
261 fprintf(stderr, " %.3f", ratio[i]);
264 if (one_point_oh < 0.99999 || one_point_oh > 1.00001)
267 /* space the colors evenly along the circumference -- that means that the
268 number of pixels on a edge is proportional to the length of that edge
269 (relative to the lengths of the other edges.)
271 for (i = 0; i < npoints; i++)
272 ncolors[i] = total_ncolors * ratio[i];
276 fprintf(stderr, "\npixels:");
277 for (i=0; i < npoints; i++)
278 fprintf(stderr, " %d", ncolors[i]);
279 fprintf(stderr, " (%d)\n", total_ncolors);
282 for (i = 0; i < npoints; i++)
284 int j = (i+1) % npoints;
288 dh[i] = 360 * (DH[i] / ncolors[i]);
289 ds[i] = (s[j] - s[i]) / ncolors[i];
290 dv[i] = (v[j] - v[i]) / ncolors[i];
295 memset (colors, 0, (*ncolorsP) * sizeof(*colors));
298 for (i = 0; i < npoints; i++)
300 int distance, direction;
301 distance = h[(i+1) % npoints] - h[i];
302 direction = (distance >= 0 ? -1 : 1);
305 distance = 180 - (distance - 180);
306 else if (distance < -180)
307 distance = -(180 - ((-distance) - 180));
309 direction = -direction;
312 fprintf (stderr, "point %d: %3d %.2f %.2f\n",
313 i, h[i], s[i], v[i]);
314 fprintf(stderr, " h[i]=%d dh[i]=%.2f ncolors[i]=%d\n",
315 h[i], dh[i], ncolors[i]);
317 for (j = 0; j < ncolors[i]; j++, k++)
319 double hh = (h[i] + (j * dh[i] * direction));
320 if (hh < 0) hh += 360;
321 else if (hh > 360) hh -= 0;
322 colors[k].flags = DoRed|DoGreen|DoBlue;
325 (s[i] + (j * ds[i])),
326 (v[i] + (j * dv[i])),
327 &colors[k].red, &colors[k].green, &colors[k].blue);
329 fprintf (stderr, "point %d+%d: %.2f %.2f %.2f %04X %04X %04X\n",
332 (s[i] + (j * ds[i])),
333 (v[i] + (j * dv[i])),
334 colors[k].red, colors[k].green, colors[k].blue);
339 /* Floating-point round-off can make us decide to use fewer colors. */
352 unsigned long *pixels = (unsigned long *)
353 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
355 /* allocate_writable_colors() won't do here, because we need exactly this
356 number of cells, or the color sequence we've chosen won't fit. */
357 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
363 for (i = 0; i < *ncolorsP; i++)
364 colors[i].pixel = pixels[i];
367 XStoreColors (dpy, cmap, colors, *ncolorsP);
371 for (i = 0; i < *ncolorsP; i++)
375 if (XAllocColor (dpy, cmap, &color))
377 colors[i].pixel = color.pixel;
381 free_colors (dpy, cmap, colors, i);
390 /* we weren't able to allocate all the colors we wanted;
391 decrease the requested number and try again.
393 total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
394 total_ncolors > 100 ? total_ncolors - 10 :
395 total_ncolors > 75 ? total_ncolors - 5 :
396 total_ncolors > 25 ? total_ncolors - 3 :
397 total_ncolors > 10 ? total_ncolors - 2 :
398 total_ncolors > 2 ? total_ncolors - 1 :
400 *ncolorsP = total_ncolors;
401 if (total_ncolors > 0)
407 make_color_loop (Display *dpy, Colormap cmap,
408 int h0, double s0, double v0, /* 0-360, 0-1.0, 0-1.0 */
409 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
410 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
411 XColor *colors, int *ncolorsP,
417 h[0] = h0; h[1] = h1; h[2] = h2;
418 s[0] = s0; s[1] = s1; s[2] = s2;
419 v[0] = v0; v[1] = v1; v[2] = v2;
420 make_color_path(dpy, cmap,
423 allocate_p, writable_p);
428 complain (int wanted_colors, int got_colors,
429 Bool wanted_writable, Bool got_writable)
431 if (wanted_writable && !got_writable)
433 "%s: wanted %d writable colors; got %d read-only colors.\n",
434 progname, wanted_colors, got_colors);
436 else if (wanted_colors > (got_colors + 10))
437 /* don't bother complaining if we're within ten pixels. */
438 fprintf(stderr, "%s: wanted %d%s colors; got %d.\n",
439 progname, wanted_colors, (got_writable ? " writable" : ""),
445 make_smooth_colormap (Display *dpy, Visual *visual, Colormap cmap,
446 XColor *colors, int *ncolorsP,
452 int ncolors = *ncolorsP;
453 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
460 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
462 if (*ncolorsP <= 0) return;
465 int n = random() % 20;
466 if (n <= 5) npoints = 2; /* 30% of the time */
467 else if (n <= 15) npoints = 3; /* 50% of the time */
468 else if (n <= 18) npoints = 4; /* 15% of the time */
469 else npoints = 5; /* 5% of the time */
473 for (i = 0; i < npoints; i++)
476 h[i] = random() % 360;
478 v[i] = frand(0.8) + 0.2;
480 /* Make sure that no two adjascent colors are *too* close together.
481 If they are, try again.
485 int j = (i+1 == npoints) ? 0 : (i-1);
486 double hi = ((double) h[i]) / 360;
487 double hj = ((double) h[j]) / 360;
490 if (dh < 0) dh = -dh;
491 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
492 distance = sqrt ((dh * dh) +
493 ((s[j] - s[i]) * (s[j] - v[i])) +
494 ((v[j] - v[i]) * (v[j] - v[i])));
496 goto REPICK_THIS_COLOR;
502 /* If the average saturation or intensity are too low, repick the colors,
503 so that we don't end up with a black-and-white or too-dark map.
505 if (total_s / npoints < 0.2)
506 goto REPICK_ALL_COLORS;
507 if (total_v / npoints < 0.3)
508 goto REPICK_ALL_COLORS;
510 /* If this visual doesn't support writable cells, don't bother trying.
512 if (wanted_writable && !has_writable_cells(screen, visual))
513 *writable_pP = False;
516 make_color_path (dpy, cmap, npoints, h, s, v, colors, &ncolors,
517 allocate_p, (writable_pP && *writable_pP));
519 /* If we tried for writable cells and got none, try for non-writable. */
520 if (allocate_p && *ncolorsP == 0 && *writable_pP)
522 *writable_pP = False;
523 goto RETRY_NON_WRITABLE;
527 complain(*ncolorsP, ncolors, wanted_writable,
528 wanted_writable && *writable_pP);
535 make_uniform_colormap (Display *dpy, Visual *visual, Colormap cmap,
536 XColor *colors, int *ncolorsP,
541 int ncolors = *ncolorsP;
542 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
543 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
545 double S = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
546 double V = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
548 if (*ncolorsP <= 0) return;
550 /* If this visual doesn't support writable cells, don't bother trying. */
551 if (wanted_writable && !has_writable_cells(screen, visual))
552 *writable_pP = False;
555 make_color_ramp(dpy, cmap,
559 False, True, wanted_writable);
561 /* If we tried for writable cells and got none, try for non-writable. */
562 if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
565 *writable_pP = False;
566 goto RETRY_NON_WRITABLE;
570 complain(*ncolorsP, ncolors, wanted_writable,
571 wanted_writable && *writable_pP);
578 make_random_colormap (Display *dpy, Visual *visual, Colormap cmap,
579 XColor *colors, int *ncolorsP,
585 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
586 int ncolors = *ncolorsP;
588 Screen *screen = DefaultScreenOfDisplay(dpy); /* #### WRONG! */
590 if (*ncolorsP <= 0) return;
592 /* If this visual doesn't support writable cells, don't bother trying. */
593 if (wanted_writable && !has_writable_cells(screen, visual))
594 *writable_pP = False;
596 for (i = 0; i < ncolors; i++)
598 colors[i].flags = DoRed|DoGreen|DoBlue;
601 int H = random() % 360; /* range 0-360 */
602 double S = ((double) (random()%70) + 30)/100.0; /* range 30%-100% */
603 double V = ((double) (random()%34) + 66)/100.0; /* range 66%-100% */
605 &colors[i].red, &colors[i].green, &colors[i].blue);
609 colors[i].red = random() % 0xFFFF;
610 colors[i].green = random() % 0xFFFF;
611 colors[i].blue = random() % 0xFFFF;
619 if (writable_pP && *writable_pP)
621 unsigned long *pixels = (unsigned long *)
622 malloc(sizeof(*pixels) * (ncolors + 1));
624 allocate_writable_colors (dpy, cmap, pixels, &ncolors);
626 for (i = 0; i < ncolors; i++)
627 colors[i].pixel = pixels[i];
630 XStoreColors (dpy, cmap, colors, ncolors);
634 for (i = 0; i < ncolors; i++)
638 if (!XAllocColor (dpy, cmap, &color))
640 colors[i].pixel = color.pixel;
645 /* If we tried for writable cells and got none, try for non-writable. */
646 if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
649 *writable_pP = False;
650 goto RETRY_NON_WRITABLE;
654 complain(*ncolorsP, ncolors, wanted_writable,
655 wanted_writable && *writable_pP);
662 rotate_colors (Display *dpy, Colormap cmap,
663 XColor *colors, int ncolors, int distance)
666 XColor *colors2 = (XColor *) malloc(sizeof(*colors2) * ncolors);
667 if (ncolors < 2) return;
668 distance = distance % ncolors;
669 for (i = 0; i < ncolors; i++)
671 int j = i - distance;
672 if (j >= ncolors) j -= ncolors;
673 if (j < 0) j += ncolors;
674 colors2[i] = colors[j];
675 colors2[i].pixel = colors[i].pixel;
677 XStoreColors (dpy, cmap, colors2, ncolors);
679 memcpy(colors, colors2, sizeof(*colors) * ncolors);