ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.6
Committed: Mon Sep 14 10:33:47 1998 UTC (25 years, 7 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.5: +10 -2 lines
Log Message:
optimized normalizing calls and bug fix in triangle counting

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 /* NOTE: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 #ifdef DEBUG
585 if(i >= smNew_tri_cnt)
586 {
587 eputs("smDepth_sort_tris():More tris than reported by smNew_tri_cnt\n");
588 break;
589 }
590 #endif
591 td[i].tri = t_id;
592 min_d = -1;
593 for(j=0;j < 3;j++)
594 {
595 v = T_NTH_V(tri,j);
596 if(!SM_BG_SAMPLE(sm,v))
597 {
598 d = DIST(vp,SM_NTH_WV(sm,v));
599 if(min_d == -1 || d < min_d)
600 min_d = d;
601 }
602 }
603 td[i].depth = min_d;
604 i++;
605 }
606 td[i].tri = -1;
607 if(i)
608 qsort((void *)td,i,sizeof(T_DEPTH),compare_tri_depths);
609 return(tlist);
610 }
611
612
613 smUpdate_Rendered_mesh(sm,vp,clr)
614 SM *sm;
615 FVECT vp;
616 int clr;
617 {
618 static T_DEPTH *td= NULL;
619 static int tsize = 0;
620 int i;
621 GLint depth_test;
622 double d;
623 LIST *bglist;
624 /* For all of the NEW triangles (since last update): assume
625 ACTIVE. Go through and sort on depth value (from vp). Turn
626 Depth Buffer test off and render back-front
627 */
628 /* NOTE: could malloc each time or hard code */
629 if(smNew_tri_cnt > tsize)
630 {
631 if(td)
632 free((char *)td);
633 td = (T_DEPTH *)malloc(smNew_tri_cnt*sizeof(T_DEPTH));
634 tsize = smNew_tri_cnt;
635 }
636 if(!td)
637 {
638 error(SYSTEM,"smUpdate_Rendered_mesh:Cannot allocate memory\n");
639 }
640 bglist = smDepth_sort_tris(sm,vp,td);
641
642 /* Turn Depth Test off -- using Painter's algorithm */
643 glPushAttrib(GL_DEPTH_BUFFER_BIT);
644 glDisable(GL_DEPTH_TEST);
645 d = (dev_zmin+dev_zmax)/2.0;
646 /* Now render back-to front */
647 /* First render bg triangles */
648 glBegin(GL_TRIANGLES);
649 while(bglist)
650 smRender_bg_tri(sm,pop_list(&bglist),vp,d,clr);
651 glEnd();
652
653
654 glBegin(GL_TRIANGLES);
655 i=0;
656 while(td[i].tri != -1)
657 if(!SM_MIXED_TRI(sm,td[i].tri))
658 smRender_tri(sm,td[i++].tri,vp,clr);
659 else
660 smRender_mixed_tri(sm,td[i++].tri,vp,clr);
661 glEnd();
662
663 /* Restore Depth Test */
664 glPopAttrib();
665 }
666
667 /*
668 * smUpdate(view, qua) : update OpenGL output geometry for view vp
669 * VIEW *view; : desired view
670 * int qual; : quality level (percentage on linear time scale)
671 *
672 * Draw new geometric representation using OpenGL calls. Assume that the
673 * view has already been set up and the correct frame buffer has been
674 * selected for drawing. The quality level is on a linear scale, where 100%
675 * is full (final) quality. It is not necessary to redraw geometry that has
676 * been output since the last call to smClean(). (The last view drawn will
677 * be view==&odev.v each time.)
678 */
679 smUpdate(view,qual)
680 VIEW *view;
681 int qual;
682 {
683 double d;
684 int last_update;
685 int t;
686
687 /* If view has moved beyond epsilon from canonical: must rebuild -
688 epsilon is calculated as running avg of distance of sample points
689 from canonical view: m = 1/(AVG(1/r)): some fraction of this
690 */
691 d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
692 if(qual >= 100 && d > SM_ALLOWED_VIEW_CHANGE(smMesh))
693 {
694 /* Re-build the mesh */
695 #ifdef TEST_DRIVER
696 odev.v = *view;
697 #endif
698 smRebuild_mesh(smMesh,view->vp);
699 }
700 /* This is our final update iff qual==100 and view==&odev.v */
701 last_update = qual>=100 && view==&(odev.v);
702 /* Check if we should draw ALL triangles in current frustum */
703 if(smClean_notify || smNew_tri_cnt > SM_NUM_TRIS(smMesh)*SM_INC_PERCENT)
704 {
705 #ifdef TEST_DRIVER
706 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
707 #else
708 if (SM_TONE_MAP(smMesh) < SM_NUM_SAMP(smMesh))
709 {
710 tmClearHisto();
711 tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
712 if(tmComputeMapping(0.,0.,0.) != TM_E_OK ||
713 tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
714 SM_NUM_SAMP(smMesh)) != TM_E_OK)
715 return;
716 }
717 #endif
718 mark_tris_in_frustum(view);
719 if (qual <= 75)
720 smRender_stree(smMesh,qual);
721 else
722 smRender_mesh(smMesh,view->vp,last_update);
723 #ifdef TEST_DRIVER
724 glFlush();
725 glutSwapBuffers();
726 #endif
727 }
728 /* Do an incremental update instead */
729 else
730 {
731 if(!smNew_tri_cnt)
732 return;
733 #ifdef TEST_DRIVER
734 glDrawBuffer(GL_FRONT);
735 #else
736 t = SM_TONE_MAP(smMesh);
737 if(t == 0)
738 {
739 tmClearHisto();
740 tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
741 if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
742 return;
743 }
744 if(tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
745 SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t) != TM_E_OK)
746 return;
747 #endif
748 smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
749
750 #ifdef TEST_DRIVER
751 glDrawBuffer(GL_BACK);
752 #endif
753 }
754 SM_TONE_MAP(smMesh) = SM_NUM_SAMP(smMesh);
755 if (last_update)
756 {
757 smClean_notify = FALSE;
758 smNew_tri_cnt = 0;
759 smClear_flags(smMesh,T_NEW_FLAG);
760 qtCache_init(0);
761 }
762
763 }