ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ctab.c
Revision: 3.6
Committed: Fri May 20 02:06:39 2011 UTC (12 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad4R2P2, rad5R0, rad5R1, rad4R2, rad4R1, rad4R2P1
Changes since 3.5: +3 -3 lines
Log Message:
Changed every instance of BYTE to uby8 to avoid conflicts

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rhd_ctab.c,v 3.5 2004/01/01 11:21:55 schorsch Exp $";
3 #endif
4 /*
5 * 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 * This module is essentially identical to src/rt/colortab.c,
16 * except there is no color mapping, since the tm library is used.
17 */
18
19 #include <string.h>
20
21 #include "standard.h"
22 #include "rhdisp.h"
23 #include "color.h"
24 /* histogram resolution */
25 #define NRED 24
26 #define NGRN 32
27 #define NBLU 16
28 #define HMAX NGRN
29 /* minimum box count for adaptive partition */
30 #define MINSAMP 7
31 /* maximum distance^2 before color reassign */
32 #define MAXDST2 12
33 /* color partition tree */
34 #define CNODE short
35 #define set_branch(p,c) ((c)<<2|(p))
36 #define set_pval(pv) ((pv)<<2|3)
37 #define is_branch(cn) (((cn)&3)!=3)
38 #define is_pval(cn) (((cn)&3)==3)
39 #define part(cn) ((cn)>>2)
40 #define prim(cn) ((cn)&3)
41 #define pval(cn) ((cn)>>2)
42 /* our color table */
43 static struct tabent {
44 long sum[3]; /* sum of colors using this entry */
45 int n; /* number of colors */
46 uby8 ent[3]; /* current table value */
47 } *clrtab = NULL;
48 /* color cube partition */
49 static CNODE *ctree = NULL;
50 /* histogram of colors used */
51 static unsigned short histo[NRED][NGRN][NBLU];
52 /* initial color cube boundary */
53 static int CLRCUBE[3][2] = {{0,NRED},{0,NGRN},{0,NBLU}};
54
55 static void cut(CNODE *tree, int level, int box[3][2], int c0, int c1);
56 static int split(int box[3][2]);
57
58
59
60 extern int
61 new_ctab( /* start new color table with max ncolors */
62 int ncolors
63 )
64 {
65 int treesize;
66
67 if (ncolors < 1)
68 return(0);
69 /* free old tables */
70 if (clrtab != NULL)
71 free((void *)clrtab);
72 if (ctree != NULL)
73 free((void *)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 memset((void *)histo, '\0', sizeof(histo));
86 /* return number of colors used */
87 return(ncolors);
88 }
89
90
91 extern int
92 get_pixel( /* get pixel for color */
93 uby8 rgb[3],
94 void (*set_pixel)(int h, int r, int g, int b)
95 )
96 {
97 int r, g, b;
98 int cv[3];
99 register CNODE *tp;
100 register int h;
101 /* get desired color */
102 r = rgb[RED];
103 g = rgb[GRN];
104 b = rgb[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 {
137 extern char errmsg[];
138 sprintf(errmsg, "pixel %d = (%d,%d,%d) (%d refs)\n",
139 h, r, g, b, clrtab[h].n);
140 eputs(errmsg);
141 }
142 #endif
143 (*set_pixel)(h, r, g, b);
144 }
145 return(h); /* return pixel value */
146 }
147
148
149 static void
150 cut( /* partition color space */
151 register CNODE *tree,
152 int level,
153 register int box[3][2],
154 int c0,
155 int c1
156 )
157 {
158 int kb[3][2];
159
160 if (c1-c0 <= 1) { /* assign pixel */
161 *tree = set_pval(c0);
162 return;
163 }
164 /* split box */
165 *tree = split(box);
166 memcpy((void *)kb, (void *)box, sizeof(kb));
167 /* do left (lesser) branch */
168 kb[prim(*tree)][1] = part(*tree);
169 cut(tree+(1<<level), level+1, kb, c0, (c0+c1)>>1);
170 /* do right branch */
171 kb[prim(*tree)][0] = part(*tree);
172 kb[prim(*tree)][1] = box[prim(*tree)][1];
173 cut(tree+(1<<(level+1)), level+1, kb, (c0+c1)>>1, c1);
174 }
175
176
177 static int
178 split( /* find median cut for box */
179 register int box[3][2]
180 )
181 {
182 #define c0 r
183 register int r, g, b;
184 int pri;
185 long t[HMAX], med;
186 /* find dominant axis */
187 pri = RED;
188 if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
189 pri = GRN;
190 if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
191 pri = BLU;
192 /* sum histogram over box */
193 med = 0;
194 switch (pri) {
195 case RED:
196 for (r = box[RED][0]; r < box[RED][1]; r++) {
197 t[r] = 0;
198 for (g = box[GRN][0]; g < box[GRN][1]; g++)
199 for (b = box[BLU][0]; b < box[BLU][1]; b++)
200 t[r] += histo[r][g][b];
201 med += t[r];
202 }
203 break;
204 case GRN:
205 for (g = box[GRN][0]; g < box[GRN][1]; g++) {
206 t[g] = 0;
207 for (b = box[BLU][0]; b < box[BLU][1]; b++)
208 for (r = box[RED][0]; r < box[RED][1]; r++)
209 t[g] += histo[r][g][b];
210 med += t[g];
211 }
212 break;
213 case BLU:
214 for (b = box[BLU][0]; b < box[BLU][1]; b++) {
215 t[b] = 0;
216 for (r = box[RED][0]; r < box[RED][1]; r++)
217 for (g = box[GRN][0]; g < box[GRN][1]; g++)
218 t[b] += histo[r][g][b];
219 med += t[b];
220 }
221 break;
222 }
223 if (med < MINSAMP) /* if too sparse, split at midpoint */
224 return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
225 /* find median position */
226 med >>= 1;
227 for (c0 = box[pri][0]; med > 0; c0++)
228 med -= t[c0];
229 if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
230 c0--; /* part left of median */
231 return(set_branch(pri,c0));
232 #undef c0
233 }