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

# User Rev Content
1 gregl 3.1 #ifndef lint
2 schorsch 3.4 static const char RCSid[] = "$Id: rhd_ctab.c,v 3.3 2003/05/13 17:58:33 greg Exp $";
3 gregl 3.1 #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 schorsch 3.4 #include <string.h>
20    
21 gregl 3.1 #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 greg 3.2 free((void *)clrtab);
68 gregl 3.1 if (ctree != NULL)
69 greg 3.2 free((void *)ctree);
70 gregl 3.1 /* 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 schorsch 3.4 memset((void *)histo, '\0', sizeof(histo));
82 gregl 3.1 /* 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 schorsch 3.4 memcpy((void *)kb, (void *)box, sizeof(kb));
158 gregl 3.1 /* 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     }