ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_odraw.c
Revision: 3.6
Committed: Wed Dec 23 17:42:24 1998 UTC (25 years, 3 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.5: +39 -16 lines
Log Message:
improved edge precheck
added odRedrawAll() routine

File Contents

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