convert line ends
[canaan.git] / prj / tech / libsrc / dev2d / ipal.c
blob31a4fe3909d669c23310e9790867bfe94d313cf0
1 /*
2 * $Source: s:/prj/tech/libsrc/dev2d/RCS/ipal.c $
3 * $Revision: 1.1 $
4 * $Author: KEVIN $
5 * $Date: 1996/04/10 16:04:00 $
7 * RGB color manipulation routines.
9 * This file is part of the dev2d library.
12 #include <grd.h>
13 #include <grmalloc.h>
14 #include <rgb.h>
16 /* Static Globals for his and her pleasure */
17 static int bcenter, gcenter, rcenter;
18 static long gdist, rdist, cdist;
19 static long cbinc, cginc, crinc;
20 static ulong *gdp, *rdp, *cdp;
21 static uchar *grgbp, *rrgbp, *crgbp;
22 static int gstride, rstride;
23 static long x, xsqr, colormax;
24 static int cindex;
26 void inv_cmap_2(int colors, uchar *colormap[3],int bits,ulong *dist_buf, uchar *rgbmap );
27 int _redloop();
28 int _greenloop(int restart);
29 int _blueloop(int restart);
30 void _maxfill(ulong *buffer);
32 /* The routines in this file operate on grs_rgb color values. The color
33 values are encoded so that each r,g, and b has 8 bits of integer, 2
34 bits of fraction, and one bit of padding. */
36 /* This routine allocates a 15 bit inverse palette for the
37 current screen palette (that 32768 bytes) and initializes
38 it for the current palette. Returns OUT_OF_MEMORY
39 if it can't allocate anything. If ipal is currently non-null
40 it tries to delete it first, in the interests of robustness */
42 int gr_alloc_ipal(void)
44 int err;
46 if (grd_ipal != NULL) {
47 if ((err = gr_free_ipal())<0) return err;
50 if ((grd_ipal = gr_malloc(32768))==NULL) return RGB_OUT_OF_MEMORY;
52 if ((err = gr_init_ipal())<0) return err;
53 return RGB_OK;
56 int gr_free_ipal(void)
58 if (grd_ipal==NULL) return RGB_CANT_DEALLOCATE;
59 gr_free(grd_ipal);
60 grd_ipal=NULL;
61 return RGB_OK;
64 /* Initializes the inverse palette to the current screen
65 palette. */
67 int gr_init_ipal(void)
69 if (grd_ipal == NULL) return RGB_IPAL_NOT_ALLOCATED;
70 return gr_calc_ipal(grd_bpal, grd_ipal);
73 /* Calculates an inverse palette from a given
74 palette. */
76 int gr_calc_ipal(grs_rgb *bpal, uchar *ipal)
78 int i;
79 uchar r,g,b;
80 uchar *data,*colormap[3];
81 ulong *dist_buf;
83 if ((data = gr_malloc(3*256)) == NULL) return RGB_OUT_OF_MEMORY;
84 /* needs to be split up into r,g,b planes */
85 colormap[0] = data;
86 colormap[1] = data + 256;
87 colormap[2] = data + 2*256;
89 for(i=0;i<256;++i) {
90 gr_split_rgb(bpal[i],&r,&g,&b);
91 colormap[2][i] = r;
92 colormap[1][i] = g;
93 colormap[0][i] = b;
96 if ((dist_buf = gr_malloc(sizeof(ulong) * 32768))==NULL) return RGB_OUT_OF_MEMORY;
98 inv_cmap_2(256,colormap,5,dist_buf,ipal);
100 gr_free(dist_buf);
101 gr_free(data);
103 return RGB_OK;
107 static void inv_cmap_2(int colors, uchar *colormap[3],int bits,ulong *dist_buf, uchar *rgbmap )
109 int nbits = 8 - bits;
111 colormax = 1 << bits;
112 x = 1 << nbits;
113 xsqr = 1 << (2 * nbits);
115 /* Compute strides for accessing the arrays. */
117 gstride = colormax;
118 rstride = colormax * colormax ;
120 _maxfill(dist_buf);
122 for(cindex = 0;cindex<colors; cindex++) {
123 /* The initial position is the cell containing the colormap
124 * entry. We get this by quantiziing the colormap values.
126 rcenter = colormap[0][cindex] >> nbits;
127 gcenter = colormap[1][cindex] >> nbits;
128 bcenter = colormap[2][cindex] >> nbits;
130 rdist = colormap[0][cindex] - (rcenter * x + x/2);
131 gdist = colormap[1][cindex] - (gcenter * x + x/2);
132 cdist = colormap[2][cindex] - (bcenter * x + x/2);
133 cdist = rdist*rdist + gdist*gdist + cdist*cdist;
135 crinc = 2 * ((rcenter+1) * xsqr - (colormap[0][cindex] * x));
136 cginc = 2 * ((gcenter+1) * xsqr - (colormap[1][cindex] * x));
137 cbinc = 2 * ((bcenter+1) * xsqr - (colormap[2][cindex] * x));
139 /* Array starting points. */
140 cdp = dist_buf + rcenter*rstride + gcenter*gstride + bcenter;
141 crgbp = rgbmap + rcenter*rstride + gcenter*gstride + bcenter;
143 _redloop();
147 /* redloop -- loop up and down from red center. */
148 static int _redloop()
150 int detect, r, first;
151 long txsqr = xsqr + xsqr;
152 static long rxx;
154 detect = 0;
156 /* Basic loop up */
157 for (r = rcenter, rdist = cdist, rxx = crinc,
158 rdp = cdp, rrgbp = crgbp, first = 1;
159 r<colormax;
160 r++, rdp += rstride, rrgbp += rstride,
161 rdist += rxx, rxx += txsqr, first = 0) {
162 if (_greenloop(first))
163 detect = 1;
164 else if (detect)
165 break;
168 /* Basic loop down */
169 for (r = rcenter - 1, rxx = crinc - txsqr, rdist = cdist - rxx,
170 rdp = cdp - rstride, rrgbp = crgbp - rstride, first = 1;
171 r >= 0;
172 r--, rdp -= rstride, rrgbp -= rstride,
173 rxx -= txsqr, rdist -= rxx, first = 0) {
174 if (_greenloop(first))
175 detect = 1;
176 else if (detect)
177 break;
180 return detect;
184 /* greenloop -- loop up and down from green center. */
185 static int _greenloop(int restart)
187 int detect, g, first;
188 long txsqr = xsqr + xsqr;
189 static int here, min, max;
190 static int prevmax, prevmin;
191 int thismax, thismin;
192 static long ginc, gxx, gcdist;
193 static ulong *gcdp;
194 static uchar *gcrgbp;
196 /* Red loop restarted, reset variables to "center" position */
197 if (restart) {
198 here = gcenter;
199 min = 0;
200 max = colormax - 1;
201 ginc = cginc;
202 prevmax = 0;
203 prevmin = colormax;
206 /* finding actual min and max on this line. */
207 thismin = min;
208 thismax = max;
209 detect = 0;
211 /* Basic loop up. */
212 for (g=here, gcdist = gdist = rdist, gxx = ginc,
213 gcdp = gdp = rdp, gcrgbp = grgbp = rrgbp, first = 1;
214 g <= max;
215 g++, gdp += gstride, gcdp += gstride,
216 grgbp += gstride, gcrgbp += gstride,
217 gdist += gxx, gcdist += gxx, gxx += txsqr, first = 0) {
218 if (_blueloop(first)) {
219 if (!detect) {
220 /* remember here and associated data! */
221 if (g>here) {
222 here = g;
223 rdp = gcdp;
224 rrgbp = gcrgbp;
225 rdist = gcdist;
226 ginc = gxx;
227 thismin = here;
229 detect = 1;
232 else if (detect) {
233 thismax = g - 1;
234 break;
238 /* Basic loop down */
239 for (g=here - 1, gxx = ginc - txsqr, gcdist = gdist = rdist - gxx,
240 gcdp = gdp = rdp - gstride, gcrgbp = grgbp = rrgbp - gstride,
241 first = 1;
242 g >= min;
243 g--, gdp -= gstride, gcdp -= gstride,
244 grgbp -= gstride, gcrgbp -= gstride,
245 gxx -= txsqr, gdist -= gxx, gcdist -= gxx, first = 0) {
246 if (_blueloop(first)) {
247 if (!detect) {
248 /* remember here! */
249 here = g;
250 rdp = gcdp;
251 rrgbp = gcrgbp;
252 rdist = gcdist;
253 ginc = gxx;
254 thismax = here;
255 detect = 1;
258 else if (detect) {
259 thismin = g + 1;
260 break;
264 /* If we saw something, update the edge tracers. Only
265 * tracks edges that are "shrinking" (min increating, max
266 * decreasing.
269 if (detect) {
270 if (thismax < prevmax)
271 max = thismax;
272 prevmax = thismax;
274 if (thismin > prevmin )
275 min = thismin;
276 prevmin = thismin;
279 return detect;
282 /* blueloop -- loop up and down from blue center. */
283 static int _blueloop(int restart)
285 int detect;
286 /* These are all registers on a Sun 3. Your mileage may differ. */
287 ulong *dp;
288 uchar *rgbp;
289 long bdist, bxx;
290 int b, i=cindex;
291 long txsqr = xsqr + xsqr;
292 int lim; /* for min and max, avoid extra registers. */
293 static int here, min, max;
294 static int prevmin, prevmax; /* For tracking min and max. */
295 int thismin, thismax;
296 static long binc;
298 if (restart) {
299 here = bcenter;
300 min = 0;
301 max = colormax - 1;
302 binc = cbinc;
303 prevmin = colormax;
304 prevmax = 0;
307 detect = 0;
308 thismin = min;
309 thismax = max;
311 /* Basic loop up. */
312 /* First loop just finds first applicable cell. */
313 for (b = here, bdist = gdist, bxx = binc, dp = gdp, rgbp = grgbp,
314 lim = max;
315 b <= lim;
316 b++, dp++, rgbp++, bdist += bxx, bxx += txsqr) {
317 if (*dp > bdist) {
318 /* Remember new here and associated data! */
319 if (b>here) {
320 here = b;
321 gdp = dp;
322 grgbp = rgbp;
323 gdist = bdist;
324 binc = bxx;
325 thismin = here;
327 detect = 1;
328 break;
331 /* Second loop fills in a run of closer cells. */
332 for (;
333 b <= lim;
334 b++, dp++, rgbp++, bdist += bxx, bxx += txsqr) {
335 if (*dp > bdist ) {
336 *dp = bdist;
337 *rgbp = i;
338 } else {
339 thismax = b - 1;
340 break;
344 /* Basic loop down */
345 /* Do initializations here, since the 'find' loop might not get
346 * executed.
348 lim = min;
349 b = here - 1;
350 bxx = binc - txsqr;
351 bdist = gdist - bxx;
352 dp = gdp - 1;
353 rgbp = grgbp - 1;
354 /* The 'find' loop ios executed on ly if we didn't already find
355 * something.
357 if (!detect)
358 for(;
359 b >= lim;
360 b--, dp--, rgbp--, bxx -= txsqr, bdist -= bxx) {
361 if ( *dp > bdist) {
362 /* Remember here! */
363 /* No test for b against here necessary because b <
364 * here by definition.
366 here = b;
367 gdp = dp;
368 grgbp = rgbp;
369 gdist = bdist;
370 binc = bxx;
371 thismax = here;
372 detect = 1;
373 break;
376 /* the 'update' loop */
377 for (;
378 b>= lim;
379 b--, dp--, rgbp--, bxx -= txsqr, bdist -= bxx) {
380 if ( *dp > bdist) {
381 *dp = bdist;
382 *rgbp = i;
383 } else {
384 thismin = b + 1;
385 break;
389 /* If we saw something, update the edge trackers. */
390 if (detect) {
391 /* Only tracks edges that are 'shrinking' (*min increasin, max
392 * decreasing).
394 if (thismax < prevmax)
395 max = thismax;
396 if (thismin > prevmin )
397 min = thismin;
399 /* Remember the min and max values. */
400 prevmax = thismax;
401 prevmin = thismin;
404 return detect;
407 /* Fill a buffer with the largest unsigned long. */
408 static void _maxfill(ulong *buffer)
410 ulong maxv = (long)-1;
411 long i;
412 ulong *bp;
414 for(i=colormax * colormax * colormax, bp = buffer;
415 i > 0;
416 i--, bp++ )
417 *bp = maxv;