ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_odraw.c
Revision: 3.11
Committed: Tue Dec 29 09:51:07 1998 UTC (25 years, 4 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.10: +43 -15 lines
Log Message:
changed to dissolve when redrawing large numbers of samples

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