ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 1.8
Committed: Thu Oct 12 11:32:09 1989 UTC (34 years, 6 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.7: +19 -10 lines
Log Message:
Dynamic allocation to eliminate cap on color table size.

File Contents

# Content
1 /* Copyright (c) 1989 Regents of the University of California */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ LBL";
5 #endif
6
7 /*
8 * colortab.c - allocate and control dynamic color table.
9 *
10 * We start off with a uniform partition of color space.
11 * As pixels are sent to the frame buffer, a histogram is built.
12 * When a new color table is requested, the histogram is used
13 * to make a pseudo-optimal partition, after which the
14 * histogram is cleared. This algorithm
15 * performs only as well as the next drawing's color
16 * distribution is correlated to the last.
17 */
18
19 #include "color.h"
20
21 #define NULL 0
22 /* histogram resolution */
23 #define NRED 24
24 #define NGRN 32
25 #define NBLU 16
26 #define HMAX NGRN
27 /* minimum box count for adaptive partition */
28 #define MINSAMP 7
29 /* maximum distance^2 before color reassign */
30 #define MAXDST2 12
31 /* map a color */
32 #define map_col(c,p) clrmap[p][ colval(c,p)<1. ? \
33 (int)(colval(c,p)*256.) : 255 ]
34 /* color partition tree */
35 #define CNODE short
36 #define set_branch(p,c) ((c)<<2|(p))
37 #define set_pval(pv) ((pv)<<2|3)
38 #define is_branch(cn) (((cn)&3)!=3)
39 #define is_pval(cn) (((cn)&3)==3)
40 #define part(cn) ((cn)>>2)
41 #define prim(cn) ((cn)&3)
42 #define pval(cn) ((cn)>>2)
43 /* our color table */
44 static struct tabent {
45 long sum[3]; /* sum of colors using this entry */
46 long n; /* number of colors */
47 short ent[3]; /* current table value */
48 } *clrtab = NULL;
49 /* color cube partition */
50 static CNODE *ctree = NULL;
51 /* our color correction map */
52 static BYTE clrmap[3][256];
53 /* histogram of colors used */
54 static unsigned histo[NRED][NGRN][NBLU];
55 /* initial color cube boundary */
56 static int CLRCUBE[3][2] = {0,NRED,0,NGRN,0,NBLU};
57
58
59 int
60 new_ctab(ncolors) /* start new color table with max ncolors */
61 int ncolors;
62 {
63 int treesize;
64
65 if (ncolors < 1)
66 return(0);
67 /* free old tables */
68 if (clrtab != NULL)
69 free((char *)clrtab);
70 if (ctree != NULL)
71 free((char *)ctree);
72 /* get new tables */
73 for (treesize = 1; treesize < ncolors; treesize <<= 1)
74 ;
75 treesize <<= 1;
76 clrtab = (struct tabent *)calloc(ncolors, sizeof(struct tabent));
77 ctree = (CNODE *)malloc(treesize*sizeof(CNODE));
78 if (clrtab == NULL || ctree == NULL)
79 return(0);
80 /* partition color space */
81 cut(ctree, 0, CLRCUBE, 0, ncolors);
82 /* clear histogram */
83 bzero(histo, sizeof(histo));
84 /* return number of colors used */
85 return(ncolors);
86 }
87
88
89 int
90 get_pixel(col, set_pixel) /* get pixel for color */
91 COLOR col;
92 int (*set_pixel)();
93 {
94 int r, g, b;
95 int cv[3];
96 register union { CNODE *t; struct tabent *e; } p;
97 register int h;
98 /* map color */
99 r = map_col(col,RED);
100 g = map_col(col,GRN);
101 b = map_col(col,BLU);
102 /* reduce resolution */
103 cv[RED] = (r*NRED)>>8;
104 cv[GRN] = (g*NGRN)>>8;
105 cv[BLU] = (b*NBLU)>>8;
106 /* add to histogram */
107 histo[cv[RED]][cv[GRN]][cv[BLU]]++;
108 /* find pixel in tree */
109 for (p.t = ctree, h = 0; is_branch(*p.t); h++)
110 if (cv[prim(*p.t)] < part(*p.t))
111 p.t += 1<<h; /* left branch */
112 else
113 p.t += 1<<(h+1); /* right branch */
114 h = pval(*p.t);
115 /* add to color table */
116 p.e = clrtab + h;
117 /* add to sum */
118 p.e->sum[RED] += r;
119 p.e->sum[GRN] += g;
120 p.e->sum[BLU] += b;
121 p.e->n++;
122 /* recompute average */
123 r = p.e->sum[RED] / p.e->n;
124 g = p.e->sum[GRN] / p.e->n;
125 b = p.e->sum[BLU] / p.e->n;
126 /* check for movement */
127 if (p.e->n == 1 ||
128 (r-p.e->ent[RED])*(r-p.e->ent[RED]) +
129 (g-p.e->ent[GRN])*(g-p.e->ent[GRN]) +
130 (b-p.e->ent[BLU])*(b-p.e->ent[BLU]) > MAXDST2) {
131 p.e->ent[RED] = r;
132 p.e->ent[GRN] = g; /* reassign pixel */
133 p.e->ent[BLU] = b;
134 #ifdef notdef
135 printf("pixel %d = (%d,%d,%d) (%d refs)\n",
136 h, r, g, b, p.e->n);
137 #endif
138 (*set_pixel)(h, r, g, b);
139 }
140 return(h); /* return pixel value */
141 }
142
143
144 make_gmap(gam) /* make gamma correction map */
145 double gam;
146 {
147 extern double pow();
148 register int i;
149
150 for (i = 0; i < 256; i++)
151 clrmap[RED][i] =
152 clrmap[GRN][i] =
153 clrmap[BLU][i] = 256.0 * pow(i/256.0, 1.0/gam);
154 }
155
156
157 set_cmap(rmap, gmap, bmap) /* set custom color correction map */
158 BYTE *rmap, *gmap, *bmap;
159 {
160 bcopy(rmap, clrmap[RED], 256);
161 bcopy(gmap, clrmap[GRN], 256);
162 bcopy(bmap, clrmap[BLU], 256);
163 }
164
165
166 static
167 cut(tree, level, box, c0, c1) /* partition color space */
168 register CNODE *tree;
169 int level;
170 register int box[3][2];
171 int c0, c1;
172 {
173 int kb[3][2];
174
175 if (c1-c0 <= 1) { /* assign pixel */
176 *tree = set_pval(c0);
177 return;
178 }
179 /* split box */
180 *tree = split(box);
181 bcopy(box, kb, sizeof(kb));
182 /* do left (lesser) branch */
183 kb[prim(*tree)][1] = part(*tree);
184 cut(tree+(1<<level), level+1, kb, c0, (c0+c1)>>1);
185 /* do right branch */
186 kb[prim(*tree)][0] = part(*tree);
187 kb[prim(*tree)][1] = box[prim(*tree)][1];
188 cut(tree+(1<<(level+1)), level+1, kb, (c0+c1)>>1, c1);
189 }
190
191
192 static int
193 split(box) /* find median cut for box */
194 register int box[3][2];
195 {
196 #define c0 r
197 register int r, g, b;
198 int pri;
199 int t[HMAX], med;
200 /* find dominant axis */
201 pri = RED;
202 if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
203 pri = GRN;
204 if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
205 pri = BLU;
206 /* sum histogram over box */
207 med = 0;
208 switch (pri) {
209 case RED:
210 for (r = box[RED][0]; r < box[RED][1]; r++) {
211 t[r] = 0;
212 for (g = box[GRN][0]; g < box[GRN][1]; g++)
213 for (b = box[BLU][0]; b < box[BLU][1]; b++)
214 t[r] += histo[r][g][b];
215 med += t[r];
216 }
217 break;
218 case GRN:
219 for (g = box[GRN][0]; g < box[GRN][1]; g++) {
220 t[g] = 0;
221 for (b = box[BLU][0]; b < box[BLU][1]; b++)
222 for (r = box[RED][0]; r < box[RED][1]; r++)
223 t[g] += histo[r][g][b];
224 med += t[g];
225 }
226 break;
227 case BLU:
228 for (b = box[BLU][0]; b < box[BLU][1]; b++) {
229 t[b] = 0;
230 for (r = box[RED][0]; r < box[RED][1]; r++)
231 for (g = box[GRN][0]; g < box[GRN][1]; g++)
232 t[b] += histo[r][g][b];
233 med += t[b];
234 }
235 break;
236 }
237 if (med < MINSAMP) /* if too sparse, split at midpoint */
238 return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
239 /* find median position */
240 med >>= 1;
241 for (c0 = box[pri][0]; med > 0; c0++)
242 med -= t[c0];
243 if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
244 c0--; /* part left of median */
245 return(set_branch(pri,c0));
246 #undef c0
247 }