ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ctab.c
Revision: 3.2
Committed: Sat Feb 22 02:07:24 2003 UTC (21 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 3.1: +3 -6 lines
Log Message:
Changes and check-in for 3.5 release
Includes new source files and modifications not recorded for many years
See ray/doc/notes/ReleaseNotes for notes between 3.1 and 3.5 release

File Contents

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