ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_ctab.c
Revision: 3.3
Committed: Tue May 13 17:58:33 2003 UTC (20 years, 11 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 3.2: +2 -2 lines
Log Message:
Changed (char *) casts for memory copies to (void *) and other fixes

File Contents

# User Rev Content
1 gregl 3.1 #ifndef lint
2 greg 3.2 static const char RCSid[] = "$Id$";
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     #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 greg 3.2 free((void *)clrtab);
66 gregl 3.1 if (ctree != NULL)
67 greg 3.2 free((void *)ctree);
68 gregl 3.1 /* 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 greg 3.3 bzero((void *)histo, sizeof(histo));
80 gregl 3.1 /* 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 greg 3.3 bcopy((void *)box, (void *)kb, sizeof(kb));
156 gregl 3.1 /* 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     }