ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ctab.c
Revision: 3.4
Committed: Mon Jun 30 14:59:11 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 3.3: +5 -3 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: rhd_ctab.c,v 3.3 2003/05/13 17:58:33 greg 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 "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 /* color partition tree */
33 #define CNODE short
34 #define set_branch(p,c) ((c)<<2|(p))
35 #define set_pval(pv) ((pv)<<2|3)
36 #define is_branch(cn) (((cn)&3)!=3)
37 #define is_pval(cn) (((cn)&3)==3)
38 #define part(cn) ((cn)>>2)
39 #define prim(cn) ((cn)&3)
40 #define pval(cn) ((cn)>>2)
41 /* our color table */
42 static struct tabent {
43 long sum[3]; /* sum of colors using this entry */
44 int n; /* number of colors */
45 BYTE ent[3]; /* current table value */
46 } *clrtab = NULL;
47 /* color cube partition */
48 static CNODE *ctree = NULL;
49 /* histogram of colors used */
50 static unsigned short histo[NRED][NGRN][NBLU];
51 /* initial color cube boundary */
52 static int CLRCUBE[3][2] = {{0,NRED},{0,NGRN},{0,NBLU}};
53
54 static int split(), cut();
55
56
57 int
58 new_ctab(ncolors) /* start new color table with max ncolors */
59 int ncolors;
60 {
61 int treesize;
62
63 if (ncolors < 1)
64 return(0);
65 /* free old tables */
66 if (clrtab != NULL)
67 free((void *)clrtab);
68 if (ctree != NULL)
69 free((void *)ctree);
70 /* get new tables */
71 for (treesize = 1; treesize < ncolors; treesize <<= 1)
72 ;
73 treesize <<= 1;
74 clrtab = (struct tabent *)calloc(ncolors, sizeof(struct tabent));
75 ctree = (CNODE *)malloc(treesize*sizeof(CNODE));
76 if (clrtab == NULL || ctree == NULL)
77 return(0);
78 /* partition color space */
79 cut(ctree, 0, CLRCUBE, 0, ncolors);
80 /* clear histogram */
81 memset((void *)histo, '\0', sizeof(histo));
82 /* return number of colors used */
83 return(ncolors);
84 }
85
86
87 int
88 get_pixel(rgb, set_pixel) /* get pixel for color */
89 BYTE rgb[3];
90 int (*set_pixel)();
91 {
92 extern char errmsg[];
93 int r, g, b;
94 int cv[3];
95 register CNODE *tp;
96 register int h;
97 /* get desired color */
98 r = rgb[RED];
99 g = rgb[GRN];
100 b = rgb[BLU];
101 /* reduce resolution */
102 cv[RED] = (r*NRED)>>8;
103 cv[GRN] = (g*NGRN)>>8;
104 cv[BLU] = (b*NBLU)>>8;
105 /* add to histogram */
106 histo[cv[RED]][cv[GRN]][cv[BLU]]++;
107 /* find pixel in tree */
108 for (tp = ctree, h = 0; is_branch(*tp); h++)
109 if (cv[prim(*tp)] < part(*tp))
110 tp += 1<<h; /* left branch */
111 else
112 tp += 1<<(h+1); /* right branch */
113 h = pval(*tp);
114 /* add to color table */
115 clrtab[h].sum[RED] += r;
116 clrtab[h].sum[GRN] += g;
117 clrtab[h].sum[BLU] += b;
118 clrtab[h].n++;
119 /* recompute average */
120 r = clrtab[h].sum[RED] / clrtab[h].n;
121 g = clrtab[h].sum[GRN] / clrtab[h].n;
122 b = clrtab[h].sum[BLU] / clrtab[h].n;
123 /* check for movement */
124 if (clrtab[h].n == 1 ||
125 (r-clrtab[h].ent[RED])*(r-clrtab[h].ent[RED]) +
126 (g-clrtab[h].ent[GRN])*(g-clrtab[h].ent[GRN]) +
127 (b-clrtab[h].ent[BLU])*(b-clrtab[h].ent[BLU]) > MAXDST2) {
128 clrtab[h].ent[RED] = r;
129 clrtab[h].ent[GRN] = g; /* reassign pixel */
130 clrtab[h].ent[BLU] = b;
131 #ifdef DEBUG
132 sprintf(errmsg, "pixel %d = (%d,%d,%d) (%d refs)\n",
133 h, r, g, b, clrtab[h].n);
134 eputs(errmsg);
135 #endif
136 (*set_pixel)(h, r, g, b);
137 }
138 return(h); /* return pixel value */
139 }
140
141
142 static
143 cut(tree, level, box, c0, c1) /* partition color space */
144 register CNODE *tree;
145 int level;
146 register int box[3][2];
147 int c0, c1;
148 {
149 int kb[3][2];
150
151 if (c1-c0 <= 1) { /* assign pixel */
152 *tree = set_pval(c0);
153 return;
154 }
155 /* split box */
156 *tree = split(box);
157 memcpy((void *)kb, (void *)box, sizeof(kb));
158 /* do left (lesser) branch */
159 kb[prim(*tree)][1] = part(*tree);
160 cut(tree+(1<<level), level+1, kb, c0, (c0+c1)>>1);
161 /* do right branch */
162 kb[prim(*tree)][0] = part(*tree);
163 kb[prim(*tree)][1] = box[prim(*tree)][1];
164 cut(tree+(1<<(level+1)), level+1, kb, (c0+c1)>>1, c1);
165 }
166
167
168 static int
169 split(box) /* find median cut for box */
170 register int box[3][2];
171 {
172 #define c0 r
173 register int r, g, b;
174 int pri;
175 long t[HMAX], med;
176 /* find dominant axis */
177 pri = RED;
178 if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
179 pri = GRN;
180 if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
181 pri = BLU;
182 /* sum histogram over box */
183 med = 0;
184 switch (pri) {
185 case RED:
186 for (r = box[RED][0]; r < box[RED][1]; r++) {
187 t[r] = 0;
188 for (g = box[GRN][0]; g < box[GRN][1]; g++)
189 for (b = box[BLU][0]; b < box[BLU][1]; b++)
190 t[r] += histo[r][g][b];
191 med += t[r];
192 }
193 break;
194 case GRN:
195 for (g = box[GRN][0]; g < box[GRN][1]; g++) {
196 t[g] = 0;
197 for (b = box[BLU][0]; b < box[BLU][1]; b++)
198 for (r = box[RED][0]; r < box[RED][1]; r++)
199 t[g] += histo[r][g][b];
200 med += t[g];
201 }
202 break;
203 case BLU:
204 for (b = box[BLU][0]; b < box[BLU][1]; b++) {
205 t[b] = 0;
206 for (r = box[RED][0]; r < box[RED][1]; r++)
207 for (g = box[GRN][0]; g < box[GRN][1]; g++)
208 t[b] += histo[r][g][b];
209 med += t[b];
210 }
211 break;
212 }
213 if (med < MINSAMP) /* if too sparse, split at midpoint */
214 return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
215 /* find median position */
216 med >>= 1;
217 for (c0 = box[pri][0]; med > 0; c0++)
218 med -= t[c0];
219 if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
220 c0--; /* part left of median */
221 return(set_branch(pri,c0));
222 #undef c0
223 }