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

# 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
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 }