ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_odraw.c
Revision: 3.17
Committed: Fri Jan 7 20:33:02 2005 UTC (19 years, 2 months ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R7P2, rad3R7P1, rad4R0, rad3R8, rad3R9
Changes since 3.16: +8 -7 lines
Log Message:
Modernized tone-mapping routines with structure pointer r.t. stack

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rhd_odraw.c,v 3.16 2004/01/01 11:21:55 schorsch Exp $";
3 #endif
4 /*
5 * Routines for drawing samples using depth buffer checks.
6 */
7
8 #include "standard.h"
9
10 #include <GL/glx.h>
11 #include <GL/glu.h>
12
13 #include "rhd_odraw.h"
14
15 #ifndef DEPTHEPS
16 #define DEPTHEPS 0.02 /* depth epsilon */
17 #endif
18 #ifndef SAMPSPERBLOCK
19 #define SAMPSPERBLOCK 1024 /* target samples per image block */
20 #endif
21 #ifndef SFREEFRAC
22 #define SFREEFRAC 0.2 /* fraction to free at a time */
23 #endif
24 #ifndef REDRAWTHRESH
25 #define REDRAWTHRESH 10240 /* number of samples for dissolve */
26 #endif
27 #ifndef MAXFAN
28 #define MAXFAN 32 /* maximum arms in a triangle fan */
29 #endif
30 #ifndef MINFAN
31 #define MINFAN 4 /* minimum arms in a triangle fan */
32 #endif
33 #ifndef FANSIZE
34 #define FANSIZE 3.5 /* fan sizing factor */
35 #endif
36
37 #define NEWMAP 01 /* need to recompute mapping */
38 #define NEWRGB 02 /* need to remap RGB values */
39 #define NEWHIST 04 /* clear histogram as well */
40
41 struct ODview *odView; /* our view list */
42 int odNViews; /* number of views in our list */
43
44 struct ODsamp odS; /* sample values */
45
46 static int needmapping; /* what needs doing with tone map */
47
48
49 #define SAMP32 (32*(2*sizeof(short)+sizeof(union ODfunion)+sizeof(TMbright)+\
50 6*sizeof(BYTE))+sizeof(int32))
51
52 static int sampcmp(const void *s0, const void *s1);
53 static int odAllocBlockSamp(int vn, int hh, int vh, double prox);
54 static int make_arms(GLshort ar[MAXFAN][3], short cp[2], struct ODview *vp,
55 double sz);
56 static int depthchange(struct ODview *vp, int x0, int y0, int x1, int y1);
57 static void clip_edge(GLshort p[3], short o[2], struct ODview *vp);
58 static int getblock(struct ODview *vp, int h, int v);
59 static int blockedge(struct ODview *vp, int bi0, int bi1);
60 static void odDrawSamp(int vn, int id);
61
62
63 extern int
64 odInit( /* initialize drawing routines */
65 int n
66 )
67 {
68 int nbytes, i, j, k, nextsamp, count, blockdiv;
69 int res[2];
70
71 if (odNViews > 0) { /* deallocate view structures */
72 for (i = odNViews; i--; ) {
73 free((void *)odView[i].bmap);
74 free((void *)odView[i].pmap);
75 if (odView[i].emap != NULL)
76 free((void *)odView[i].emap);
77 }
78 free((void *)odView);
79 odView = NULL;
80 odNViews = 0;
81 }
82 if (n && n != odS.nsamp) {
83 /* round space up to nearest power of 2 */
84 nbytes = (n+31)/32 * SAMP32;
85 for (i = 1024; nbytes > i-8; i <<= 1)
86 ;
87 n = (i-8)/SAMP32 * 32;
88 needmapping = NEWHIST;
89 }
90 if (n != odS.nsamp) { /* (re)allocate sample array */
91 if (odS.nsamp)
92 free(odS.base);
93 odS.nsamp = 0;
94 if (!n)
95 return(0);
96 nbytes = (n+31)/32 * SAMP32;
97 odS.base = (char *)malloc(nbytes);
98 if (odS.base == NULL)
99 return(0);
100 /* assign larger alignment types earlier */
101 odS.f = (union ODfunion *)odS.base;
102 odS.redraw = (int32 *)(odS.f + n);
103 odS.ip = (short (*)[2])(odS.redraw + n/32);
104 odS.brt = (TMbright *)(odS.ip + n);
105 odS.chr = (BYTE (*)[3])(odS.brt + n);
106 odS.rgb = (BYTE (*)[3])(odS.chr + n);
107 odS.nsamp = n;
108 }
109 if (!n)
110 return(0);
111 /* allocate view information */
112 count = 0; /* count pixels */
113 for (i = 0; dev_auxview(i, res) != NULL; i++)
114 count += res[0]*res[1];
115 odView = (struct ODview *)malloc(i*sizeof(struct ODview));
116 if (odView == NULL)
117 return(0);
118 odNViews = i;
119 blockdiv = sqrt(count/(n/SAMPSPERBLOCK)) + 0.5;
120 if (blockdiv < 8) blockdiv = 8;
121 nextsamp = 0; count /= blockdiv*blockdiv; /* # blocks */
122 while (i--) { /* initialize each view */
123 dev_auxview(i, res);
124 odView[i].hhi = res[0];
125 odView[i].hlow = (res[0] + blockdiv/2) / blockdiv;
126 if (odView[i].hlow < 1) odView[i].hlow = 1;
127 odView[i].vhi = res[1];
128 odView[i].vlow = (res[1] + blockdiv/2) / blockdiv;
129 if (odView[i].vlow < 1) odView[i].vlow = 1;
130 odView[i].emap = NULL;
131 odView[i].dmap = NULL;
132 odView[i].pmap = (int32 *)calloc(FL4NELS(res[0]*res[1]),
133 sizeof(int32));
134 if (odView[i].pmap == NULL)
135 return(0);
136 j = odView[i].hlow*odView[i].vlow;
137 odView[i].bmap = (struct ODblock *)malloc(
138 j * sizeof(struct ODblock));
139 if (odView[i].bmap == NULL)
140 return(0);
141 DCHECK(count<=0 | nextsamp>=n,
142 CONSISTENCY, "counter botch in odInit");
143 if (!i) count = j;
144 odView[i].sfirst = nextsamp;
145 while (j--) { /* initialize blocks & free lists */
146 odView[i].bmap[j].pthresh = FHUGE;
147 odView[i].bmap[j].first = k = nextsamp;
148 nextsamp += odView[i].bmap[j].nsamp =
149 (n - nextsamp)/count--;
150 odView[i].bmap[j].free = k;
151 while (++k < nextsamp)
152 odS.nextfree(k-1) = k;
153 odS.nextfree(k-1) = ENDFREE;
154 odView[i].bmap[j].nused = 0;
155 }
156 odView[i].snext = nextsamp;
157 odView[i].n2redraw = 0;
158 }
159 CLR4ALL(odS.redraw, odS.nsamp); /* clear redraw flags */
160 for (i = odS.nsamp; i--; ) { /* clear values */
161 odS.ip[i][0] = odS.ip[i][1] = -1;
162 odS.brt[i] = TM_NOBRT;
163 }
164 needmapping |= NEWMAP; /* compute new map on update */
165 return(odS.nsamp); /* return number of samples */
166 }
167
168 #undef SAMP32
169
170
171 int
172 sampcmp( /* sample order, descending proximity */
173 const void *s0,
174 const void *s1
175 )
176 {
177 register double diff = odS.closeness(*(int*)s1) - odS.closeness(*(int*)s0);
178
179 return (diff > FTINY ? 1 : diff < -FTINY ? -1 : 0);
180 }
181
182
183 int
184 odAllocBlockSamp( /* allocate sample from block */
185 int vn,
186 int hh,
187 int vh,
188 double prox
189 )
190 {
191 int si[SAMPSPERBLOCK+SAMPSPERBLOCK/4];
192 int hl, vl;
193 VIEW *vw;
194 int res[2];
195 register struct ODblock *bp;
196 register int i, j;
197 /* get block */
198 hl = hh*odView[vn].hlow/odView[vn].hhi;
199 vl = vh*odView[vn].vlow/odView[vn].vhi;
200 bp = odView[vn].bmap + vl*odView[vn].hlow + hl;
201 if (prox > bp->pthresh)
202 return(-1); /* worse than free list occupants */
203 /* check for duplicate pixel */
204 if (CHK4(odView[vn].pmap, vh*odView[vn].hhi + hh))
205 i = bp->first + bp->nsamp;
206 else
207 i = 0;
208 while (i-- > bp->first)
209 if (hh == odS.ip[i][0] && vh == odS.ip[i][1]) { /* found it! */
210 /* search free list for it */
211 if (i == bp->free)
212 break; /* special case */
213 if (bp->free != ENDFREE)
214 for (j = bp->free; odS.nextfree(j) != ENDFREE;
215 j = odS.nextfree(j))
216 if (odS.nextfree(j) == i) {
217 odS.nextfree(j) =
218 odS.nextfree(i);
219 bp->nused++;
220 goto gotit;
221 }
222 if (prox >= 0.99*odS.closeness(i))
223 return(-1); /* previous sample is fine */
224 goto gotit;
225 }
226 if (bp->free != ENDFREE) { /* allocate from free list */
227 i = bp->free;
228 if ((odS.ip[i][0] >= 0) & (odS.ip[i][1] >= 0))
229 CLR4(odView[vn].pmap, odS.ip[i][1]*odView[vn].hhi +
230 odS.ip[i][0]);
231 bp->free = odS.nextfree(i);
232 bp->nused++;
233 goto gotit;
234 }
235 DCHECK(bp->nsamp<=0, CONSISTENCY,
236 "no available samples in odAllocBlockSamp");
237 DCHECK(bp->nsamp > sizeof(si)/sizeof(si[0]), CONSISTENCY,
238 "too many samples in odAllocBlockSamp");
239 /* free some samples */
240 if ((vw = dev_auxview(vn, res)) == NULL)
241 error(CONSISTENCY, "bad view number in odAllocBlockSamp");
242 for (i = bp->nsamp; i--; ) /* figure out which are worse */
243 si[i] = bp->first + i;
244 qsort((char *)si, bp->nsamp, sizeof(int), sampcmp);
245 i = bp->nsamp*SFREEFRAC + .5; /* put them into free list */
246 if (i >= bp->nsamp) i = bp->nsamp-1; /* paranoia */
247 bp->pthresh = odS.closeness(si[i]); /* new proximity threshold */
248 while (--i > 0) {
249 odS.nextfree(si[i]) = bp->free;
250 bp->free = si[i];
251 bp->nused--;
252 }
253 i = si[0]; /* use worst sample */
254 CLR4(odView[vn].pmap, odS.ip[i][1]*odView[vn].hhi + odS.ip[i][0]);
255 gotit:
256 odS.ip[i][0] = hh;
257 odS.ip[i][1] = vh;
258 odS.closeness(i) = prox;
259 SET4(odView[vn].pmap, vh*odView[vn].hhi + hh);
260 return(i);
261 }
262
263
264 extern void
265 odSample( /* add a sample value */
266 COLR c,
267 FVECT d,
268 FVECT p
269 )
270 {
271 FVECT disp;
272 double d0, d1, h, v, prox;
273 register VIEW *vw;
274 int hh, vh;
275 int res[2];
276 register int i, id;
277
278 DCHECK(odS.nsamp<=0, CONSISTENCY, "no samples allocated in odSample");
279 /* add value to each view */
280 for (i = 0; (vw = dev_auxview(i, res)) != NULL; i++) {
281 DCHECK(i>=odNViews, CONSISTENCY, "too many views in odSample");
282 CHECK(vw->type!=VT_PER, INTERNAL,
283 "cannot handle non-perspective views");
284 if (p != NULL) { /* compute view position */
285 VSUB(disp, p, vw->vp);
286 d0 = DOT(disp, vw->vdir);
287 if (d0 <= vw->vfore+FTINY)
288 continue; /* too close */
289 } else {
290 VCOPY(disp, d);
291 d0 = DOT(disp, vw->vdir);
292 if (d0 <= FTINY) /* behind view */
293 continue;
294 }
295 h = DOT(disp,vw->hvec)/(d0*vw->hn2) + 0.5 - vw->hoff;
296 if (h < 0. || h >= 1.)
297 continue; /* left or right */
298 v = DOT(disp,vw->vvec)/(d0*vw->vn2) + 0.5 - vw->voff;
299 if (v < 0. || v >= 1.)
300 continue; /* above or below */
301 hh = h * res[0];
302 vh = v * res[1];
303 if (odView[i].dmap != NULL) { /* check depth */
304 d1 = odView[i].dmap[vh*res[0] + hh];
305 if (d1 < 0.99*FHUGE && (d0 > (1.+DEPTHEPS)*d1 ||
306 (1.+DEPTHEPS)*d0 < d1))
307 continue; /* occlusion error */
308 }
309 if (p != NULL) { /* compute closeness (sin^2) */
310 d1 = DOT(disp, d);
311 prox = 1. - d1*d1/DOT(disp,disp);
312 } else
313 prox = 0.;
314 /* allocate sample */
315 id = odAllocBlockSamp(i, hh, vh, prox);
316 if (id < 0)
317 continue; /* not good enough */
318 /* convert color */
319 tmCvColrs(tmGlobal, &odS.brt[id], odS.chr[id], (COLR *)c, 1);
320 if (imm_mode | needmapping) /* if immediate mode */
321 needmapping |= NEWRGB; /* map it later */
322 else /* else map it now */
323 tmMapPixels(tmGlobal, odS.rgb[id], &odS.brt[id],
324 odS.chr[id], 1);
325 SET4(odS.redraw, id); /* mark for redraw */
326 odView[i].n2redraw++;
327 }
328 }
329
330
331 extern void
332 odRemap( /* recompute tone mapping */
333 int newhist
334 )
335 {
336 needmapping |= NEWMAP|NEWRGB;
337 if (newhist)
338 needmapping |= NEWHIST;
339 }
340
341
342 extern void
343 odRedrawAll(void) /* mark all samples for redraw */
344 {
345 register int i;
346
347 if ((needmapping&(NEWMAP|NEWRGB)) == (NEWMAP|NEWRGB))
348 return; /* will be called later, anyway */
349 for (i = odS.nsamp; i--; )
350 if (odS.ip[i][0] >= 0)
351 SET4(odS.redraw, i);
352 /* not right, but not important */
353 for (i = 0; i < odNViews; i++)
354 odView[i].n2redraw = odView[i].snext - odView[i].sfirst;
355 }
356
357
358 extern void
359 odRedraw( /* redraw view region */
360 int vn,
361 int hmin,
362 int vmin,
363 int hmax,
364 int vmax
365 )
366 {
367 int i, j;
368 register struct ODblock *bp;
369 register int k;
370
371 if ((vn<0) | (vn>=odNViews))
372 return;
373 /* check view limits */
374 if (hmin < 0) hmin = 0;
375 if (hmax >= odView[vn].hhi) hmax = odView[vn].hhi-1;
376 if (vmin < 0) vmin = 0;
377 if (vmax >= odView[vn].vhi) vmax = odView[vn].vhi-1;
378 if ((hmax <= hmin) | (vmax <= vmin))
379 return;
380 /* convert to low resolution */
381 hmin = hmin * odView[vn].hlow / odView[vn].hhi;
382 hmax = hmax * odView[vn].hlow / odView[vn].hhi;
383 vmin = vmin * odView[vn].vlow / odView[vn].vhi;
384 vmax = vmax * odView[vn].vlow / odView[vn].vhi;
385 /* mark block samples for redraw, inclusive */
386 for (i = hmin; i <= hmax; i++)
387 for (j = vmin; j <= vmax; j++) {
388 bp = odView[vn].bmap + j*odView[vn].hlow + i;
389 for (k = bp->nsamp; k--; )
390 if (odS.ip[bp->first+k][0] >= 0) {
391 SET4(odS.redraw, bp->first+k);
392 odView[vn].n2redraw++;
393 }
394 }
395 }
396
397
398 extern void
399 odDepthMap( /* assign depth map for view */
400 int vn,
401 GLfloat *dm
402 )
403 {
404 double d0, d1;
405 int i, j, hmin, hmax, vmin, vmax;
406 register int k, l;
407
408 if (dm == NULL) { /* free edge map */
409 if ((vn<0) | (vn>=odNViews))
410 return; /* too late -- they're gone! */
411 if (odView[vn].emap != NULL)
412 free((void *)odView[vn].emap);
413 odView[vn].emap = NULL;
414 odView[vn].dmap = NULL;
415 return;
416 }
417 DCHECK(vn<0 | vn>=odNViews, CONSISTENCY,
418 "bad view number in odDepthMap");
419 odView[vn].dmap = dm; /* initialize edge map */
420 if (odView[vn].emap == NULL) {
421 odView[vn].emap = (int32 *)malloc(
422 FL4NELS(odView[vn].hlow*odView[vn].vlow)*sizeof(int32));
423 if (odView[vn].emap == NULL)
424 error(SYSTEM, "out of memory in odDepthMap");
425 }
426 CLR4ALL(odView[vn].emap, odView[vn].hlow*odView[vn].vlow);
427 /* compute edge map */
428 vmin = odView[vn].vhi; /* enter loopsville */
429 for (j = odView[vn].vlow; j--; ) {
430 vmax = vmin;
431 vmin = j*odView[vn].vhi/odView[vn].vlow;
432 hmin = odView[vn].hhi;
433 for (i = odView[vn].hlow; i--; ) {
434 hmax = hmin;
435 hmin = i*odView[vn].hhi/odView[vn].hlow;
436 for (l = vmin; l < vmax; l++) { /* vertical edges */
437 d1 = dm[l*odView[vn].hhi+hmin];
438 for (k = hmin+1; k < hmax; k++) {
439 d0 = d1;
440 d1 = dm[l*odView[vn].hhi+k];
441 if (d0 > (1.+DEPTHEPS)*d1 ||
442 (1.+DEPTHEPS)*d0 < d1) {
443 SET4(odView[vn].emap,
444 j*odView[vn].hlow + i);
445 break;
446 }
447 }
448 if (k < hmax)
449 break;
450 }
451 if (l < vmax)
452 continue;
453 for (k = hmin; k < hmax; k++) { /* horizontal edges */
454 d1 = dm[vmin*odView[vn].hhi+k];
455 for (l = vmin+1; l < vmax; l++) {
456 d0 = d1;
457 d1 = dm[l*odView[vn].hhi+k];
458 if (d0 > (1.+DEPTHEPS)*d1 ||
459 (1.+DEPTHEPS)*d0 < d1) {
460 SET4(odView[vn].emap,
461 j*odView[vn].hlow + i);
462 break;
463 }
464 }
465 if (l < vmax)
466 break;
467 }
468 }
469 }
470 }
471
472
473 extern void
474 odUpdate( /* update this view */
475 int vn
476 )
477 {
478 static short primes[] = {9431,6803,4177,2659,1609,887,587,251,47,1};
479 int myprime;
480 register int i, n;
481
482 DCHECK(vn<0 | vn>=odNViews, CONSISTENCY,
483 "bad view number in odUpdate");
484 /* need to do some tone mapping? */
485 if (needmapping & NEWRGB) {
486 if (needmapping & NEWMAP) {
487 if (needmapping & NEWHIST)
488 tmClearHisto(tmGlobal);
489 needmapping &= ~NEWHIST;
490 if (tmAddHisto(tmGlobal, odS.brt,odS.nsamp,1) != TM_E_OK)
491 return;
492 if (tmComputeMapping(tmGlobal, 0.,0.,0.) != TM_E_OK)
493 return;
494 needmapping &= ~NEWMAP;
495 odRedrawAll(); /* redraw everything */
496 }
497 if (tmMapPixels(tmGlobal, (BYTE *)(odS.rgb), odS.brt,
498 (BYTE *)(odS.chr), odS.nsamp) != TM_E_OK)
499 return;
500 needmapping &= ~NEWRGB;
501 }
502 if (odView[vn].n2redraw <= 0)
503 return;
504 #if REDRAWTHRESH
505 if (odView[vn].n2redraw < REDRAWTHRESH)
506 goto quickdraw;
507 /* pick a good prime step size */
508 n = odView[vn].snext - odView[vn].sfirst;
509 for (i = 0; primes[i]<<5 >= n; i++)
510 ;
511 while ((myprime = primes[i++]) > 1)
512 if (n % myprime)
513 break;
514 /* dissolve in new samples */
515 for (i = odView[vn].sfirst; n-- > 0; i += myprime) {
516 if (i >= odView[vn].snext)
517 i -= odView[vn].snext - odView[vn].sfirst;
518 if (CHK4(odS.redraw, i)) {
519 odDrawSamp(vn, i);
520 CLR4(odS.redraw, i);
521 }
522 }
523 odView[vn].n2redraw = 0;
524 return;
525 quickdraw: /* quicker sparse flag checking */
526 #endif
527 /* redraw samples at end */
528 for (i = odView[vn].snext-31; i < odView[vn].snext; i++)
529 if (CHK4(odS.redraw, i)) {
530 odDrawSamp(vn, i);
531 CLR4(odS.redraw, i);
532 }
533 /* faster flag checks in middle */
534 for (n = odView[vn].snext>>5; n-- > (odView[vn].sfirst+0x1f)>>5; )
535 for (i = 0; odS.redraw[n]; i++) /* skips faster */
536 if (odS.redraw[n] & 1L<<i) {
537 odDrawSamp(vn, (n<<5)+i);
538 odS.redraw[n] &= ~(1L<<i);
539 }
540 /* redraw samples at beginning */
541 for (i = odView[vn].sfirst; i < odView[vn].sfirst+31; i++)
542 if (CHK4(odS.redraw, i)) {
543 odDrawSamp(vn, i);
544 CLR4(odS.redraw, i);
545 }
546 odView[vn].n2redraw = 0;
547 }
548
549
550 /* this turned out to be unnecessary */
551 #if 0
552 static
553 clip_end(p, o, vp) /* clip line segment to view */
554 GLshort p[3];
555 short o[2];
556 register struct ODview *vp;
557 {
558 if (p[0] < 0) {
559 p[1] = -o[0]*(p[1]-o[1])/(p[0]-o[0]) + o[1];
560 p[2] = -o[0]*p[2]/(p[0]-o[0]);
561 p[0] = 0;
562 } else if (p[0] >= vp->hhi) {
563 p[1] = (vp->hhi-1-o[0])*(p[1]-o[1])/(p[0]-o[0]) + o[1];
564 p[2] = (vp->hhi-1-o[0])*p[2]/(p[0]-o[0]);
565 p[0] = vp->hhi-1;
566 }
567 if (p[1] < 0) {
568 p[0] = -o[1]*(p[0]-o[0])/(p[1]-o[1]) + o[0];
569 p[2] = -o[1]*p[2]/(p[1]-o[1]);
570 p[1] = 0;
571 } else if (p[1] >= vp->vhi) {
572 p[0] = (vp->vhi-1-o[1])*(p[0]-o[0])/(p[1]-o[1]) + o[0];
573 p[2] = (vp->vhi-1-o[1])*p[2]/(p[1]-o[1]);
574 p[1] = vp->vhi-1;
575 }
576 }
577 #endif
578
579
580 static int
581 make_arms( /* make arms for triangle fan */
582 GLshort ar[MAXFAN][3],
583 short cp[2],
584 register struct ODview *vp,
585 double sz
586 )
587 {
588 int na, dv;
589 double hrad, vrad, phi;
590 register int i;
591
592 DCHECK(sz > 1, CONSISTENCY, "super-unary size in make_arms");
593 na = MAXFAN*sz + 0.5; /* keep arc length constant */
594 if (na < MINFAN) na = MINFAN;
595 hrad = FANSIZE*sz*vp->hhi/vp->hlow;
596 vrad = FANSIZE*sz*vp->vhi/vp->vlow;
597 if (hrad*vrad < 2.25)
598 hrad = vrad = 1.5;
599 dv = OMAXDEPTH*sz + 0.5;
600 for (i = 0; i < na; i++) {
601 phi = (2.*PI)*i/na;
602 ar[i][0] = cp[0] + tcos(phi)*hrad + 0.5;
603 ar[i][1] = cp[1] + tsin(phi)*vrad + 0.5;
604 ar[i][2] = dv;
605 /* clip_end(ar[i], cp, vp); */
606 }
607 return(na);
608 }
609
610
611 static int
612 depthchange( /* check depth discontinuity */
613 register struct ODview *vp,
614 int x0,
615 int y0,
616 int x1,
617 int y1
618 )
619 {
620 register double d0, d1;
621
622 DCHECK(x0<0 | x0>=vp->hhi | y0<0 | y0>=vp->vhi,
623 CONSISTENCY, "coordinates off view in depthchange");
624
625 if ((x1<0) | (x1>=vp->hhi) | (y1<0) | (y1>=vp->vhi))
626 return(1);
627
628 d0 = vp->dmap[y0*vp->hhi + x0];
629 d1 = vp->dmap[y1*vp->hhi + x1];
630
631 return((1.+DEPTHEPS)*d0 < d1 || d0 > (1.+DEPTHEPS)*d1);
632 }
633
634
635 static void
636 clip_edge( /* clip line segment to depth edge */
637 GLshort p[3],
638 short o[2],
639 register struct ODview *vp
640 )
641 {
642 int x, y, xstep, ystep, rise, rise2, run, run2, n;
643
644 DCHECK(vp->dmap==NULL, CONSISTENCY,
645 "clip_edge called with no depth map");
646 x = o[0]; y = o[1];
647 run = p[0] - x;
648 xstep = run > 0 ? 1 : -1;
649 run *= xstep;
650 rise = p[1] - y;
651 ystep = rise > 0 ? 1 : -1;
652 rise *= ystep;
653 rise2 = run2 = 0;
654 if (rise > run) rise2 = 1;
655 else run2 = 1;
656 n = rise + run;
657 while (n--) /* run out arm, checking depth */
658 if (run2 > rise2) {
659 x += xstep;
660 rise2 += rise;
661 if (depthchange(vp, x-xstep, y, x, y))
662 break;
663 } else {
664 y += ystep;
665 run2 += run;
666 if (depthchange(vp, x, y-ystep, x, y))
667 break;
668 }
669 if (n < 0) /* found something? */
670 return;
671 if (run > rise)
672 p[2] = (x - o[0])*p[2]/(p[0] - o[0]);
673 else
674 p[2] = (y - o[1])*p[2]/(p[1] - o[1]);
675 p[0] = x;
676 p[1] = y;
677 }
678
679
680 static int
681 getblock( /* get block index */
682 register struct ODview *vp,
683 register int h,
684 register int v
685 )
686 {
687 if ((h<0) | (h>=vp->hhi) | (v<0) | (v>=vp->vhi))
688 return(-1);
689 return(h*vp->hlow/vp->hhi + v*vp->vlow/vp->vhi*vp->hlow);
690 }
691
692
693 static int
694 blockedge( /* check for edge between blocks? */
695 register struct ODview *vp,
696 register int bi0,
697 register int bi1
698 )
699 {
700 if (bi1 == bi0)
701 return(0); /* same block */
702 if (bi1 < 0)
703 return(1); /* end off view */
704 if (CHK4(vp->emap, bi1))
705 return(1); /* end block has edges */
706 if (bi1 == bi0+1 || bi1 == bi0-1 ||
707 bi1 == bi0+vp->hlow || bi1 == bi0-vp->hlow)
708 return(0); /* end in adjacent block -- no edges */
709 return(1); /* conservative for rarer case */
710 }
711
712
713 static void
714 odDrawSamp( /* draw view sample */
715 int vn,
716 register int id
717 )
718 {
719 GLshort arm[MAXFAN][3];
720 int narms, blockindex;
721 register struct ODview *vp;
722 double size;
723 int home_edges;
724 register int i;
725
726 vp = odView + vn;
727 blockindex = getblock(vp, odS.ip[id][0], odS.ip[id][1]);
728 DCHECK(blockindex<0, CONSISTENCY, "bad sample handed to odDrawSamp");
729 DCHECK(vp->bmap[blockindex].nused <= 0,
730 CONSISTENCY, "bad in-use count in odDrawSamp");
731 /* create triangle fan */
732 size = 1./sqrt((double)vp->bmap[blockindex].nused);
733 narms = make_arms(arm, odS.ip[id], vp, size);
734 if (vp->emap != NULL) { /* check for edge collisions */
735 home_edges = CHK4(vp->emap, blockindex);
736 for (i = 0; i < narms; i++)
737 if (home_edges || blockedge(vp, blockindex,
738 getblock(vp, arm[i][0], arm[i][1])))
739 clip_edge(arm[i], odS.ip[id], vp);
740 }
741 /* draw triangle fan */
742 glColor3ub(odS.rgb[id][0], odS.rgb[id][1], odS.rgb[id][2]);
743 glBegin(GL_TRIANGLE_FAN);
744 glVertex3s((GLshort)odS.ip[id][0], (GLshort)odS.ip[id][1], (GLshort)0);
745 for (i = 0; i < narms; i++)
746 glVertex3sv(arm[i]);
747 glVertex3sv(arm[0]); /* connect last to first */
748 glEnd();
749 }