ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_qtree.c
Revision: 3.4
Committed: Fri Nov 21 09:52:06 1997 UTC (26 years, 5 months ago) by gregl
Content type: text/plain
Branch: MAIN
Changes since 3.3: +18 -10 lines
Log Message:
fixed bug in newleaf()

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
14 RTREE qtrunk; /* our quadtree trunk */
15 double qtDepthEps = .02; /* epsilon to compare depths (z fraction) */
16 int qtMinNodesiz = 2; /* minimum node dimension (pixels) */
17
18 static RLEAF *leafpile; /* our collection of leaf values */
19 static int nleaves; /* count of leaves in our pile */
20 static int bleaf, tleaf; /* bottom and top (next) leaf index (ring) */
21
22 #define TBUNDLESIZ 409 /* number of twigs in a bundle */
23
24 static RTREE **twigbundle; /* free twig blocks (NULL term.) */
25 static int nexttwig; /* next free twig */
26
27 static RTREE emptytree; /* empty tree for test below */
28
29 #define is_stump(t) (!bcmp((char *)(t), (char *)&emptytree, sizeof(RTREE)))
30
31
32 static RTREE *
33 newtwig() /* allocate a twig */
34 {
35 register int bi;
36
37 if (twigbundle == NULL) { /* initialize */
38 twigbundle = (RTREE **)malloc(sizeof(RTREE *));
39 if (twigbundle == NULL)
40 goto memerr;
41 twigbundle[0] = NULL;
42 }
43 bi = nexttwig / TBUNDLESIZ;
44 if (twigbundle[bi] == NULL) { /* new block */
45 twigbundle = (RTREE **)realloc((char *)twigbundle,
46 (bi+2)*sizeof(RTREE *));
47 if (twigbundle == NULL)
48 goto memerr;
49 twigbundle[bi] = (RTREE *)calloc(TBUNDLESIZ, sizeof(RTREE));
50 if (twigbundle[bi] == NULL)
51 goto memerr;
52 twigbundle[bi+1] = NULL;
53 }
54 /* nexttwig++ % TBUNDLESIZ */
55 return(twigbundle[bi] + (nexttwig++ - bi*TBUNDLESIZ));
56 memerr:
57 error(SYSTEM, "out of memory in newtwig");
58 }
59
60
61 qtFreeTree(really) /* free allocated twigs */
62 int really;
63 {
64 register int i;
65
66 tmClearHisto();
67 bzero((char *)&qtrunk, sizeof(RTREE));
68 nexttwig = 0;
69 if (twigbundle == NULL)
70 return;
71 if (!really) { /* just clear allocated blocks */
72 for (i = 0; twigbundle[i] != NULL; i++)
73 bzero((char *)twigbundle[i], TBUNDLESIZ*sizeof(RTREE));
74 return;
75 }
76 /* else "really" means free up memory */
77 for (i = 0; twigbundle[i] != NULL; i++)
78 free((char *)twigbundle[i]);
79 free((char *)twigbundle);
80 twigbundle = NULL;
81 }
82
83
84 static RLEAF *
85 newleaf() /* allocate a leaf from our pile */
86 {
87 RLEAF *lp;
88
89 lp = leafpile + tleaf++;
90 if (tleaf >= nleaves) /* get next leaf in ring */
91 tleaf = 0;
92 if (tleaf == bleaf) /* need to shake some free */
93 qtCompost(LFREEPCT);
94 return(lp);
95 }
96
97
98 int
99 qtAllocLeaves(n) /* allocate space for n leaves */
100 int n;
101 {
102 unsigned nbytes;
103 register unsigned i;
104
105 qtFreeTree(0); /* make sure tree is empty */
106 if (n <= 0)
107 return(0);
108 if (nleaves >= n)
109 return(nleaves);
110 else if (nleaves > 0)
111 free((char *)leafpile);
112 /* round space up to nearest power of 2 */
113 nbytes = n*sizeof(RLEAF) + 8;
114 for (i = 1024; nbytes > i; i <<= 1)
115 ;
116 n = (i - 8) / sizeof(RLEAF);
117 leafpile = (RLEAF *)malloc(n*sizeof(RLEAF));
118 if (leafpile == NULL)
119 return(-1);
120 nleaves = n;
121 bleaf = tleaf = 0;
122 return(nleaves);
123 }
124
125
126 qtFreeLeaves() /* free our allocated leaves and twigs */
127 {
128 qtFreeTree(1); /* free tree also */
129 if (nleaves <= 0)
130 return;
131 free((char *)leafpile);
132 leafpile = NULL;
133 nleaves = 0;
134 }
135
136
137 static
138 shaketree(tp) /* shake dead leaves from tree */
139 register RTREE *tp;
140 {
141 register int i, li;
142
143 for (i = 0; i < 4; i++)
144 if (tp->flgs & BRF(i))
145 shaketree(tp->k[i].b);
146 else if (tp->k[i].l != NULL) {
147 li = tp->k[i].l - leafpile;
148 if (bleaf < tleaf ? (li < bleaf || li >= tleaf) :
149 (li < bleaf && li >= tleaf)) {
150 tmAddHisto(&tp->k[i].l->brt, 1, -1);
151 tp->k[i].l = NULL;
152 }
153 }
154 }
155
156
157 int
158 qtCompost(pct) /* free up some leaves */
159 int pct;
160 {
161 int nused, nclear;
162
163 if (is_stump(&qtrunk))
164 return(0);
165 /* figure out how many leaves to clear */
166 nclear = nleaves * pct / 100;
167 nused = tleaf > bleaf ? tleaf-bleaf : tleaf+nleaves-bleaf;
168 nclear -= nleaves - nused; /* less what's already free */
169 if (nclear <= 0)
170 return(0);
171 if (nclear >= nused) { /* clear them all */
172 qtFreeTree(0);
173 bleaf = tleaf = 0;
174 return(nused);
175 }
176 /* else clear leaves from bottom */
177 bleaf += nclear;
178 if (bleaf >= nleaves) bleaf -= nleaves;
179 shaketree(&qtrunk);
180 return(nclear);
181 }
182
183
184 RLEAF *
185 qtFindLeaf(x, y) /* find closest leaf to (x,y) */
186 int x, y;
187 {
188 register RTREE *tp = &qtrunk;
189 RLEAF *lp = NULL;
190 int x0=0, y0=0, x1=odev.hres, y1=odev.vres;
191 int mx, my;
192 register int q;
193 /* check limits */
194 if (x < 0 || x >= odev.hres || y < 0 || y >= odev.vres)
195 return(NULL);
196 /* find nearby leaf in our tree */
197 for ( ; ; ) {
198 for (q = 0; q < 4; q++) /* find any leaf this level */
199 if (!(tp->flgs & BRF(q)) && tp->k[q].l != NULL) {
200 lp = tp->k[q].l;
201 break;
202 }
203 q = 0; /* which quadrant are we? */
204 mx = (x0 + x1) >> 1;
205 my = (y0 + y1) >> 1;
206 if (x < mx) x1 = mx;
207 else {x0 = mx; q |= 01;}
208 if (y < my) y1 = my;
209 else {y0 = my; q |= 02;}
210 if (tp->flgs & BRF(q)) { /* branch down if not a leaf */
211 tp = tp->k[q].b;
212 continue;
213 }
214 if (tp->k[q].l != NULL) /* good shot! */
215 return(tp->k[q].l);
216 return(lp); /* else return what we have */
217 }
218 }
219
220
221 static
222 addleaf(lp) /* add a leaf to our tree */
223 RLEAF *lp;
224 {
225 register RTREE *tp = &qtrunk;
226 int x0=0, y0=0, x1=odev.hres, y1=odev.vres;
227 RLEAF *lo = NULL;
228 int x, y, mx, my;
229 double z;
230 FVECT ip, wp;
231 register int q;
232 /* compute leaf location */
233 VCOPY(wp, lp->wp);
234 viewloc(ip, &odev.v, wp);
235 if (ip[2] <= 0. || ip[0] < 0. || ip[0] >= 1.
236 || ip[1] < 0. || ip[1] >= 1.)
237 return;
238 x = ip[0] * odev.hres;
239 y = ip[1] * odev.vres;
240 z = ip[2];
241 /* find the place for it */
242 for ( ; ; ) {
243 q = 0; /* which quadrant? */
244 mx = (x0 + x1) >> 1;
245 my = (y0 + y1) >> 1;
246 if (x < mx) x1 = mx;
247 else {x0 = mx; q |= 01;}
248 if (y < my) y1 = my;
249 else {y0 = my; q |= 02;}
250 if (tp->flgs & BRF(q)) { /* move to next branch */
251 tp->flgs |= CHF(q); /* not sure; guess */
252 tp = tp->k[q].b;
253 continue;
254 }
255 if (tp->k[q].l == NULL) { /* found stem for leaf */
256 tp->k[q].l = lp;
257 tp->flgs |= CHF(q);
258 break;
259 }
260 /* check existing leaf */
261 if (lo != tp->k[q].l) {
262 lo = tp->k[q].l;
263 VCOPY(wp, lo->wp);
264 viewloc(ip, &odev.v, wp);
265 }
266 /* is node minimum size? */
267 if (x1-x0 <= qtMinNodesiz || y1-y0 <= qtMinNodesiz) {
268 if (z > (1.-qtDepthEps)*ip[2]) /* who is closer? */
269 return; /* old one is */
270 tp->k[q].l = lp; /* new one is */
271 tp->flgs |= CHF(q);
272 tmAddHisto(&lo->brt, 1, -1); /* drop old one */
273 break;
274 }
275 tp->flgs |= CHBRF(q); /* else grow tree */
276 tp = tp->k[q].b = newtwig();
277 tp->flgs |= CH_ANY; /* all new */
278 q = 0; /* old leaf -> new branch */
279 mx = ip[0] * odev.hres;
280 my = ip[1] * odev.vres;
281 if (mx >= (x0 + x1) >> 1) q |= 01;
282 if (my >= (y0 + y1) >> 1) q |= 02;
283 tp->k[q].l = lo;
284 }
285 tmAddHisto(&lp->brt, 1, 1); /* add leaf to histogram */
286 }
287
288
289 dev_value(c, p) /* add a pixel value to our output queue */
290 COLR c;
291 FVECT p;
292 {
293 register RLEAF *lp;
294
295 lp = newleaf();
296 VCOPY(lp->wp, p);
297 tmCvColrs(&lp->brt, lp->chr, c, 1);
298 addleaf(lp);
299 }
300
301
302 qtReplant() /* replant our tree using new view */
303 {
304 register int i;
305
306 if (bleaf == tleaf) /* anything to replant? */
307 return;
308 qtFreeTree(0); /* blow the tree away */
309 /* now rebuild it */
310 for (i = bleaf; i != tleaf; ) {
311 addleaf(leafpile+i);
312 if (++i >= nleaves) i = 0;
313 }
314 tmComputeMapping(0., 0., 0.); /* update the display */
315 qtUpdate();
316 }
317
318
319 static
320 redraw(ca, tp, x0, y0, x1, y1, l) /* redraw portion of a tree */
321 BYTE ca[3]; /* returned average color */
322 register RTREE *tp;
323 int x0, y0, x1, y1;
324 int l[2][2];
325 {
326 int csm[3], nc;
327 BYTE rgb[3];
328 int quads = CH_ANY;
329 int mx, my;
330 register int i;
331 /* compute midpoint */
332 mx = (x0 + x1) >> 1;
333 my = (y0 + y1) >> 1;
334 /* see what to do */
335 if (l[0][0] >= mx)
336 quads &= ~(CHF(2)|CHF(0));
337 else if (l[0][1] <= mx)
338 quads &= ~(CHF(3)|CHF(1));
339 if (l[1][0] >= my)
340 quads &= ~(CHF(1)|CHF(0));
341 else if (l[1][1] <= my)
342 quads &= ~(CHF(3)|CHF(2));
343 tp->flgs &= ~quads; /* mark them done */
344 csm[0] = csm[1] = csm[2] = nc = 0;
345 /* do leaves first */
346 for (i = 0; i < 4; i++)
347 if (quads & CHF(i) && !(tp->flgs & BRF(i)) &&
348 tp->k[i].l != NULL) {
349 tmMapPixels(rgb, &tp->k[i].l->brt, tp->k[i].l->chr, 1);
350 dev_paintr(rgb, i&01 ? mx : x0, i&02 ? my : y0,
351 i&01 ? x1 : mx, i&02 ? y1 : my);
352 csm[0] += rgb[0]; csm[1] += rgb[1]; csm[2] += rgb[2];
353 nc++;
354 quads &= ~CHF(i);
355 }
356 /* now do branches */
357 for (i = 0; i < 4; i++)
358 if (quads & CHF(i) && tp->flgs & BRF(i)) {
359 redraw(rgb, tp->k[i].b, i&01 ? mx : x0, i&02 ? my : y0,
360 i&01 ? x1 : mx, i&02 ? y1 : my, l);
361 csm[0] += rgb[0]; csm[1] += rgb[1]; csm[2] += rgb[2];
362 nc++;
363 quads &= ~CHF(i);
364 }
365 if (nc > 1) {
366 ca[0] = csm[0]/nc; ca[1] = csm[1]/nc; ca[2] = csm[2]/nc;
367 } else {
368 ca[0] = csm[0]; ca[1] = csm[1]; ca[2] = csm[2];
369 }
370 if (!quads) return;
371 /* fill in gaps with average */
372 for (i = 0; i < 4; i++)
373 if (quads & CHF(i))
374 dev_paintr(ca, i&01 ? mx : x0, i&02 ? my : y0,
375 i&01 ? x1 : mx, i&02 ? y1 : my);
376 }
377
378
379 static
380 update(ca, tp, x0, y0, x1, y1) /* update tree display as needed */
381 BYTE ca[3]; /* returned average color */
382 register RTREE *tp;
383 int x0, y0, x1, y1;
384 {
385 int csm[3], nc;
386 BYTE rgb[3];
387 int gaps = 0;
388 int mx, my;
389 register int i;
390 /* compute midpoint */
391 mx = (x0 + x1) >> 1;
392 my = (y0 + y1) >> 1;
393 csm[0] = csm[1] = csm[2] = nc = 0;
394 /* do leaves first */
395 for (i = 0; i < 4; i++)
396 if ((tp->flgs & CHBRF(i)) == CHF(i)) {
397 if (tp->k[i].l == NULL) {
398 gaps |= 1<<i; /* empty stem */
399 continue;
400 }
401 tmMapPixels(rgb, &tp->k[i].l->brt, tp->k[i].l->chr, 1);
402 dev_paintr(rgb, i&01 ? mx : x0, i&02 ? my : y0,
403 i&01 ? x1 : mx, i&02 ? y1 : my);
404 csm[0] += rgb[0]; csm[1] += rgb[1]; csm[2] += rgb[2];
405 nc++;
406 }
407 /* now do branches */
408 for (i = 0; i < 4; i++)
409 if ((tp->flgs & CHBRF(i)) == CHBRF(i)) {
410 update(rgb, tp->k[i].b, i&01 ? mx : x0, i&02 ? my : y0,
411 i&01 ? x1 : mx, i&02 ? y1 : my);
412 csm[0] += rgb[0]; csm[1] += rgb[1]; csm[2] += rgb[2];
413 nc++;
414 }
415 if (nc > 1) {
416 ca[0] = csm[0]/nc; ca[1] = csm[1]/nc; ca[2] = csm[2]/nc;
417 } else {
418 ca[0] = csm[0]; ca[1] = csm[1]; ca[2] = csm[2];
419 }
420 /* fill in gaps with average */
421 for (i = 0; gaps && i < 4; gaps >>= 1, i++)
422 if (gaps & 01)
423 dev_paintr(ca, i&01 ? mx : x0, i&02 ? my : y0,
424 i&01 ? x1 : mx, i&02 ? y1 : my);
425 tp->flgs &= ~CH_ANY; /* all done */
426 }
427
428
429 qtRedraw(x0, y0, x1, y1) /* redraw part of our screen */
430 int x0, y0, x1, y1;
431 {
432 int lim[2][2];
433 BYTE ca[3];
434
435 if (is_stump(&qtrunk))
436 return;
437 if ((lim[0][0]=x0) <= 0 & (lim[1][0]=y0) <= 0 &
438 (lim[0][1]=x1) >= odev.hres-1 & (lim[1][1]=y1) >= odev.vres-1
439 || tmTop->lumap == NULL)
440 if (tmComputeMapping(0., 0., 0.) != TM_E_OK)
441 return;
442 redraw(ca, &qtrunk, 0, 0, odev.hres, odev.vres, lim);
443 }
444
445
446 qtUpdate() /* update our tree display */
447 {
448 BYTE ca[3];
449
450 if (is_stump(&qtrunk))
451 return;
452 if (tmTop->lumap == NULL)
453 tmComputeMapping(0., 0., 0.);
454 update(ca, &qtrunk, 0, 0, odev.hres, odev.vres);
455 }