ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 2.8
Committed: Mon Jun 30 14:59:12 2003 UTC (20 years, 10 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.7: +9 -7 lines
Log Message:
Replaced most outdated BSD function calls with their posix equivalents, and cleaned up a few other platform dependencies.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: colortab.c,v 2.7 2003/05/13 17:58:33 greg Exp $";
3 #endif
4 /*
5 * colortab.c - allocate and control dynamic color table.
6 *
7 * We start off with a uniform partition of color space.
8 * As pixels are sent to the frame buffer, a histogram is built.
9 * When a new color table is requested, the histogram is used
10 * to make a pseudo-optimal partition, after which the
11 * histogram is cleared. This algorithm
12 * performs only as well as the next drawing's color
13 * distribution is correlated to the last.
14 *
15 * External symbols declared in drvier.h
16 */
17
18 #include "copyright.h"
19
20 #include <string.h>
21
22 #include "standard.h"
23 #include "color.h"
24
25 /* histogram resolution */
26 #define NRED 24
27 #define NGRN 32
28 #define NBLU 16
29 #define HMAX NGRN
30 /* minimum box count for adaptive partition */
31 #define MINSAMP 7
32 /* maximum distance^2 before color reassign */
33 #define MAXDST2 12
34 /* map a color */
35 #define map_col(c,p) clrmap[p][ colval(c,p)<1. ? \
36 (int)(colval(c,p)*256.) : 255 ]
37 /* color partition tree */
38 #define CNODE short
39 #define set_branch(p,c) ((c)<<2|(p))
40 #define set_pval(pv) ((pv)<<2|3)
41 #define is_branch(cn) (((cn)&3)!=3)
42 #define is_pval(cn) (((cn)&3)==3)
43 #define part(cn) ((cn)>>2)
44 #define prim(cn) ((cn)&3)
45 #define pval(cn) ((cn)>>2)
46 /* our color table */
47 static struct tabent {
48 long sum[3]; /* sum of colors using this entry */
49 int n; /* number of colors */
50 BYTE ent[3]; /* current table value */
51 } *clrtab = NULL;
52 /* color cube partition */
53 static CNODE *ctree = NULL;
54 /* our color correction map */
55 static BYTE clrmap[3][256];
56 /* histogram of colors used */
57 static unsigned short histo[NRED][NGRN][NBLU];
58 /* initial color cube boundary */
59 static int CLRCUBE[3][2] = {{0,NRED},{0,NGRN},{0,NBLU}};
60
61 static int split();
62 static void cut();
63
64
65 int
66 new_ctab(ncolors) /* start new color table with max ncolors */
67 int ncolors;
68 {
69 int treesize;
70
71 if (ncolors < 1)
72 return(0);
73 /* free old tables */
74 if (clrtab != NULL)
75 free((void *)clrtab);
76 if (ctree != NULL)
77 free((void *)ctree);
78 /* get new tables */
79 for (treesize = 1; treesize < ncolors; treesize <<= 1)
80 ;
81 treesize <<= 1;
82 clrtab = (struct tabent *)calloc(ncolors, sizeof(struct tabent));
83 ctree = (CNODE *)malloc(treesize*sizeof(CNODE));
84 if (clrtab == NULL || ctree == NULL)
85 return(0);
86 /* partition color space */
87 cut(ctree, 0, CLRCUBE, 0, ncolors);
88 /* clear histogram */
89 memset((void *)histo, '\0', sizeof(histo));
90 /* return number of colors used */
91 return(ncolors);
92 }
93
94
95 int
96 get_pixel(col, set_pixel) /* get pixel for color */
97 COLOR col;
98 void (*set_pixel)();
99 {
100 int r, g, b;
101 int cv[3];
102 register CNODE *tp;
103 register int h;
104 /* map color */
105 r = map_col(col,RED);
106 g = map_col(col,GRN);
107 b = map_col(col,BLU);
108 /* reduce resolution */
109 cv[RED] = (r*NRED)>>8;
110 cv[GRN] = (g*NGRN)>>8;
111 cv[BLU] = (b*NBLU)>>8;
112 /* add to histogram */
113 histo[cv[RED]][cv[GRN]][cv[BLU]]++;
114 /* find pixel in tree */
115 for (tp = ctree, h = 0; is_branch(*tp); h++)
116 if (cv[prim(*tp)] < part(*tp))
117 tp += 1<<h; /* left branch */
118 else
119 tp += 1<<(h+1); /* right branch */
120 h = pval(*tp);
121 /* add to color table */
122 clrtab[h].sum[RED] += r;
123 clrtab[h].sum[GRN] += g;
124 clrtab[h].sum[BLU] += b;
125 clrtab[h].n++;
126 /* recompute average */
127 r = clrtab[h].sum[RED] / clrtab[h].n;
128 g = clrtab[h].sum[GRN] / clrtab[h].n;
129 b = clrtab[h].sum[BLU] / clrtab[h].n;
130 /* check for movement */
131 if (clrtab[h].n == 1 ||
132 (r-clrtab[h].ent[RED])*(r-clrtab[h].ent[RED]) +
133 (g-clrtab[h].ent[GRN])*(g-clrtab[h].ent[GRN]) +
134 (b-clrtab[h].ent[BLU])*(b-clrtab[h].ent[BLU]) > MAXDST2) {
135 clrtab[h].ent[RED] = r;
136 clrtab[h].ent[GRN] = g; /* reassign pixel */
137 clrtab[h].ent[BLU] = b;
138 #ifdef DEBUG
139 sprintf(errmsg, "pixel %d = (%d,%d,%d) (%d refs)\n",
140 h, r, g, b, clrtab[h].n);
141 eputs(errmsg);
142 #endif
143 (*set_pixel)(h, r, g, b);
144 }
145 return(h); /* return pixel value */
146 }
147
148
149 void
150 make_gmap(gam) /* make gamma correction map */
151 double gam;
152 {
153 register int i;
154
155 for (i = 0; i < 256; i++)
156 clrmap[RED][i] =
157 clrmap[GRN][i] =
158 clrmap[BLU][i] = 256.0 * pow((i+0.5)/256.0, 1.0/gam);
159 }
160
161
162 void
163 set_cmap(rmap, gmap, bmap) /* set custom color correction map */
164 BYTE *rmap, *gmap, *bmap;
165 {
166 memcpy((void *)clrmap[RED], (void *)rmap, 256);
167 memcpy((void *)clrmap[GRN], (void *)gmap, 256);
168 memcpy((void *)clrmap[BLU], (void *)bmap, 256);
169 }
170
171
172 void
173 map_color(rgb, col) /* map a color to a byte triplet */
174 BYTE rgb[3];
175 COLOR col;
176 {
177 rgb[RED] = map_col(col,RED);
178 rgb[GRN] = map_col(col,GRN);
179 rgb[BLU] = map_col(col,BLU);
180 }
181
182
183 static void
184 cut(tree, level, box, c0, c1) /* partition color space */
185 register CNODE *tree;
186 int level;
187 register int box[3][2];
188 int c0, c1;
189 {
190 int kb[3][2];
191
192 if (c1-c0 <= 1) { /* assign pixel */
193 *tree = set_pval(c0);
194 return;
195 }
196 /* split box */
197 *tree = split(box);
198 memcpy((void *)kb, (void *)box, sizeof(kb));
199 /* do left (lesser) branch */
200 kb[prim(*tree)][1] = part(*tree);
201 cut(tree+(1<<level), level+1, kb, c0, (c0+c1)>>1);
202 /* do right branch */
203 kb[prim(*tree)][0] = part(*tree);
204 kb[prim(*tree)][1] = box[prim(*tree)][1];
205 cut(tree+(1<<(level+1)), level+1, kb, (c0+c1)>>1, c1);
206 }
207
208
209 static int
210 split(box) /* find median cut for box */
211 register int box[3][2];
212 {
213 #define c0 r
214 register int r, g, b;
215 int pri;
216 long t[HMAX], med;
217 /* find dominant axis */
218 pri = RED;
219 if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
220 pri = GRN;
221 if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
222 pri = BLU;
223 /* sum histogram over box */
224 med = 0;
225 switch (pri) {
226 case RED:
227 for (r = box[RED][0]; r < box[RED][1]; r++) {
228 t[r] = 0;
229 for (g = box[GRN][0]; g < box[GRN][1]; g++)
230 for (b = box[BLU][0]; b < box[BLU][1]; b++)
231 t[r] += histo[r][g][b];
232 med += t[r];
233 }
234 break;
235 case GRN:
236 for (g = box[GRN][0]; g < box[GRN][1]; g++) {
237 t[g] = 0;
238 for (b = box[BLU][0]; b < box[BLU][1]; b++)
239 for (r = box[RED][0]; r < box[RED][1]; r++)
240 t[g] += histo[r][g][b];
241 med += t[g];
242 }
243 break;
244 case BLU:
245 for (b = box[BLU][0]; b < box[BLU][1]; b++) {
246 t[b] = 0;
247 for (r = box[RED][0]; r < box[RED][1]; r++)
248 for (g = box[GRN][0]; g < box[GRN][1]; g++)
249 t[b] += histo[r][g][b];
250 med += t[b];
251 }
252 break;
253 }
254 if (med < MINSAMP) /* if too sparse, split at midpoint */
255 return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
256 /* find median position */
257 med >>= 1;
258 for (c0 = box[pri][0]; med > 0; c0++)
259 med -= t[c0];
260 if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
261 c0--; /* part left of median */
262 return(set_branch(pri,c0));
263 #undef c0
264 }