ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/rhd_odraw.c
Revision: 3.1
Committed: Fri Dec 18 11:55:19 1998 UTC (25 years, 4 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Log Message:
Initial revision

File Contents

# User Rev Content
1 gwlarson 3.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    
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) { /* deallocate view structures */
61     for (i = 0; i < odNViews; i++) {
62     free((char *)odView[i].bmap);
63     if (odView[i].emap != NULL)
64     free((char *)odView[i].emap);
65     }
66     free((char *)odView);
67     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     needmapping = NEWMAP;
77     }
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     odView[i].emap = NULL;
112     odView[i].dmap = NULL;
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     j = odView[i].hlow*odView[i].vlow;
121     odView[i].bmap = (struct ODblock *)malloc(
122     j * sizeof(struct ODblock));
123     if (odView[i].bmap == NULL)
124     return(0);
125     DCHECK(count<=0 | nextsamp>=n,
126     CONSISTENCY, "counter botch in odInit");
127     if (!i) count = j;
128     while (j--) {
129     odView[i].bmap[j].first = k = nextsamp;
130     nextsamp += odView[i].bmap[j].nsamp =
131     (n - nextsamp)/count--;
132     odView[i].bmap[j].free = k;
133     while (++k < nextsamp)
134     odS.nextfree(k-1) = k;
135     odS.nextfree(k-1) = ENDFREE;
136     odView[i].bmap[j].nused = 0;
137     }
138     }
139     CLR4ALL(odS.redraw, odS.nsamp); /* clear redraw flags */
140     for (i = odS.nsamp; i--; ) /* clear values */
141     odS.ip[i][0] = odS.ip[i][1] = -1;
142     return(odS.nsamp); /* return number of samples */
143     }
144    
145     #undef SAMP32
146    
147    
148     int
149     sampcmp(s0, s1) /* sample order, descending proximity */
150     int *s0, *s1;
151     {
152     register double diff = odS.closeness(*s1) - odS.closeness(*s0);
153    
154     return (diff > FTINY ? 1 : diff < -FTINY ? -1 : 0);
155     }
156    
157    
158     int
159     odAllocBlockSamp(vn, hl, vl) /* allocate sample from block */
160     int vn, hl, vl;
161     {
162     int si[SAMPSPERBLOCK+SAMPSPERBLOCK/4];
163     VIEW *vw;
164     FVECT ro, rd;
165     int res[2];
166     register struct ODblock *bp;
167     register int i;
168    
169     bp = odView[vn].bmap + vl*odView[vn].hlow + hl;
170     if (bp->free != ENDFREE) { /* check free list first */
171     i = bp->free;
172     bp->free = odS.nextfree(i);
173     bp->nused++;
174     return(i);
175     }
176     DCHECK(bp->nsamp<=0, CONSISTENCY,
177     "no available samples in odAllocBlockSamp");
178     DCHECK(bp->nsamp > sizeof(si)/sizeof(si[0]), CONSISTENCY,
179     "too many samples in odAllocBlockSamp");
180     /* free some samples */
181     if ((vw = dev_auxview(vn, res)) == NULL)
182     error(CONSISTENCY, "bad view number in odAllocBlockSamp");
183     for (i = bp->nsamp; i--; ) /* figure out which are worse */
184     si[i] = bp->first + i;
185     qsort((char *)si, bp->nsamp, sizeof(int), sampcmp);
186     i = bp->nsamp*SFREEFRAC + .5; /* put them in a list */
187     while (--i > 0) {
188     odS.nextfree(si[i]) = bp->free;
189     bp->free = si[i];
190     bp->nused--;
191     }
192     return(si[0]); /* return first free sample */
193     }
194    
195    
196     odSample(c, d, p) /* add a sample value */
197     COLR c;
198     FVECT d, p;
199     {
200     FVECT disp;
201     double d0, d1, h, v;
202     register VIEW *vw;
203     int hl, vl, hh, vh;
204     int res[2];
205     register int i, id;
206    
207     DCHECK(odS.nsamp<=0, CONSISTENCY, "no samples allocated in odSample");
208     /* add value to each view */
209     for (i = 0; (vw = dev_auxview(i, res)) != NULL; i++) {
210     DCHECK(i>=odNViews, CONSISTENCY, "too many views in odSample");
211     CHECK(vw->type!=VT_PER, INTERNAL,
212     "cannot handle non-perspective views");
213     if (p != NULL) { /* compute view position */
214     VSUB(disp, p, vw->vp);
215     d0 = DOT(disp, vw->vdir);
216     if (d0 <= vw->vfore+FTINY)
217     continue; /* too close */
218     } else {
219     VCOPY(disp, d);
220     d0 = DOT(disp, vw->vdir);
221     if (d0 <= FTINY) /* behind view */
222     continue;
223     }
224     h = DOT(disp,vw->hvec)/(d0*vw->hn2) + 0.5 - vw->hoff;
225     if (h < 0. || h >= 1.)
226     continue; /* left or right */
227     v = DOT(disp,vw->vvec)/(d0*vw->vn2) + 0.5 - vw->voff;
228     if (v < 0. || v >= 1.)
229     continue; /* above or below */
230     hh = h * res[0];
231     vh = v * res[1];
232     if (odView[i].dmap != NULL) { /* check depth */
233     d1 = odView[i].dmap[vh*res[0] + hh];
234     if (d1 < 0.99*FHUGE && (d0 > (1.+DEPTHEPS)*d1 ||
235     (1.+DEPTHEPS)*d0 < d1))
236     continue; /* occlusion error */
237     }
238     hl = hh*odView[i].hlow/res[0];
239     vl = vh*odView[i].vlow/res[1];
240     /* may duplicate samples */
241     id = odAllocBlockSamp(i, hl, vl);
242     odS.ip[id][0] = hh;
243     odS.ip[id][1] = vh;
244     if (p != NULL) { /* compute closeness (sin^2) */
245     d1 = DOT(disp, d);
246     odS.closeness(id) = 1. - d1*d1/DOT(disp,disp);
247     } else
248     odS.closeness(id) = 0.;
249     /* convert color */
250     tmCvColrs(&odS.brt[id], odS.chr[id], c, 1);
251     if (imm_mode | needmapping) /* if immediate mode */
252     needmapping |= NEWRGB; /* map it later */
253     else /* else map it now */
254     tmMapPixels(odS.rgb[id], &odS.brt[id], odS.chr[id], 1);
255     SET4(odS.redraw, id); /* mark for redraw */
256     }
257     }
258    
259    
260     odRemap() /* recompute tone mapping */
261     {
262     needmapping |= NEWMAP|NEWRGB;
263     }
264    
265    
266     odRedraw(vn, hmin, vmin, hmax, vmax) /* redraw view region */
267     int vn, hmin, vmin, hmax, vmax;
268     {
269     int i, j;
270     register struct ODblock *bp;
271     register int k;
272    
273     if (vn<0 | vn>=odNViews)
274     return;
275     /* check view limits */
276     if (hmin < 0) hmin = 0;
277     if (hmax >= odView[vn].hhi) hmax = odView[vn].hhi-1;
278     if (vmin < 0) vmin = 0;
279     if (vmax >= odView[vn].vhi) vmax = odView[vn].vhi-1;
280     if (hmax <= hmin | vmax <= vmin)
281     return;
282     /* convert to low resolution */
283     hmin = hmin * odView[vn].hlow / odView[vn].hhi;
284     hmax = hmax * odView[vn].hlow / odView[vn].hhi;
285     vmin = vmin * odView[vn].vlow / odView[vn].vhi;
286     vmax = vmax * odView[vn].vlow / odView[vn].vhi;
287     /* mark block samples for redraw, inclusive */
288     for (i = hmin; i <= hmax; i++)
289     for (j = vmin; j <= vmax; j++) {
290     bp = odView[vn].bmap + j*odView[vn].hlow + i;
291     for (k = bp->nsamp; k--; )
292     if (odS.ip[bp->first+k][0] >= 0)
293     SET4(odS.redraw, bp->first+k);
294     }
295     }
296    
297    
298     odDepthMap(vn, dm) /* assign depth map for view */
299     int vn;
300     GLfloat *dm;
301     {
302     double d0, d1;
303     int i, j, hmin, hmax, vmin, vmax;
304     register int k, l;
305    
306     DCHECK(vn<0 | vn>=odNViews, CONSISTENCY,
307     "bad view number in odDepthMap");
308     if (dm == NULL) { /* free edge map */
309     if (odView[vn].emap != NULL)
310     free((char *)odView[vn].emap);
311     odView[vn].emap = NULL;
312     odView[vn].dmap = NULL;
313     return;
314     }
315     odView[vn].dmap = dm; /* initialize edge map */
316     if (odView[vn].emap == NULL) {
317     odView[vn].emap = (int4 *)malloc(
318     FL4NELS(odView[vn].hlow*odView[vn].vlow)*sizeof(int4));
319     if (odView[vn].emap == NULL)
320     error(SYSTEM, "out of memory in odDepthMap");
321     }
322     CLR4ALL(odView[vn].emap, odView[vn].hlow*odView[vn].vlow);
323     /* compute edge map */
324     vmin = odView[vn].vhi; /* enter loopsville */
325     for (j = odView[vn].vlow; j--; ) {
326     vmax = vmin;
327     vmin = j*odView[vn].vhi/odView[vn].vlow;
328     hmin = odView[vn].hhi;
329     for (i = odView[vn].hlow; i--; ) {
330     hmax = hmin;
331     hmin = i*odView[vn].hhi/odView[vn].hlow;
332     for (l = vmin; l < vmax; l++) { /* vertical edges */
333     d1 = dm[l*odView[vn].hhi+hmin];
334     for (k = hmin+1; k < hmax; k++) {
335     d0 = d1;
336     d1 = dm[l*odView[vn].hhi+k];
337     if (d0 > (1.+DEPTHEPS)*d1 ||
338     (1.+DEPTHEPS)*d0 < d1) {
339     SET4(odView[vn].emap,
340     j*odView[vn].hlow + i);
341     break;
342     }
343     }
344     if (k < hmax)
345     break;
346     }
347     if (l < vmax)
348     continue;
349     for (k = hmin; k < hmax; k++) { /* horizontal edges */
350     d1 = dm[vmin*odView[vn].hhi+k];
351     for (l = vmin+1; l < vmax; l++) {
352     d0 = d1;
353     d1 = dm[l*odView[vn].hhi+k];
354     if (d0 > (1.+DEPTHEPS)*d1 ||
355     (1.+DEPTHEPS)*d0 < d1) {
356     SET4(odView[vn].emap,
357     j*odView[vn].hlow + i);
358     break;
359     }
360     }
361     if (l < vmax)
362     break;
363     }
364     }
365     }
366     }
367    
368    
369     odUpdate(vn) /* update this view */
370     int vn;
371     {
372     int i, j;
373     register struct ODblock *bp;
374     register int k;
375    
376     DCHECK(vn<0 | vn>=odNViews, CONSISTENCY,
377     "bad view number in odUpdate");
378     /* need to do some tone mapping? */
379     if (needmapping & NEWRGB) {
380     if (needmapping & NEWMAP) {
381     tmClearHisto();
382     if (tmAddHisto(odS.brt,odS.nsamp,1) != TM_E_OK)
383     return;
384     if (tmComputeMapping(0.,0.,0.) != TM_E_OK)
385     return;
386     for (k = odS.nsamp; k--; ) /* redraw all */
387     if (odS.ip[k][0] >= 0)
388     SET4(odS.redraw, k);
389     }
390     if (tmMapPixels(odS.rgb,odS.brt,odS.chr,odS.nsamp) != TM_E_OK)
391     return;
392     needmapping = 0; /* reset flag */
393     }
394     /* draw each block in view */
395     for (i = odView[vn].hlow; i--; )
396     for (j = odView[vn].vlow; j--; ) {
397     /* get block */
398     bp = odView[vn].bmap + j*odView[vn].hlow + i;
399     /* do quick, conservative flag check */
400     for (k = (bp->first+bp->nsamp+31)>>5;
401     k-- > bp->first>>5; )
402     if (odS.redraw[k])
403     break; /* non-zero flag */
404     if (k < bp->first>>5)
405     continue; /* no flags set */
406     for (k = bp->nsamp; k--; ) /* sample by sample */
407     if (CHK4(odS.redraw, bp->first+k)) {
408     odDrawBlockSamp(vn, i, j, bp->first+k);
409     CLR4(odS.redraw, bp->first+k);
410     }
411     }
412     }
413    
414    
415     #if 0
416     static
417     clip_end(p, o, vp) /* clip line segment to view */
418     GLshort p[3];
419     short o[2];
420     register struct ODview *vp;
421     {
422     if (p[0] < 0) {
423     p[1] = -o[0]*(p[1]-o[1])/(p[0]-o[0]) + o[1];
424     p[2] = -o[0]*p[2]/(p[0]-o[0]);
425     p[0] = 0;
426     } else if (p[0] >= vp->hhi) {
427     p[1] = (vp->hhi-1-o[0])*(p[1]-o[1])/(p[0]-o[0]) + o[1];
428     p[2] = (vp->hhi-1-o[0])*p[2]/(p[0]-o[0]);
429     p[0] = vp->hhi-1;
430     }
431     if (p[1] < 0) {
432     p[0] = -o[1]*(p[0]-o[0])/(p[1]-o[1]) + o[0];
433     p[2] = -o[1]*p[2]/(p[1]-o[1]);
434     p[1] = 0;
435     } else if (p[1] >= vp->vhi) {
436     p[0] = (vp->vhi-1-o[1])*(p[0]-o[0])/(p[1]-o[1]) + o[0];
437     p[2] = (vp->vhi-1-o[1])*p[2]/(p[1]-o[1]);
438     p[1] = vp->vhi-1;
439     }
440     }
441     #endif
442    
443    
444     static int
445     make_arms(ar, cp, vp, sz) /* make arms for triangle fan */
446     GLshort ar[MAXFAN][3];
447     short cp[2];
448     register struct ODview *vp;
449     double sz;
450     {
451     int na, dv;
452     double hrad, vrad, phi0, phi;
453     register int i;
454    
455     DCHECK(sz > 1, CONSISTENCY, "super-unary size in make_arms");
456     na = MAXFAN*sz*sz + 0.5; /* keep area constant */
457     if (na < MINFAN) na = MINFAN;
458     hrad = FANSIZE*sz*vp->hhi/vp->hlow;
459     vrad = FANSIZE*sz*vp->vhi/vp->vlow;
460     if (hrad*vrad < 2.25)
461     hrad = vrad = 1.5;
462     phi0 = (2.*PI) * frandom();
463     dv = OMAXDEPTH*sz + 0.5;
464     for (i = 0; i < na; i++) {
465     phi = phi0 + (2.*PI)*i/na;
466     ar[i][0] = cp[0] + tcos(phi)*hrad + 0.5;
467     ar[i][1] = cp[1] + tsin(phi)*vrad + 0.5;
468     ar[i][2] = dv;
469     /* clip_end(ar[i], cp, vp); */
470     }
471     return(na);
472     }
473    
474    
475     static int
476     depthchange(vp, x0, y0, x1, y1) /* check depth discontinuity */
477     register struct ODview *vp;
478     int x0, y0, x1, y1;
479     {
480     register double d0, d1;
481    
482     DCHECK(x0<0 | x0>=vp->hhi | y0<0 | y0>=vp->vhi,
483     CONSISTENCY, "coordinates off view in depthchange");
484    
485     if (x1<0 | x1>=vp->hhi | y1<0 | y1>=vp->vhi)
486     return(1);
487    
488     d0 = vp->dmap[y0*vp->hhi + x0];
489     d1 = vp->dmap[y1*vp->hhi + x1];
490    
491     return((1.+DEPTHEPS)*d0 < d1 || d0 > (1.+DEPTHEPS)*d1);
492     }
493    
494    
495     static
496     clip_edge(p, o, vp) /* clip line segment to depth edge */
497     GLshort p[3];
498     short o[2];
499     register struct ODview *vp;
500     {
501     int x, y, xstep, ystep, rise, rise2, run, run2, n;
502    
503     DCHECK(vp->dmap==NULL, CONSISTENCY,
504     "clip_edge called with no depth map");
505     x = o[0]; y = o[1];
506     run = p[0] - x;
507     xstep = run > 0 ? 1 : -1;
508     run *= xstep;
509     rise = p[1] - y;
510     ystep = rise > 0 ? 1 : -1;
511     rise *= ystep;
512     rise2 = run2 = 0;
513     if (rise > run) rise2 = 1;
514     else run2 = 1;
515     n = rise + run;
516     while (n--) /* run out arm, checking depth */
517     if (run2 > rise2) {
518     if (depthchange(vp, x, y, x+xstep, y))
519     break;
520     x += xstep;
521     rise2 += rise;
522     } else {
523     if (depthchange(vp, x, y, x, y+ystep))
524     break;
525     y += ystep;
526     run2 += run;
527     }
528     if (n < 0) /* found something? */
529     return;
530     if (run > rise)
531     p[2] = (x - o[0])*p[2]/(p[0] - o[0]);
532     else
533     p[2] = (y - o[1])*p[2]/(p[1] - o[1]);
534     p[0] = x;
535     p[1] = y;
536     }
537    
538    
539     static int
540     getblock(vp, h, v) /* get block index */
541     register struct ODview *vp;
542     register int h, v;
543     {
544     if (h<0 | h>=vp->hhi | v<0 | v>=vp->vhi)
545     return(-1);
546     return(h*vp->hlow/vp->hhi + v*vp->vlow/vp->vhi*vp->hlow);
547     }
548    
549    
550     odDrawBlockSamp(vn, h, v, id) /* draw sample in view block */
551     int vn, h, v;
552     register int id;
553     {
554     GLshort arm[MAXFAN][3];
555     int narms, blockindex, bi1;
556     register struct ODview *vp;
557     double size;
558     int home_edges;
559     register int i;
560    
561     vp = odView + vn;
562     blockindex = v*vp->hlow + h;
563     DCHECK(odS.ip[id][0]*vp->hlow/vp->hhi != h |
564     odS.ip[id][1]*vp->vlow/vp->vhi != v,
565     CONSISTENCY, "bad sample position in odDrawBlockSamp");
566     DCHECK(vp->bmap[blockindex].nused <= 0,
567     CONSISTENCY, "bad in-use count in odDrawBlockSamp");
568     /* create triangle fan */
569     size = 1./sqrt((double)vp->bmap[blockindex].nused);
570     narms = make_arms(arm, odS.ip[id], vp, size);
571     if (vp->emap != NULL) { /* check for edge collisions */
572     home_edges = CHK4(vp->emap, blockindex);
573     for (i = 0; i < narms; i++)
574     /* the following test is flawed, because we could
575     * be passing through a block on a diagonal run */
576     if (home_edges ||
577     ( (bi1 = getblock(vp, arm[i][0], arm[i][1]))
578     != blockindex &&
579     (bi1 < 0 || CHK4(vp->emap, bi1)) ))
580     clip_edge(arm[i], odS.ip[id], vp);
581     }
582     /* draw triangle fan */
583     glColor3ub(odS.rgb[id][0], odS.rgb[id][1], odS.rgb[id][2]);
584     glBegin(GL_TRIANGLE_FAN);
585     glVertex3s((GLshort)odS.ip[id][0], (GLshort)odS.ip[id][1], (GLshort)0);
586     for (i = 0; i < narms; i++)
587     glVertex3sv(arm[i]);
588     glVertex3sv(arm[0]); /* connect last to first */
589     glEnd();
590     }