1 /* $Header: /home/yav/catty/fkiss/RCS/color.c,v 1.8 2000/09/28 07:50:29 yav Exp $
2 * fkiss color management
3 * written by yav <yav@bigfoot.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19
20 #include <X11/Xos.h>
21 #include <X11/Xlib.h>
22 #include <stdio.h>
23
24 #include "config.h"
25
26 #include "headers.h"
27 #include "fkiss.h"
28 #include "work.h"
29 #define PUBLIC_COLOR_C
30 #include "extern.h"
31
32
33 char id_color[] = "$Id: color.c,v 1.8 2000/09/28 07:50:29 yav Exp $";
34 static int loaded_colfcnt; /* loaded color file count */
35
read_color_file(fp,p)36 int read_color_file(fp, p)
37 FILE *fp;
38 COLOR *p;
39 {
40 int i, n;
41 int preload;
42 KISSCOLOR *kc;
43 unsigned char buf[1024];
44
45 /* read color file */
46 i = 4; /* max(4, strlen(kiss_magic_number)) */
47 if (!fread(buf, i, 1, fp))
48 return 1;
49 buf[i] = '\0';
50 if (strcmp(buf, kiss_magic_number) == 0) {
51 if (!fread(buf+i, PAL_HEADER_SIZE-i, 1, fp))
52 return 1;
53 if (buf[PAL_MARK] != 0x10)
54 return 1;
55 p->bpc = buf[PAL_BPC];
56 p->cpg = GET_SHORT(buf+PAL_CPPG);
57 p->pg = GET_SHORT(buf+PAL_PG);
58 preload = 0;
59 } else {
60 p->bpc = 12;
61 p->cpg = 16;
62 p->pg = 10;
63 preload = i;
64 }
65 debug_printf("%s :\n\tbits/color:%d, colors/palette:%d, pages:%2d, preload:%d,",
66 p->filename, p->bpc, p->cpg, p->pg, preload);
67 if (!loaded_colfcnt)
68 colindex = (short *)ks_malloc(sizeof(short));
69 else
70 colindex = (short *)ks_realloc(colindex, sizeof(short)*(loaded_colfcnt+1));
71 *(colindex+loaded_colfcnt) = colcnt - !!colcnt;
72 loaded_colfcnt++;
73
74 for (i = 0; i < MAXPAL; i++) {
75 kcol[i] = (KISSCOLOR *)ks_realloc(kcol[i],
76 sizeof(KISSCOLOR)*(colcnt + p->cpg - !!colcnt));
77 }
78
79 for (n = 0; n < p->pg; n++) {
80 i = ((p->bpc+7)>>3) * p->cpg; /* bytes per group */
81 if (!fread(buf+preload, i-preload, 1, fp))
82 break;
83 preload = 0;
84 kc = kcol[n]+colcnt;
85 debug_printf("\npg%3d:", n);
86 for (i = !!colcnt; i < p->cpg; i++) {
87 if (p->bpc == 12) {
88 kc->b = (buf[i*2] & 15) * 0x11;
89 kc->r = (buf[i*2] >> 4) * 0x11;
90 kc->g = (buf[i*2+1] & 15) * 0x11;
91 } else {
92 kc->r = buf[i*3+0];
93 kc->g = buf[i*3+1];
94 kc->b = buf[i*3+2];
95 }
96 if (debug_mode) {
97 if ( i % 5 )
98 fprintf(stderr, "\t");
99 else
100 fprintf(stderr, "\n\t");
101 fprintf(stderr, "%3d:%02x,%02x,%02x;", i, kc->r, kc->g, kc->b);
102 }
103 kc++;
104 }
105 }
106 if (debug_mode)
107 if ( --i % 5 )
108 fprintf(stderr, "\n");
109 /* correct real loaded palette group count */
110 if (n < p->pg)
111 p->pg = n;
112 debug_printf("colcnt changed from %d to %d (%d + %d - %d) !\n",
113 colcnt, colcnt + p->cpg - !!colcnt, colcnt, p->cpg, !!colcnt);
114 colcnt = colcnt + p->cpg - !!colcnt;
115
116 if (palcnt < p->pg) {
117 debug_printf("palcnt changed from %d to %d !\n", palcnt, p->pg);
118 palcnt = p->pg;
119 }
120 return 0;
121 }
122
read_colors()123 int read_colors()
124 {
125 int i, j, r;
126 COLOR *p;
127 FILE *fp;
128
129 for (i = 0; i < MAXPAL; i++) {
130 kcol[i] = (KISSCOLOR *)ks_malloc(sizeof(KISSCOLOR));
131 }
132
133 loaded_colfcnt = 0;
134 for (p = kcflist, i = 0; i < colorfilecnt; p++, i++) {
135 fp = ks_fopen(p->filename, "rb");
136 if (fp == NULL) {
137 msg("E color file ``%s'' not found!\n", p->filename);
138 } else {
139 r = read_color_file(fp, p);
140 if (r) {
141 msg("E color file ``%s'' read error!\n", p->filename);
142 }
143 fclose(fp);
144 }
145 }
146 /* fill remaining palette group with group 0 */
147 p = kcflist;
148 for (i = 0; i < colorfilecnt; i++) {
149 for (j = p->pg; j < palcnt; j++) {
150 bcopy((char *)(kcol[0]+*(colindex+i)),
151 (char *)(kcol[j]+*(colindex+i)), sizeof(*kcol)*p->cpg);
152 }
153 p++;
154 }
155 return 0;
156 }
157
set_private_colorcells(n)158 int set_private_colorcells(n)
159 int n;
160 {
161 XStoreColors(dsp, cmap, xcol[n], colcnt);
162 return 0;
163 }
164
alloc_private_colorcells()165 int alloc_private_colorcells()
166 {
167 int i, pal;
168 XColor *p;
169 unsigned long plane_masks[1];
170 unsigned long *pixels;
171
172 pixels = (unsigned long *)ks_malloc(sizeof(unsigned long)*colcnt);
173 if (!XAllocColorCells(dsp, cmap, False, plane_masks, 0, pixels, colcnt)) {
174 free(pixels);
175 return 1;
176 }
177 debug_printf("get %d private colorcells\n", colcnt);
178 for (pal = 0; pal < palcnt; pal++) {
179 p = xcol[pal];
180 for (i = 0; i < colcnt; p++, i++) {
181 p->pixel = pixels[i];
182 p->flags = DoRed|DoGreen|DoBlue;
183 }
184 }
185 free(pixels);
186 set_private_colorcells(0);
187 return 0;
188 }
189
free_alloced_colors(status,npal,ncol)190 void free_alloced_colors(status, npal, ncol)
191 char **status;
192 int npal;
193 int ncol;
194 {
195 int i, j, pal;
196 int pixelcount;
197 unsigned long *pixels;
198 XColor *xp;
199
200 pixels = (unsigned long *)ks_malloc(sizeof(*pixels)*npal*ncol);
201 pixelcount = 0;
202 for (pal = 0; pal < npal; pal++) {
203 xp = xcol[pal];
204 for (i = 0; i < colcnt; i++) {
205 if (*(status[pal]+i)) {
206 for (j = 0; j < pixelcount; j++) {
207 if (xp->pixel == *(pixels+j))
208 break;
209 }
210 if (j == pixelcount) {
211 *(pixels+pixelcount) = xp->pixel;
212 pixelcount++;
213 }
214 }
215 xp++;
216 }
217 }
218 msg("M free all %d colors.\n", pixelcount);
219 if (debug_mode)
220 for (i = 0; i < pixelcount; i++)
221 fprintf(stderr, "free pixel %d %ld\n", i, *(pixels+i));
222 XFreeColors(dsp, cmap, pixels, pixelcount, 0);
223 free(pixels);
224 }
225
226 #define BRIGHT_G 151 /* 0.59 * 256 */
227 #define BRIGHT_R 77 /* 0.30 * 256 */
228 #define BRIGHT_B 28 /* 0.11 * 256 */
229
230 /* Convert KISS 8bit RGB to X11 16bit RGB value
231 * input: kcol
232 * output: xcol
233 */
convert_xcolors()234 void convert_xcolors()
235 {
236 int i, pal;
237 KISSCOLOR *kp;
238 XColor *xp;
239
240 for (pal = 0; pal < palcnt; pal++) {
241 kp = kcol[pal];
242 xp = xcol[pal];
243 for (i = 0; i < colcnt; i++) {
244 if (gray_mode) {
245 xp->red = xp->green = xp->blue =
246 ((kp->r*BRIGHT_R + kp->g*BRIGHT_G + kp->b*BRIGHT_B) >> 8) * 0x101;
247 } else {
248 xp->red = kp->r * 0x101; /* convert 8bit to 16bit */
249 xp->green = kp->g * 0x101;
250 xp->blue = kp->b * 0x101;
251 }
252 kp++;
253 xp++;
254 }
255 }
256 }
257
258 /* reduce color level R:16 G:16 B:8 */
reduce_color_level()259 void reduce_color_level()
260 {
261 int i, pal;
262 KISSCOLOR *kp;
263 XColor *xp;
264
265 for (pal = 0; pal < palcnt; pal++) {
266 kp = kcol[pal];
267 xp = xcol[pal];
268 for (i = 0; i < colcnt; i++) {
269 xp->red = (kp->r / (255/16)) * (255/16) * 0x101;
270 xp->green = (kp->g / (255/16)) * (255/16) * 0x101;
271 xp->blue = (kp->b / (255/8)) * (255/8) * 0x101;
272 kp++;
273 xp++;
274 }
275 }
276 }
277
get_near_color(xp,xp0,cells)278 int get_near_color(xp, xp0, cells)
279 XColor *xp; /* need color */
280 XColor *xp0; /* Colormap */
281 int cells; /* number of colorcells */
282 {
283 int i;
284 int near_color;
285 double r0, g0, b0, r, g, b, d, d0;
286
287 near_color = 0;
288 d0 = 1.0e100;
289 r0 = xp->red;
290 g0 = xp->green;
291 b0 = xp->blue;
292 for (i = 0; i < cells; i++) {
293 r = (xp0+i)->red - r0;
294 g = (xp0+i)->green - g0;
295 b = (xp0+i)->blue - b0;
296 d = r*r + g*g + b*b;
297 if (d < d0) {
298 d0 = d;
299 near_color = i;
300 }
301 }
302 return near_color;
303 }
304
very_poor_system_pixels(xp0,cells)305 void very_poor_system_pixels(xp0, cells)
306 XColor *xp0;
307 int cells;
308 {
309 int i, near_color;
310 XColor col[SPX_MAX];
311
312 XQueryColors(dsp, cmap, xp0, cells);
313 parse_system_colors(col);
314 for (i = 0; i < SPX_MAX; i++) {
315 near_color = get_near_color(&col[i], xp0, cells);
316 spx[i] = (xcol[0]+near_color)->pixel;
317 }
318 set_system_pixels();
319 }
320
alloc_colors()321 int alloc_colors()
322 {
323 int i, pal, phase;
324 XColor *xp;
325 XColor *xp0;
326 int cells, missed_color, near_color;
327 Bool syscol_free;
328 char *status[MAXPAL];
329
330 convert_xcolors();
331 for (i = 0; i < MAXPAL; i++) {
332 status[i] = ks_malloc(colcnt);
333 bzero(status[i], colcnt);
334 }
335 cells = DisplayCells(dsp, scr);
336 xp0 = NULL;
337 syscol_free = 0;
338 for (phase = 0; phase < 10; phase++) {
339 missed_color = 0;
340 if (private_color_mode) {
341 if (alloc_private_colorcells())
342 missed_color = colcnt;
343 } else {
344 for (pal = 0; pal < palcnt; pal++) {
345 xp = xcol[pal];
346 for (i = 0; i < colcnt; i++) {
347 if (!status[pal][i]) {
348 status[pal][i] = XAllocColor(dsp, cmap, xp);
349 if (!status[pal][i])
350 missed_color++;
351 }
352 xp++;
353 }
354 }
355 }
356 if (missed_color == 0)
357 break;
358 msg("W allocation missed %3d colors in phase %d.\n",
359 missed_color, phase);
360 if (phase == 0) {
361 /* free system colors */
362 msg("M free system colors.\n");
363 poor_system_pixels();
364 /* ready colormap read buffer */
365 xp0 = (XColor *)ks_malloc(sizeof(XColor)*cells);
366 for (i = 0; i < cells; i++)
367 (xp0+i)->pixel = i;
368 continue;
369 } else if (phase == 1) {
370 if (private_colormap_mode) {
371 msg("M make a new colormap.\n");
372 cmap = XCopyColormapAndFree(dsp, cmap);
373 XSetWindowColormap(dsp, topwin, cmap);
374 }
375 continue; /* Retry! */
376 } else if (phase == 2) {
377 if (private_color_mode) {
378 free_system_colors();
379 syscol_free = True;
380 }
381 continue; /* Retry! */
382 } else if (phase == 3) {
383 if (private_color_mode) {
384 poor_system_pixels();
385 syscol_free = False;
386 msg("M abandon to use private color cells.\n");
387 private_color_mode = 0;
388 }
389 continue; /* Retry! */
390 } else if (phase == 4) {
391 /* free all colors */
392 free_alloced_colors(status, palcnt, colcnt);
393 for (i = 0; i < MAXPAL; i++) {
394 bzero(status[i], colcnt);
395 }
396 msg("W reduce color levels.\n");
397 reduce_color_level();
398 continue; /* Retry more! */
399 }
400 /* change near color */
401 XQueryColors(dsp, cmap, xp0, cells);
402 for (pal = 0; pal < palcnt; pal++) {
403 xp = xcol[pal];
404 for (i = 0; i < colcnt; i++) {
405 if (!status[pal][i]) {
406 near_color = get_near_color(xp, xp0, cells);
407 msgset("W pal %d color %3d %04x %04x %04x",
408 pal, i, xp->red, xp->green, xp->blue);
409 xp->red = (xp0+near_color)->red;
410 xp->green = (xp0+near_color)->green;
411 xp->blue = (xp0+near_color)->blue;
412 msg(" -> %04x %04x %04x.\n",
413 xp->red, xp->green, xp->blue);
414 }
415 xp++;
416 }
417 }
418 }
419 if (syscol_free)
420 very_poor_system_pixels(xp0, cells);
421 if (xp0 != NULL)
422 free(xp0);
423 if (missed_color)
424 msg("W give up color allocation.\n");
425 for (i = 0; i < MAXPAL; i++) {
426 free(status[i]);
427 }
428 return 0;
429 }
430
431 /* End of file */
432