ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.5
Committed: Fri Sep 11 11:52:26 1998 UTC (25 years, 7 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.4: +16 -19 lines
Log Message:
fixed triangle insertion using edge tracing

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