ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.4
Committed: Thu Sep 3 11:29:00 1998 UTC (25 years, 8 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.3: +93 -50 lines
Log Message:
switched to custom replacement for lookup.c routines

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