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, direction;
340 distance = h[(i+1) % npoints] - h[i];
341 direction = (distance >= 0 ? -1 : 1);
344 distance = 180 - (distance - 180);
345 else if (distance < -180)
346 distance = -(180 - ((-distance) - 180));
348 direction = -direction;
351 fprintf (stderr, "point %d: %3d %.2f %.2f\n",
352 i, h[i], s[i], v[i]);
353 fprintf(stderr, " h[i]=%d dh[i]=%.2f ncolors[i]=%d\n",
354 h[i], dh[i], ncolors[i]);
356 for (j = 0; j < ncolors[i]; j++, k++)
358 double hh = (h[i] + (j * dh[i] * direction));
359 if (hh < 0) hh += 360;
360 else if (hh > 360) hh -= 0;
361 colors[k].flags = DoRed|DoGreen|DoBlue;
364 (s[i] + (j * ds[i])),
365 (v[i] + (j * dv[i])),
366 &colors[k].red, &colors[k].green, &colors[k].blue);
368 fprintf (stderr, "point %d+%d: %.2f %.2f %.2f %04X %04X %04X\n",
371 (s[i] + (j * ds[i])),
372 (v[i] + (j * dv[i])),
373 colors[k].red, colors[k].green, colors[k].blue);
378 /* Floating-point round-off can make us decide to use fewer colors. */
391 unsigned long *pixels = (unsigned long *)
392 malloc(sizeof(*pixels) * ((*ncolorsP) + 1));
394 /* allocate_writable_colors() won't do here, because we need exactly this
395 number of cells, or the color sequence we've chosen won't fit. */
396 if (! XAllocColorCells(dpy, cmap, False, 0, 0, pixels, *ncolorsP))
402 for (i = 0; i < *ncolorsP; i++)
403 colors[i].pixel = pixels[i];
406 XStoreColors (dpy, cmap, colors, *ncolorsP);
410 for (i = 0; i < *ncolorsP; i++)
414 if (XAllocColor (dpy, cmap, &color))
416 colors[i].pixel = color.pixel;
420 free_colors (dpy, cmap, colors, i);
429 /* we weren't able to allocate all the colors we wanted;
430 decrease the requested number and try again.
432 total_ncolors = (total_ncolors > 170 ? total_ncolors - 20 :
433 total_ncolors > 100 ? total_ncolors - 10 :
434 total_ncolors > 75 ? total_ncolors - 5 :
435 total_ncolors > 25 ? total_ncolors - 3 :
436 total_ncolors > 10 ? total_ncolors - 2 :
437 total_ncolors > 2 ? total_ncolors - 1 :
439 *ncolorsP = total_ncolors;
440 if (total_ncolors > 0)
446 make_color_loop (Display *dpy, Colormap cmap,
447 int h0, double s0, double v0, /* 0-360, 0-1.0, 0-1.0 */
448 int h1, double s1, double v1, /* 0-360, 0-1.0, 0-1.0 */
449 int h2, double s2, double v2, /* 0-360, 0-1.0, 0-1.0 */
450 XColor *colors, int *ncolorsP,
456 h[0] = h0; h[1] = h1; h[2] = h2;
457 s[0] = s0; s[1] = s1; s[2] = s2;
458 v[0] = v0; v[1] = v1; v[2] = v2;
459 make_color_path(dpy, cmap,
462 allocate_p, writable_p);
467 make_smooth_colormap (Display *dpy, Visual *visual, Colormap cmap,
468 XColor *colors, int *ncolorsP,
474 int ncolors = *ncolorsP;
475 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
482 Screen *screen = (dpy ? DefaultScreenOfDisplay(dpy) : 0); /* #### WRONG! */
485 if (*ncolorsP <= 0) return;
488 int n = random() % 20;
489 if (n <= 5) npoints = 2; /* 30% of the time */
490 else if (n <= 15) npoints = 3; /* 50% of the time */
491 else if (n <= 18) npoints = 4; /* 15% of the time */
492 else npoints = 5; /* 5% of the time */
496 for (i = 0; i < npoints; i++)
499 if (++loop > 10000) abort();
500 h[i] = random() % 360;
502 v[i] = frand(0.8) + 0.2;
504 /* Make sure that no two adjascent colors are *too* close together.
505 If they are, try again.
509 int j = (i+1 == npoints) ? 0 : (i-1);
510 double hi = ((double) h[i]) / 360;
511 double hj = ((double) h[j]) / 360;
514 if (dh < 0) dh = -dh;
515 if (dh > 0.5) dh = 0.5 - (dh - 0.5);
516 distance = sqrt ((dh * dh) +
517 ((s[j] - s[i]) * (s[j] - s[i])) +
518 ((v[j] - v[i]) * (v[j] - v[i])));
520 goto REPICK_THIS_COLOR;
526 /* If the average saturation or intensity are too low, repick the colors,
527 so that we don't end up with a black-and-white or too-dark map.
529 if (total_s / npoints < 0.2)
530 goto REPICK_ALL_COLORS;
531 if (total_v / npoints < 0.3)
532 goto REPICK_ALL_COLORS;
534 /* If this visual doesn't support writable cells, don't bother trying.
536 if (wanted_writable && !has_writable_cells(screen, visual))
537 *writable_pP = False;
540 make_color_path (dpy, cmap, npoints, h, s, v, colors, &ncolors,
541 allocate_p, (writable_pP && *writable_pP));
543 /* If we tried for writable cells and got none, try for non-writable. */
544 if (allocate_p && *ncolorsP == 0 && *writable_pP)
546 *writable_pP = False;
547 goto RETRY_NON_WRITABLE;
551 complain(*ncolorsP, ncolors, wanted_writable,
552 wanted_writable && *writable_pP);
559 make_uniform_colormap (Display *dpy, Visual *visual, Colormap cmap,
560 XColor *colors, int *ncolorsP,
565 int ncolors = *ncolorsP;
566 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
567 Screen *screen = (dpy ? DefaultScreenOfDisplay(dpy) : 0); /* #### WRONG! */
569 double S = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
570 double V = ((double) (random() % 34) + 66) / 100.0; /* range 66%-100% */
572 if (*ncolorsP <= 0) return;
574 /* If this visual doesn't support writable cells, don't bother trying. */
575 if (wanted_writable && !has_writable_cells(screen, visual))
576 *writable_pP = False;
579 make_color_ramp(dpy, cmap,
584 (writable_pP && *writable_pP));
586 /* If we tried for writable cells and got none, try for non-writable. */
587 if (allocate_p && *ncolorsP == 0 && writable_pP && *writable_pP)
590 *writable_pP = False;
591 goto RETRY_NON_WRITABLE;
595 complain(*ncolorsP, ncolors, wanted_writable,
596 wanted_writable && *writable_pP);
603 make_random_colormap (Display *dpy, Visual *visual, Colormap cmap,
604 XColor *colors, int *ncolorsP,
610 Bool wanted_writable = (allocate_p && writable_pP && *writable_pP);
611 int ncolors = *ncolorsP;
613 Screen *screen = (dpy ? DefaultScreenOfDisplay(dpy) : 0); /* #### WRONG! */
615 if (*ncolorsP <= 0) return;
617 /* If this visual doesn't support writable cells, don't bother trying. */
618 if (wanted_writable && !has_writable_cells(screen, visual))
619 *writable_pP = False;
621 for (i = 0; i < ncolors; i++)
623 colors[i].flags = DoRed|DoGreen|DoBlue;
626 int H = random() % 360; /* range 0-360 */
627 double S = ((double) (random()%70) + 30)/100.0; /* range 30%-100% */
628 double V = ((double) (random()%34) + 66)/100.0; /* range 66%-100% */
630 &colors[i].red, &colors[i].green, &colors[i].blue);
634 colors[i].red = random() % 0xFFFF;
635 colors[i].green = random() % 0xFFFF;
636 colors[i].blue = random() % 0xFFFF;
644 if (writable_pP && *writable_pP)
646 unsigned long *pixels = (unsigned long *)
647 malloc(sizeof(*pixels) * (ncolors + 1));
649 allocate_writable_colors (dpy, cmap, pixels, &ncolors);
651 for (i = 0; i < ncolors; i++)
652 colors[i].pixel = pixels[i];
655 XStoreColors (dpy, cmap, colors, ncolors);
659 for (i = 0; i < ncolors; i++)
663 if (!XAllocColor (dpy, cmap, &color))
665 colors[i].pixel = color.pixel;
670 /* If we tried for writable cells and got none, try for non-writable. */
671 if (allocate_p && ncolors == 0 && writable_pP && *writable_pP)
674 *writable_pP = False;
675 goto RETRY_NON_WRITABLE;
679 complain(*ncolorsP, ncolors, wanted_writable,
680 wanted_writable && *writable_pP);
687 rotate_colors (Display *dpy, Colormap cmap,
688 XColor *colors, int ncolors, int distance)
691 XColor *colors2 = (XColor *) malloc(sizeof(*colors2) * ncolors);
692 if (ncolors < 2) return;
693 distance = distance % ncolors;
694 for (i = 0; i < ncolors; i++)
696 int j = i - distance;
697 if (j >= ncolors) j -= ncolors;
698 if (j < 0) j += ncolors;
699 colors2[i] = colors[j];
700 colors2[i].pixel = colors[i].pixel;
702 XStoreColors (dpy, cmap, colors2, ncolors);
704 memcpy(colors, colors2, sizeof(*colors) * ncolors);