1 
2 #include <stdio.h>
3 #include <stdlib.h>
4 
5 #include <X11/Xlib.h>
6 
7 #include <grass/gis.h>
8 #include <grass/glocale.h>
9 
10 extern Display *dpy;
11 extern int scrn;
12 extern Window grwin;
13 extern XWindowAttributes xwa;
14 
15 static int NCOLORS;
16 static unsigned long *xpixels;
17 
18 static int Red[256], Grn[256], Blu[256];
19 static int Gray[256];
20 
21 static int r_pos, g_pos, b_pos;
22 static int r_size, g_size, b_size;
23 static int r_scale, g_scale, b_scale;
24 
25 
get_shifts(unsigned long mask,int * pos,int * size,int * scale)26 static void get_shifts(unsigned long mask, int *pos, int *size, int *scale)
27 {
28     int i, j;
29 
30     for (i = 0; (mask & 1) == 0; i++)
31 	mask >>= 1;
32     if (pos)
33 	*pos = i;
34 
35     for (j = i; (mask & 1) != 0; j++)
36 	mask >>= 1;
37     if (size)
38 	*size = j - i;
39     if (scale)
40 	*scale = 8 - (j - i);
41 }
42 
get_rgb_shifts(void)43 static int get_rgb_shifts(void)
44 {
45     get_shifts(xwa.visual->red_mask, &r_pos, &r_size, &r_scale);
46     get_shifts(xwa.visual->green_mask, &g_pos, &g_size, &g_scale);
47     get_shifts(xwa.visual->blue_mask, &b_pos, &b_size, &b_scale);
48 
49     return (1 << r_size) * (1 << g_size) * (1 << b_size);
50 }
51 
52 static unsigned long
find_color_gray(unsigned int r,unsigned int g,unsigned int b)53 find_color_gray(unsigned int r, unsigned int g, unsigned int b)
54 {
55     unsigned int y = (r + g + b) / 3;
56 
57     return xpixels[Gray[y]];
58 }
59 
60 static unsigned long
find_color_indexed(unsigned int r,unsigned int g,unsigned int b)61 find_color_indexed(unsigned int r, unsigned int g, unsigned int b)
62 {
63     return xpixels[Red[r] + Grn[g] + Blu[b]];
64 }
65 
66 static unsigned long
find_color_rgb(unsigned int r,unsigned int g,unsigned int b)67 find_color_rgb(unsigned int r, unsigned int g, unsigned int b)
68 {
69     unsigned int rr = r >> r_scale;
70     unsigned int gg = g >> g_scale;
71     unsigned int bb = b >> b_scale;
72 
73     return (rr << r_pos) + (gg << g_pos) + (bb << b_pos);
74 }
75 
find_color(unsigned int r,unsigned int g,unsigned int b)76 unsigned long find_color(unsigned int r, unsigned int g, unsigned int b)
77 {
78 
79     switch (xwa.visual->class) {
80     case StaticGray:
81     case GrayScale:
82 	return find_color_gray(r, g, b);
83     case StaticColor:
84     case PseudoColor:
85 	return find_color_indexed(r, g, b);
86     case TrueColor:
87     case DirectColor:
88 	return find_color_rgb(r, g, b);
89     default:
90 	G_fatal_error(_("Unknown visual class [%d]."), xwa.visual->class);
91 	return 0;
92     }
93 }
94 
get_max_levels(int n_colors,int * rr,int * gg,int * bb)95 static void get_max_levels(int n_colors, int *rr, int *gg, int *bb)
96 {
97     int r, g, b, i;
98 
99     for (i = 0; i * i * i < n_colors; i++) ;
100 
101     for (r = g = b = i;;) {
102 	if (r * g * b <= n_colors)
103 	    break;
104 	b--;
105 	if (r * g * b <= n_colors)
106 	    break;
107 	r--;
108 	if (r * g * b <= n_colors)
109 	    break;
110 	g--;
111     }
112 
113     *rr = r;
114     *gg = g;
115     *bb = b;
116 }
117 
get_fewer_levels(int * rr,int * gg,int * bb)118 static int get_fewer_levels(int *rr, int *gg, int *bb)
119 {
120     int r = *rr;
121     int g = *gg;
122     int b = *bb;
123 
124     /* 888 -> 887 -> 787 -> 777 -> ... */
125 
126     if (r > b)			/* 887 -> 787 */
127 	r--;
128     else if (g > b)		/* 787 -> 777 */
129 	g--;
130     else			/* 888 -> 888 */
131 	b--;
132 
133     *rr = r;
134     *gg = g;
135     *bb = b;
136 
137     return r >= 2 && g >= 2 && b >= 2;
138 }
139 
try_get_colors(Colormap cmap,int nr,int ng,int nb)140 static int try_get_colors(Colormap cmap, int nr, int ng, int nb)
141 {
142     XColor xcolor;
143     int n_pixels;
144     int r, g, b;
145 
146     xpixels = (unsigned long *)G_realloc(xpixels,
147 					 nr * ng * nb *
148 					 sizeof(unsigned long));
149     n_pixels = 0;
150 
151     xcolor.flags = DoRed | DoGreen | DoBlue;
152 
153     for (r = 0; r < nr; r++) {
154 	for (g = 0; g < ng; g++) {
155 	    for (b = 0; b < nb; b++) {
156 		xcolor.red = (unsigned short)(r * 0xFFFF / (nr - 1));
157 		xcolor.green = (unsigned short)(g * 0xFFFF / (ng - 1));
158 		xcolor.blue = (unsigned short)(b * 0xFFFF / (nb - 1));
159 		if (!XAllocColor(dpy, cmap, &xcolor)) {
160 		    XFreeColors(dpy, cmap, xpixels, n_pixels,
161 				(unsigned long)0);
162 		    return 0;
163 		}
164 
165 		xpixels[n_pixels++] = xcolor.pixel;
166 	    }
167 	}
168     }
169 
170     return 1;
171 }
172 
try_get_grays(Colormap cmap,int ny)173 static int try_get_grays(Colormap cmap, int ny)
174 {
175     XColor xcolor;
176     int n_pixels;
177     int y;
178 
179     xpixels = (unsigned long *)G_realloc(xpixels, ny * sizeof(unsigned long));
180     n_pixels = 0;
181 
182     xcolor.flags = DoRed | DoGreen | DoBlue;
183 
184     for (y = 0; y < ny; y++) {
185 	unsigned short v = (unsigned short)(y * 0xFFFF / (ny - 1));
186 
187 	xcolor.red = v;
188 	xcolor.green = v;
189 	xcolor.blue = v;
190 
191 	if (!XAllocColor(dpy, cmap, &xcolor)) {
192 	    XFreeColors(dpy, cmap, xpixels, n_pixels, (unsigned long)0);
193 	    return y;
194 	}
195 
196 	xpixels[n_pixels++] = xcolor.pixel;
197     }
198 
199     return ny;
200 }
201 
ramp_colormap(void)202 static Colormap ramp_colormap(void)
203 {
204     int n_colors = xwa.visual->map_entries;
205     Colormap cmap = XCreateColormap(dpy, RootWindow(dpy, scrn),
206 				    xwa.visual, AllocAll);
207     int i;
208 
209     for (i = 0; i < n_colors; i++) {
210 	unsigned int k = i * 65535 / (n_colors - 1);
211 	unsigned int l = i * 255 / (n_colors - 1);
212 	XColor xcolor;
213 
214 	xcolor.flags = DoRed | DoGreen | DoBlue;
215 	xcolor.blue = k;
216 	xcolor.green = k;
217 	xcolor.red = k;
218 	xcolor.pixel = find_color_rgb(l, l, l);
219 
220 	XStoreColor(dpy, cmap, &xcolor);
221     }
222 
223     return cmap;
224 }
225 
InitColorTableFixed(Colormap cmap)226 Colormap InitColorTableFixed(Colormap cmap)
227 {
228     int n_colors = xwa.visual->map_entries;
229     int r, g, b, y, i;
230 
231     switch (xwa.visual->class) {
232     case StaticGray:
233     case GrayScale:
234 	/* determine how many levels of gray we can actually get */
235 	y = try_get_grays(cmap, n_colors);
236 	if (y > 2 && y < n_colors)
237 	    y = try_get_grays(cmap, y);
238 	if (y < 2)
239 	    G_fatal_error(_("Unable to get sufficient gray shades."));
240 
241 	NCOLORS = y;
242 
243 	for (i = 0; i < 256; i++)
244 	    Gray[i] = i * y / 256;
245 
246 	break;
247 
248     case StaticColor:
249     case PseudoColor:
250 	/* determine how many levels of r, g, and b are possible */
251 	get_max_levels(n_colors, &r, &g, &b);
252 
253 	/* now see how many we can actually get */
254 	while (!try_get_colors(cmap, r, g, b))
255 	    if (!get_fewer_levels(&r, &g, &b))
256 		G_fatal_error(_("Unable to get sufficient colors."));
257 
258 	NCOLORS = r * g * b;
259 
260 	for (i = 0; i < 256; i++) {
261 	    Red[i] = (i * r / 256) * g * b;
262 	    Grn[i] = (i * g / 256) * b;
263 	    Blu[i] = (i * b / 256);
264 	}
265 
266 	break;
267 
268     case DirectColor:
269 	G_warning(_("Using private colormap for DirectColor visual."));
270 
271 	/* free any previously-allocated Colormap */
272 	if (cmap != DefaultColormap(dpy, scrn))
273 	    XFreeColormap(dpy, cmap);
274 
275 	/* get shift factors for R,G,B masks */
276 	NCOLORS = get_rgb_shifts();
277 
278 	/* create colormap (emulates TrueColor visual) */
279 	cmap = ramp_colormap();
280 	break;
281 
282     case TrueColor:
283 	/* get shift factors for R,G,B masks */
284 	NCOLORS = get_rgb_shifts();
285 	break;
286 
287     default:
288 	G_fatal_error(_("Unknown visual class [%d]."), xwa.visual->class);
289 	break;
290     }
291 
292     return cmap;
293 }
294