ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.8
Committed: Tue Oct 6 18:16:54 1998 UTC (25 years, 6 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.7: +162 -93 lines
Log Message:
new triangulate routine
added smTestSample to check for occlusion
added frustum culling before rebuild
changed base quadtree to use octahedron and created new point locate
added "sample active" flags and implemented LRU replacement
started handling case of too many triangles
set sizes are now unbounded
changed all quadtree pointers to quadtrees

File Contents

# User Rev Content
1 gwlarson 3.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 gwlarson 3.8 #include "sm_flag.h"
20 gwlarson 3.3 #include "sm_list.h"
21 gwlarson 3.1 #include "sm_geom.h"
22 gwlarson 3.8 #include "sm_qtree.h"
23     #include "sm_stree.h"
24 gwlarson 3.1 #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 gwlarson 3.4 static int smClean_notify = TRUE;
34 gwlarson 3.1 #endif
35    
36 gwlarson 3.3 typedef struct {
37 gwlarson 3.4 float dist; /* average distance */
38 gwlarson 3.3 BYTE rgb[3]; /* average color */
39     } QTRAVG; /* average quadtree value */
40    
41 gwlarson 3.4 typedef struct {
42     QUADTREE qt; /* quadtree node (key & hash value) */
43     QTRAVG av; /* node average */
44     } QT_LUENT; /* lookup table entry */
45 gwlarson 3.3
46 gwlarson 3.5 static QT_LUENT *qt_htbl = NULL; /* quadtree cache */
47     static int qt_hsiz = 0; /* quadtree cache size */
48 gwlarson 3.3
49    
50 gwlarson 3.8
51     mark_active_tris(qtptr,fptr)
52 gwlarson 3.1 QUADTREE *qtptr;
53 gwlarson 3.8 int *fptr;
54 gwlarson 3.1 {
55 gwlarson 3.3 QUADTREE qt = *qtptr;
56 gwlarson 3.5 OBJECT *os,*optr;
57 gwlarson 3.3 register int i,t_id;
58 gwlarson 3.8 TRI *tri;
59 gwlarson 3.1
60 gwlarson 3.8
61 gwlarson 3.7 if(!QT_FLAG_FILL_TRI(*fptr))
62     (*fptr)++;
63 gwlarson 3.8
64     if(QT_IS_EMPTY(qt) || QT_LEAF_IS_FLAG(qt))
65     return;
66 gwlarson 3.3 /* For each triangle in the set, set the which flag*/
67 gwlarson 3.5 os = qtqueryset(qt);
68 gwlarson 3.1
69 gwlarson 3.3 for (i = QT_SET_CNT(os), optr = QT_SET_PTR(os); i > 0; i--)
70 gwlarson 3.1 {
71 gwlarson 3.3 t_id = QT_SET_NEXT_ELEM(optr);
72     /* Set the render flag */
73 gwlarson 3.8 tri = SM_NTH_TRI(smMesh,t_id);
74     if(!T_IS_VALID(tri) || SM_IS_NTH_T_BASE(smMesh,t_id))
75 gwlarson 3.1 continue;
76 gwlarson 3.3 SM_SET_NTH_T_ACTIVE(smMesh,t_id);
77 gwlarson 3.8 /* Set the Active bits of the Vertices */
78     S_SET_FLAG(T_NTH_V(tri,0));
79     S_SET_FLAG(T_NTH_V(tri,1));
80     S_SET_FLAG(T_NTH_V(tri,2));
81    
82 gwlarson 3.1 }
83     }
84    
85 gwlarson 3.8 #define mark_active_interior mark_active_tris
86 gwlarson 3.7
87 gwlarson 3.3 mark_tris_in_frustum(view)
88     VIEW *view;
89 gwlarson 3.1 {
90     FVECT nr[4],far[4];
91 gwlarson 3.8 FPEQ peq;
92     int debug=0;
93 gwlarson 3.1 /* Mark triangles in approx. view frustum as being active:set
94     LRU counter: for use in discarding samples when out
95     of space
96     Radiance often has no far clipping plane: but driver will set
97     dev_zmin,dev_zmax to satisfy OGL
98     */
99    
100 gwlarson 3.3 /* First clear all the quadtree node and triangle active flags */
101     qtClearAllFlags();
102     smClear_flags(smMesh,T_ACTIVE_FLAG);
103 gwlarson 3.8 /* Clear all of the active sample flags*/
104     sClear_all_flags(smMesh->samples);
105 gwlarson 3.1
106 gwlarson 3.8
107 gwlarson 3.1 /* calculate the world space coordinates of the view frustum */
108 gwlarson 3.3 calculate_view_frustum(view->vp,view->hvec,view->vvec,view->horiz,
109     view->vert, dev_zmin,dev_zmax,nr,far);
110 gwlarson 3.1
111     #ifdef TEST_DRIVER
112     VCOPY(FrustumFar[0],far[0]);
113     VCOPY(FrustumFar[1],far[1]);
114     VCOPY(FrustumFar[2],far[2]);
115     VCOPY(FrustumFar[3],far[3]);
116     VCOPY(FrustumNear[0],nr[0]);
117     VCOPY(FrustumNear[1],nr[1]);
118     VCOPY(FrustumNear[2],nr[2]);
119     VCOPY(FrustumNear[3],nr[3]);
120     #endif
121 gwlarson 3.8 /* Project the view frustum onto the spherical quadtree */
122     /* For every cell intersected by the projection of the faces
123    
124     of the frustum: mark all triangles in the cell as ACTIVE-
125     Also set the triangles LRU clock counter
126     */
127    
128     if(EQUAL_VEC3(view->vp,SM_VIEW_CENTER(smMesh)))
129     {/* Near face triangles */
130     smLocator_apply_func(smMesh,nr[3],nr[2],nr[0],mark_active_tris,
131     mark_active_interior,NULL);
132     smLocator_apply_func(smMesh,nr[1],nr[0],nr[2],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 gwlarson 3.1 }
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 gwlarson 3.4 int
245 gwlarson 3.5 qtCache_init(nel) /* initialize for at least nel elements */
246 gwlarson 3.4 int nel;
247     {
248     static int hsiztab[] = {
249     8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 0
250     };
251     register int i;
252 gwlarson 3.1
253 gwlarson 3.4 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 gwlarson 3.5 qtCache_find(qt) /* find a quadtree table entry */
277 gwlarson 3.4 QUADTREE qt;
278     {
279     int i, n;
280     register int ndx;
281     register QT_LUENT *le;
282    
283 gwlarson 3.5 if (qt_hsiz == 0 && !qtCache_init(1))
284     return(NULL);
285 gwlarson 3.4 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 gwlarson 3.5 if (!qtCache_init(ndx+1)) { /* no more memory! */
298 gwlarson 3.4 qt_htbl = le;
299     qt_hsiz = ndx;
300     return(NULL);
301     }
302 gwlarson 3.5 /* copy old table to new and free */
303 gwlarson 3.4 while (ndx--)
304     if (!QT_IS_EMPTY(le[ndx].qt))
305 gwlarson 3.5 copystruct(qtCache_find(le[ndx].qt), &le[ndx]);
306 gwlarson 3.4 free((char *)le);
307     goto tryagain; /* should happen only once! */
308     }
309    
310 gwlarson 3.3 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 gwlarson 3.1 SM *sm;
334 gwlarson 3.3 int lvl;
335     {
336     FVECT a,b,c;
337 gwlarson 3.4 register QT_LUENT *le;
338 gwlarson 3.3 QTRAVG *rc[4];
339 gwlarson 3.7 TRI *tri;
340 gwlarson 3.3
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 gwlarson 3.5 if ((le = qtCache_find(qt)) == NULL)
347 gwlarson 3.4 error(SYSTEM, "out of memory in qtRender_level");
348     if (QT_IS_TREE(qt) && (QT_IS_EMPTY(le->qt) || lvl > 0))
349 gwlarson 3.3 { /* 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 gwlarson 3.4 if (QT_IS_EMPTY(le->qt))
357 gwlarson 3.3 { /* let's make some data! */
358     int rgbs[3];
359     double distsum;
360 gwlarson 3.4 register int i, n;
361 gwlarson 3.3 /* 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 gwlarson 3.4 if (rc[i] != NULL)
368 gwlarson 3.3 {
369 gwlarson 3.4 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 gwlarson 3.3 }
372     }
373     else
374     { /* from triangle set */
375 gwlarson 3.5 OBJECT *os;
376 gwlarson 3.3 int s0, s1, s2;
377    
378 gwlarson 3.5 os = qtqueryset(qt);
379 gwlarson 3.3 for (n = os[0]; n; n--)
380     {
381 gwlarson 3.7 tri = SM_NTH_TRI(sm,os[n]);
382 gwlarson 3.8 if(!T_IS_VALID(tri))
383     continue;
384    
385 gwlarson 3.7 s0 = T_NTH_V(tri,0);
386     s1 = T_NTH_V(tri,1);
387     s2 = T_NTH_V(tri,2);
388     VCOPY(a,SM_NTH_WV(sm,s0));
389     VCOPY(b,SM_NTH_WV(sm,s1));
390     VCOPY(c,SM_NTH_WV(sm,s2));
391 gwlarson 3.3 distsum += SM_BG_SAMPLE(sm,s0) ? dev_zmax
392     : sqrt(dist2(a,SM_VIEW_CENTER(sm)));
393     distsum += SM_BG_SAMPLE(sm,s1) ? dev_zmax
394     : sqrt(dist2(b,SM_VIEW_CENTER(sm)));
395     distsum += SM_BG_SAMPLE(sm,s2) ? dev_zmax
396     : sqrt(dist2(c,SM_VIEW_CENTER(sm)));
397     rgbs[0] += SM_NTH_RGB(sm,s0)[0] + SM_NTH_RGB(sm,s1)[0]
398     + SM_NTH_RGB(sm,s2)[0];
399     rgbs[1] += SM_NTH_RGB(sm,s0)[1] + SM_NTH_RGB(sm,s1)[1]
400     + SM_NTH_RGB(sm,s2)[1];
401     rgbs[2] += SM_NTH_RGB(sm,s0)[2] + SM_NTH_RGB(sm,s1)[2]
402     + SM_NTH_RGB(sm,s2)[2];
403     }
404     n = 3*os[0];
405     }
406     if (!n)
407     return(NULL);
408 gwlarson 3.4 le->qt = qt;
409     le->av.rgb[0] = rgbs[0]/n; le->av.rgb[1] = rgbs[1]/n;
410     le->av.rgb[2] = rgbs[2]/n; le->av.dist = distsum/(double)n;
411 gwlarson 3.3 }
412     if (lvl == 0 || (lvl > 0 && QT_IS_LEAF(qt)))
413     { /* render this node */
414     /* compute pseudo vertices */
415     VCOPY(a,v0); VCOPY(b,v1); VCOPY(c,v2);
416     normalize(a); normalize(b); normalize(c);
417 gwlarson 3.4 VSUM(a,SM_VIEW_CENTER(sm),a,le->av.dist);
418     VSUM(b,SM_VIEW_CENTER(sm),b,le->av.dist);
419     VSUM(c,SM_VIEW_CENTER(sm),c,le->av.dist);
420 gwlarson 3.3 /* draw triangle */
421 gwlarson 3.4 glColor3ub(le->av.rgb[0],le->av.rgb[1],le->av.rgb[2]);
422 gwlarson 3.3 /* NOTE: Triangle vertex order may change */
423     glVertex3d(c[0],c[1],c[2]);
424     glVertex3d(b[0],b[1],b[2]);
425     glVertex3d(a[0],a[1],a[2]);
426     }
427 gwlarson 3.4 return(&le->av);
428 gwlarson 3.3 }
429    
430    
431     smRender_stree_level(sm,lvl)
432     SM *sm;
433     int lvl;
434     {
435     QUADTREE root;
436     int i;
437     FVECT t0,t1,t2;
438 gwlarson 3.8 STREE *st;
439 gwlarson 3.3
440 gwlarson 3.8
441 gwlarson 3.3 if (lvl < 1)
442     return;
443 gwlarson 3.8 st = SM_LOCATOR(sm);
444 gwlarson 3.3 glPushAttrib(GL_LIGHTING_BIT);
445     glShadeModel(GL_FLAT);
446     glBegin(GL_TRIANGLES);
447 gwlarson 3.8 for(i=0; i < ST_NUM_ROOT_NODES; i++)
448 gwlarson 3.3 {
449 gwlarson 3.8 root = ST_NTH_ROOT(st,i);
450     qtRender_level(root,ST_NTH_V(st,i,0),ST_NTH_V(st,i,1),ST_NTH_V(st,i,2),
451     sm,lvl-1);
452 gwlarson 3.3 }
453     glEnd();
454     glPopAttrib();
455     }
456    
457    
458     smRender_stree(sm, qual) /* render some quadtree triangles */
459     SM *sm;
460     int qual;
461     {
462     int i, ntarget;
463     int lvlcnt[QT_MAX_LEVELS];
464    
465     if (qual <= 0)
466     return;
467     /* compute rendering target */
468     ntarget = 0;
469     SM_FOR_ALL_ACTIVE_TRIS(sm,i)
470     ntarget++;
471     ntarget = ntarget*qual/100;
472     if (!ntarget)
473     return;
474     for (i = QT_MAX_LEVELS; i--; )
475     lvlcnt[i] = 0;
476 gwlarson 3.8 stCount_level_leaves(lvlcnt, ST_TOP_ROOT(SM_LOCATOR(sm)));
477     stCount_level_leaves(lvlcnt, ST_BOTTOM_ROOT(SM_LOCATOR(sm)));
478 gwlarson 3.3 for (ntarget -= lvlcnt[i=0]; i < QT_MAX_LEVELS-1; ntarget -= lvlcnt[++i])
479     if (ntarget < lvlcnt[i+1])
480     break;
481     /* compute and render target level */
482     smRender_stree_level(sm,i);
483     }
484    
485    
486     smRender_tri(sm,i,vp,clr)
487     SM *sm;
488 gwlarson 3.1 int i;
489     FVECT vp;
490 gwlarson 3.3 int clr;
491 gwlarson 3.1 {
492     TRI *tri;
493     double ptr[3];
494     int j;
495    
496     tri = SM_NTH_TRI(sm,i);
497 gwlarson 3.8 if (clr) SM_CLR_NTH_T_NEW(sm,i);
498 gwlarson 3.3
499 gwlarson 3.1 /* NOTE:Triangles are defined clockwise:historical relative to spherical
500     tris: could change
501     */
502     for(j=2; j>= 0; j--)
503     {
504 gwlarson 3.2 #ifdef DEBUG
505     if(SM_BG_SAMPLE(sm,T_NTH_V(tri,j)))
506     eputs("SmRenderTri(): shouldnt have bg samples\n");
507     #endif
508 gwlarson 3.1 glColor3ub(SM_NTH_RGB(sm,T_NTH_V(tri,j))[0],
509     SM_NTH_RGB(sm,T_NTH_V(tri,j))[1],
510     SM_NTH_RGB(sm,T_NTH_V(tri,j))[2]);
511     VCOPY(ptr,SM_T_NTH_WV(sm,tri,j));
512     glVertex3d(ptr[0],ptr[1],ptr[2]);
513     }
514     }
515    
516 gwlarson 3.3 smRender_mixed_tri(sm,i,vp,clr)
517 gwlarson 3.1 SM *sm;
518     int i;
519     FVECT vp;
520 gwlarson 3.3 int clr;
521 gwlarson 3.1 {
522     TRI *tri;
523 gwlarson 3.3 double p[3],d;
524 gwlarson 3.1 int j,ids[3],cnt;
525 gwlarson 3.2 int rgb[3];
526 gwlarson 3.1
527 gwlarson 3.3 tri = SM_NTH_TRI(sm,i);
528 gwlarson 3.8 if (clr) SM_CLR_NTH_T_NEW(sm,i);
529 gwlarson 3.2
530 gwlarson 3.1 /* NOTE:Triangles are defined clockwise:historical relative to spherical
531     tris: could change
532     */
533     cnt = 0;
534 gwlarson 3.3 d = 0.0;
535 gwlarson 3.1 rgb[0] = rgb[1] = rgb[2] = 0;
536 gwlarson 3.3 for(j=0;j < 3;j++)
537 gwlarson 3.1 {
538 gwlarson 3.3 ids[j] = T_NTH_V(tri,j);
539     if(!SM_BG_SAMPLE(sm,ids[j]))
540     {
541     rgb[0] += SM_NTH_RGB(sm,ids[j])[0];
542     rgb[1] += SM_NTH_RGB(sm,ids[j])[1];
543     rgb[2] += SM_NTH_RGB(sm,ids[j])[2];
544     cnt++;
545     d += DIST(vp,SM_NTH_WV(sm,ids[j]));
546     }
547 gwlarson 3.1 }
548 gwlarson 3.3 if(cnt > 1)
549 gwlarson 3.1 {
550     rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
551 gwlarson 3.3 d /= (double)cnt;
552 gwlarson 3.1 }
553     for(j=2; j>= 0; j--)
554     {
555     if(SM_BG_SAMPLE(sm,ids[j]))
556 gwlarson 3.3 {
557     glColor3ub(rgb[0],rgb[1],rgb[2]);
558     VSUB(p,SM_NTH_WV(sm,ids[j]),SM_VIEW_CENTER(sm));
559     p[0] *= d;
560     p[1] *= d;
561     p[2] *= d;
562     VADD(p,p,SM_VIEW_CENTER(sm));
563     }
564 gwlarson 3.1 else
565 gwlarson 3.2 {
566 gwlarson 3.3 glColor3ub(SM_NTH_RGB(sm,ids[j])[0],SM_NTH_RGB(sm,ids[j])[1],
567     SM_NTH_RGB(sm,ids[j])[2]);
568     VCOPY(p,SM_NTH_WV(sm,ids[j]));
569 gwlarson 3.2 }
570 gwlarson 3.1 glVertex3d(p[0],p[1],p[2]);
571 gwlarson 3.3 }
572     }
573    
574     smRender_bg_tri(sm,i,vp,d,clr)
575     SM *sm;
576     int i;
577     FVECT vp;
578     double d;
579     int clr;
580     {
581     double p[3];
582     int j,id;
583     TRI *tri;
584    
585     tri = SM_NTH_TRI(sm,i);
586 gwlarson 3.8 if (clr) SM_CLR_NTH_T_NEW(sm,i);
587 gwlarson 3.3
588     /* NOTE:Triangles are defined clockwise:historical relative to spherical
589     tris: could change
590     */
591     for(j=2; j>= 0; j--)
592     {
593     id = T_NTH_V(tri,j);
594     glColor3ub(SM_NTH_RGB(sm,id)[0],SM_NTH_RGB(sm,id)[1],
595     SM_NTH_RGB(sm,id)[2]);
596     VSUB(p,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
597     if(dev_zmin >= 0.99)
598     {
599     p[0] *= d;
600     p[1] *= d;
601     p[2] *= d;
602     }
603     VADD(p,p,vp);
604     glVertex3d(p[0],p[1],p[2]);
605 gwlarson 3.1 }
606     }
607    
608 gwlarson 3.3 smRender_mesh(sm,vp,clr)
609 gwlarson 3.1 SM *sm;
610     FVECT vp;
611 gwlarson 3.3 int clr;
612 gwlarson 3.1 {
613     int i;
614     TRI *tri;
615 gwlarson 3.2 double ptr[3],d;
616 gwlarson 3.1 int j;
617    
618 gwlarson 3.2 d = (dev_zmin+dev_zmax)/2.0;
619 gwlarson 3.1 glPushAttrib(GL_DEPTH_BUFFER_BIT);
620    
621     /* First draw background polygons */
622     glDisable(GL_DEPTH_TEST);
623     glBegin(GL_TRIANGLES);
624     SM_FOR_ALL_ACTIVE_BG_TRIS(sm,i)
625 gwlarson 3.3 smRender_bg_tri(sm,i,vp,d,clr);
626 gwlarson 3.1 glEnd();
627     glEnable(GL_DEPTH_TEST);
628     glBegin(GL_TRIANGLES);
629     SM_FOR_ALL_ACTIVE_FG_TRIS(sm,i)
630 gwlarson 3.3 {
631 gwlarson 3.8 if(SM_BG_TRI(sm,i))
632     continue;
633 gwlarson 3.3 if(!SM_MIXED_TRI(sm,i))
634     smRender_tri(sm,i,vp,clr);
635 gwlarson 3.8 else
636 gwlarson 3.3 smRender_mixed_tri(sm,i,vp,clr);
637     }
638 gwlarson 3.1 glEnd();
639    
640     glPopAttrib();
641     }
642 gwlarson 3.3
643 gwlarson 3.1 smRender_tri_edges(sm,i)
644     SM *sm;
645     int i;
646     {
647     TRI *tri;
648     int j;
649     double ptr[3];
650    
651    
652     tri = SM_NTH_TRI(sm,i);
653    
654     /* Triangles are defined clockwise:historical relative to spherical
655     tris: could change
656     */
657     for(j=2; j >=0; j--)
658     {
659     VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,j)));
660     glVertex3d(ptr[0],ptr[1],ptr[2]);
661     VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,(j+1)%3)));
662     glVertex3d(ptr[0],ptr[1],ptr[2]);
663     }
664     }
665    
666     int
667     compare_tri_depths(T_DEPTH *td1,T_DEPTH *td2)
668     {
669     double d;
670    
671     d = td2->depth-td1->depth;
672    
673     if(d > 0.0)
674     return(1);
675     if(d < 0.0)
676     return(-1);
677    
678     return(0);
679     }
680    
681 gwlarson 3.3 LIST
682     *smDepth_sort_tris(sm,vp,td)
683 gwlarson 3.1 SM *sm;
684 gwlarson 3.3 FVECT vp;
685 gwlarson 3.1 T_DEPTH *td;
686     {
687 gwlarson 3.3 int i,j,t_id,v;
688 gwlarson 3.1 TRI *tri;
689 gwlarson 3.3 double d,min_d;
690     LIST *tlist=NULL;
691 gwlarson 3.1
692     i = 0;
693     SM_FOR_ALL_NEW_TRIS(sm,t_id)
694     {
695 gwlarson 3.3 if(SM_BG_TRI(sm,t_id))
696 gwlarson 3.1 {
697 gwlarson 3.3 tlist = push_data(tlist,t_id);
698     continue;
699 gwlarson 3.1 }
700     tri = SM_NTH_TRI(sm,t_id);
701 gwlarson 3.6 #ifdef DEBUG
702     if(i >= smNew_tri_cnt)
703     {
704     eputs("smDepth_sort_tris():More tris than reported by smNew_tri_cnt\n");
705     break;
706     }
707     #endif
708 gwlarson 3.1 td[i].tri = t_id;
709 gwlarson 3.3 min_d = -1;
710 gwlarson 3.1 for(j=0;j < 3;j++)
711 gwlarson 3.3 {
712     v = T_NTH_V(tri,j);
713     if(!SM_BG_SAMPLE(sm,v))
714     {
715     d = DIST(vp,SM_NTH_WV(sm,v));
716     if(min_d == -1 || d < min_d)
717     min_d = d;
718     }
719     }
720     td[i].depth = min_d;
721 gwlarson 3.1 i++;
722     }
723 gwlarson 3.3 td[i].tri = -1;
724     if(i)
725     qsort((void *)td,i,sizeof(T_DEPTH),compare_tri_depths);
726     return(tlist);
727 gwlarson 3.1 }
728    
729    
730 gwlarson 3.3 smUpdate_Rendered_mesh(sm,vp,clr)
731 gwlarson 3.1 SM *sm;
732 gwlarson 3.3 FVECT vp;
733     int clr;
734 gwlarson 3.1 {
735     static T_DEPTH *td= NULL;
736     static int tsize = 0;
737     int i;
738     GLint depth_test;
739 gwlarson 3.2 double d;
740 gwlarson 3.3 LIST *bglist;
741 gwlarson 3.1 /* For all of the NEW triangles (since last update): assume
742     ACTIVE. Go through and sort on depth value (from vp). Turn
743     Depth Buffer test off and render back-front
744     */
745     /* NOTE: could malloc each time or hard code */
746     if(smNew_tri_cnt > tsize)
747     {
748     if(td)
749 gwlarson 3.3 free((char *)td);
750 gwlarson 3.1 td = (T_DEPTH *)malloc(smNew_tri_cnt*sizeof(T_DEPTH));
751     tsize = smNew_tri_cnt;
752     }
753     if(!td)
754     {
755     error(SYSTEM,"smUpdate_Rendered_mesh:Cannot allocate memory\n");
756     }
757 gwlarson 3.3 bglist = smDepth_sort_tris(sm,vp,td);
758 gwlarson 3.1
759 gwlarson 3.3 /* Turn Depth Test off -- using Painter's algorithm */
760 gwlarson 3.1 glPushAttrib(GL_DEPTH_BUFFER_BIT);
761 gwlarson 3.3 glDisable(GL_DEPTH_TEST);
762 gwlarson 3.2 d = (dev_zmin+dev_zmax)/2.0;
763 gwlarson 3.1 /* Now render back-to front */
764     /* First render bg triangles */
765     glBegin(GL_TRIANGLES);
766 gwlarson 3.3 while(bglist)
767     smRender_bg_tri(sm,pop_list(&bglist),vp,d,clr);
768 gwlarson 3.1 glEnd();
769    
770 gwlarson 3.6
771 gwlarson 3.1 glBegin(GL_TRIANGLES);
772 gwlarson 3.3 i=0;
773     while(td[i].tri != -1)
774     if(!SM_MIXED_TRI(sm,td[i].tri))
775     smRender_tri(sm,td[i++].tri,vp,clr);
776     else
777     smRender_mixed_tri(sm,td[i++].tri,vp,clr);
778 gwlarson 3.1 glEnd();
779    
780     /* Restore Depth Test */
781     glPopAttrib();
782     }
783    
784     /*
785 gwlarson 3.3 * smUpdate(view, qua) : update OpenGL output geometry for view vp
786     * VIEW *view; : desired view
787 gwlarson 3.1 * int qual; : quality level (percentage on linear time scale)
788     *
789     * Draw new geometric representation using OpenGL calls. Assume that the
790     * view has already been set up and the correct frame buffer has been
791     * selected for drawing. The quality level is on a linear scale, where 100%
792     * is full (final) quality. It is not necessary to redraw geometry that has
793 gwlarson 3.3 * been output since the last call to smClean(). (The last view drawn will
794     * be view==&odev.v each time.)
795 gwlarson 3.1 */
796 gwlarson 3.3 smUpdate(view,qual)
797     VIEW *view;
798 gwlarson 3.1 int qual;
799     {
800     double d;
801 gwlarson 3.3 int last_update;
802 gwlarson 3.1 int t;
803 gwlarson 3.3
804 gwlarson 3.1 /* If view has moved beyond epsilon from canonical: must rebuild -
805     epsilon is calculated as running avg of distance of sample points
806 gwlarson 3.3 from canonical view: m = 1/(AVG(1/r)): some fraction of this
807 gwlarson 3.1 */
808 gwlarson 3.8
809     if(!smMesh)
810     return;
811 gwlarson 3.3 d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
812 gwlarson 3.1 if(qual >= 100 && d > SM_ALLOWED_VIEW_CHANGE(smMesh))
813     {
814     /* Re-build the mesh */
815 gwlarson 3.3 #ifdef TEST_DRIVER
816     odev.v = *view;
817 gwlarson 3.8 #endif
818     mark_tris_in_frustum(view);
819     smRebuild_mesh(smMesh,view);
820 gwlarson 3.1 }
821 gwlarson 3.3 /* This is our final update iff qual==100 and view==&odev.v */
822     last_update = qual>=100 && view==&(odev.v);
823     /* Check if we should draw ALL triangles in current frustum */
824 gwlarson 3.8 if(smClean_notify || smNew_tri_cnt > SM_SAMPLE_TRIS(smMesh)*SM_INC_PERCENT)
825 gwlarson 3.1 {
826     #ifdef TEST_DRIVER
827     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
828     #else
829 gwlarson 3.8 if ( SM_TONE_MAP(smMesh) < SM_NUM_SAMP(smMesh))
830 gwlarson 3.3 {
831     tmClearHisto();
832     tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
833     if(tmComputeMapping(0.,0.,0.) != TM_E_OK ||
834     tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
835     SM_NUM_SAMP(smMesh)) != TM_E_OK)
836     return;
837     }
838 gwlarson 3.1 #endif
839 gwlarson 3.3 mark_tris_in_frustum(view);
840     if (qual <= 75)
841     smRender_stree(smMesh,qual);
842     else
843     smRender_mesh(smMesh,view->vp,last_update);
844 gwlarson 3.1 #ifdef TEST_DRIVER
845     glFlush();
846     glutSwapBuffers();
847     #endif
848     }
849     /* Do an incremental update instead */
850     else
851 gwlarson 3.8 {
852     if(!smNew_tri_cnt)
853 gwlarson 3.1 return;
854     #ifdef TEST_DRIVER
855     glDrawBuffer(GL_FRONT);
856     #else
857     t = SM_TONE_MAP(smMesh);
858     if(t == 0)
859     {
860     tmClearHisto();
861     tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
862     if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
863     return;
864     }
865     if(tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
866     SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t) != TM_E_OK)
867     return;
868     #endif
869 gwlarson 3.3 smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
870 gwlarson 3.1
871     #ifdef TEST_DRIVER
872     glDrawBuffer(GL_BACK);
873     #endif
874     }
875     SM_TONE_MAP(smMesh) = SM_NUM_SAMP(smMesh);
876 gwlarson 3.3 if (last_update)
877     {
878     smClean_notify = FALSE;
879     smNew_tri_cnt = 0;
880 gwlarson 3.6 smClear_flags(smMesh,T_NEW_FLAG);
881 gwlarson 3.5 qtCache_init(0);
882 gwlarson 3.3 }
883    
884 gwlarson 3.1 }