ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/rt/colortab.c
Revision: 1.4
Committed: Tue Oct 3 14:06:58 1989 UTC (34 years, 7 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 1.3: +21 -16 lines
Log Message:
Changed calling conventions slightly and added custom color map.

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 5
31 /* maximum frame buffer depth */
32 #define FBDEPTH 8
33 /* map a color */
34 #define map_col(c,p) clrmap[p][ colval(c,p)<1. ? \
35 (int)(colval(c,p)*256.) : 255 ]
36 /* color partition tree */
37 #define CNODE short
38 #define set_branch(p,c) ((c)<<2|(p))
39 #define set_pval(pv) ((pv)<<2|3)
40 #define is_pval(cn) (((cn)&3)==3)
41 #define part(cn) ((cn)>>2)
42 #define prim(cn) ((cn)&3)
43 #define pval(cn) ((cn)>>2)
44 /* our color table */
45 struct tabent {
46 long sum[3]; /* sum of colors using this entry */
47 long n; /* number of colors */
48 short ent[3]; /* current table value */
49 } clrtab[1<<FBDEPTH];
50 /* our color correction map */
51 static BYTE clrmap[3][256];
52 /* histogram of colors used */
53 static unsigned histo[NRED][NGRN][NBLU];
54 /* initial color cube boundaries */
55 static int CLRCUBE[3][2] = {0,NRED,0,NGRN,0,NBLU};
56 /* color cube partition */
57 static CNODE ctree[1<<(FBDEPTH+1)];
58
59
60 int
61 new_ctab(ncolors) /* start new color table with max ncolors */
62 int ncolors;
63 {
64 if (ncolors < 1 || ncolors > 1<<FBDEPTH)
65 return(0);
66 /* clear color table */
67 bzero(clrtab, sizeof(clrtab));
68 /* partition color space */
69 cut(ctree, FBDEPTH, CLRCUBE, 0, ncolors);
70 /* clear histogram */
71 bzero(histo, sizeof(histo));
72 /* return number of colors used */
73 return(ncolors);
74 }
75
76
77 int
78 get_pixel(col, set_pixel) /* get pixel for color */
79 COLOR col;
80 int (*set_pixel)();
81 {
82 int r, g, b;
83 int cv[3];
84 register union { CNODE *t; struct tabent *e; } p;
85 register int h;
86 /* map color */
87 r = map_col(col,RED);
88 g = map_col(col,GRN);
89 b = map_col(col,BLU);
90 /* reduce resolution */
91 cv[RED] = (r*NRED)>>8;
92 cv[GRN] = (g*NGRN)>>8;
93 cv[BLU] = (b*NBLU)>>8;
94 /* add to histogram */
95 histo[cv[RED]][cv[GRN]][cv[BLU]]++;
96 /* find pixel in tree */
97 p.t = ctree;
98 for (h = FBDEPTH; h > 0; h--) {
99 if (is_pval(*p.t))
100 break;
101 if (cv[prim(*p.t)] < part(*p.t))
102 p.t++; /* left branch */
103 else
104 p.t += 1<<h; /* right branch */
105 }
106 h = pval(*p.t);
107 /* add to color table */
108 p.e = clrtab + h;
109 /* add to sum */
110 p.e->sum[RED] += r;
111 p.e->sum[GRN] += g;
112 p.e->sum[BLU] += b;
113 p.e->n++;
114 /* recompute average */
115 r = p.e->sum[RED] / p.e->n;
116 g = p.e->sum[GRN] / p.e->n;
117 b = p.e->sum[BLU] / p.e->n;
118 /* check for movement */
119 if (p.e->n == 1 ||
120 (r-p.e->ent[RED])*(r-p.e->ent[RED]) +
121 (g-p.e->ent[GRN])*(g-p.e->ent[GRN]) +
122 (b-p.e->ent[BLU])*(b-p.e->ent[BLU]) > MAXDST2) {
123 p.e->ent[RED] = r;
124 p.e->ent[GRN] = g; /* reassign pixel */
125 p.e->ent[BLU] = b;
126 #ifdef notdef
127 printf("pixel %d = (%d,%d,%d) (%d refs)\n",
128 h, r, g, b, p.e->n);
129 #endif
130 (*set_pixel)(h, r, g, b);
131 }
132 return(h); /* return pixel value */
133 }
134
135
136 make_gmap(gam) /* make gamma correction map */
137 double gam;
138 {
139 extern double pow();
140 register int i;
141
142 for (i = 0; i < 256; i++)
143 clrmap[RED][i] =
144 clrmap[GRN][i] =
145 clrmap[BLU][i] = 256.0 * pow(i/256.0, 1.0/gam);
146 }
147
148
149 set_cmap(rmap, gmap, bmap) /* set custom color correction map */
150 BYTE *rmap, *gmap, *bmap;
151 {
152 bcopy(rmap, clrmap[RED], 256);
153 bcopy(gmap, clrmap[GRN], 256);
154 bcopy(bmap, clrmap[BLU], 256);
155 }
156
157
158 static
159 cut(tree, height, box, c0, c1) /* partition color space */
160 register CNODE *tree;
161 int height;
162 register int box[3][2];
163 int c0, c1;
164 {
165 int kb[3][2];
166
167 if (c1-c0 <= 1) { /* assign pixel */
168 *tree = set_pval(c0);
169 return;
170 }
171 /* split box */
172 *tree = split(box);
173 bcopy(box, kb, sizeof(kb));
174 /* do left (lesser) branch */
175 kb[prim(*tree)][1] = part(*tree);
176 cut(tree+1, height-1, kb, c0, (c0+c1)>>1);
177 /* do right branch */
178 kb[prim(*tree)][0] = part(*tree);
179 kb[prim(*tree)][1] = box[prim(*tree)][1];
180 cut(tree+(1<<height), height-1, kb, (c0+c1)>>1, c1);
181 }
182
183
184 static int
185 split(box) /* find median cut for box */
186 register int box[3][2];
187 {
188 #define c0 r
189 register int r, g, b;
190 int pri;
191 int t[HMAX], med;
192 /* find dominant axis */
193 pri = RED;
194 if (box[GRN][1]-box[GRN][0] > box[pri][1]-box[pri][0])
195 pri = GRN;
196 if (box[BLU][1]-box[BLU][0] > box[pri][1]-box[pri][0])
197 pri = BLU;
198 /* sum histogram over box */
199 med = 0;
200 switch (pri) {
201 case RED:
202 for (r = box[RED][0]; r < box[RED][1]; r++) {
203 t[r] = 0;
204 for (g = box[GRN][0]; g < box[GRN][1]; g++)
205 for (b = box[BLU][0]; b < box[BLU][1]; b++)
206 t[r] += histo[r][g][b];
207 med += t[r];
208 }
209 break;
210 case GRN:
211 for (g = box[GRN][0]; g < box[GRN][1]; g++) {
212 t[g] = 0;
213 for (b = box[BLU][0]; b < box[BLU][1]; b++)
214 for (r = box[RED][0]; r < box[RED][1]; r++)
215 t[g] += histo[r][g][b];
216 med += t[g];
217 }
218 break;
219 case BLU:
220 for (b = box[BLU][0]; b < box[BLU][1]; b++) {
221 t[b] = 0;
222 for (r = box[RED][0]; r < box[RED][1]; r++)
223 for (g = box[GRN][0]; g < box[GRN][1]; g++)
224 t[b] += histo[r][g][b];
225 med += t[b];
226 }
227 break;
228 }
229 if (med < MINSAMP) /* if too sparse, split at midpoint */
230 return(set_branch(pri,(box[pri][0]+box[pri][1])>>1));
231 /* find median position */
232 med >>= 1;
233 for (c0 = box[pri][0]; med > 0; c0++)
234 med -= t[c0];
235 if (c0 > (box[pri][0]+box[pri][1])>>1) /* if past the midpoint */
236 c0--; /* part left of median */
237 return(set_branch(pri,c0));
238 #undef c0
239 }