1 /**
2  ** colors.c ---- color management functions
3  **
4  ** Copyright (c) 1995 Csaba Biegl, 820 Stirrup Dr, Nashville, TN 37221
5  ** [e-mail: csaba@vuse.vanderbilt.edu]
6  **
7  ** This file is part of the GRX graphics library.
8  **
9  ** The GRX graphics library is free software; you can redistribute it
10  ** and/or modify it under some conditions; see the "copying.grx" file
11  ** for details.
12  **
13  ** This library is distributed in the hope that it will be useful,
14  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
15  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  **
17  **/
18 
19 #include "libgrx.h"
20 #include "memcopy.h"
21 #include "memfill.h"
22 
23 static void (*DACload)(int c,int r,int g,int b) = NULL;
24 
loadcolor(int c,int r,int g,int b)25 static void loadcolor(int c,int r,int g,int b)
26 {
27 	CLRINFO->ctable[c].r = (r &= CLRINFO->mask[0]);
28 	CLRINFO->ctable[c].g = (g &= CLRINFO->mask[1]);
29 	CLRINFO->ctable[c].b = (b &= CLRINFO->mask[2]);
30 	if(DACload) (*DACload)(c,r,g,b);
31 }
32 
setbits(char * prec,char * pos)33 static void setbits(char *prec,char *pos)
34 {
35 	int i,tmp;
36 	CLRINFO->norm = 0;
37 	for(i = 0; i < 3; i++,prec++,pos++) {
38 	    CLRINFO->prec[i]  = *prec;
39 	    CLRINFO->pos[i]   = *prec + *pos - 1;
40 	    CLRINFO->mask[i]  = (tmp = 0xff ^ (0xff >> *prec));
41 	    CLRINFO->round[i] = (tmp >> 1) & ~tmp;
42 	    CLRINFO->shift[i] = (tmp = CLRINFO->pos[i] - 7);
43 	    CLRINFO->norm     = imax(CLRINFO->norm,(-tmp));
44 	}
45 	CLRINFO->shift[0] += CLRINFO->norm;
46 	CLRINFO->shift[1] += CLRINFO->norm;
47 	CLRINFO->shift[2] += CLRINFO->norm;
48 }
49 
GrRefreshColors(void)50 void GrRefreshColors(void)
51 {
52 	int i;
53 	for(i = 0; i < (int)CLRINFO->ncolors; i++) {
54 	    if(CLRINFO->ctable[i].defined) loadcolor(
55 		(int)(i),
56 		CLRINFO->ctable[i].r,
57 		CLRINFO->ctable[i].g,
58 		CLRINFO->ctable[i].b
59 	    );
60 	}
61 }
62 
63 /* _GR_firstFreeColor is normally zero but some systems may protect some
64 ** colors for other programs (eg. X11). In this case we don't touch them.
65 ** These variables are only used in palette modes
66 */
67 #ifdef __XWIN__
68 int _GR_firstFreeColor =  0;
69 int _GR_lastFreeColor  = -1;
70 #else
71 #define _GR_firstFreeColor 0
72 #endif
73 
_GrResetColors(void)74 int _GrResetColors(void)
75 {
76 #       define NSAVED 16
77 	static char *infosave = NULL;
78 	static int  firsttime = TRUE;
79 	int i;
80 	if(firsttime) {
81 		infosave = malloc(offsetof(struct _GR_colorInfo,ctable[NSAVED]));
82 		if ( infosave ) {
83 			memcpy(infosave,CLRINFO,offsetof(struct _GR_colorInfo,ctable[NSAVED]));
84 		}
85 	    firsttime = FALSE;
86 	}
87 	sttzero(CLRINFO);
88 	if(DRVINFO->actmode.extinfo->mode == GR_frameText) {
89 		if ( infosave ) {
90 			memcpy(CLRINFO,infosave,sizeof(infosave));
91 			return TRUE;
92 		}
93 		return FALSE;
94 	}
95 	DACload = DRVINFO->actmode.extinfo->loadcolor;
96 	CLRINFO->black   = GrNOCOLOR;
97 	CLRINFO->white   = GrNOCOLOR;
98 	CLRINFO->ncolors = DRVINFO->actmode.bpp>=32 ? 0 : (1L << DRVINFO->actmode.bpp);
99 	if ( ((CLRINFO->ncolors-1)&GrCVALUEMASK) != (CLRINFO->ncolors-1) ) {
100 	    /* can happen on 32bpp systems. */
101 	    int cbpp = 0;
102 	    for(i=0; i < 3; ++i)
103 		cbpp += DRVINFO->actmode.extinfo->cprec[i];
104 	    CLRINFO->ncolors = 1L << cbpp;
105 	}
106 	setbits(
107 	    DRVINFO->actmode.extinfo->cprec,
108 	    DRVINFO->actmode.extinfo->cpos
109 	);
110 	switch(DRVINFO->actmode.bpp) {
111 	  case 4:
112 	  case 8:
113 #ifdef __XWIN__
114 	    if (_GR_lastFreeColor >= _GR_firstFreeColor)
115 	      CLRINFO->nfree = _GR_lastFreeColor - _GR_firstFreeColor + 1;
116 	    else
117 #endif
118 	      CLRINFO->nfree = CLRINFO->ncolors - _GR_firstFreeColor;
119 		if ( infosave ) {
120 	      for(i = 0; i < NSAVED; i++) {
121 		  loadcolor(
122 		      (i + _GR_firstFreeColor),
123 		      ((struct _GR_colorInfo *)(infosave))->ctable[i].r,
124 		      ((struct _GR_colorInfo *)(infosave))->ctable[i].g,
125 		      ((struct _GR_colorInfo *)(infosave))->ctable[i].b
126 		  );
127 		  CLRINFO->ctable[i].defined = TRUE;
128 		  }
129 	    }
130 	    break;
131 	  default:
132 	    CLRINFO->RGBmode = TRUE;
133 	    break;
134 	}
135 	return ((CLRINFO->ncolors-1)&GrCVALUEMASK) == CLRINFO->ncolors-1;
136 }
137 
GrResetColors(void)138 void GrResetColors(void)
139 {
140 	_GrResetColors();
141 }
142 
GrSetRGBcolorMode(void)143 void GrSetRGBcolorMode(void)
144 {
145 	if(!CLRINFO->RGBmode) {
146 	    GrColor c;
147 	    switch(CLRINFO->ncolors) {
148 		case 16L:  setbits("\1\2\1","\3\1\0"); break;
149 		case 256L: setbits("\3\3\2","\5\2\0"); break;
150 		default:   return;
151 	    }
152 	    CLRINFO->RGBmode = TRUE;
153 	    CLRINFO->nfree   = 0L;
154 	    CLRINFO->black   = 0L;
155 	    CLRINFO->white   = CLRINFO->ncolors - 1L;
156 	    for(c = 0; c < CLRINFO->ncolors; c++) loadcolor(
157 		(int)(c),
158 		(int)GrRGBcolorRed(c),
159 		(int)GrRGBcolorGreen(c),
160 		(int)GrRGBcolorBlue(c)
161 	    );
162 	}
163 }
164 
165 #define ROUNDCOLORCOMP(x,n) (                                   \
166     ((unsigned int)(x) >= CLRINFO->mask[n]) ?                   \
167 	CLRINFO->mask[n] :                                      \
168 	(((x) + CLRINFO->round[n]) & CLRINFO->mask[n])          \
169 )
170 
GrAllocColor(int r,int g,int b)171 GrColor GrAllocColor(int r,int g,int b)
172 {
173         GrColor res;
174 
175         GRX_ENTER();
176         res = GrNOCOLOR;
177 	r = ROUNDCOLORCOMP(r,0);
178 	g = ROUNDCOLORCOMP(g,1);
179 	b = ROUNDCOLORCOMP(b,2);
180 	if(CLRINFO->RGBmode) {
181             res = GrBuildRGBcolorT(r,g,b);
182 	}
183 	else {
184             GR_int32u minerr = 1000;
185 	    int i;
186 	    int free_ = (-1),allfree = (-1),best = (-1);
187 	    int ndef = (int)CLRINFO->ncolors - (int)CLRINFO->nfree;
188             DBGPRINTF(DBG_COLOR,("Allocating color: r=%d, g=%d, b=%d\n",r,g,b));
189 	    for(i = 0; i < (int)CLRINFO->ncolors; i++) {
190 		if(CLRINFO->ctable[i].defined) {
191 		    if(!CLRINFO->ctable[i].writable) {
192                         GR_int32u err = 0;
193                         GR_int16u colerr;
194                         colerr = iabs(r - CLRINFO->ctable[i].r);
195                         colerr = colerr * colerr;
196                         err += colerr;
197                         colerr = iabs(g - CLRINFO->ctable[i].g);
198                         colerr = colerr * colerr;
199                         err += colerr;
200                         colerr = iabs(b - CLRINFO->ctable[i].b);
201                         colerr = colerr * colerr;
202                         err += colerr;
203 			if(err < minerr) {
204                             DBGPRINTF(DBG_COLOR,("New best color %d (err=%ld): r=%d, g=%d, b=%d\n", i, err, \
205                               (int)CLRINFO->ctable[i].r,(int)CLRINFO->ctable[i].g,(int)CLRINFO->ctable[i].b));
206 			    best = i;
207 			    if((minerr = err) == 0) goto foundbest;
208 			}
209 			if((free_ <= 0) && !CLRINFO->ctable[i].nused) {
210                             DBGPRINTF(DBG_COLOR,("First free color: r=%d\n", i));
211 			    free_ = i;
212 			}
213 		    }
214 		    if(CLRINFO->ctable[i].nused) ndef--;
215 		}
216 		else {
217 		    if(allfree < 0) allfree = i;
218 		}
219 		if((allfree >= 0) && (ndef <= 0)) {
220                     DBGPRINTF(DBG_COLOR,("Found a usable color: allfree = %d, ndef = %d\n", allfree, ndef));
221 		    break;
222 		}
223 	    }
224 	    if(allfree >= 0) {
225                 DBGPRINTF(DBG_COLOR,("Using %d as free color (free=%d)\n", allfree, free_));
226 		free_ = allfree;
227 	    }
228 	    if(free_ >= 0) {
229                 DBGPRINTF(DBG_COLOR,("Allocating %d\n", free_));
230 		CLRINFO->ctable[free_].defined  = TRUE;
231 		CLRINFO->ctable[free_].writable = FALSE;
232 		CLRINFO->ctable[free_].nused    = 1;
233 		CLRINFO->nfree--;
234 		loadcolor(free_,r,g,b);
235 		res = free_;
236                 goto done;
237 	    }
238 	  foundbest:
239 	    if(best >= 0) {
240                 DBGPRINTF(DBG_COLOR,("Using best %d\n", best));
241 		if(!CLRINFO->ctable[best].nused) CLRINFO->nfree--;
242 		CLRINFO->ctable[best].nused++;
243 		res = best;
244                 goto done;
245 	    }
246 	}
247 done:   GRX_RETURN(res);
248 }
249 
GrAllocCell(void)250 GrColor GrAllocCell(void)
251 {
252 	if(!CLRINFO->RGBmode && CLRINFO->nfree) {
253 	    int i,free_ = (-1);
254 	    for(i = 0; i < (int)CLRINFO->ncolors; i++) {
255 		if(!CLRINFO->ctable[i].defined) {
256 		    free_ = i;
257 		    break;
258 		}
259 		if(!CLRINFO->ctable[i].nused) {
260 		    if(free_ < 0) free_ = i;
261 		}
262 	    }
263 	    if(free_ >= 0) {
264 		CLRINFO->ctable[free_].defined  = TRUE;
265 		CLRINFO->ctable[free_].writable = TRUE;
266 		CLRINFO->ctable[free_].nused    = 1;
267 		CLRINFO->nfree--;
268 		loadcolor(free_,0,0,0);
269 		return((GrColor)(free_));
270 	    }
271 	}
272 	return(GrNOCOLOR);
273 }
274 
GrFreeColor(GrColor c)275 void GrFreeColor(GrColor c)
276 {
277 	if(!CLRINFO->RGBmode && ((GrColor)(c) < CLRINFO->ncolors) &&
278 	    !CLRINFO->ctable[(int)(c)].writable &&
279 	    CLRINFO->ctable[(int)(c)].defined &&
280 	    (--CLRINFO->ctable[(int)(c)].nused == 0)) {
281 		CLRINFO->nfree++;
282 		CLRINFO->ctable[(int)(c)].defined  = FALSE;
283 		CLRINFO->ctable[(int)(c)].writable = FALSE;
284 		CLRINFO->ctable[(int)(c)].nused    = 0;
285 	    }
286 }
287 
GrFreeCell(GrColor c)288 void GrFreeCell(GrColor c)
289 {
290         GRX_ENTER();
291 	if(!CLRINFO->RGBmode && ((GrColor)(c) < CLRINFO->ncolors)) {
292 	    if(CLRINFO->ctable[(int)(c)].writable) {
293 		CLRINFO->nfree++;
294 		CLRINFO->ctable[(int)(c)].defined  = FALSE;
295 		CLRINFO->ctable[(int)(c)].writable = FALSE;
296 		CLRINFO->ctable[(int)(c)].nused    = 0;
297 	    }
298 	}
299         GRX_LEAVE();
300 }
301 
GrSetColor(GrColor c,int r,int g,int b)302 void GrSetColor(GrColor c,int r,int g,int b)
303 {
304         GRX_ENTER();
305 	if(!CLRINFO->RGBmode && ((GrColor)(c) < CLRINFO->ncolors)) {
306 	    if(!CLRINFO->ctable[(int)(c)].defined) {
307 		CLRINFO->ctable[(int)(c)].defined  = TRUE;
308 		CLRINFO->ctable[(int)(c)].nused    = 0;
309 	    }
310 	    if(!CLRINFO->ctable[(int)(c)].nused) {
311 		CLRINFO->ctable[(int)(c)].writable = TRUE;
312 		CLRINFO->ctable[(int)(c)].nused    = 1;
313 		CLRINFO->nfree--;
314 	    }
315 	    if(CLRINFO->ctable[(int)(c)].writable) loadcolor(
316 		(int)(c),
317 		(int)ROUNDCOLORCOMP(r,0),
318 		(int)ROUNDCOLORCOMP(g,1),
319 		(int)ROUNDCOLORCOMP(b,2)
320 	    );
321 	}
322         GRX_LEAVE();
323 }
324 
GrQueryColor(GrColor c,int * r,int * g,int * b)325 void GrQueryColor(GrColor c,int *r,int *g,int *b)
326 {
327         GRX_ENTER();
328 	GrQueryColorID(c,r,g,b);
329         GRX_LEAVE();
330 }
331 
GrQueryColor2(GrColor c,long * hcolor)332 void GrQueryColor2(GrColor c,long *hcolor)
333 {
334         GRX_ENTER();
335         GrQueryColor2ID(c,hcolor);
336         GRX_LEAVE();
337 }
338 
339 #define CSAVE_MAGIC     0x7abf5698UL
340 
341 typedef struct {
342     GrColor magic;
343     GrColor nc;
344     struct _GR_colorInfo info;
345 } colorsave;
346 
GrColorSaveBufferSize(void)347 int GrColorSaveBufferSize(void)
348 {
349 	return(sizeof(colorsave));
350 }
351 
GrSaveColors(void * buffer)352 void GrSaveColors(void *buffer)
353 {
354 	colorsave *cp = (colorsave *)buffer;
355 	cp->magic = CSAVE_MAGIC;
356 	cp->nc    = GrNumColors();
357 	sttcopy(&cp->info,CLRINFO);
358 }
359 
GrRestoreColors(void * buffer)360 void GrRestoreColors(void *buffer)
361 {
362 	colorsave *cp = (colorsave *)buffer;
363 	if((cp->magic == CSAVE_MAGIC) && (cp->nc == GrNumColors())) {
364 	    sttcopy(CLRINFO,&cp->info);
365 	    GrRefreshColors();
366 	}
367 }
368 
369