ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 2.7
Committed: Tue May 13 17:58:33 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.6: +5 -5 lines
Log Message:
Changed (char *) casts for memory copies to (void *) and other fixes

File Contents

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