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