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