ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_odraw.c
Revision: 3.16
Committed: Thu Jan 1 11:21:55 2004 UTC (20 years, 3 months ago) by schorsch
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R6, rad3R6P1
Changes since 3.15: +96 -52 lines
Log Message:
Ansification and prototypes.

File Contents

# Content
1 #ifndef lint
2 static const char RCSid[] = "$Id: rhd_odraw.c,v 3.15 2003/06/20 00:25:49 greg 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(&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(odS.rgb[id], &odS.brt[id], odS.chr[id], 1);
324 SET4(odS.redraw, id); /* mark for redraw */
325 odView[i].n2redraw++;
326 }
327 }
328
329
330 extern void
331 odRemap( /* recompute tone mapping */
332 int newhist
333 )
334 {
335 needmapping |= NEWMAP|NEWRGB;
336 if (newhist)
337 needmapping |= NEWHIST;
338 }
339
340
341 extern void
342 odRedrawAll(void) /* mark all samples for redraw */
343 {
344 register int i;
345
346 if ((needmapping&(NEWMAP|NEWRGB)) == (NEWMAP|NEWRGB))
347 return; /* will be called later, anyway */
348 for (i = odS.nsamp; i--; )
349 if (odS.ip[i][0] >= 0)
350 SET4(odS.redraw, i);
351 /* not right, but not important */
352 for (i = 0; i < odNViews; i++)
353 odView[i].n2redraw = odView[i].snext - odView[i].sfirst;
354 }
355
356
357 extern void
358 odRedraw( /* redraw view region */
359 int vn,
360 int hmin,
361 int vmin,
362 int hmax,
363 int vmax
364 )
365 {
366 int i, j;
367 register struct ODblock *bp;
368 register int k;
369
370 if ((vn<0) | (vn>=odNViews))
371 return;
372 /* check view limits */
373 if (hmin < 0) hmin = 0;
374 if (hmax >= odView[vn].hhi) hmax = odView[vn].hhi-1;
375 if (vmin < 0) vmin = 0;
376 if (vmax >= odView[vn].vhi) vmax = odView[vn].vhi-1;
377 if ((hmax <= hmin) | (vmax <= vmin))
378 return;
379 /* convert to low resolution */
380 hmin = hmin * odView[vn].hlow / odView[vn].hhi;
381 hmax = hmax * odView[vn].hlow / odView[vn].hhi;
382 vmin = vmin * odView[vn].vlow / odView[vn].vhi;
383 vmax = vmax * odView[vn].vlow / odView[vn].vhi;
384 /* mark block samples for redraw, inclusive */
385 for (i = hmin; i <= hmax; i++)
386 for (j = vmin; j <= vmax; j++) {
387 bp = odView[vn].bmap + j*odView[vn].hlow + i;
388 for (k = bp->nsamp; k--; )
389 if (odS.ip[bp->first+k][0] >= 0) {
390 SET4(odS.redraw, bp->first+k);
391 odView[vn].n2redraw++;
392 }
393 }
394 }
395
396
397 extern void
398 odDepthMap( /* assign depth map for view */
399 int vn,
400 GLfloat *dm
401 )
402 {
403 double d0, d1;
404 int i, j, hmin, hmax, vmin, vmax;
405 register int k, l;
406
407 if (dm == NULL) { /* free edge map */
408 if ((vn<0) | (vn>=odNViews))
409 return; /* too late -- they're gone! */
410 if (odView[vn].emap != NULL)
411 free((void *)odView[vn].emap);
412 odView[vn].emap = NULL;
413 odView[vn].dmap = NULL;
414 return;
415 }
416 DCHECK(vn<0 | vn>=odNViews, CONSISTENCY,
417 "bad view number in odDepthMap");
418 odView[vn].dmap = dm; /* initialize edge map */
419 if (odView[vn].emap == NULL) {
420 odView[vn].emap = (int32 *)malloc(
421 FL4NELS(odView[vn].hlow*odView[vn].vlow)*sizeof(int32));
422 if (odView[vn].emap == NULL)
423 error(SYSTEM, "out of memory in odDepthMap");
424 }
425 CLR4ALL(odView[vn].emap, odView[vn].hlow*odView[vn].vlow);
426 /* compute edge map */
427 vmin = odView[vn].vhi; /* enter loopsville */
428 for (j = odView[vn].vlow; j--; ) {
429 vmax = vmin;
430 vmin = j*odView[vn].vhi/odView[vn].vlow;
431 hmin = odView[vn].hhi;
432 for (i = odView[vn].hlow; i--; ) {
433 hmax = hmin;
434 hmin = i*odView[vn].hhi/odView[vn].hlow;
435 for (l = vmin; l < vmax; l++) { /* vertical edges */
436 d1 = dm[l*odView[vn].hhi+hmin];
437 for (k = hmin+1; k < hmax; k++) {
438 d0 = d1;
439 d1 = dm[l*odView[vn].hhi+k];
440 if (d0 > (1.+DEPTHEPS)*d1 ||
441 (1.+DEPTHEPS)*d0 < d1) {
442 SET4(odView[vn].emap,
443 j*odView[vn].hlow + i);
444 break;
445 }
446 }
447 if (k < hmax)
448 break;
449 }
450 if (l < vmax)
451 continue;
452 for (k = hmin; k < hmax; k++) { /* horizontal edges */
453 d1 = dm[vmin*odView[vn].hhi+k];
454 for (l = vmin+1; l < vmax; l++) {
455 d0 = d1;
456 d1 = dm[l*odView[vn].hhi+k];
457 if (d0 > (1.+DEPTHEPS)*d1 ||
458 (1.+DEPTHEPS)*d0 < d1) {
459 SET4(odView[vn].emap,
460 j*odView[vn].hlow + i);
461 break;
462 }
463 }
464 if (l < vmax)
465 break;
466 }
467 }
468 }
469 }
470
471
472 extern void
473 odUpdate( /* update this view */
474 int vn
475 )
476 {
477 static short primes[] = {9431,6803,4177,2659,1609,887,587,251,47,1};
478 int myprime;
479 register int i, n;
480
481 DCHECK(vn<0 | vn>=odNViews, CONSISTENCY,
482 "bad view number in odUpdate");
483 /* need to do some tone mapping? */
484 if (needmapping & NEWRGB) {
485 if (needmapping & NEWMAP) {
486 if (needmapping & NEWHIST)
487 tmClearHisto();
488 needmapping &= ~NEWHIST;
489 if (tmAddHisto(odS.brt,odS.nsamp,1) != TM_E_OK)
490 return;
491 if (tmComputeMapping(0.,0.,0.) != TM_E_OK)
492 return;
493 needmapping &= ~NEWMAP;
494 odRedrawAll(); /* redraw everything */
495 }
496 if (tmMapPixels((BYTE *)(odS.rgb), odS.brt,
497 (BYTE *)(odS.chr), odS.nsamp) != TM_E_OK)
498 return;
499 needmapping &= ~NEWRGB;
500 }
501 if (odView[vn].n2redraw <= 0)
502 return;
503 #if REDRAWTHRESH
504 if (odView[vn].n2redraw < REDRAWTHRESH)
505 goto quickdraw;
506 /* pick a good prime step size */
507 n = odView[vn].snext - odView[vn].sfirst;
508 for (i = 0; primes[i]<<5 >= n; i++)
509 ;
510 while ((myprime = primes[i++]) > 1)
511 if (n % myprime)
512 break;
513 /* dissolve in new samples */
514 for (i = odView[vn].sfirst; n-- > 0; i += myprime) {
515 if (i >= odView[vn].snext)
516 i -= odView[vn].snext - odView[vn].sfirst;
517 if (CHK4(odS.redraw, i)) {
518 odDrawSamp(vn, i);
519 CLR4(odS.redraw, i);
520 }
521 }
522 odView[vn].n2redraw = 0;
523 return;
524 quickdraw: /* quicker sparse flag checking */
525 #endif
526 /* redraw samples at end */
527 for (i = odView[vn].snext-31; i < odView[vn].snext; i++)
528 if (CHK4(odS.redraw, i)) {
529 odDrawSamp(vn, i);
530 CLR4(odS.redraw, i);
531 }
532 /* faster flag checks in middle */
533 for (n = odView[vn].snext>>5; n-- > (odView[vn].sfirst+0x1f)>>5; )
534 for (i = 0; odS.redraw[n]; i++) /* skips faster */
535 if (odS.redraw[n] & 1L<<i) {
536 odDrawSamp(vn, (n<<5)+i);
537 odS.redraw[n] &= ~(1L<<i);
538 }
539 /* redraw samples at beginning */
540 for (i = odView[vn].sfirst; i < odView[vn].sfirst+31; i++)
541 if (CHK4(odS.redraw, i)) {
542 odDrawSamp(vn, i);
543 CLR4(odS.redraw, i);
544 }
545 odView[vn].n2redraw = 0;
546 }
547
548
549 /* this turned out to be unnecessary */
550 #if 0
551 static
552 clip_end(p, o, vp) /* clip line segment to view */
553 GLshort p[3];
554 short o[2];
555 register struct ODview *vp;
556 {
557 if (p[0] < 0) {
558 p[1] = -o[0]*(p[1]-o[1])/(p[0]-o[0]) + o[1];
559 p[2] = -o[0]*p[2]/(p[0]-o[0]);
560 p[0] = 0;
561 } else if (p[0] >= vp->hhi) {
562 p[1] = (vp->hhi-1-o[0])*(p[1]-o[1])/(p[0]-o[0]) + o[1];
563 p[2] = (vp->hhi-1-o[0])*p[2]/(p[0]-o[0]);
564 p[0] = vp->hhi-1;
565 }
566 if (p[1] < 0) {
567 p[0] = -o[1]*(p[0]-o[0])/(p[1]-o[1]) + o[0];
568 p[2] = -o[1]*p[2]/(p[1]-o[1]);
569 p[1] = 0;
570 } else if (p[1] >= vp->vhi) {
571 p[0] = (vp->vhi-1-o[1])*(p[0]-o[0])/(p[1]-o[1]) + o[0];
572 p[2] = (vp->vhi-1-o[1])*p[2]/(p[1]-o[1]);
573 p[1] = vp->vhi-1;
574 }
575 }
576 #endif
577
578
579 static int
580 make_arms( /* make arms for triangle fan */
581 GLshort ar[MAXFAN][3],
582 short cp[2],
583 register struct ODview *vp,
584 double sz
585 )
586 {
587 int na, dv;
588 double hrad, vrad, phi;
589 register int i;
590
591 DCHECK(sz > 1, CONSISTENCY, "super-unary size in make_arms");
592 na = MAXFAN*sz + 0.5; /* keep arc length constant */
593 if (na < MINFAN) na = MINFAN;
594 hrad = FANSIZE*sz*vp->hhi/vp->hlow;
595 vrad = FANSIZE*sz*vp->vhi/vp->vlow;
596 if (hrad*vrad < 2.25)
597 hrad = vrad = 1.5;
598 dv = OMAXDEPTH*sz + 0.5;
599 for (i = 0; i < na; i++) {
600 phi = (2.*PI)*i/na;
601 ar[i][0] = cp[0] + tcos(phi)*hrad + 0.5;
602 ar[i][1] = cp[1] + tsin(phi)*vrad + 0.5;
603 ar[i][2] = dv;
604 /* clip_end(ar[i], cp, vp); */
605 }
606 return(na);
607 }
608
609
610 static int
611 depthchange( /* check depth discontinuity */
612 register struct ODview *vp,
613 int x0,
614 int y0,
615 int x1,
616 int y1
617 )
618 {
619 register double d0, d1;
620
621 DCHECK(x0<0 | x0>=vp->hhi | y0<0 | y0>=vp->vhi,
622 CONSISTENCY, "coordinates off view in depthchange");
623
624 if ((x1<0) | (x1>=vp->hhi) | (y1<0) | (y1>=vp->vhi))
625 return(1);
626
627 d0 = vp->dmap[y0*vp->hhi + x0];
628 d1 = vp->dmap[y1*vp->hhi + x1];
629
630 return((1.+DEPTHEPS)*d0 < d1 || d0 > (1.+DEPTHEPS)*d1);
631 }
632
633
634 static void
635 clip_edge( /* clip line segment to depth edge */
636 GLshort p[3],
637 short o[2],
638 register struct ODview *vp
639 )
640 {
641 int x, y, xstep, ystep, rise, rise2, run, run2, n;
642
643 DCHECK(vp->dmap==NULL, CONSISTENCY,
644 "clip_edge called with no depth map");
645 x = o[0]; y = o[1];
646 run = p[0] - x;
647 xstep = run > 0 ? 1 : -1;
648 run *= xstep;
649 rise = p[1] - y;
650 ystep = rise > 0 ? 1 : -1;
651 rise *= ystep;
652 rise2 = run2 = 0;
653 if (rise > run) rise2 = 1;
654 else run2 = 1;
655 n = rise + run;
656 while (n--) /* run out arm, checking depth */
657 if (run2 > rise2) {
658 x += xstep;
659 rise2 += rise;
660 if (depthchange(vp, x-xstep, y, x, y))
661 break;
662 } else {
663 y += ystep;
664 run2 += run;
665 if (depthchange(vp, x, y-ystep, x, y))
666 break;
667 }
668 if (n < 0) /* found something? */
669 return;
670 if (run > rise)
671 p[2] = (x - o[0])*p[2]/(p[0] - o[0]);
672 else
673 p[2] = (y - o[1])*p[2]/(p[1] - o[1]);
674 p[0] = x;
675 p[1] = y;
676 }
677
678
679 static int
680 getblock( /* get block index */
681 register struct ODview *vp,
682 register int h,
683 register int v
684 )
685 {
686 if ((h<0) | (h>=vp->hhi) | (v<0) | (v>=vp->vhi))
687 return(-1);
688 return(h*vp->hlow/vp->hhi + v*vp->vlow/vp->vhi*vp->hlow);
689 }
690
691
692 static int
693 blockedge( /* check for edge between blocks? */
694 register struct ODview *vp,
695 register int bi0,
696 register int bi1
697 )
698 {
699 if (bi1 == bi0)
700 return(0); /* same block */
701 if (bi1 < 0)
702 return(1); /* end off view */
703 if (CHK4(vp->emap, bi1))
704 return(1); /* end block has edges */
705 if (bi1 == bi0+1 || bi1 == bi0-1 ||
706 bi1 == bi0+vp->hlow || bi1 == bi0-vp->hlow)
707 return(0); /* end in adjacent block -- no edges */
708 return(1); /* conservative for rarer case */
709 }
710
711
712 static void
713 odDrawSamp( /* draw view sample */
714 int vn,
715 register int id
716 )
717 {
718 GLshort arm[MAXFAN][3];
719 int narms, blockindex;
720 register struct ODview *vp;
721 double size;
722 int home_edges;
723 register int i;
724
725 vp = odView + vn;
726 blockindex = getblock(vp, odS.ip[id][0], odS.ip[id][1]);
727 DCHECK(blockindex<0, CONSISTENCY, "bad sample handed to odDrawSamp");
728 DCHECK(vp->bmap[blockindex].nused <= 0,
729 CONSISTENCY, "bad in-use count in odDrawSamp");
730 /* create triangle fan */
731 size = 1./sqrt((double)vp->bmap[blockindex].nused);
732 narms = make_arms(arm, odS.ip[id], vp, size);
733 if (vp->emap != NULL) { /* check for edge collisions */
734 home_edges = CHK4(vp->emap, blockindex);
735 for (i = 0; i < narms; i++)
736 if (home_edges || blockedge(vp, blockindex,
737 getblock(vp, arm[i][0], arm[i][1])))
738 clip_edge(arm[i], odS.ip[id], vp);
739 }
740 /* draw triangle fan */
741 glColor3ub(odS.rgb[id][0], odS.rgb[id][1], odS.rgb[id][2]);
742 glBegin(GL_TRIANGLE_FAN);
743 glVertex3s((GLshort)odS.ip[id][0], (GLshort)odS.ip[id][1], (GLshort)0);
744 for (i = 0; i < narms; i++)
745 glVertex3sv(arm[i]);
746 glVertex3sv(arm[0]); /* connect last to first */
747 glEnd();
748 }