ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_odraw.c
Revision: 3.14
Committed: Tue Mar 4 05:49:21 2003 UTC (21 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
CVS Tags: rad3R5
Changes since 3.13: +3 -2 lines
Log Message:
Moved dircode.c and fixed prototype compiles in hd directory

File Contents

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