ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 2.3
Committed: Mon Mar 8 12:37:21 1993 UTC (31 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.2: +3 -1 lines
Log Message:
portability fixes (removed gcc warnings)

File Contents

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