ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_qtree.c
Revision: 3.9
Committed: Tue Nov 25 16:52:04 1997 UTC (26 years, 4 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 3.8: +1 -109 lines
Log Message:
moved routines specific to rectangle update to rhd_qtree2r.c

File Contents

# Content
1 /* Copyright (c) 1997 Silicon Graphics, Inc. */
2
3 #ifndef lint
4 static char SCCSid[] = "$SunId$ SGI";
5 #endif
6
7 /*
8 * Quadtree driver support routines.
9 */
10
11 #include "standard.h"
12 #include "rhd_qtree.h"
13 /* quantity of leaves to free at a time */
14 #ifndef LFREEPCT
15 #define LFREEPCT 25
16 #endif
17
18 RTREE qtrunk; /* our quadtree trunk */
19 double qtDepthEps = .02; /* epsilon to compare depths (z fraction) */
20 int qtMinNodesiz = 2; /* minimum node dimension (pixels) */
21 struct rleaves qtL; /* our pile of leaves */
22
23 #define TBUNDLESIZ 409 /* number of twigs in a bundle */
24
25 static RTREE **twigbundle; /* free twig blocks (NULL term.) */
26 static int nexttwig; /* next free twig */
27
28
29 static RTREE *
30 newtwig() /* allocate a twig */
31 {
32 register int bi;
33
34 if (twigbundle == NULL) { /* initialize */
35 twigbundle = (RTREE **)malloc(sizeof(RTREE *));
36 if (twigbundle == NULL)
37 goto memerr;
38 twigbundle[0] = NULL;
39 }
40 bi = nexttwig / TBUNDLESIZ;
41 if (twigbundle[bi] == NULL) { /* new block */
42 twigbundle = (RTREE **)realloc((char *)twigbundle,
43 (bi+2)*sizeof(RTREE *));
44 if (twigbundle == NULL)
45 goto memerr;
46 twigbundle[bi] = (RTREE *)calloc(TBUNDLESIZ, sizeof(RTREE));
47 if (twigbundle[bi] == NULL)
48 goto memerr;
49 twigbundle[bi+1] = NULL;
50 }
51 /* nexttwig++ % TBUNDLESIZ */
52 return(twigbundle[bi] + (nexttwig++ - bi*TBUNDLESIZ));
53 memerr:
54 error(SYSTEM, "out of memory in newtwig");
55 }
56
57
58 qtFreeTree(really) /* free allocated twigs */
59 int really;
60 {
61 register int i;
62
63 qtrunk.flgs = CH_ANY; /* chop down tree */
64 if (twigbundle == NULL)
65 return;
66 i = (TBUNDLESIZ-1+nexttwig)/TBUNDLESIZ;
67 nexttwig = 0;
68 if (!really) { /* just clear allocated blocks */
69 while (i--)
70 bzero((char *)twigbundle[i], TBUNDLESIZ*sizeof(RTREE));
71 return;
72 }
73 /* else "really" means free up memory */
74 for (i = 0; twigbundle[i] != NULL; i++)
75 free((char *)twigbundle[i]);
76 free((char *)twigbundle);
77 twigbundle = NULL;
78 }
79
80
81 static int
82 newleaf() /* allocate a leaf from our pile */
83 {
84 int li;
85
86 li = qtL.tl++;
87 if (qtL.tl >= qtL.nl) /* get next leaf in ring */
88 qtL.tl = 0;
89 if (qtL.tl == qtL.bl) /* need to shake some free */
90 qtCompost(LFREEPCT);
91 return(li);
92 }
93
94
95 #define LEAFSIZ (3*sizeof(float)+sizeof(TMbright)+6*sizeof(BYTE))
96
97 int
98 qtAllocLeaves(n) /* allocate space for n leaves */
99 register int n;
100 {
101 unsigned nbytes;
102 register unsigned i;
103
104 qtFreeTree(0); /* make sure tree is empty */
105 if (n <= 0)
106 return(0);
107 if (qtL.nl >= n)
108 return(qtL.nl);
109 else if (qtL.nl > 0)
110 free(qtL.base);
111 /* round space up to nearest power of 2 */
112 nbytes = n*LEAFSIZ + 8;
113 for (i = 1024; nbytes > i; i <<= 1)
114 ;
115 n = (i - 8) / LEAFSIZ; /* should we make sure n is even? */
116 qtL.base = (char *)malloc(n*LEAFSIZ);
117 if (qtL.base == NULL)
118 return(0);
119 /* assign larger alignment types earlier */
120 qtL.wp = (float (*)[3])qtL.base;
121 qtL.brt = (TMbright *)(qtL.wp + n);
122 qtL.chr = (BYTE (*)[3])(qtL.brt + n);
123 qtL.rgb = (BYTE (*)[3])(qtL.chr + n);
124 qtL.nl = n;
125 qtL.tml = qtL.bl = qtL.tl = 0;
126 return(n);
127 }
128
129 #undef LEAFSIZ
130
131
132 qtFreeLeaves() /* free our allocated leaves and twigs */
133 {
134 qtFreeTree(1); /* free tree also */
135 if (qtL.nl <= 0)
136 return;
137 free(qtL.base);
138 qtL.base = NULL;
139 qtL.nl = 0;
140 }
141
142
143 static
144 shaketree(tp) /* shake dead leaves from tree */
145 register RTREE *tp;
146 {
147 register int i, li;
148
149 for (i = 0; i < 4; i++)
150 if (tp->flgs & BRF(i)) {
151 shaketree(tp->k[i].b);
152 if (is_stump(tp->k[i].b))
153 tp->flgs &= ~BRF(i);
154 } else if (tp->flgs & LFF(i)) {
155 li = tp->k[i].li;
156 if (qtL.bl < qtL.tl ?
157 (li < qtL.bl || li >= qtL.tl) :
158 (li < qtL.bl && li >= qtL.tl))
159 tp->flgs &= ~LFF(i);
160 }
161 }
162
163
164 int
165 qtCompost(pct) /* free up some leaves */
166 int pct;
167 {
168 int nused, nclear, nmapped;
169
170 /* figure out how many leaves to clear */
171 nclear = qtL.nl * pct / 100;
172 nused = qtL.tl - qtL.bl;
173 if (nused <= 0) nused += qtL.nl;
174 nclear -= qtL.nl - nused;
175 if (nclear <= 0)
176 return(0);
177 if (nclear >= nused) { /* clear them all */
178 qtFreeTree(0);
179 qtL.tml = qtL.bl = qtL.tl = 0;
180 return(nused);
181 }
182 /* else clear leaves from bottom */
183 nmapped = qtL.tml - qtL.bl;
184 if (nmapped < 0) nmapped += qtL.nl;
185 qtL.bl += nclear;
186 if (qtL.bl >= qtL.nl) qtL.bl -= qtL.nl;
187 if (nmapped <= nclear) qtL.tml = qtL.bl;
188 shaketree(&qtrunk);
189 return(nclear);
190 }
191
192
193 int
194 qtFindLeaf(x, y) /* find closest leaf to (x,y) */
195 int x, y;
196 {
197 register RTREE *tp = &qtrunk;
198 int li = -1;
199 int x0=0, y0=0, x1=odev.hres, y1=odev.vres;
200 int mx, my;
201 register int q;
202 /* check limits */
203 if (x < 0 || x >= odev.hres || y < 0 || y >= odev.vres)
204 return(-1);
205 /* find nearby leaf in our tree */
206 for ( ; ; ) {
207 for (q = 0; q < 4; q++) /* find any leaf this level */
208 if (tp->flgs & LFF(q)) {
209 li = tp->k[q].li;
210 break;
211 }
212 q = 0; /* which quadrant are we? */
213 mx = (x0 + x1) >> 1;
214 my = (y0 + y1) >> 1;
215 if (x < mx) x1 = mx;
216 else {x0 = mx; q |= 01;}
217 if (y < my) y1 = my;
218 else {y0 = my; q |= 02;}
219 if (tp->flgs & BRF(q)) { /* branch down if not a leaf */
220 tp = tp->k[q].b;
221 continue;
222 }
223 if (tp->flgs & LFF(q)) /* good shot! */
224 return(tp->k[q].li);
225 return(li); /* else return what we have */
226 }
227 }
228
229
230 static
231 addleaf(li) /* add a leaf to our tree */
232 int li;
233 {
234 register RTREE *tp = &qtrunk;
235 int x0=0, y0=0, x1=odev.hres, y1=odev.vres;
236 int lo = -1;
237 int x, y, mx, my;
238 double z;
239 FVECT ip, wp;
240 register int q;
241 /* compute leaf location */
242 VCOPY(wp, qtL.wp[li]);
243 viewloc(ip, &odev.v, wp);
244 if (ip[2] <= 0. || ip[0] < 0. || ip[0] >= 1.
245 || ip[1] < 0. || ip[1] >= 1.)
246 return;
247 x = ip[0] * odev.hres;
248 y = ip[1] * odev.vres;
249 z = ip[2];
250 /* find the place for it */
251 for ( ; ; ) {
252 q = 0; /* which quadrant? */
253 mx = (x0 + x1) >> 1;
254 my = (y0 + y1) >> 1;
255 if (x < mx) x1 = mx;
256 else {x0 = mx; q |= 01;}
257 if (y < my) y1 = my;
258 else {y0 = my; q |= 02;}
259 if (tp->flgs & BRF(q)) { /* move to next branch */
260 tp->flgs |= CHF(q); /* not sure; guess */
261 tp = tp->k[q].b;
262 continue;
263 }
264 if (!(tp->flgs & LFF(q))) { /* found stem for leaf */
265 tp->k[q].li = li;
266 tp->flgs |= CHLFF(q);
267 break;
268 }
269 /* check existing leaf */
270 if (lo != tp->k[q].li) {
271 lo = tp->k[q].li;
272 VCOPY(wp, qtL.wp[lo]);
273 viewloc(ip, &odev.v, wp);
274 }
275 /* is node minimum size? */
276 if (x1-x0 <= qtMinNodesiz || y1-y0 <= qtMinNodesiz) {
277 if (z > (1.-qtDepthEps)*ip[2]) /* who is closer? */
278 return; /* old one is */
279 tp->k[q].li = li; /* new one is */
280 tp->flgs |= CHF(q);
281 break;
282 }
283 tp->flgs &= ~LFF(q); /* else grow tree */
284 tp->flgs |= CHBRF(q);
285 tp = tp->k[q].b = newtwig();
286 q = 0; /* old leaf -> new branch */
287 mx = ip[0] * odev.hres;
288 my = ip[1] * odev.vres;
289 if (mx >= (x0 + x1) >> 1) q |= 01;
290 if (my >= (y0 + y1) >> 1) q |= 02;
291 tp->k[q].li = lo;
292 tp->flgs |= LFF(q)|CH_ANY; /* all new */
293 }
294 }
295
296
297 dev_value(c, p) /* add a pixel value to our quadtree */
298 COLR c;
299 FVECT p;
300 {
301 register int li;
302
303 li = newleaf();
304 VCOPY(qtL.wp[li], p);
305 tmCvColrs(&qtL.brt[li], qtL.chr[li], c, 1);
306 addleaf(li);
307 }
308
309
310 qtReplant() /* replant our tree using new view */
311 {
312 register int i;
313 /* anything to replant? */
314 if (qtL.bl == qtL.tl)
315 return;
316 qtFreeTree(0); /* blow the old tree away */
317 /* regrow it in new place */
318 for (i = qtL.bl; i != qtL.tl; ) {
319 addleaf(i);
320 if (++i >= qtL.nl) i = 0;
321 }
322 }
323
324
325 qtMapLeaves(redo) /* map our leaves to RGB */
326 int redo;
327 {
328 int aorg, alen, borg, blen;
329 /* recompute mapping? */
330 if (redo)
331 qtL.tml = qtL.bl;
332 /* already done? */
333 if (qtL.tml == qtL.tl)
334 return(1);
335 /* compute segments */
336 aorg = qtL.tml;
337 if (qtL.tl >= aorg) {
338 alen = qtL.tl - aorg;
339 blen = 0;
340 } else {
341 alen = qtL.nl - aorg;
342 borg = 0;
343 blen = qtL.tl;
344 }
345 /* (re)compute tone mapping? */
346 if (qtL.tml == qtL.bl) {
347 tmClearHisto();
348 tmAddHisto(qtL.brt+aorg, alen, 1);
349 if (blen > 0)
350 tmAddHisto(qtL.brt+borg, blen, 1);
351 if (tmComputeMapping(0., 0., 0.) != TM_E_OK)
352 return(0);
353 }
354 if (tmMapPixels(qtL.rgb+aorg, qtL.brt+aorg,
355 qtL.chr+aorg, alen) != TM_E_OK)
356 return(0);
357 if (blen > 0)
358 tmMapPixels(qtL.rgb+borg, qtL.brt+borg,
359 qtL.chr+borg, blen);
360 qtL.tml = qtL.tl;
361 return(1);
362 }