ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.9
Committed: Wed Nov 11 12:05:39 1998 UTC (25 years, 5 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.8: +24 -29 lines
Log Message:
new triangulation code
changed triangle vertex order to CCW
changed numbering of triangle neighbors to match quadtree
fixed tone-mapping bug
removed errant printf() statements
redid logic for adding and testing samples with new epsilon

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 * sm_ogl.c
9 */
10 #include "standard.h"
11
12 #include <GL/gl.h>
13
14 #ifdef TEST_DRIVER
15 #include <gl/device.h>
16 #include <GL/glu.h>
17 #include <glut.h>
18 #endif
19 #include "sm_flag.h"
20 #include "sm_list.h"
21 #include "sm_geom.h"
22 #include "sm_qtree.h"
23 #include "sm_stree.h"
24 #include "sm.h"
25
26 #ifdef TEST_DRIVER
27 #include "sm_draw.h"
28 /*static char smClean_notify = TRUE;
29 MAKE STATIC LATER: ui.c using for now;
30 */
31 char smClean_notify = TRUE;
32 #else
33 static int smClean_notify = TRUE;
34 #endif
35
36 typedef struct {
37 float dist; /* average distance */
38 BYTE rgb[3]; /* average color */
39 } QTRAVG; /* average quadtree value */
40
41 typedef struct {
42 QUADTREE qt; /* quadtree node (key & hash value) */
43 QTRAVG av; /* node average */
44 } QT_LUENT; /* lookup table entry */
45
46 static QT_LUENT *qt_htbl = NULL; /* quadtree cache */
47 static int qt_hsiz = 0; /* quadtree cache size */
48
49
50
51 mark_active_tris(qtptr,fptr)
52 QUADTREE *qtptr;
53 int *fptr;
54 {
55 QUADTREE qt = *qtptr;
56 OBJECT *os,*optr;
57 register int i,t_id;
58 TRI *tri;
59
60 if(!QT_FLAG_FILL_TRI(*fptr))
61 (*fptr)++;
62 if(QT_IS_EMPTY(qt) || QT_LEAF_IS_FLAG(qt))
63 return;
64
65 /* For each triangle in the set, set the which flag*/
66 os = qtqueryset(qt);
67
68 for (i = QT_SET_CNT(os), optr = QT_SET_PTR(os); i > 0; i--)
69 {
70 t_id = QT_SET_NEXT_ELEM(optr);
71 /* Set the render flag */
72 tri = SM_NTH_TRI(smMesh,t_id);
73 if(!T_IS_VALID(tri) || SM_IS_NTH_T_BASE(smMesh,t_id))
74 continue;
75 SM_SET_NTH_T_ACTIVE(smMesh,t_id);
76 /* Set the Active bits of the Vertices */
77 S_SET_FLAG(T_NTH_V(tri,0));
78 S_SET_FLAG(T_NTH_V(tri,1));
79 S_SET_FLAG(T_NTH_V(tri,2));
80
81 }
82 }
83
84 #define mark_active_interior mark_active_tris
85
86 mark_tris_in_frustum(view)
87 VIEW *view;
88 {
89 FVECT nr[4],far[4];
90 FPEQ peq;
91 int debug=0;
92 /* Mark triangles in approx. view frustum as being active:set
93 LRU counter: for use in discarding samples when out
94 of space
95 Radiance often has no far clipping plane: but driver will set
96 dev_zmin,dev_zmax to satisfy OGL
97 */
98
99 /* First clear all the quadtree node and triangle active flags */
100 qtClearAllFlags();
101 smClear_flags(smMesh,T_ACTIVE_FLAG);
102 /* Clear all of the active sample flags*/
103 sClear_all_flags(SM_SAMP(smMesh));
104
105
106 /* calculate the world space coordinates of the view frustum */
107 calculate_view_frustum(view->vp,view->hvec,view->vvec,view->horiz,
108 view->vert, dev_zmin,dev_zmax,nr,far);
109
110 #ifdef TEST_DRIVER
111 VCOPY(FrustumFar[0],far[0]);
112 VCOPY(FrustumFar[1],far[1]);
113 VCOPY(FrustumFar[2],far[2]);
114 VCOPY(FrustumFar[3],far[3]);
115 VCOPY(FrustumNear[0],nr[0]);
116 VCOPY(FrustumNear[1],nr[1]);
117 VCOPY(FrustumNear[2],nr[2]);
118 VCOPY(FrustumNear[3],nr[3]);
119 #endif
120 /* Project the view frustum onto the spherical quadtree */
121 /* For every cell intersected by the projection of the faces
122
123 of the frustum: mark all triangles in the cell as ACTIVE-
124 Also set the triangles LRU clock counter
125 */
126
127 if(EQUAL_VEC3(view->vp,SM_VIEW_CENTER(smMesh)))
128 {/* Near face triangles */
129
130 smLocator_apply_func(smMesh,nr[0],nr[2],nr[3],mark_active_tris,
131 mark_active_interior,NULL);
132 smLocator_apply_func(smMesh,nr[2],nr[0],nr[1],mark_active_tris,
133 mark_active_interior,NULL);
134 return;
135 }
136
137 /* Test the view against the planes: and swap orientation if inside:*/
138 tri_plane_equation(nr[0],nr[2],nr[3], &peq,FALSE);
139 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) < 0.0)
140 {/* Near face triangles */
141 smLocator_apply_func(smMesh,nr[3],nr[2],nr[0],mark_active_tris,
142 mark_active_interior,NULL);
143 smLocator_apply_func(smMesh,nr[1],nr[0],nr[2],mark_active_tris,
144 mark_active_interior,NULL);
145 }
146 else
147 {/* Near face triangles */
148 smLocator_apply_func(smMesh,nr[0],nr[2],nr[3],mark_active_tris,
149 mark_active_interior,NULL);
150 smLocator_apply_func(smMesh,nr[2],nr[0],nr[1],mark_active_tris,
151 mark_active_interior,NULL);
152 }
153 tri_plane_equation(nr[0],far[3],far[0], &peq,FALSE);
154 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) < 0.0)
155 { /* Right face triangles */
156 smLocator_apply_func(smMesh,far[0],far[3],nr[0],mark_active_tris,
157 mark_active_interior,NULL);
158 smLocator_apply_func(smMesh,nr[3],nr[0],far[3],mark_active_tris,
159 mark_active_interior,NULL);
160 }
161 else
162 {/* Right face triangles */
163 smLocator_apply_func(smMesh,nr[0],far[3],far[0],mark_active_tris,
164 mark_active_interior,NULL);
165 smLocator_apply_func(smMesh,far[3],nr[0],nr[3],mark_active_tris,
166 mark_active_interior,NULL);
167 }
168
169 tri_plane_equation(nr[1],far[2],nr[2], &peq,FALSE);
170 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) < 0.0)
171 { /* Left face triangles */
172 smLocator_apply_func(smMesh,nr[2],far[2],nr[1],mark_active_tris,
173 mark_active_interior,NULL);
174 smLocator_apply_func(smMesh,far[1],nr[1],far[2],mark_active_tris,
175 mark_active_interior,NULL);
176 }
177 else
178 { /* Left face triangles */
179 smLocator_apply_func(smMesh,nr[1],far[2],nr[2],mark_active_tris,
180 mark_active_interior,NULL);
181 smLocator_apply_func(smMesh,far[2],nr[1],far[1],mark_active_tris,
182 mark_active_interior,NULL);
183
184 }
185 tri_plane_equation(nr[0],far[0],nr[1], &peq,FALSE);
186 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) < 0.0)
187 {/* Top face triangles */
188 smLocator_apply_func(smMesh,nr[1],far[0],nr[0],mark_active_tris,
189 mark_active_interior,NULL);
190 smLocator_apply_func(smMesh,far[1],far[0],nr[1],mark_active_tris,
191 mark_active_interior,NULL);
192 }
193 else
194 {/* Top face triangles */
195 smLocator_apply_func(smMesh,nr[0],far[0],nr[1],mark_active_tris,
196 mark_active_interior,NULL);
197 smLocator_apply_func(smMesh,nr[1],far[0],far[1],mark_active_tris,
198 mark_active_interior,NULL);
199 }
200 tri_plane_equation(nr[3],nr[2],far[3], &peq,FALSE);
201 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) < 0.0)
202 {/* Bottom face triangles */
203 smLocator_apply_func(smMesh,far[3],nr[2],nr[3],mark_active_tris,
204 mark_active_interior,NULL);
205 smLocator_apply_func(smMesh,far[3],far[2],nr[2],mark_active_tris,
206 mark_active_interior,NULL);
207 }
208 else
209 { /* Bottom face triangles */
210 smLocator_apply_func(smMesh,nr[3],nr[2],far[3],mark_active_tris,
211 mark_active_interior,NULL);
212 smLocator_apply_func(smMesh,nr[2],far[2],far[3],mark_active_tris,
213 mark_active_interior,NULL);
214 }
215 tri_plane_equation(far[2],far[0],far[1], &peq,FALSE);
216 if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) < 0.0)
217 {/* Far face triangles */
218 smLocator_apply_func(smMesh,far[0],far[2],far[1],mark_active_tris,
219 mark_active_interior,NULL);
220 smLocator_apply_func(smMesh,far[2],far[0],far[3],mark_active_tris,
221 mark_active_interior,NULL);
222 }
223 else
224 {/* Far face triangles */
225 smLocator_apply_func(smMesh,far[1],far[2],far[0],mark_active_tris,
226 mark_active_interior,NULL);
227 smLocator_apply_func(smMesh,far[3],far[0],far[2],mark_active_tris,
228 mark_active_interior,NULL);
229 }
230
231 }
232
233 /*
234 * smClean() : display has been wiped clean
235 *
236 * Called after display has been effectively cleared, meaning that all
237 * geometry must be resent down the pipeline in the next call to smUpdate().
238 */
239 smClean()
240 {
241 smClean_notify = TRUE;
242 }
243
244 int
245 qtCache_init(nel) /* initialize for at least nel elements */
246 int nel;
247 {
248 static int hsiztab[] = {
249 8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 0
250 };
251 register int i;
252
253 if (nel <= 0) { /* call to free table */
254 if (qt_hsiz) {
255 free((char *)qt_htbl);
256 qt_htbl = NULL;
257 qt_hsiz = 0;
258 }
259 return(0);
260 }
261 nel += nel>>1; /* 66% occupancy */
262 for (i = 0; hsiztab[i]; i++)
263 if (hsiztab[i] > nel)
264 break;
265 if (!(qt_hsiz = hsiztab[i]))
266 qt_hsiz = nel*2 + 1; /* not always prime */
267 qt_htbl = (QT_LUENT *)calloc(qt_hsiz, sizeof(QT_LUENT));
268 if (qt_htbl == NULL)
269 qt_hsiz = 0;
270 for (i = qt_hsiz; i--; )
271 qt_htbl[i].qt = EMPTY;
272 return(qt_hsiz);
273 }
274
275 QT_LUENT *
276 qtCache_find(qt) /* find a quadtree table entry */
277 QUADTREE qt;
278 {
279 int i, n;
280 register int ndx;
281 register QT_LUENT *le;
282
283 if (qt_hsiz == 0 && !qtCache_init(1))
284 return(NULL);
285 tryagain: /* hash table lookup */
286 ndx = (unsigned long)qt % qt_hsiz;
287 for (i = 0, n = 1; i < qt_hsiz; i++, n += 2) {
288 le = &qt_htbl[ndx];
289 if (QT_IS_EMPTY(le->qt) || le->qt == qt)
290 return(le);
291 if ((ndx += n) >= qt_hsiz) /* this happens rarely */
292 ndx = ndx % qt_hsiz;
293 }
294 /* table is full, reallocate */
295 le = qt_htbl;
296 ndx = qt_hsiz;
297 if (!qtCache_init(ndx+1)) { /* no more memory! */
298 qt_htbl = le;
299 qt_hsiz = ndx;
300 return(NULL);
301 }
302 /* copy old table to new and free */
303 while (ndx--)
304 if (!QT_IS_EMPTY(le[ndx].qt))
305 copystruct(qtCache_find(le[ndx].qt), &le[ndx]);
306 free((char *)le);
307 goto tryagain; /* should happen only once! */
308 }
309
310 stCount_level_leaves(lcnt, qt) /* count quadtree leaf nodes at each level */
311 int lcnt[];
312 register QUADTREE qt;
313 {
314 if (QT_IS_EMPTY(qt))
315 return;
316 if (QT_IS_TREE(qt)) {
317 if (!QT_IS_FLAG(qt)) /* not in our frustum */
318 return;
319 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,0));
320 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,1));
321 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,2));
322 stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,3));
323 }
324 else
325 lcnt[0]++;
326 }
327
328
329 QTRAVG *
330 qtRender_level(qt,v0,v1,v2,sm,lvl)
331 QUADTREE qt;
332 FVECT v0,v1,v2;
333 SM *sm;
334 int lvl;
335 {
336 FVECT a,b,c;
337 register QT_LUENT *le;
338 QTRAVG *rc[4];
339 TRI *tri;
340
341 if (QT_IS_EMPTY(qt)) /* empty leaf node */
342 return(NULL);
343 if (QT_IS_TREE(qt) && !QT_IS_FLAG(qt)) /* not in our frustum */
344 return(NULL);
345 /* else look up node */
346 if ((le = qtCache_find(qt)) == NULL)
347 error(SYSTEM, "out of memory in qtRender_level");
348 if (QT_IS_TREE(qt) && (QT_IS_EMPTY(le->qt) || lvl > 0))
349 { /* compute children */
350 qtSubdivide_tri(v0,v1,v2,a,b,c);
351 rc[0] = qtRender_level(QT_NTH_CHILD(qt,0),v0,a,c,sm,lvl-1);
352 rc[1] = qtRender_level(QT_NTH_CHILD(qt,1),a,v1,b,sm,lvl-1);
353 rc[2] = qtRender_level(QT_NTH_CHILD(qt,2),c,b,v2,sm,lvl-1);
354 rc[3] = qtRender_level(QT_NTH_CHILD(qt,3),b,c,a,sm,lvl-1);
355 }
356 if (QT_IS_EMPTY(le->qt))
357 { /* let's make some data! */
358 int rgbs[3];
359 double distsum;
360 register int i, n;
361 /* average our triangle vertices */
362 rgbs[0] = rgbs[1] = rgbs[2] = 0;
363 distsum = 0.; n = 0;
364 if(QT_IS_TREE(qt))
365 { /* from subtree */
366 for (i = 4; i--; )
367 if (rc[i] != NULL)
368 {
369 rgbs[0] += rc[i]->rgb[0]; rgbs[1] += rc[i]->rgb[1];
370 rgbs[2] += rc[i]->rgb[2]; distsum += rc[i]->dist; n++;
371 }
372 }
373 else
374 { /* from triangle set */
375 OBJECT *os;
376 int s0, s1, s2;
377
378 os = qtqueryset(qt);
379 for (n = os[0]; n; n--)
380 {
381 if(SM_IS_NTH_T_BASE(sm,os[n]))
382 continue;
383 tri = SM_NTH_TRI(sm,os[n]);
384 if(!T_IS_VALID(tri))
385 continue;
386
387 s0 = T_NTH_V(tri,0);
388 s1 = T_NTH_V(tri,1);
389 s2 = T_NTH_V(tri,2);
390 VCOPY(a,SM_NTH_WV(sm,s0));
391 VCOPY(b,SM_NTH_WV(sm,s1));
392 VCOPY(c,SM_NTH_WV(sm,s2));
393 distsum += SM_BG_SAMPLE(sm,s0) ? dev_zmax
394 : sqrt(dist2(a,SM_VIEW_CENTER(sm)));
395 distsum += SM_BG_SAMPLE(sm,s1) ? dev_zmax
396 : sqrt(dist2(b,SM_VIEW_CENTER(sm)));
397 distsum += SM_BG_SAMPLE(sm,s2) ? dev_zmax
398 : sqrt(dist2(c,SM_VIEW_CENTER(sm)));
399 rgbs[0] += SM_NTH_RGB(sm,s0)[0] + SM_NTH_RGB(sm,s1)[0]
400 + SM_NTH_RGB(sm,s2)[0];
401 rgbs[1] += SM_NTH_RGB(sm,s0)[1] + SM_NTH_RGB(sm,s1)[1]
402 + SM_NTH_RGB(sm,s2)[1];
403 rgbs[2] += SM_NTH_RGB(sm,s0)[2] + SM_NTH_RGB(sm,s1)[2]
404 + SM_NTH_RGB(sm,s2)[2];
405 }
406 n = 3*os[0];
407 }
408 if (!n)
409 return(NULL);
410 le->qt = qt;
411 le->av.rgb[0] = rgbs[0]/n; le->av.rgb[1] = rgbs[1]/n;
412 le->av.rgb[2] = rgbs[2]/n; le->av.dist = distsum/(double)n;
413 }
414 if (lvl == 0 || (lvl > 0 && QT_IS_LEAF(qt)))
415 { /* render this node */
416 /* compute pseudo vertices */
417 VCOPY(a,v0); VCOPY(b,v1); VCOPY(c,v2);
418 normalize(a); normalize(b); normalize(c);
419 VSUM(a,SM_VIEW_CENTER(sm),a,le->av.dist);
420 VSUM(b,SM_VIEW_CENTER(sm),b,le->av.dist);
421 VSUM(c,SM_VIEW_CENTER(sm),c,le->av.dist);
422 /* draw triangle */
423 glColor3ub(le->av.rgb[0],le->av.rgb[1],le->av.rgb[2]);
424 glVertex3d(a[0],a[1],a[2]);
425 glVertex3d(b[0],b[1],b[2]);
426 glVertex3d(c[0],c[1],c[2]);
427
428 }
429 return(&le->av);
430 }
431
432
433 smRender_stree_level(sm,lvl)
434 SM *sm;
435 int lvl;
436 {
437 QUADTREE root;
438 int i;
439 FVECT t0,t1,t2;
440 STREE *st;
441
442
443 if (lvl < 1)
444 return;
445 st = SM_LOCATOR(sm);
446 glPushAttrib(GL_LIGHTING_BIT);
447 glShadeModel(GL_FLAT);
448 glBegin(GL_TRIANGLES);
449 for(i=0; i < ST_NUM_ROOT_NODES; i++)
450 {
451 root = ST_NTH_ROOT(st,i);
452 qtRender_level(root,ST_NTH_V(st,i,0),ST_NTH_V(st,i,1),ST_NTH_V(st,i,2),
453 sm,lvl-1);
454 }
455 glEnd();
456 glPopAttrib();
457 }
458
459
460 smRender_stree(sm, qual) /* render some quadtree triangles */
461 SM *sm;
462 int qual;
463 {
464 int i, ntarget;
465 int lvlcnt[QT_MAX_LEVELS];
466
467 if (qual <= 0)
468 return;
469 /* compute rendering target */
470 ntarget = 0;
471 SM_FOR_ALL_ACTIVE_TRIS(sm,i)
472 ntarget++;
473 ntarget = ntarget*qual/100;
474 if (!ntarget)
475 return;
476 for (i = QT_MAX_LEVELS; i--; )
477 lvlcnt[i] = 0;
478 stCount_level_leaves(lvlcnt, ST_TOP_ROOT(SM_LOCATOR(sm)));
479 stCount_level_leaves(lvlcnt, ST_BOTTOM_ROOT(SM_LOCATOR(sm)));
480 for (ntarget -= lvlcnt[i=0]; i < QT_MAX_LEVELS-1; ntarget -= lvlcnt[++i])
481 if (ntarget < lvlcnt[i+1])
482 break;
483 /* compute and render target level */
484 smRender_stree_level(sm,i);
485 }
486
487
488 smRender_tri(sm,i,vp,clr)
489 SM *sm;
490 int i;
491 FVECT vp;
492 int clr;
493 {
494 TRI *tri;
495 double ptr[3];
496 int j;
497
498 tri = SM_NTH_TRI(sm,i);
499 if (clr) SM_CLR_NTH_T_NEW(sm,i);
500 for(j=0; j <= 2; j++)
501 {
502 #ifdef DEBUG
503 if(SM_BG_SAMPLE(sm,T_NTH_V(tri,j)))
504 eputs("SmRenderTri(): shouldnt have bg samples\n");
505 #endif
506 glColor3ub(SM_NTH_RGB(sm,T_NTH_V(tri,j))[0],
507 SM_NTH_RGB(sm,T_NTH_V(tri,j))[1],
508 SM_NTH_RGB(sm,T_NTH_V(tri,j))[2]);
509 VCOPY(ptr,SM_T_NTH_WV(sm,tri,j));
510 glVertex3d(ptr[0],ptr[1],ptr[2]);
511 }
512 }
513
514 smRender_mixed_tri(sm,i,vp,clr)
515 SM *sm;
516 int i;
517 FVECT vp;
518 int clr;
519 {
520 TRI *tri;
521 double p[3],d;
522 int j,ids[3],cnt;
523 int rgb[3];
524
525 tri = SM_NTH_TRI(sm,i);
526 if (clr) SM_CLR_NTH_T_NEW(sm,i);
527
528 /* NOTE:Triangles are defined clockwise:historical relative to spherical
529 tris: could change
530 */
531 cnt = 0;
532 d = 0.0;
533 rgb[0] = rgb[1] = rgb[2] = 0;
534 for(j=0;j < 3;j++)
535 {
536 ids[j] = T_NTH_V(tri,j);
537 if(!SM_BG_SAMPLE(sm,ids[j]))
538 {
539 rgb[0] += SM_NTH_RGB(sm,ids[j])[0];
540 rgb[1] += SM_NTH_RGB(sm,ids[j])[1];
541 rgb[2] += SM_NTH_RGB(sm,ids[j])[2];
542 cnt++;
543 d += DIST(vp,SM_NTH_WV(sm,ids[j]));
544 }
545 }
546 if(cnt > 1)
547 {
548 rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
549 d /= (double)cnt;
550 }
551 for(j=0; j <= 2; j++)
552 {
553 if(SM_BG_SAMPLE(sm,ids[j]))
554 {
555 glColor3ub(rgb[0],rgb[1],rgb[2]);
556 VSUB(p,SM_NTH_WV(sm,ids[j]),SM_VIEW_CENTER(sm));
557 p[0] *= d;
558 p[1] *= d;
559 p[2] *= d;
560 VADD(p,p,SM_VIEW_CENTER(sm));
561 }
562 else
563 {
564 glColor3ub(SM_NTH_RGB(sm,ids[j])[0],SM_NTH_RGB(sm,ids[j])[1],
565 SM_NTH_RGB(sm,ids[j])[2]);
566 VCOPY(p,SM_NTH_WV(sm,ids[j]));
567 }
568 glVertex3d(p[0],p[1],p[2]);
569 }
570 }
571
572 smRender_bg_tri(sm,i,vp,d,clr)
573 SM *sm;
574 int i;
575 FVECT vp;
576 double d;
577 int clr;
578 {
579 double p[3];
580 int j,id;
581 TRI *tri;
582
583 tri = SM_NTH_TRI(sm,i);
584 if (clr) SM_CLR_NTH_T_NEW(sm,i);
585
586 /* NOTE:Triangles are defined clockwise:historical relative to spherical
587 tris: could change
588 */
589 for(j=0; j <= 2; j++)
590 {
591 id = T_NTH_V(tri,j);
592 glColor3ub(SM_NTH_RGB(sm,id)[0],SM_NTH_RGB(sm,id)[1],
593 SM_NTH_RGB(sm,id)[2]);
594 VSUB(p,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
595 if(dev_zmin >= 0.99)
596 {
597 p[0] *= d;
598 p[1] *= d;
599 p[2] *= d;
600 }
601 VADD(p,p,vp);
602 glVertex3d(p[0],p[1],p[2]);
603 }
604 }
605
606 smRender_mesh(sm,vp,clr)
607 SM *sm;
608 FVECT vp;
609 int clr;
610 {
611 int i;
612 TRI *tri;
613 double ptr[3],d;
614 int j;
615
616 d = (dev_zmin+dev_zmax)/2.0;
617 glPushAttrib(GL_DEPTH_BUFFER_BIT);
618
619 /* First draw background polygons */
620 glDisable(GL_DEPTH_TEST);
621 glBegin(GL_TRIANGLES);
622 SM_FOR_ALL_ACTIVE_BG_TRIS(sm,i)
623 smRender_bg_tri(sm,i,vp,d,clr);
624 glEnd();
625 glEnable(GL_DEPTH_TEST);
626 glBegin(GL_TRIANGLES);
627 SM_FOR_ALL_ACTIVE_FG_TRIS(sm,i)
628 {
629 if(!SM_MIXED_TRI(sm,i))
630 smRender_tri(sm,i,vp,clr);
631 else
632 smRender_mixed_tri(sm,i,vp,clr);
633 }
634 glEnd();
635
636 glPopAttrib();
637 }
638
639 smRender_tri_edges(sm,i)
640 SM *sm;
641 int i;
642 {
643 TRI *tri;
644 int j;
645 double ptr[3];
646
647
648 tri = SM_NTH_TRI(sm,i);
649
650 for(j=0; j <= 2; j++)
651 {
652 VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,j)));
653 glVertex3d(ptr[0],ptr[1],ptr[2]);
654 VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,(j+1)%3)));
655 glVertex3d(ptr[0],ptr[1],ptr[2]);
656 }
657 }
658
659 int
660 compare_tri_depths(T_DEPTH *td1,T_DEPTH *td2)
661 {
662 double d;
663
664 d = td2->depth-td1->depth;
665
666 if(d > 0.0)
667 return(1);
668 if(d < 0.0)
669 return(-1);
670
671 return(0);
672 }
673
674 LIST
675 *smDepth_sort_tris(sm,vp,td)
676 SM *sm;
677 FVECT vp;
678 T_DEPTH *td;
679 {
680 int i,j,t_id,v;
681 TRI *tri;
682 double d,min_d;
683 LIST *tlist=NULL;
684
685 i = 0;
686 SM_FOR_ALL_NEW_TRIS(sm,t_id)
687 {
688 if(SM_BG_TRI(sm,t_id))
689 {
690 tlist = push_data(tlist,t_id);
691 continue;
692 }
693 tri = SM_NTH_TRI(sm,t_id);
694 #ifdef DEBUG
695 if(i >= smNew_tri_cnt)
696 {
697 eputs("smDepth_sort_tris():More tris than reported by smNew_tri_cnt\n");
698 break;
699 }
700 #endif
701 td[i].tri = t_id;
702 min_d = -1;
703 for(j=0;j < 3;j++)
704 {
705 v = T_NTH_V(tri,j);
706 if(!SM_BG_SAMPLE(sm,v))
707 {
708 d = DIST(vp,SM_NTH_WV(sm,v));
709 if(min_d == -1 || d < min_d)
710 min_d = d;
711 }
712 }
713 td[i].depth = min_d;
714 i++;
715 }
716 td[i].tri = -1;
717 if(i)
718 qsort((void *)td,i,sizeof(T_DEPTH),compare_tri_depths);
719 return(tlist);
720 }
721
722
723 smUpdate_Rendered_mesh(sm,vp,clr)
724 SM *sm;
725 FVECT vp;
726 int clr;
727 {
728 static T_DEPTH *td= NULL;
729 static int tsize = 0;
730 int i;
731 GLint depth_test;
732 double d;
733 LIST *bglist;
734 /* For all of the NEW triangles (since last update): assume
735 ACTIVE. Go through and sort on depth value (from vp). Turn
736 Depth Buffer test off and render back-front
737 */
738 /* NOTE: could malloc each time or hard code */
739 if(smNew_tri_cnt > tsize)
740 {
741 if(td)
742 free((char *)td);
743 td = (T_DEPTH *)malloc(smNew_tri_cnt*sizeof(T_DEPTH));
744 tsize = smNew_tri_cnt;
745 }
746 if(!td)
747 {
748 error(SYSTEM,"smUpdate_Rendered_mesh:Cannot allocate memory\n");
749 }
750 bglist = smDepth_sort_tris(sm,vp,td);
751
752 /* Turn Depth Test off -- using Painter's algorithm */
753 glPushAttrib(GL_DEPTH_BUFFER_BIT);
754 glDepthFunc(GL_ALWAYS);
755 d = (dev_zmin+dev_zmax)/2.0;
756 /* Now render back-to front */
757 /* First render bg triangles */
758 glBegin(GL_TRIANGLES);
759 while(bglist)
760 smRender_bg_tri(sm,pop_list(&bglist),vp,d,clr);
761 glEnd();
762
763
764 glBegin(GL_TRIANGLES);
765 i=0;
766 while(td[i].tri != -1)
767 if(!SM_MIXED_TRI(sm,td[i].tri))
768 smRender_tri(sm,td[i++].tri,vp,clr);
769 else
770 smRender_mixed_tri(sm,td[i++].tri,vp,clr);
771 glEnd();
772
773 /* Restore Depth Test */
774 glPopAttrib();
775 }
776
777 /*
778 * smUpdate(view, qua) : update OpenGL output geometry for view vp
779 * VIEW *view; : desired view
780 * int qual; : quality level (percentage on linear time scale)
781 *
782 * Draw new geometric representation using OpenGL calls. Assume that the
783 * view has already been set up and the correct frame buffer has been
784 * selected for drawing. The quality level is on a linear scale, where 100%
785 * is full (final) quality. It is not necessary to redraw geometry that has
786 * been output since the last call to smClean(). (The last view drawn will
787 * be view==&odev.v each time.)
788 */
789 smUpdate(view,qual)
790 VIEW *view;
791 int qual;
792 {
793 double d;
794 int last_update;
795 int t;
796
797 /* If view has moved beyond epsilon from canonical: must rebuild -
798 epsilon is calculated as running avg of distance of sample points
799 from canonical view: m = 1/(AVG(1/r)): some fraction of this
800 */
801
802 if(!smMesh)
803 return;
804 d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
805 if(qual >= 100 && d > SM_ALLOWED_VIEW_CHANGE(smMesh))
806 {
807 /* Re-build the mesh */
808 #ifdef TEST_DRIVER
809 odev.v = *view;
810 #endif
811 mark_tris_in_frustum(view);
812 smRebuild_mesh(smMesh,view);
813 }
814 /* This is our final update iff qual==100 and view==&odev.v */
815 last_update = qual>=100 && view==&(odev.v);
816 /* Check if we should draw ALL triangles in current frustum */
817 if(smClean_notify || smNew_tri_cnt > SM_SAMPLE_TRIS(smMesh)*SM_INC_PERCENT)
818 {
819 #ifdef TEST_DRIVER
820 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
821 #else
822 if ( SM_TONE_MAP(smMesh) < SM_NUM_SAMP(smMesh))
823 {
824 tmClearHisto();
825 tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
826 if(tmComputeMapping(0.,0.,0.) != TM_E_OK ||
827 tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
828 SM_NUM_SAMP(smMesh)) != TM_E_OK)
829 return;
830 }
831 #endif
832 mark_tris_in_frustum(view);
833 if (qual <= 75)
834 smRender_stree(smMesh,qual);
835 else
836 smRender_mesh(smMesh,view->vp,last_update);
837 #ifdef TEST_DRIVER
838 glFlush();
839 glutSwapBuffers();
840 #endif
841 }
842 /* Do an incremental update instead */
843 else
844 {
845 if(!smNew_tri_cnt)
846 return;
847 #ifdef TEST_DRIVER
848 glDrawBuffer(GL_FRONT);
849 #else
850 t = SM_TONE_MAP(smMesh);
851 if(t == 0)
852 {
853 tmClearHisto();
854 tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
855 if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
856 return;
857 }
858 if(tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
859 SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t) != TM_E_OK)
860 return;
861 #endif
862 smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
863
864 #ifdef TEST_DRIVER
865 glDrawBuffer(GL_BACK);
866 #endif
867 }
868
869 SM_TONE_MAP(smMesh) = SM_NUM_SAMP(smMesh);
870
871 if (last_update)
872 {
873 smClean_notify = FALSE;
874 smNew_tri_cnt = 0;
875 smClear_flags(smMesh,T_NEW_FLAG);
876 qtCache_init(0);
877 }
878
879 }