ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_odraw.c
Revision: 3.5
Committed: Tue Dec 22 17:05:54 1998 UTC (25 years, 4 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.4: +24 -2 lines
Log Message:
fixed odUpdate() for multiple views

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