1 /* $Id: colors.c,v 5.1 2001/05/08 11:35:29 bertg Exp $
2  *
3  * XPilot, a multiplayer gravity war game.  Copyright (C) 1991-2001 by
4  *
5  *      Bj�rn Stabell        <bjoern@xpilot.org>
6  *      Ken Ronny Schouten   <ken@xpilot.org>
7  *      Bert Gijsbers        <bert@xpilot.org>
8  *      Dick Balaska         <dick@xpilot.org>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24 
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <ctype.h>
28 #include <string.h>
29 #include <errno.h>
30 #include <sys/types.h>
31 
32 #ifndef _WINDOWS
33 # include <unistd.h>
34 # include <X11/Xlib.h>
35 # include <X11/Xos.h>
36 # include <X11/Xutil.h>
37 #endif
38 
39 #ifdef _WINDOWS
40 # include "NT/winX.h"
41 #endif
42 
43 #include "version.h"
44 #include "config.h"
45 #include "const.h"
46 #include "types.h"
47 #include "paint.h"
48 #include "xinit.h"
49 #include "error.h"
50 #include "dbuff.h"
51 #include "protoclient.h"
52 
53 
54 char colors_version[] = VERSION;
55 
56 
57 /* Kludge for visuals under C++ */
58 #if defined(__cplusplus)
59 #define class c_class
60 #endif
61 
62 
63 /*
64  * The number of X11 visuals.
65  */
66 #define MAX_VISUAL_CLASS	6
67 
68 
69 /*
70  * Default colors.
71  */
72 char			color_names[MAX_COLORS][MAX_COLOR_LEN];
73 static const char	*color_defaults[MAX_COLORS] = {
74     "#000000", "#FFFFFF", "#4E7CFF", "#FF3A27",
75     "#33BB44", "#992200", "#BB7700", "#EE9900",
76     "#770000", "#CC4400", "#DD8800", "#FFBB11",
77     "#9f9f9f", "#5f5f5f", "#dfdfdf", "#202020"
78 };
79 static const char	*gray_defaults[MAX_COLORS] = {
80     "#000000", "#FFFFFF", "#AAAAAA", "#CCCCCC",
81     "#BBBBBB", "#888888", "#AAAAAA", "#CCCCCC",
82     "#777777", "#999999", "#BBBBBB", "#DDDDDD",
83     "#9f9f9f", "#5f5f5f", "#dfdfdf", "#202020"
84 };
85 
86 char		visualName[MAX_VISUAL_NAME];
87 Visual		*visual;
88 int		dispDepth;
89 bool		mono;
90 bool		colorSwitch;
91 bool		multibuffer;
92 bool		blockBitmaps;		/* Whether to draw everything as bitmaps. */
93 
94 #ifndef _WINDOWS
95 
96 /*
97  * Dimensions of color cubes in decreasing
98  * total number of colors used.
99  */
100 static struct rgb_cube_size {
101     unsigned char	r, g, b;
102 } rgb_cube_sizes[] = {
103     { 6, 6, 5 },	/* 180 */
104     { 5, 6, 5 },	/* 150 */
105     { 6, 6, 4 },	/* 144 */
106     { 5, 5, 5 },	/* 125 */
107     { 5, 6, 4 },	/* 120 */
108     { 6, 6, 3 },	/* 108 */
109     { 5, 5, 4 },	/* 100 */
110     { 5, 6, 3 },	/* 90 */
111     { 4, 5, 4 },	/* 80 */
112     { 5, 5, 3 },	/* 75 */
113     { 4, 4, 4 },	/* 64 */
114     { 4, 5, 3 },	/* 60 */
115     { 4, 4, 3 },	/* 48 */
116 };
117 
118 unsigned long		(*RGB)(u_byte r, u_byte g, u_byte b);
119 static unsigned long	RGB_PC(u_byte r, u_byte g, u_byte b);
120 static unsigned long	RGB_TC(u_byte r, u_byte g, u_byte b);
121 
122 /*
123  * Visual names.
124  */
125 static struct Visual_class_name {
126     int		visual_class;
127     const char	*visual_name;
128 } visual_class_names[MAX_VISUAL_CLASS] = {
129     { StaticGray,	"StaticGray"  },
130     { GrayScale,	"GrayScale"   },
131     { StaticColor,	"StaticColor" },
132     { PseudoColor,	"PseudoColor" },
133     { TrueColor,	"TrueColor"   },
134     { DirectColor,	"DirectColor" }
135 };
136 
137 /*
138  * Structure to hold pixel information
139  * for a color cube for PseudoColor visuals.
140  */
141 struct Color_cube {
142     int				reds;
143     int				greens;
144     int				blues;
145     int				mustfree;
146     unsigned long		pixels[256];
147 };
148 static struct Color_cube	*color_cube;
149 
150 /*
151  * Structure to hold pixel information
152  * for a true color visual.
153  */
154 struct True_color {
155     unsigned long		red_bits[256];
156     unsigned long		green_bits[256];
157     unsigned long		blue_bits[256];
158 };
159 static struct True_color	*true_color;
160 
161 static void Colors_init_radar_hack(void);
162 static int  Colors_init_color_cube(void);
163 static int  Colors_init_true_color(void);
164 
165 /*
166  * Create a private colormap.
167  */
Get_colormap(void)168 static void Get_colormap(void)
169 {
170     printf("Creating a private colormap\n");
171     colormap = XCreateColormap(dpy, DefaultRootWindow(dpy),
172 			       visual, AllocNone);
173 }
174 
175 
176 /*
177  * Convert a visual class to its name.
178  */
Visual_class_name(int visual_class)179 static const char *Visual_class_name(int visual_class)
180 {
181     int			i;
182 
183     for (i = 0; i < MAX_VISUAL_CLASS; i++) {
184 	if (visual_class_names[i].visual_class == visual_class) {
185 	    return visual_class_names[i].visual_name;
186 	}
187     }
188     return "UnknownVisual";
189 }
190 
191 
192 /*
193  * List the available visuals for the default screen.
194  */
List_visuals(void)195 void List_visuals(void)
196 {
197     int				i,
198 				num;
199     XVisualInfo			*vinfo_ptr,
200 				my_vinfo;
201     long			mask;
202 
203     num = 0;
204     mask = 0;
205     my_vinfo.screen = DefaultScreen(dpy);
206     mask |= VisualScreenMask;
207     vinfo_ptr = XGetVisualInfo(dpy, mask, &my_vinfo, &num);
208     printf("Listing all visuals:\n");
209     for (i = 0; i < num; i++) {
210 	printf("Visual class    %12s\n",
211 	       Visual_class_name(vinfo_ptr[i].class));
212 	printf("    id                  0x%02x\n", (unsigned)vinfo_ptr[i].visualid);
213 	printf("    screen          %8d\n", vinfo_ptr[i].screen);
214 	printf("    depth           %8d\n", vinfo_ptr[i].depth);
215 	printf("    red_mask        0x%06x\n", (unsigned)vinfo_ptr[i].red_mask);
216 	printf("    green_mask      0x%06x\n", (unsigned)vinfo_ptr[i].green_mask);
217 	printf("    blue_mask       0x%06x\n", (unsigned)vinfo_ptr[i].blue_mask);
218 	printf("    colormap_size   %8d\n", vinfo_ptr[i].colormap_size);
219 	printf("    bits_per_rgb    %8d\n", vinfo_ptr[i].bits_per_rgb);
220     }
221     XFree((void *) vinfo_ptr);
222 
223 #ifdef DEVELOPMENT
224     dbuff_list(dpy);
225 #endif
226 }
227 
228 
229 /*
230  * Support all available visuals.
231  */
Choose_visual(void)232 static void Choose_visual(void)
233 {
234     int				i,
235 				num,
236 				best_size,
237 				cmap_size,
238 				using_default,
239 				visual_id,
240 				visual_class;
241     XVisualInfo			*vinfo_ptr,
242 				my_vinfo,
243 				*best_vinfo;
244     long			mask;
245 
246     visual_id = -1;
247     visual_class = -1;
248     if (visualName[0] != '\0') {
249 	if (strncmp(visualName, "0x", 2) == 0) {
250 	    if (sscanf(visualName, "%x", &visual_id) < 1) {
251 		errno = 0;
252 		error("Bad visual id \"%s\", using default\n", visualName);
253 		visual_id = -1;
254 	    }
255 	} else {
256 	    for (i = 0; i < MAX_VISUAL_CLASS; i++) {
257 		if (strncasecmp(visualName, visual_class_names[i].visual_name,
258 				strlen(visual_class_names[i].visual_name))
259 				== 0) {
260 		    visual_class = visual_class_names[i].visual_class;
261 		    break;
262 		}
263 	    }
264 	    if (visual_class == -1) {
265 		errno = 0;
266 		error("Unknown visual class named \"%s\", using default\n",
267 		    visualName);
268 	    }
269 	}
270     }
271     if (visual_class < 0 && visual_id < 0) {
272 	visual = DefaultVisual(dpy, DefaultScreen(dpy));
273 	if (visual->class == TrueColor || visual->class == DirectColor) {
274 	    visual_class = PseudoColor;
275 	    strcpy(visualName, "PseudoColor");
276 	}
277 	using_default = true;
278     } else {
279 	using_default = false;
280     }
281     if (visual_class >= 0 || visual_id >= 0) {
282 	mask = 0;
283 	my_vinfo.screen = DefaultScreen(dpy);
284 	mask |= VisualScreenMask;
285 	if (visual_class >= 0) {
286 	    my_vinfo.class = visual_class;
287 	    mask |= VisualClassMask;
288 	}
289 	if (visual_id >= 0) {
290 	    my_vinfo.visualid = visual_id;
291 	    mask |= VisualIDMask;
292 	}
293 	num = 0;
294 	if ((vinfo_ptr = XGetVisualInfo(dpy, mask, &my_vinfo, &num)) == NULL
295 	    || num <= 0) {
296 	    if (using_default == false) {
297 		errno = 0;
298 		error("No visuals available with class name \"%s\", using default",
299 		    visualName);
300 	    }
301 	    visual_class = -1;
302 	}
303 	else {
304 	    best_vinfo = vinfo_ptr;
305 	    for (i = 1; i < num; i++) {
306 		best_size = best_vinfo->colormap_size;
307 		cmap_size = vinfo_ptr[i].colormap_size;
308 		if (cmap_size > best_size) {
309 		    if (best_size < 256) {
310 			best_vinfo = &vinfo_ptr[i];
311 		    }
312 		}
313 		else if (cmap_size >= 256) {
314 		    best_vinfo = &vinfo_ptr[i];
315 		}
316 	    }
317 	    visual = best_vinfo->visual;
318 	    visual_class = best_vinfo->class;
319 	    dispDepth = best_vinfo->depth;
320 	    XFree((void *) vinfo_ptr);
321 	    printf("Using visual %s with depth %d and %d colors\n",
322 		   Visual_class_name(visual->class), dispDepth,
323 		   visual->map_entries);
324 	    Get_colormap();
325 	}
326     }
327     if (visual_class < 0) {
328 	visual = DefaultVisual(dpy, DefaultScreen(dpy));
329 	dispDepth = DefaultDepth(dpy, DefaultScreen(dpy));
330 	colormap = 0;
331     }
332 }
333 
334 
335 /*
336  * Parse the user configurable color definitions.
337  */
Parse_colors(Colormap cmap)338 static int Parse_colors(Colormap cmap)
339 {
340     int			i;
341     const char		**def;
342 
343     /*
344      * Get the color definitions.
345      */
346     if (mono == true) {
347 	colors[0].red = colors[0].green = colors[0].blue = 0;
348 	colors[0].flags = DoRed | DoGreen | DoBlue;
349 	colors[1].red = colors[1].green = colors[1].blue = 0xFFFF;
350 	colors[1].flags = DoRed | DoGreen | DoBlue;
351 	colors[2] = colors[1];
352 	colors[3] = colors[1];
353 	return 0;
354     }
355 
356     if (visual->class == StaticGray || visual->class == GrayScale) {
357 	def = &gray_defaults[0];
358     } else {
359 	def = &color_defaults[0];
360     }
361     for (i = 0; i < maxColors; i++) {
362 	if (color_names[i][0] != '\0') {
363 	    if (XParseColor(dpy, cmap, color_names[i], &colors[i])) {
364 		continue;
365 	    }
366 	    printf("Can't parse color %d \"%s\"\n", i, color_names[i]);
367 	}
368 	if (def[i] != NULL && def[i][0] != '\0') {
369 	    if (XParseColor(dpy, cmap, def[i], &colors[i])) {
370 		continue;
371 	    }
372 	    printf("Can't parse default color %d \"%s\"\n", i, def[i]);
373 	}
374 	if (i < NUM_COLORS) {
375 	    return -1;
376 	} else {
377 	    colors[i] = colors[i % NUM_COLORS];
378 	}
379     }
380     return 0;
381 }
382 
383 
384 /*
385  * If we have a private colormap and color switching is on then
386  * copy the first few colors from the default colormap into it
387  * to prevent ugly color effects on the rest of the screen.
388  */
Fill_colormap(void)389 static void Fill_colormap(void)
390 {
391     int			i,
392 			cells_needed,
393 			max_fill;
394     unsigned long	pixels[256];
395     XColor		mycolors[256];
396 
397     if (colormap == 0 || colorSwitch != true) {
398 	return;
399     }
400     cells_needed = (maxColors == 16) ? 256
401 	: (maxColors == 8) ? 64
402 	: 16;
403     max_fill = MAX(256, visual->map_entries) - cells_needed;
404     if (max_fill <= 0) {
405 	return;
406     }
407 
408     if (XAllocColorCells(dpy, colormap,
409 			 False, NULL,
410 			 0, pixels, max_fill) == False) {
411 	errno = 0;
412 	error("Can't pre-alloc color cells");
413 	return;
414     }
415 
416     /* Check for misunderstanding of X colormap stuff. */
417     for (i = 0; i < max_fill; i++) {
418 	if (i != (int) pixels[i]) {
419 #ifdef DEVELOPMENT
420 	    errno = 0;
421 	    error("Can't pre-fill color map, got %d'th pixel %lu",
422 		  i, pixels[i]);
423 #endif
424 	    XFreeColors(dpy, colormap, pixels, max_fill, 0);
425 	    return;
426 	}
427     }
428     for (i = 0; i < max_fill; i++) {
429 	mycolors[i].pixel = pixels[i];
430     }
431     XQueryColors(dpy, DefaultColormap(dpy, DefaultScreen(dpy)),
432 		 mycolors, max_fill);
433     XStoreColors(dpy, colormap, mycolors, max_fill);
434 }
435 
436 
437 /*
438  * Setup color and double buffering resources.
439  * It returns 0 if the initialization was successful,
440  * or -1 if it couldn't initialize the double buffering routine.
441  */
Colors_init(void)442 int Colors_init(void)
443 {
444     int				i, num_planes;
445 
446     colormap = 0;
447 
448     Choose_visual();
449 
450     /*
451      * Get misc. display info.
452      */
453     if (visual->class == StaticGray ||
454 	visual->class == StaticColor ||
455 	visual->class == TrueColor) {
456 	colorSwitch = false;
457     }
458     if (visual->map_entries < 16) {
459 	colorSwitch = false;
460 	if (visual->map_entries < 4) {
461 	    mono = true;
462 	}
463     }
464     if (mono == true) {
465 	colorSwitch = false;
466 	maxColors = 4;
467     }
468     else if (colorSwitch == true) {
469 	maxColors = (maxColors >= 16 && visual->map_entries >= 256) ? 16
470 	    : (maxColors >= 8 && visual->map_entries >= 64) ? 8
471 	    : 4;
472     }
473     else {
474 	maxColors = (maxColors >= 16 && visual->map_entries >= 16) ? 16
475 	    : (maxColors >= 8 && visual->map_entries >= 8) ? 8
476 	    : 4;
477     }
478     num_planes = (mono == true) ? 1
479 	: (maxColors == 16) ? 4
480 	: (maxColors == 8) ? 3
481 	: 2;
482 
483     if (Parse_colors(DefaultColormap(dpy, DefaultScreen(dpy))) == -1) {
484 	printf("Color parsing failed\n");
485 	return -1;
486     }
487 
488     if (colormap != 0) {
489 	Fill_colormap();
490     }
491 
492     /*
493      * Initialize the double buffering routine.
494      */
495     dbuf_state = NULL;
496 
497     if (multibuffer) {
498 	dbuf_state = start_dbuff(dpy,
499 				 (colormap != 0)
500 				     ? colormap
501 				     : DefaultColormap(dpy,
502 						       DefaultScreen(dpy)),
503 				 MULTIBUFFER,
504 				 num_planes,
505 				 colors);
506     }
507     if (dbuf_state == NULL) {
508 	dbuf_state = start_dbuff(dpy,
509 				 (colormap != 0)
510 				     ? colormap
511 				     : DefaultColormap(dpy,
512 						       DefaultScreen(dpy)),
513 				 ((colorSwitch) ? COLOR_SWITCH : PIXMAP_COPY),
514 				 num_planes,
515 				 colors);
516     }
517     if (dbuf_state == NULL && colormap == 0) {
518 
519 	/*
520 	 * Create a private colormap if we can't allocate enough colors.
521 	 */
522 	Get_colormap();
523 	Fill_colormap();
524 
525 	/*
526 	 * Try to initialize the double buffering again.
527 	 */
528 
529 	if (multibuffer) {
530 	    dbuf_state = start_dbuff(dpy, colormap,
531 				     MULTIBUFFER,
532 				     num_planes,
533 				     colors);
534 	}
535 
536 	if (dbuf_state == NULL) {
537 	    dbuf_state = start_dbuff(dpy, colormap,
538 				     ((colorSwitch) ? COLOR_SWITCH : PIXMAP_COPY),
539 				     num_planes,
540 				     colors);
541 	}
542     }
543 
544     if (dbuf_state == NULL) {
545 	/* Can't setup double buffering */
546 	errno = 0;
547 	error("Can't setup colors with visual %s and %d colormap entries",
548 	      Visual_class_name(visual->class), visual->map_entries);
549 	return -1;
550     }
551 
552     switch (dbuf_state->type) {
553     case COLOR_SWITCH:
554 	printf("Using color switching\n");
555 	break;
556 
557     case PIXMAP_COPY:
558 	printf("Using pixmap copying\n");
559 	break;
560 
561     case MULTIBUFFER:
562 #ifdef	DBE
563 	printf("Using double-buffering\n");
564 	break;
565 #else
566 #ifdef	MBX
567 	printf("Using multi-buffering\n");
568 	break;
569 #endif
570 #endif
571 
572     default:
573 	printf("Unknown dbuf state %d\n", dbuf_state->type);
574 	exit(1);
575     }
576 
577     for (i = maxColors; i < MAX_COLORS; i++) {
578 	colors[i] = colors[i % maxColors];
579     }
580 
581     Colors_init_radar_hack();
582 
583     Colors_init_block_bitmaps();
584 
585     return 0;
586 }
587 
588 
589 /*
590  * A little hack that enables us to draw on both sets of double buffering
591  * planes at once.
592  */
Colors_init_radar_hack(void)593 static void Colors_init_radar_hack(void)
594 {
595     int				i, p;
596 
597     for (p = 0; p < 2; p++) {
598 	int num = 0;
599 
600 	dpl_1[p] = dpl_2[p] = 0;
601 
602 	for (i = 0; i < 32; i++) {
603 	    if (!((1 << i) & dbuf_state->drawing_plane_masks[p])) {
604 	        num++;
605 		if (num == 1 || num == 3) {
606 		    dpl_1[p] |= 1<<i;   /* planes with moving radar objects */
607 		}
608 		else {
609 		    dpl_2[p] |= 1<<i;   /* constant map part of radar */
610 		}
611 	    }
612 	}
613     }
614 }
615 
616 
617 /*
618  * Setup color structures for use with drawing bitmaps.
619  *
620  * on error return -1,
621  * on success return 0.
622  */
Colors_init_block_bitmap_colors(void)623 static int Colors_init_block_bitmap_colors(void)
624 {
625     int r = -1;
626 
627     switch (visual->class) {
628     case PseudoColor:
629 	r = Colors_init_color_cube();
630 	break;
631 
632     case DirectColor:
633 	/*
634 	 * I don't really understand the difference between
635 	 * DirectColor and TrueColor.  Let's test if we can
636 	 * consider DirectColor to be similar to TrueColor.
637 	 */
638 	/*FALLTHROUGH*/
639 
640     case StaticColor:
641     case TrueColor:
642 	r = Colors_init_true_color();
643 	break;
644 
645     case GrayScale:
646     case StaticGray:
647 	/*
648 	 * Haven't implemented implemented bitmaps for gray colors yet.
649 	 */
650 	/*FALLTHROUGH*/
651 
652     default:
653 	printf("blockBitmaps not implemented for visual \"%s\"\n",
654 		Visual_class_name(visual->class));
655 	blockBitmaps = false;
656 	break;
657     }
658 
659     return r;
660 }
661 
662 
663 /*
664  * See if we can use block bitmaps.
665  * If we can then setup the colors
666  * and allocate the bitmaps.
667  *
668  * on error return -1,
669  * on success return 0.
670  */
Colors_init_block_bitmaps(void)671 int Colors_init_block_bitmaps(void)
672 {
673     if (dbuf_state->type == COLOR_SWITCH) {
674 	if (blockBitmaps) {
675 	    printf("Can't do blockBitmaps if colorSwitch\n");
676 	    blockBitmaps = false;
677 	}
678     }
679     if (blockBitmaps) {
680 	if (Colors_init_block_bitmap_colors() == -1) {
681 	    blockBitmaps = false;
682 	}
683     }
684     if (blockBitmaps) {
685 	if (Block_bitmaps_create() == -1) {
686 	    /*
687 	    ** not sure if this is possible after
688 	    ** blockbitmap colors have been created.
689 	    */
690 	    blockBitmaps = false;
691 	}
692     }
693 
694     return (blockBitmaps == true) ? 0 : -1;
695 }
696 
697 
698 /*
699  * Calculate a pixel from a RGB triplet for a PseudoColor visual.
700  */
RGB_PC(u_byte r,u_byte g,u_byte b)701 static unsigned long RGB_PC(u_byte r, u_byte g, u_byte b)
702 {
703     int			i;
704 
705     r = (r * color_cube->reds) >> 8;
706     g = (g * color_cube->greens) >> 8;
707     b = (b * color_cube->blues) >> 8;
708     i = (((r * color_cube->greens) + g) * color_cube->blues) + b;
709 
710     return color_cube->pixels[i];
711 }
712 
713 
714 /*
715  * Calculate a pixel from a RGB triplet for a TrueColor visual.
716  */
RGB_TC(u_byte r,u_byte g,u_byte b)717 static unsigned long RGB_TC(u_byte r, u_byte g, u_byte b)
718 {
719     unsigned long	pixel = 0;
720 
721     pixel |= true_color->red_bits[r];
722     pixel |= true_color->green_bits[g];
723     pixel |= true_color->blue_bits[b];
724 
725     return pixel;
726 }
727 
728 
729 /*
730  * Fill a color cube.
731  *
732  * Simple implementation for now.
733  * Make it more ambitious wrt. read-only cells later.
734  *
735  * Two ways to allocate colors for a RGB cube.
736  * One is to use the outer edges and sides for colors.
737  * Another is to divide the cube in r*g*b sub-cubes and
738  * choose the color in the centre of each sub-cube.
739  * The latter option looks better because it will most
740  * likely result in better color matches with on average
741  * less color distance.
742  */
Fill_color_cube(int reds,int greens,int blues,XColor colors[256])743 static void Fill_color_cube(int reds, int greens, int blues,
744 			    XColor colors[256])
745 {
746     int			i, r, g, b;
747 
748     i = 0;
749     for (r = 0; r < reds; r++) {
750 	for (g = 0; g < greens; g++) {
751 	    for (b = 0; b < blues; b++, i++) {
752 		colors[i].pixel = color_cube->pixels[i];
753 		colors[i].flags = DoRed | DoGreen | DoBlue;
754 		colors[i].red   = (((r * 256) + 128) / reds) * 0x101;
755 		colors[i].green = (((g * 256) + 128) / greens) * 0x101;
756 		colors[i].blue  = (((b * 256) + 128) / blues) * 0x101;
757 	    }
758 	}
759     }
760 
761     color_cube->reds = reds;
762     color_cube->greens = greens;
763     color_cube->blues = blues;
764 }
765 
766 
767 /*
768  * Allocate a color cube.
769  *
770  * Simple implementation for now.
771  * Make it more ambitious wrt. read-only cells later.
772  */
Colors_init_color_cube(void)773 static int Colors_init_color_cube(void)
774 {
775     int			i, n, r, g, b;
776     XColor		colors[256];
777 
778     if (color_cube != NULL) {
779 	error("Already a cube!\n");
780 	exit(1);
781     }
782 
783     color_cube = (struct Color_cube *) calloc(1, sizeof(struct Color_cube));
784     if (!color_cube) {
785 	error("Could not allocate memory for a color cube");
786 	return -1;
787     }
788     for (i = 0; i < NELEM(rgb_cube_sizes); i++) {
789 
790 	r = rgb_cube_sizes[i].r;
791 	g = rgb_cube_sizes[i].g;
792 	b = rgb_cube_sizes[i].b;
793 	n = r * g * b;
794 
795 	if (XAllocColorCells(dpy,
796 			     (colormap != 0)
797 				 ? colormap
798 				 : DefaultColormap(dpy,
799 						   DefaultScreen(dpy)),
800 			     False, NULL, 0,
801 			     &color_cube->pixels[0],
802 			     n) == False) {
803 	    /*printf("Could not alloc %d colors for RGB cube\n", n);*/
804 	    continue;
805 	}
806 
807 	printf("Got %d colors for a %d*%d*%d RGB cube\n",
808 		n, r, g, b);
809 
810 	color_cube->mustfree = 1;
811 
812 	Fill_color_cube(r, g, b, &colors[0]);
813 
814 	XStoreColors(dpy,
815 		     (colormap != 0)
816 			 ? colormap
817 			 : DefaultColormap(dpy,
818 					   DefaultScreen(dpy)),
819 		     colors,
820 		     n);
821 
822 	RGB = RGB_PC;
823 
824 	return 0;
825     }
826 
827     printf("Could not alloc colors for RGB cube\n");
828 
829     return -1;
830 }
831 
832 
833 /*
834  * Free our color cube.
835  */
Colors_free_color_cube(void)836 static void Colors_free_color_cube(void)
837 {
838     if (color_cube) {
839 	if (color_cube->mustfree) {
840 	    XFreeColors(dpy,
841 			(colormap != 0)
842 			    ? colormap
843 			    : DefaultColormap(dpy,
844 					      DefaultScreen(dpy)),
845 			&color_cube->pixels[0],
846 			color_cube->reds * color_cube->greens * color_cube->blues,
847 			0);
848 	    color_cube->mustfree = 0;
849 	}
850 	free(color_cube);
851 	color_cube = NULL;
852 	RGB = NULL;
853     }
854 }
855 
856 
857 /*
858  * Allocate and initialize a true color structure.
859  */
Colors_init_true_color(void)860 static int Colors_init_true_color(void)
861 {
862     int			i, j, r, g, b;
863 
864     if ((visual->red_mask == 0) ||
865 	(visual->green_mask == 0) ||
866 	(visual->blue_mask == 0) ||
867 	((visual->red_mask &
868 	  visual->green_mask &
869 	  visual->blue_mask) != 0)) {
870 
871 	printf("Your visual \"%s\" has weird characteristics:\n",
872 		Visual_class_name(visual->class));
873 	printf("\tred mask 0x%06lx, green mask 0x%06lx, blue mask 0x%06lx,\n",
874 		visual->red_mask, visual->green_mask, visual->blue_mask);
875 	printf("\toverlap mask 0x%06lx\n",
876 		visual->red_mask & visual->green_mask & visual->blue_mask);
877 	return -1;
878     }
879 
880     if (true_color) {
881 	error("Already a True_color!");
882 	exit(1);
883     }
884 
885     true_color = (struct True_color *) calloc(1, sizeof(struct True_color));
886     if (!true_color) {
887 	error("Could not allocate memory for a true color structure");
888 	return -1;
889     }
890 
891     r = 7;
892     g = 7;
893     b = 7;
894     for (i = 31; i >= 0; --i) {
895 	if ((visual->red_mask & (1UL << i)) != 0) {
896 	    if (r >= 0) {
897 		for (j = 0; j < 256; j++) {
898 		    if (j & (1 << r)) {
899 			true_color->red_bits[j] |= (1UL << i);
900 		    }
901 		}
902 		r--;
903 	    }
904 	}
905 	if ((visual->green_mask & (1UL << i)) != 0) {
906 	    if (g >= 0) {
907 		for (j = 0; j < 256; j++) {
908 		    if (j & (1 << g)) {
909 			true_color->green_bits[j] |= (1UL << i);
910 		    }
911 		}
912 		g--;
913 	    }
914 	}
915 	if ((visual->blue_mask & (1UL << i)) != 0) {
916 	    if (b >= 0) {
917 		for (j = 0; j < 256; j++) {
918 		    if (j & (1 << b)) {
919 			true_color->blue_bits[j] |= (1UL << i);
920 		    }
921 		}
922 		b--;
923 	    }
924 	}
925     }
926 
927     RGB = RGB_TC;
928 
929     return 0;
930 }
931 
932 
933 /*
934  * Free a true color structure.
935  */
Colors_free_true_color(void)936 static void Colors_free_true_color(void)
937 {
938     if (true_color) {
939 	free(true_color);
940 	true_color = NULL;
941 	RGB = NULL;
942     }
943 }
944 
945 
946 /*
947  * Deallocate everything related to colors.
948  */
Colors_free_block_bitmaps(void)949 void Colors_free_block_bitmaps(void)
950 {
951     Colors_free_color_cube();
952     Colors_free_true_color();
953 
954     if (blockBitmaps) {
955 
956 	blockBitmaps = false;
957     }
958 }
959 
960 
961 /*
962  * Deallocate everything related to colors.
963  */
Colors_cleanup(void)964 void Colors_cleanup(void)
965 {
966     Colors_free_block_bitmaps();
967 
968     if (dbuf_state) {
969 	end_dbuff(dbuf_state);
970 	dbuf_state = NULL;
971     }
972     if (colormap) {
973 	XFreeColormap(dpy, colormap);
974 	colormap = 0;
975     }
976 }
977 
978 
979 #ifdef DEVELOPMENT
Colors_debug(void)980 void Colors_debug(void)
981 {
982     int			i, n, r, g, b;
983     XColor		colors[256];
984     FILE		*fp = fopen("rgb", "w");
985 
986     if (!color_cube) {
987 	static struct Color_cube cc;
988 	color_cube = &cc;
989 	for (i = 0; i < 256; i++) {
990 	    cc.pixels[i] = i;
991 	}
992     }
993 
994     for (i = 0; i < NELEM(rgb_cube_sizes); i++) {
995 
996 	r = rgb_cube_sizes[i].r;
997 	g = rgb_cube_sizes[i].g;
998 	b = rgb_cube_sizes[i].b;
999 	n = r * g * b;
1000 
1001 	Fill_color_cube(r, g, b, colors);
1002 
1003 	fprintf(fp, "\n\n  RGB  %d %d %d\n\n", r, g, b);
1004 	i = 0;
1005 	for (r = 0; r < color_cube->reds; r++) {
1006 	    for (g = 0; g < color_cube->greens; g++) {
1007 		for (b = 0; b < color_cube->blues; b++, i++) {
1008 		    fprintf(fp, "color %4d    %04X  %04X  %04X\n",
1009 			    i, colors[i].red, colors[i].green, colors[i].blue);
1010 		}
1011 	    }
1012 	}
1013 	fprintf(fp, "\nblack %3lu\nwhite %3lu\nred   %3lu\ngreen %3lu\nblue  %3lu\n",
1014 		RGB_PC(0, 0, 0),
1015 		RGB_PC(255, 255, 255),
1016 		RGB_PC(255, 0, 0),
1017 		RGB_PC(0, 255, 0),
1018 		RGB_PC(0, 0, 255));
1019     }
1020 
1021     fclose(fp);
1022 
1023     exit(1);
1024 }
1025 #endif	/* DEVELOPMENT */
1026 
1027 
1028 #endif	/* _WINDOWS */
1029