ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.14
Committed: Fri Mar 5 16:33:32 1999 UTC (25 years, 2 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.13: +937 -322 lines
Log Message:
Added display list rendering

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 gwlarson 3.14 *
10     * Rendering routines for triangle mesh representation utilizing OpenGL
11 gwlarson 3.1 */
12     #include "standard.h"
13    
14     #include <GL/gl.h>
15    
16 gwlarson 3.8 #include "sm_flag.h"
17 gwlarson 3.3 #include "sm_list.h"
18 gwlarson 3.1 #include "sm_geom.h"
19 gwlarson 3.8 #include "sm_qtree.h"
20     #include "sm_stree.h"
21 gwlarson 3.1 #include "sm.h"
22    
23 gwlarson 3.14 static int smClean_notify = TRUE; /*If true:Do full redraw on next update*/
24     static int smCompute_mapping = TRUE;/*If true:re-tonemap on next update */
25     static int smIncremental = FALSE; /*If true: there has been incremental
26     rendering since last full draw */
27     #define SM_RENDER_FG 0 /* Render foreground tris only*/
28     #define SM_RENDER_BG 1 /* Render background tris only */
29     #define SM_RENDER_MIXED 4 /* Render mixed tris only */
30     #define SM_RENDER_CULL 8 /* Perform view frustum culling */
31     #define BASE 1
32     #define DIR 2
33     /* FOR DISPLAY LIST RENDERING: **********************************************/
34     #define SM_DL_LEVELS 2 /* # of levels down to create display lists */
35     #define SM_DL_LISTS 42 /* # of qtree nodes in tree at above level:
36     should be 2*(4^(SM_DL_LEVELS+1)-1)/(4-1) */
37     static GLuint Display_lists[SM_DL_LISTS][2] = {0};
38     /****************************************************************************/
39 gwlarson 3.1
40 gwlarson 3.14 /* FOR APPROXIMATION RENDERING **********************************************/
41 gwlarson 3.3 typedef struct {
42 gwlarson 3.4 float dist; /* average distance */
43 gwlarson 3.3 BYTE rgb[3]; /* average color */
44     } QTRAVG; /* average quadtree value */
45    
46 gwlarson 3.4 typedef struct {
47     QUADTREE qt; /* quadtree node (key & hash value) */
48     QTRAVG av; /* node average */
49     } QT_LUENT; /* lookup table entry */
50 gwlarson 3.3
51 gwlarson 3.5 static QT_LUENT *qt_htbl = NULL; /* quadtree cache */
52     static int qt_hsiz = 0; /* quadtree cache size */
53 gwlarson 3.14 /****************************************************************************/
54 gwlarson 3.3
55 gwlarson 3.14 /* For DEPTH SORTING ********************************************************/
56 gwlarson 3.13 typedef struct _T_DEPTH {
57     int tri;
58     double depth;
59     }T_DEPTH;
60 gwlarson 3.14 /**********************************************************************/
61 gwlarson 3.13
62 gwlarson 3.14
63 gwlarson 3.10 /*
64 gwlarson 3.13 * smClean(tmflag) : display has been wiped clean
65     * int tmflag;
66 gwlarson 3.10 * Called after display has been effectively cleared, meaning that all
67     * geometry must be resent down the pipeline in the next call to smUpdate().
68 gwlarson 3.13 * If tmflag is set, tone-mapping should be performed
69 gwlarson 3.10 */
70 gwlarson 3.13 smClean(tmflag)
71     int tmflag;
72 gwlarson 3.1 {
73     smClean_notify = TRUE;
74 gwlarson 3.13 if(tmflag)
75 gwlarson 3.14 smCompute_mapping = TRUE;
76 gwlarson 3.1 }
77    
78 gwlarson 3.4 int
79 gwlarson 3.5 qtCache_init(nel) /* initialize for at least nel elements */
80 gwlarson 3.4 int nel;
81     {
82     static int hsiztab[] = {
83     8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 0
84     };
85     register int i;
86 gwlarson 3.1
87 gwlarson 3.4 if (nel <= 0) { /* call to free table */
88     if (qt_hsiz) {
89     free((char *)qt_htbl);
90     qt_htbl = NULL;
91     qt_hsiz = 0;
92     }
93     return(0);
94     }
95     nel += nel>>1; /* 66% occupancy */
96     for (i = 0; hsiztab[i]; i++)
97     if (hsiztab[i] > nel)
98     break;
99     if (!(qt_hsiz = hsiztab[i]))
100     qt_hsiz = nel*2 + 1; /* not always prime */
101     qt_htbl = (QT_LUENT *)calloc(qt_hsiz, sizeof(QT_LUENT));
102     if (qt_htbl == NULL)
103     qt_hsiz = 0;
104     for (i = qt_hsiz; i--; )
105     qt_htbl[i].qt = EMPTY;
106     return(qt_hsiz);
107     }
108    
109     QT_LUENT *
110 gwlarson 3.5 qtCache_find(qt) /* find a quadtree table entry */
111 gwlarson 3.4 QUADTREE qt;
112     {
113     int i, n;
114     register int ndx;
115     register QT_LUENT *le;
116    
117 gwlarson 3.5 if (qt_hsiz == 0 && !qtCache_init(1))
118     return(NULL);
119 gwlarson 3.4 tryagain: /* hash table lookup */
120     ndx = (unsigned long)qt % qt_hsiz;
121     for (i = 0, n = 1; i < qt_hsiz; i++, n += 2) {
122     le = &qt_htbl[ndx];
123     if (QT_IS_EMPTY(le->qt) || le->qt == qt)
124     return(le);
125     if ((ndx += n) >= qt_hsiz) /* this happens rarely */
126     ndx = ndx % qt_hsiz;
127     }
128     /* table is full, reallocate */
129     le = qt_htbl;
130     ndx = qt_hsiz;
131 gwlarson 3.5 if (!qtCache_init(ndx+1)) { /* no more memory! */
132 gwlarson 3.4 qt_htbl = le;
133     qt_hsiz = ndx;
134     return(NULL);
135     }
136 gwlarson 3.5 /* copy old table to new and free */
137 gwlarson 3.4 while (ndx--)
138     if (!QT_IS_EMPTY(le[ndx].qt))
139 gwlarson 3.5 copystruct(qtCache_find(le[ndx].qt), &le[ndx]);
140 gwlarson 3.4 free((char *)le);
141     goto tryagain; /* should happen only once! */
142     }
143    
144 gwlarson 3.3 stCount_level_leaves(lcnt, qt) /* count quadtree leaf nodes at each level */
145     int lcnt[];
146     register QUADTREE qt;
147     {
148     if (QT_IS_EMPTY(qt))
149     return;
150     if (QT_IS_TREE(qt)) {
151     if (!QT_IS_FLAG(qt)) /* not in our frustum */
152     return;
153     stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,0));
154     stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,1));
155     stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,2));
156     stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,3));
157     }
158     else
159 gwlarson 3.10 if(QT_LEAF_IS_FLAG(qt))
160     lcnt[0]++;
161 gwlarson 3.3 }
162    
163    
164     QTRAVG *
165     qtRender_level(qt,v0,v1,v2,sm,lvl)
166     QUADTREE qt;
167     FVECT v0,v1,v2;
168 gwlarson 3.1 SM *sm;
169 gwlarson 3.3 int lvl;
170     {
171     FVECT a,b,c;
172 gwlarson 3.4 register QT_LUENT *le;
173 gwlarson 3.3 QTRAVG *rc[4];
174 gwlarson 3.7 TRI *tri;
175 gwlarson 3.3
176     if (QT_IS_EMPTY(qt)) /* empty leaf node */
177     return(NULL);
178     if (QT_IS_TREE(qt) && !QT_IS_FLAG(qt)) /* not in our frustum */
179     return(NULL);
180 gwlarson 3.10 if(QT_IS_LEAF(qt) && !QT_LEAF_IS_FLAG(qt)) /* not in our frustum */
181     return(NULL);
182 gwlarson 3.3 /* else look up node */
183 gwlarson 3.5 if ((le = qtCache_find(qt)) == NULL)
184 gwlarson 3.4 error(SYSTEM, "out of memory in qtRender_level");
185     if (QT_IS_TREE(qt) && (QT_IS_EMPTY(le->qt) || lvl > 0))
186 gwlarson 3.3 { /* compute children */
187     qtSubdivide_tri(v0,v1,v2,a,b,c);
188 gwlarson 3.11 rc[0] = qtRender_level(QT_NTH_CHILD(qt,0),v0,c,b,sm,lvl-1);
189     rc[1] = qtRender_level(QT_NTH_CHILD(qt,1),c,v1,a,sm,lvl-1);
190     rc[2] = qtRender_level(QT_NTH_CHILD(qt,2),b,a,v2,sm,lvl-1);
191     rc[3] = qtRender_level(QT_NTH_CHILD(qt,3),a,b,c,sm,lvl-1);
192 gwlarson 3.3 }
193 gwlarson 3.4 if (QT_IS_EMPTY(le->qt))
194 gwlarson 3.3 { /* let's make some data! */
195     int rgbs[3];
196     double distsum;
197 gwlarson 3.4 register int i, n;
198 gwlarson 3.3 /* average our triangle vertices */
199     rgbs[0] = rgbs[1] = rgbs[2] = 0;
200     distsum = 0.; n = 0;
201     if(QT_IS_TREE(qt))
202     { /* from subtree */
203     for (i = 4; i--; )
204 gwlarson 3.4 if (rc[i] != NULL)
205 gwlarson 3.3 {
206 gwlarson 3.4 rgbs[0] += rc[i]->rgb[0]; rgbs[1] += rc[i]->rgb[1];
207     rgbs[2] += rc[i]->rgb[2]; distsum += rc[i]->dist; n++;
208 gwlarson 3.3 }
209     }
210     else
211     { /* from triangle set */
212 gwlarson 3.5 OBJECT *os;
213 gwlarson 3.3 int s0, s1, s2;
214 gwlarson 3.11
215 gwlarson 3.5 os = qtqueryset(qt);
216 gwlarson 3.11 for (i = os[0]; i; i--)
217 gwlarson 3.3 {
218 gwlarson 3.11 if(SM_IS_NTH_T_BASE(sm,os[i]))
219 gwlarson 3.9 continue;
220 gwlarson 3.11 tri = SM_NTH_TRI(sm,os[i]);
221 gwlarson 3.8 if(!T_IS_VALID(tri))
222     continue;
223 gwlarson 3.11 n++;
224 gwlarson 3.7 s0 = T_NTH_V(tri,0);
225     s1 = T_NTH_V(tri,1);
226     s2 = T_NTH_V(tri,2);
227     VCOPY(a,SM_NTH_WV(sm,s0));
228     VCOPY(b,SM_NTH_WV(sm,s1));
229     VCOPY(c,SM_NTH_WV(sm,s2));
230 gwlarson 3.3 distsum += SM_BG_SAMPLE(sm,s0) ? dev_zmax
231     : sqrt(dist2(a,SM_VIEW_CENTER(sm)));
232     distsum += SM_BG_SAMPLE(sm,s1) ? dev_zmax
233     : sqrt(dist2(b,SM_VIEW_CENTER(sm)));
234     distsum += SM_BG_SAMPLE(sm,s2) ? dev_zmax
235     : sqrt(dist2(c,SM_VIEW_CENTER(sm)));
236     rgbs[0] += SM_NTH_RGB(sm,s0)[0] + SM_NTH_RGB(sm,s1)[0]
237     + SM_NTH_RGB(sm,s2)[0];
238     rgbs[1] += SM_NTH_RGB(sm,s0)[1] + SM_NTH_RGB(sm,s1)[1]
239     + SM_NTH_RGB(sm,s2)[1];
240     rgbs[2] += SM_NTH_RGB(sm,s0)[2] + SM_NTH_RGB(sm,s1)[2]
241     + SM_NTH_RGB(sm,s2)[2];
242     }
243 gwlarson 3.11 n *= 3;
244 gwlarson 3.3 }
245     if (!n)
246     return(NULL);
247 gwlarson 3.4 le->qt = qt;
248     le->av.rgb[0] = rgbs[0]/n; le->av.rgb[1] = rgbs[1]/n;
249     le->av.rgb[2] = rgbs[2]/n; le->av.dist = distsum/(double)n;
250 gwlarson 3.3 }
251     if (lvl == 0 || (lvl > 0 && QT_IS_LEAF(qt)))
252     { /* render this node */
253     /* compute pseudo vertices */
254     VCOPY(a,v0); VCOPY(b,v1); VCOPY(c,v2);
255     normalize(a); normalize(b); normalize(c);
256 gwlarson 3.4 VSUM(a,SM_VIEW_CENTER(sm),a,le->av.dist);
257     VSUM(b,SM_VIEW_CENTER(sm),b,le->av.dist);
258     VSUM(c,SM_VIEW_CENTER(sm),c,le->av.dist);
259 gwlarson 3.3 /* draw triangle */
260 gwlarson 3.4 glColor3ub(le->av.rgb[0],le->av.rgb[1],le->av.rgb[2]);
261 gwlarson 3.9 glVertex3d(a[0],a[1],a[2]);
262     glVertex3d(b[0],b[1],b[2]);
263 gwlarson 3.3 glVertex3d(c[0],c[1],c[2]);
264 gwlarson 3.9
265 gwlarson 3.3 }
266 gwlarson 3.4 return(&le->av);
267 gwlarson 3.3 }
268    
269    
270 gwlarson 3.14 smRender_approx_stree_level(sm,lvl)
271 gwlarson 3.3 SM *sm;
272     int lvl;
273     {
274 gwlarson 3.10 QUADTREE qt;
275 gwlarson 3.3 int i;
276     FVECT t0,t1,t2;
277 gwlarson 3.8 STREE *st;
278 gwlarson 3.3
279 gwlarson 3.8
280 gwlarson 3.11 if (lvl < 0)
281 gwlarson 3.3 return;
282 gwlarson 3.8 st = SM_LOCATOR(sm);
283 gwlarson 3.3 glPushAttrib(GL_LIGHTING_BIT);
284     glShadeModel(GL_FLAT);
285     glBegin(GL_TRIANGLES);
286 gwlarson 3.8 for(i=0; i < ST_NUM_ROOT_NODES; i++)
287 gwlarson 3.3 {
288 gwlarson 3.10 qt = ST_ROOT_QT(st,i);
289     qtRender_level(qt,ST_NTH_V(st,i,0),ST_NTH_V(st,i,1),ST_NTH_V(st,i,2),
290 gwlarson 3.11 sm,lvl);
291 gwlarson 3.3 }
292     glEnd();
293     glPopAttrib();
294     }
295    
296 gwlarson 3.14 /*
297     * smRender_approx(sm,qual,view)
298     * SM *sm; : mesh
299     * int qual; : quality level
300     * VIEW *view; : current view
301     *
302     * Renders an approximation to the current mesh based on the quadtree
303     * subdivision. The quadtree is traversed to a level (based upon the quality:
304     * the lower the quality, the fewer levels visited, and the coarser, and
305     * faster, the approximation). The quadtree triangles are drawn relative to
306     * the current viewpoint, with a depth and color averaged from all of the
307     * triangles that lie beneath the node.
308     */
309     smRender_approx(sm, qual,view)
310 gwlarson 3.3 SM *sm;
311     int qual;
312 gwlarson 3.14 VIEW *view;
313 gwlarson 3.3 {
314 gwlarson 3.13 int i, n,ntarget;
315 gwlarson 3.3 int lvlcnt[QT_MAX_LEVELS];
316 gwlarson 3.10 STREE *st;
317 gwlarson 3.13 int4 *active_flag;
318 gwlarson 3.14
319 gwlarson 3.3 if (qual <= 0)
320     return;
321 gwlarson 3.14 smCull(sm,view,SM_ALL_LEVELS);
322 gwlarson 3.3 /* compute rendering target */
323     ntarget = 0;
324 gwlarson 3.13
325     active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
326     for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
327     if(active_flag[n])
328     for(i=0; i < 32; i++)
329     if(active_flag[n] & (1L << i))
330     ntarget++;
331    
332     ntarget = ntarget*qual/MAXQUALITY;
333 gwlarson 3.3 if (!ntarget)
334     return;
335     for (i = QT_MAX_LEVELS; i--; )
336     lvlcnt[i] = 0;
337 gwlarson 3.10
338     st = SM_LOCATOR(sm);
339     for(i=0; i < ST_NUM_ROOT_NODES;i++)
340     stCount_level_leaves(lvlcnt, ST_ROOT_QT(st,i));
341    
342 gwlarson 3.3 for (ntarget -= lvlcnt[i=0]; i < QT_MAX_LEVELS-1; ntarget -= lvlcnt[++i])
343     if (ntarget < lvlcnt[i+1])
344     break;
345     /* compute and render target level */
346 gwlarson 3.14 smRender_approx_stree_level(sm,i);
347 gwlarson 3.3 }
348    
349 gwlarson 3.12 #define render_tri(v0,v1,v2,rgb0,rgb1,rgb2) \
350     {glColor3ub(rgb0[0],rgb0[1],rgb0[2]); glVertex3fv(v0); \
351     glColor3ub(rgb1[0],rgb1[1],rgb1[2]); glVertex3fv(v1); \
352 gwlarson 3.14 glColor3ub(rgb2[0],rgb2[1],rgb2[2]); glVertex3fv(v2);}
353 gwlarson 3.1
354 gwlarson 3.14
355     render_bg_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,d)
356     float v0[3],v1[3],v2[3];
357     BYTE rgb0[3],rgb1[3],rgb2[3];
358     FVECT vp,vc;
359     double d;
360     {
361     double p[3];
362    
363     glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
364     VSUB(p,v0,vc);
365     if(dev_zmin >= 0.99)
366     {
367     p[0] *= d;
368     p[1] *= d;
369     p[2] *= d;
370     }
371     VADD(p,p,vp);
372     glVertex3dv(p);
373    
374     glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
375     VSUB(p,v1,vc);
376     if(dev_zmin >= 0.99)
377     {
378     p[0] *= d;
379     p[1] *= d;
380     p[2] *= d;
381     }
382     VADD(p,p,vp);
383     glVertex3dv(p);
384    
385    
386     glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
387     VSUB(p,v2,vc);
388     if(dev_zmin >= 0.99)
389     {
390     p[0] *= d;
391     p[1] *= d;
392     p[2] *= d;
393     VADD(p,p,vp);
394     glVertex3dv(p);
395     }
396     }
397    
398    
399     /*
400     * render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,b0,b1,b2)
401     * float v0[3],v1[3],v2[3]; : triangle vertex coordinates
402     * BYTE rgb0[3],rgb1[3],rgb2[3]; : vertex RGBs
403     * int b0,b1,b2; : background or base vertex flag
404     *
405     * render foreground or base vertex color as average of the background
406     * vertex RGBs.
407     */
408     render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,bg0,bg1,bg2)
409 gwlarson 3.12 float v0[3],v1[3],v2[3];
410     BYTE rgb0[3],rgb1[3],rgb2[3];
411 gwlarson 3.14 FVECT vp,vc;
412 gwlarson 3.12 int bg0,bg1,bg2;
413 gwlarson 3.1 {
414 gwlarson 3.14 double d,p[3];
415     int j,cnt,rgb[3],base;
416    
417     base = bg0==BASE || bg1==BASE || bg2==BASE;
418    
419     if(base)
420     {
421     cnt = 0;
422     rgb[0] = rgb[1] = rgb[2] = 0;
423     if(bg0 != BASE)
424     {
425     IADDV3(rgb,rgb0);
426     cnt++;
427     }
428     if(bg1 !=BASE)
429     {
430     IADDV3(rgb,rgb1);
431     cnt++;
432     }
433     if(bg2 != BASE)
434     {
435     IADDV3(rgb,rgb2);
436     cnt++;
437     }
438     IDIVV3(rgb,cnt);
439     }
440    
441     if(bg0== BASE)
442     glColor3ub(rgb[0],rgb[1],rgb[2]);
443     else
444     glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
445    
446     if(!bg0)
447     {
448     VSUB(p,v0,vp);
449     normalize(p);
450     IADDV3(p,vc);
451     glVertex3dv(p);
452     }
453     else
454     glVertex3fv(v0);
455    
456     if(bg1== BASE)
457     glColor3ub(rgb[0],rgb[1],rgb[2]);
458     else
459     glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
460    
461     if(!bg1)
462     {
463     VSUB(p,v1,vp);
464     normalize(p);
465     IADDV3(p,vc);
466     glVertex3dv(p);
467     }
468     else
469     glVertex3fv(v1);
470    
471     if(bg2== BASE)
472     glColor3ub(rgb[0],rgb[1],rgb[2]);
473     else
474     glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
475    
476     if(!bg2)
477     {
478     VSUB(p,v2,vp);
479     normalize(p);
480     IADDV3(p,vc);
481     glVertex3dv(p);
482     }
483     else
484     glVertex3fv(v2);
485     }
486    
487     /*
488     * smRender_bg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
489     * SM *sm; : mesh
490     * FVECT vp; : current viewpoint
491     * int4 *t_flag,*bg_flag; : triangle flags: t_flag is generic,
492     * and bg_flag indicates if background tri;
493     * float (*wp)[3];BYTE (*rgb)[3]; : arrays of sample points and RGB colors
494     *
495     * Sequentially gos through triangle list and renders all valid tris who
496     * have t_flag set, and bg_flag set.
497     */
498    
499     smRender_bg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
500     SM *sm;
501     FVECT vp;
502     int4 *t_flag,*bg_flag;
503     float (*wp)[3];
504     BYTE (*rgb)[3];
505     {
506     double d;
507     int v0_id,v1_id,v2_id;
508     int i,n,bg0,bg1,bg2;
509     TRI *tri;
510    
511     glMatrixMode(GL_MODELVIEW);
512    
513     glPushMatrix();
514     glTranslated(vp[0],vp[1],vp[2]);
515     /* The points are a distance of 1 away from the origin: if necessary scale
516     so that they fit in frustum and are therefore not clipped away
517     */
518     if(dev_zmin >= 0.99)
519     {
520     d = (dev_zmin+dev_zmax)/2.0;
521     glScaled(d,d,d);
522     }
523     /* move relative to the new view */
524     /* move points to unit sphere at origin */
525     glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
526     -SM_VIEW_CENTER(sm)[2]);
527     glBegin(GL_TRIANGLES);
528     for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
529     if(t_flag[n] & bg_flag[n])
530     for(i=0; i < 32; i++)
531     if(t_flag[n] & bg_flag[n] & (1L << i))
532     {
533     tri = SM_NTH_TRI(sm,(n<<5)+i);
534     v0_id = T_NTH_V(tri,0);
535     v1_id = T_NTH_V(tri,1);
536     v2_id = T_NTH_V(tri,2);
537     bg0 = SM_DIR_ID(sm,v0_id)?DIR:SM_BASE_ID(sm,v0_id)?BASE:0;
538     bg1 = SM_DIR_ID(sm,v1_id)?DIR:SM_BASE_ID(sm,v1_id)?BASE:0;
539     bg2 = SM_DIR_ID(sm,v2_id)?DIR:SM_BASE_ID(sm,v2_id)?BASE:0;
540     if(bg0==DIR && bg1==DIR && bg2==DIR)
541     render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
542     rgb[v2_id])
543     else
544     render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
545     rgb[v1_id],rgb[v2_id],vp,SM_VIEW_CENTER(sm),bg0,bg1,bg2);
546     }
547     glEnd();
548    
549     glPopMatrix();
550    
551     }
552     /*
553     * render_base_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,b0,b1,b2)
554     * float v0[3],v1[3],v2[3]; : triangle vertex coordinates
555     * BYTE rgb0[3],rgb1[3],rgb2[3]; : vertex RGBs
556     * FVECT vp; : current viewpoint
557     * int b0,b1,b2; : vertex base flag
558     *
559     * render base vertex color as average of the non-base vertex RGBs. The
560     * base vertex coordinate is taken as the stored vector, scaled out by
561     * the average distance to the non-base vertices
562     */
563     render_base_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,b0,b1,b2)
564     float v0[3],v1[3],v2[3];
565     BYTE rgb0[3],rgb1[3],rgb2[3];
566     FVECT vp;
567     int b0,b1,b2;
568     {
569     int cnt;
570 gwlarson 3.2 int rgb[3];
571 gwlarson 3.14 double d;
572     double p[3];
573 gwlarson 3.1
574     cnt = 0;
575 gwlarson 3.14 rgb[0] = rgb[1] = rgb[2] = 0;
576 gwlarson 3.3 d = 0.0;
577 gwlarson 3.12
578 gwlarson 3.14 if(b0&&b1&&b2)
579     return;
580     /* First calculate color and coordinates
581     for base vertices based on world space vertices*/
582     if(!b0)
583 gwlarson 3.1 {
584 gwlarson 3.14 IADDV3(rgb,rgb0);
585     d += DIST(v0,vp);
586 gwlarson 3.12 cnt++;
587 gwlarson 3.1 }
588 gwlarson 3.14 if(!b1)
589 gwlarson 3.12 {
590 gwlarson 3.14 IADDV3(rgb,rgb1);
591     d += DIST(v1,vp);
592 gwlarson 3.12 cnt++;
593     }
594 gwlarson 3.14 if(!b2)
595 gwlarson 3.12 {
596 gwlarson 3.14 IADDV3(rgb,rgb2);
597     d += DIST(v2,vp);
598 gwlarson 3.12 cnt++;
599     }
600 gwlarson 3.14 IDIVV3(rgb,cnt);
601     d /= (double)cnt;
602    
603     /* Now render triangle */
604     if(b0)
605 gwlarson 3.1 {
606 gwlarson 3.12 glColor3ub(rgb[0],rgb[1],rgb[2]);
607 gwlarson 3.14 SUBV3(p,v0,vp);
608     ISCALEV3(p,d);
609     IADDV3(p,vp);
610     glVertex3dv(p);
611 gwlarson 3.12 }
612     else
613     {
614     glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
615     glVertex3fv(v0);
616 gwlarson 3.14 }
617     if(b1)
618 gwlarson 3.12 {
619     glColor3ub(rgb[0],rgb[1],rgb[2]);
620 gwlarson 3.14 SUBV3(p,v1,vp);
621     ISCALEV3(p,d);
622     IADDV3(p,vp);
623 gwlarson 3.12 glVertex3dv(p);
624     }
625     else
626     {
627     glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
628     glVertex3fv(v1);
629 gwlarson 3.14 }
630     if(b2)
631 gwlarson 3.12 {
632     glColor3ub(rgb[0],rgb[1],rgb[2]);
633 gwlarson 3.14 SUBV3(p,v2,vp);
634     ISCALEV3(p,d);
635     IADDV3(p,vp);
636 gwlarson 3.12 glVertex3dv(p);
637     }
638     else
639     {
640     glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
641     glVertex3fv(v2);
642     }
643 gwlarson 3.1 }
644 gwlarson 3.14 /*
645     * smRender_fg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
646     * SM *sm; : mesh
647     * FVECT vp; : current viewpoint
648     * int4 *t_flag,*bg_flag; : triangle flags: t_flag is generic,bg_flag
649     * indicates if background tri;
650     * float (*wp)[3];BYTE (*rgb)[3]; : arrays of sample points and RGB colors
651     *
652     * Sequentially gos through triangle list and renders all valid tris who
653     * have t_flag set, and NOT bg_flag set.
654     */
655     smRender_fg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
656 gwlarson 3.1 SM *sm;
657     FVECT vp;
658 gwlarson 3.14 int4 *t_flag,*bg_flag;
659     float (*wp)[3];
660     BYTE (*rgb)[3];
661 gwlarson 3.1 {
662 gwlarson 3.14 TRI *tri;
663     int i,n,b0,b1,b2;
664 gwlarson 3.12 int v0_id,v1_id,v2_id;
665 gwlarson 3.1
666     glBegin(GL_TRIANGLES);
667 gwlarson 3.13 for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
668 gwlarson 3.14 if(t_flag[n])
669 gwlarson 3.13 for(i=0; i < 32; i++)
670 gwlarson 3.14 if(t_flag[n] & (1L << i) & ~bg_flag[n])
671 gwlarson 3.13 {
672     tri = SM_NTH_TRI(sm,(n<<5)+i);
673     v0_id = T_NTH_V(tri,0);
674     v1_id = T_NTH_V(tri,1);
675     v2_id = T_NTH_V(tri,2);
676 gwlarson 3.14 b0 = SM_BASE_ID(sm,v0_id);
677     b1 = SM_BASE_ID(sm,v1_id);
678     b2 = SM_BASE_ID(sm,v2_id);
679     if(b0 || b1 || b2)
680     render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
681     rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),b0,b1,b2);
682     else
683 gwlarson 3.13 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
684     rgb[v2_id])
685     }
686 gwlarson 3.1 glEnd();
687    
688     }
689 gwlarson 3.3
690 gwlarson 3.14
691 gwlarson 3.12 int
692     compare_tri_depths(T_DEPTH *td1,T_DEPTH *td2)
693 gwlarson 3.1 {
694 gwlarson 3.12 double d;
695 gwlarson 3.1
696 gwlarson 3.12 d = td2->depth-td1->depth;
697     if(d > 0.0)
698     return(1);
699     if(d < 0.0)
700     return(-1);
701     return(0);
702 gwlarson 3.13
703 gwlarson 3.1 }
704    
705 gwlarson 3.13 #ifdef DEBUG
706     #define freebuf(b) tempbuf(-1)
707     #endif
708 gwlarson 3.1
709 gwlarson 3.13 char *
710     tempbuf(len) /* get a temporary buffer */
711     unsigned len;
712 gwlarson 3.1 {
713 gwlarson 3.14 extern char *malloc(), *realloc();
714     static char *tempbuf = NULL;
715     static unsigned tempbuflen = 0;
716 gwlarson 3.1
717 gwlarson 3.13 #ifdef DEBUG
718     static int in_use=FALSE;
719    
720     if(len == -1)
721     {
722     in_use = FALSE;
723     return(NULL);
724     }
725     if(in_use)
726     {
727     eputs("Buffer in use:cannot allocate:tempbuf()\n");
728     return(NULL);
729 gwlarson 3.3 }
730 gwlarson 3.13 #endif
731     if (len > tempbuflen) {
732     if (tempbuflen > 0)
733     tempbuf = realloc(tempbuf, len);
734     else
735     tempbuf = malloc(len);
736     tempbuflen = tempbuf==NULL ? 0 : len;
737     }
738     #ifdef DEBUG
739     in_use = TRUE;
740     #endif
741     return(tempbuf);
742 gwlarson 3.1 }
743    
744 gwlarson 3.14 /*
745     * smOrder_new_tris(sm,vp,td)
746     * SM *sm; : mesh
747     * FVECT vp; : current viewpoint
748     * T_DEPTH *td; : holds returned list of depth sorted tris
749     *
750     * Creates list of all new tris, with their distance from the current
751     * viewpoint, and sorts the list based on this distance
752     */
753 gwlarson 3.13 smOrder_new_tris(sm,vp,td)
754 gwlarson 3.12 SM *sm;
755     FVECT vp;
756     T_DEPTH *td;
757     {
758 gwlarson 3.13 int n,i,j,tcnt,v;
759 gwlarson 3.12 TRI *tri;
760     double d,min_d;
761     FVECT diff;
762 gwlarson 3.13 int4 *new_flag,*bg_flag;
763 gwlarson 3.12
764 gwlarson 3.13 tcnt=0;
765     new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
766     bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
767     for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
768     if(new_flag[n] & ~bg_flag[n])
769     for(i=0; i < 32; i++)
770     if(new_flag[n] & (1L << i) & ~bg_flag[n])
771     {
772     tri = SM_NTH_TRI(sm,(n<<5)+i);
773     td[tcnt].tri = (n << 5)+i;
774     min_d = -1;
775     for(j=0;j < 3;j++)
776     {
777     v = T_NTH_V(tri,j);
778 gwlarson 3.14 VSUB(diff,SM_NTH_WV(sm,v),vp);
779     d = DOT(diff,diff);
780     if(min_d == -1 || d < min_d)
781     min_d = d;
782 gwlarson 3.13 }
783     td[tcnt++].depth = min_d;
784 gwlarson 3.12 }
785 gwlarson 3.13 td[tcnt].tri = -1;
786     if(tcnt)
787     qsort((void *)td,tcnt,sizeof(T_DEPTH),compare_tri_depths);
788 gwlarson 3.12 }
789    
790 gwlarson 3.14 /*
791     * smUpdate_tm(sm) : Update the tone-mapping
792     * SM *sm; : mesh
793     *
794     */
795     smUpdate_tm(sm)
796     SM *sm;
797     {
798     int t = SM_TONE_MAP(sm);
799 gwlarson 3.12
800 gwlarson 3.14 if(t==0 || smCompute_mapping)
801     {
802     tmClearHisto();
803     tmAddHisto(SM_BRT(sm),SM_NUM_SAMP(sm),1);
804     if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
805     return;
806     t = 0;
807     smCompute_mapping = FALSE;
808     }
809     tmMapPixels(SM_NTH_RGB(sm,t),&SM_NTH_BRT(sm,t),SM_NTH_CHR(sm,t),
810     SM_NUM_SAMP(sm)-t);
811     SM_TONE_MAP(sm) = SM_NUM_SAMP(sm);
812     }
813    
814     /*
815     * smRender_inc(sm,vp) : Incremental update of mesh
816     * SM * sm; : mesh
817     * FVECT vp; : current view point
818     *
819     * If a relatively small number of new triangles have been created,
820     * do an incremental update. Render new triangles with depth buffering
821     * turned off, if the current viewpoint is not the same as canonical view-
822     * point, must use painter's approach to resolve visibility:first depth sort
823     * triangles, then render back-to-front.
824     */
825     smRender_inc(sm,vp)
826 gwlarson 3.1 SM *sm;
827 gwlarson 3.3 FVECT vp;
828 gwlarson 3.1 {
829 gwlarson 3.14 int i,n,v0_id,v1_id,v2_id,b0,b1,b2;
830 gwlarson 3.12 TRI *tri;
831     float (*wp)[3];
832     BYTE (*rgb)[3];
833 gwlarson 3.13 int4 *new_flag,*bg_flag;
834     T_DEPTH *td = NULL;
835 gwlarson 3.14
836     smUpdate_tm(sm);
837    
838 gwlarson 3.1 /* For all of the NEW triangles (since last update): assume
839     ACTIVE. Go through and sort on depth value (from vp). Turn
840     Depth Buffer test off and render back-front
841     */
842 gwlarson 3.13 if(!EQUAL_VEC3(SM_VIEW_CENTER(sm),vp))
843 gwlarson 3.1 {
844 gwlarson 3.13 /* Must depth sort if view points do not coincide */
845     td = (T_DEPTH *)tempbuf(smNew_tri_cnt*sizeof(T_DEPTH));
846 gwlarson 3.14 if(td)
847     smOrder_new_tris(sm,vp,td);
848 gwlarson 3.13 #ifdef DEBUG
849 gwlarson 3.14 else
850     eputs("Cant create list:wont depth sort:smUpdate_incremental\n");
851 gwlarson 3.13 #endif
852 gwlarson 3.1 }
853 gwlarson 3.12 wp = SM_WP(sm);
854     rgb =SM_RGB(sm);
855 gwlarson 3.14 new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
856     bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
857 gwlarson 3.3 /* Turn Depth Test off -- using Painter's algorithm */
858 gwlarson 3.1 glPushAttrib(GL_DEPTH_BUFFER_BIT);
859 gwlarson 3.9 glDepthFunc(GL_ALWAYS);
860 gwlarson 3.13
861 gwlarson 3.14 smRender_bg_tris(sm,vp,new_flag,bg_flag,wp,rgb);
862 gwlarson 3.13 if(!td)
863 gwlarson 3.14 smRender_fg_tris(sm,vp,new_flag,bg_flag,wp,rgb);
864 gwlarson 3.13 else
865     {
866 gwlarson 3.14 glBegin(GL_TRIANGLES);
867 gwlarson 3.13 for(i=0; td[i].tri != -1;i++)
868     {
869     tri = SM_NTH_TRI(sm,td[i].tri);
870     /* Dont need to check for valid tri because flags are
871     cleared on delete
872     */
873     v0_id = T_NTH_V(tri,0);
874     v1_id = T_NTH_V(tri,1);
875     v2_id = T_NTH_V(tri,2);
876 gwlarson 3.14 b0 = SM_BASE_ID(sm,v0_id);
877     b1 = SM_BASE_ID(sm,v1_id);
878     b2 = SM_BASE_ID(sm,v2_id);
879     if(b0 || b1 || b2)
880     render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
881     rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),b0,b1,b2);
882     else
883 gwlarson 3.13 render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
884     rgb[v2_id])
885     }
886 gwlarson 3.14 glEnd();
887 gwlarson 3.13 freebuf(td);
888     }
889 gwlarson 3.14 /* Restore Depth Test */
890     glPopAttrib();
891     }
892    
893     /*
894     * smRender_qtree_dl(sm,qt,vp,wp,rgb,i,level_i,max_level,leaf_cnt,which)
895     * SM *sm; : mesh
896     * QUADTREE qt; : quadtree base node
897     * FVECT vp; : current viewpoint
898     * float (*wp)[3]; : array of sample points
899     * BYTE (*rgb)[3]; : array of RGB values for samples
900     * int i,level_i,level,max_level,leaf_cnt;
901     * : variables to keep track of where
902     * we are in the quadtree traversal in order to map nodes to
903     * corresponding array locations, where nodes are stored in breadth-
904     * first order. i is the index of the current node,level_i is the
905     * index of the first node on the current quadtree level, max_level is
906     * the maximum number of levels to traverse, and leaf_cnt is the number
907     * of leaves on the current level
908     * int which; flag indicates whether to render fg or bg tris
909     *
910     *
911     * Render the tris stored in qtree using display lists. For each node at
912     * the leaf or max_level, call the display_list if it exists, else traverse
913     * down the subtree and render the nodes into a new display list which is
914     * stored for future use.
915     */
916     smRender_qtree_dl(sm,qt,vp,wp,rgb,i,level_i,level,max_level,leaf_cnt,which)
917     SM *sm;
918     QUADTREE qt;
919     FVECT vp;
920     float (*wp)[3];
921     BYTE (*rgb)[3];
922     int i,level_i,level,max_level,leaf_cnt;
923     int which;
924     {
925     int j;
926    
927     if(QT_IS_EMPTY(qt))
928     return;
929    
930     if(QT_IS_LEAF(qt) || level == max_level)
931     {
932     if(QT_IS_LEAF(qt))
933     {
934     if(!QT_LEAF_IS_FLAG(qt))
935     return;
936     }
937     else
938     if(!QT_IS_FLAG(qt))
939     return;
940    
941     if(!Display_lists[i][which])
942     {
943     Display_lists[i][which] = i+1 + which*SM_DL_LISTS;
944     glNewList(Display_lists[i][which],GL_COMPILE_AND_EXECUTE);
945     smClear_flags(sm,T_NEW_FLAG);
946     glBegin(GL_TRIANGLES);
947     smRender_qtree(sm,qt,vp,wp,rgb,which,FALSE);
948     glEnd();
949     glEndList();
950     }
951     else
952     {
953     glCallList(Display_lists[i][which]);
954     }
955     }
956     else
957     if(QT_IS_FLAG(qt))
958     {
959     i = ((i - level_i)<< 2) + level_i + leaf_cnt;
960     level_i += leaf_cnt;
961     leaf_cnt <<= 2;
962     for(j=0; j < 4; j++)
963     smRender_qtree_dl(sm,QT_NTH_CHILD(qt,j),vp,wp,rgb,
964     i+j,level_i,level+1,max_level,leaf_cnt,which);
965     }
966    
967     }
968    
969     /*
970     * smRender_qtree(sm,qt,vp,wp,rgb,which,cull) : Render the tris stored in qtree
971     * SM *sm; : mesh
972     * QUADTREE qt; : quadtree base node
973     * FVECT vp; : current viewpoint
974     * float (*wp)[3] : array of sample points
975     * BYTE (*rgb)[3] : array of RGB values for samples
976     * int which; : flag indicates whether to render fg or bg tris
977     * int cull; : if true, only traverse active (flagged) nodes
978     *
979     */
980     smRender_qtree(sm,qt,vp,wp,rgb,which,cull)
981     SM *sm;
982     QUADTREE qt;
983     FVECT vp;
984     float (*wp)[3];
985     BYTE (*rgb)[3];
986     int which,cull;
987     {
988     int i;
989    
990     if(QT_IS_EMPTY(qt))
991     return;
992    
993     if(QT_IS_LEAF(qt))
994     {
995     TRI *t;
996     OBJECT *optr;
997     int t_id,v0_id,v1_id,v2_id,bg0,bg1,bg2;
998    
999     if(cull && !QT_LEAF_IS_FLAG(qt))
1000     return;
1001    
1002     optr = qtqueryset(qt);
1003     for (i = QT_SET_CNT(optr),optr = QT_SET_PTR(optr);i > 0; i--)
1004     {
1005     t_id = QT_SET_NEXT_ELEM(optr);
1006     t = SM_NTH_TRI(sm,t_id);
1007     if(!T_IS_VALID(t) || (cull &&!SM_IS_NTH_T_ACTIVE(sm,t_id)) ||
1008     SM_IS_NTH_T_NEW(sm,t_id))
1009     continue;
1010    
1011     bg0 = SM_IS_NTH_T_BG(sm,t_id);
1012     if((which== SM_RENDER_FG && bg0) || (which== SM_RENDER_BG && !bg0))
1013     continue;
1014    
1015     v0_id = T_NTH_V(t,0);
1016     v1_id = T_NTH_V(t,1);
1017     v2_id = T_NTH_V(t,2);
1018     if(bg0)
1019     {
1020     bg0 = SM_DIR_ID(sm,v0_id)?DIR:SM_BASE_ID(sm,v0_id)?BASE:0;
1021     bg1 = SM_DIR_ID(sm,v1_id)?DIR:SM_BASE_ID(sm,v1_id)?BASE:0;
1022     bg2 = SM_DIR_ID(sm,v2_id)?DIR:SM_BASE_ID(sm,v2_id)?BASE:0;
1023     SM_SET_NTH_T_NEW(sm,t_id);
1024     if(bg0==DIR && bg1==DIR && bg2==DIR)
1025     render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1026     rgb[v2_id])
1027     else
1028     render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
1029     rgb[v1_id],rgb[v2_id],vp,SM_VIEW_CENTER(sm),bg0,bg1,bg2);
1030     }
1031     else
1032     {
1033     SM_SET_NTH_T_NEW(sm,t_id);
1034     bg0 = SM_BASE_ID(sm,v0_id);
1035     bg1 = SM_BASE_ID(sm,v1_id);
1036     bg2 = SM_BASE_ID(sm,v2_id);
1037     if(bg0 || bg1 || bg2)
1038     render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
1039     rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),bg0,bg1,bg2);
1040     else
1041     render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1042     rgb[v2_id])
1043     }
1044     }
1045     }
1046     else
1047     if(!cull || QT_IS_FLAG(qt))
1048     for(i=0; i < 4; i++)
1049     smRender_qtree(sm,QT_NTH_CHILD(qt,i),vp,wp,rgb,which,cull);
1050     }
1051    
1052     /*
1053     * smRender_mesh(sm,view,cull) : Render mesh Triangles
1054     * SM *sm; : mesh
1055     * VIEW *view; : current view
1056     * int cull; : cull Flag
1057     *
1058     * If cull is TRUE, first mark tris in current
1059     * frustum and only render them. Normally, cull will be FALSE only if
1060     * it is known that all tris lie in frustum, e.g. after a rebuild
1061     *
1062     */
1063     smRender_mesh(sm,view,cull)
1064     SM *sm;
1065     VIEW *view;
1066     int cull;
1067     {
1068     float (*wp)[3];
1069     BYTE (*rgb)[3];
1070     int i;
1071     STREE *st= SM_LOCATOR(sm);
1072    
1073     smUpdate_tm(sm);
1074    
1075     wp = SM_WP(sm);
1076     rgb =SM_RGB(sm);
1077    
1078     smClear_flags(sm,T_NEW_FLAG);
1079    
1080     if(cull)
1081     smCull(sm,view,SM_ALL_LEVELS);
1082    
1083    
1084     glPushAttrib(GL_DEPTH_BUFFER_BIT);
1085     glDisable(GL_DEPTH_TEST);
1086    
1087     glMatrixMode(GL_MODELVIEW);
1088     glPushMatrix();
1089     /* move relative to the new view */
1090     glTranslated(view->vp[0],view->vp[1],view->vp[2]);
1091    
1092    
1093     /* The points are a distance of 1 away from the origin: if necessary
1094     scale so that they fit in frustum and are therefore not clipped away
1095     */
1096     if(dev_zmin >= 0.99)
1097     {
1098     double d;
1099    
1100     d = (dev_zmin+dev_zmax)/2.0;
1101     glScaled(d,d,d);
1102     }
1103     /* move points to unit sphere at origin */
1104     glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
1105     -SM_VIEW_CENTER(sm)[2]);
1106    
1107     glBegin(GL_TRIANGLES);
1108     for(i=0; i < ST_NUM_ROOT_NODES; i++)
1109     smRender_qtree(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,SM_RENDER_BG,cull);
1110 gwlarson 3.1 glEnd();
1111    
1112 gwlarson 3.14 glPopMatrix();
1113    
1114     glEnable(GL_DEPTH_TEST);
1115    
1116     glBegin(GL_TRIANGLES);
1117     for(i=0; i < ST_NUM_ROOT_NODES; i++)
1118     smRender_qtree(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,SM_RENDER_FG,cull);
1119     glEnd();
1120    
1121 gwlarson 3.1 glPopAttrib();
1122     }
1123    
1124 gwlarson 3.14 /*
1125     * smRender_mesh_dl(sm,view) : Render stree utilizing display lists
1126     * SM *sm; : mesh
1127     * VIEW *view; : current view
1128     */
1129     smRender_mesh_dl(sm,view)
1130     SM *sm;
1131     VIEW *view;
1132     {
1133     float (*wp)[3];
1134     BYTE (*rgb)[3];
1135     STREE *st;
1136     int i;
1137    
1138     if(SM_DL_LEVELS == 0)
1139     {
1140     if(!Display_lists[0][0])
1141     {
1142     Display_lists[0][0] = 1;
1143     glNewList(Display_lists[0][0],GL_COMPILE_AND_EXECUTE);
1144     smRender_mesh(sm,view,FALSE);
1145     glEndList();
1146     }
1147     else
1148     glCallList(Display_lists[0][0]);
1149    
1150     return;
1151     }
1152     smCull(sm,view,SM_DL_LEVELS);
1153    
1154     st = SM_LOCATOR(sm);
1155    
1156     wp = SM_WP(sm);
1157     rgb =SM_RGB(sm);
1158    
1159     /* For all active quadtree nodes- first render bg tris, then fg */
1160     /* If display list exists, use otherwise create/display list */
1161     glPushAttrib(GL_DEPTH_BUFFER_BIT);
1162     glDisable(GL_DEPTH_TEST);
1163    
1164     glMatrixMode(GL_MODELVIEW);
1165     glPushMatrix();
1166    
1167     /* move relative to the new view */
1168     glTranslated(view->vp[0],view->vp[1],view->vp[2]);
1169    
1170     /* The points are a distance of 1 away from the origin: if necessary
1171     scale so that they fit in frustum and are therefore not clipped away
1172     */
1173     if(dev_zmin >= 0.99)
1174     {
1175     double d;
1176     d = (dev_zmin+dev_zmax)/2.0;
1177     glScaled(d,d,d);
1178     }
1179     /* move points to unit sphere at origin */
1180     glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
1181     -SM_VIEW_CENTER(sm)[2]);
1182     for(i=0; i < ST_NUM_ROOT_NODES; i++)
1183     smRender_qtree_dl(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,i,0,1,
1184     SM_DL_LEVELS,8,SM_RENDER_BG);
1185     glPopMatrix();
1186    
1187     glEnable(GL_DEPTH_TEST);
1188     for(i=0; i < ST_NUM_ROOT_NODES; i++)
1189     smRender_qtree_dl(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,i,0,1,
1190     SM_DL_LEVELS,8,SM_RENDER_FG);
1191     glPopAttrib();
1192     }
1193    
1194    
1195    
1196 gwlarson 3.1 /*
1197 gwlarson 3.14 * smRender_tris(sm,view,render_flag) : Render all of the mesh triangles
1198     * SM *sm : current geometry
1199     * VIEW *view : current view
1200     * int render_flag : if render_flag & SM_RENDER_CULL: do culling first
1201     *
1202     * Renders mesh by traversing triangle list and drawing all active tris-
1203     * background tris first, then foreground and mixed tris
1204     */
1205     smRender_tris(sm,view,render_flag)
1206     SM *sm;
1207     VIEW *view;
1208     int render_flag;
1209     {
1210     int4 *active_flag,*bg_flag;
1211     float (*wp)[3];
1212     BYTE (*rgb)[3];
1213    
1214     wp = SM_WP(sm);
1215     rgb =SM_RGB(sm);
1216     active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
1217     bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
1218    
1219     if(render_flag & SM_RENDER_CULL)
1220     smCull(sm,view,SM_ALL_LEVELS);
1221    
1222     /* Render triangles made up of points at infinity by turning off
1223     depth-buffering and projecting the points onto a sphere around the view*/
1224     glPushAttrib(GL_DEPTH_BUFFER_BIT);
1225     glDisable(GL_DEPTH_TEST);
1226     smRender_bg_tris(sm,view->vp,active_flag,bg_flag,wp,rgb);
1227    
1228     /* Render triangles containing world-space points */
1229     glEnable(GL_DEPTH_TEST);
1230     smRender_fg_tris(sm,view->vp,active_flag,bg_flag,wp,rgb);
1231    
1232     glPopAttrib();
1233    
1234     }
1235    
1236     /* Clear all of the display lists */
1237     clear_display_lists()
1238     {
1239     int i;
1240     for(i=0; i< SM_DL_LISTS; i++)
1241     {
1242     if(Display_lists[i][0])
1243     { /* Clear the foreground display list */
1244     glDeleteLists(Display_lists[i][0],1);
1245     Display_lists[i][0] = 0;
1246     }
1247     if(Display_lists[i][1])
1248     { /* Clear the background display list */
1249     glDeleteLists(Display_lists[i][1],1);
1250     Display_lists[i][1] = 0;
1251     }
1252     }
1253     }
1254    
1255     /*
1256     * qtClear_dl(qt,i,level_i,level,max_level,leaf_cnt) :clear display lists
1257     * QUADTREE *qt; : Quadtree node
1258     * int i; : index into list of display lists for this node
1259     * int level_i; : index for first node at this level
1260     * int level,max_level; : current level, maximum level to descend
1261     * int leaf_cnt; : number of leaves at this level
1262     *
1263     * For each node under this node that has its flag set: delete all
1264     * existing display lists. Display lists are stored in an array indexed as
1265     * if the quadtree was traversed in a breadth first order (indices 0-7 are
1266     * the 8 quadtree roots, indices 8-11 the first level children of root 0,
1267     * indices 12-15 the children of root 1, etc). It is assumes that the display
1268     * lists will only be stored for a small number of levels: if this is not
1269     * true, a hashing scheme would work better for storing/retrieving the
1270     * display lists
1271     */
1272     qtClear_dl(qt,i,level_i,level,max_level,leaf_cnt)
1273     QUADTREE qt;
1274     int i,level_i,level,max_level,leaf_cnt;
1275     {
1276     int j;
1277    
1278     if(QT_IS_EMPTY(qt))
1279     return;
1280     if(QT_IS_LEAF(qt) || level== max_level)
1281     {
1282     if(QT_IS_LEAF(qt))
1283     {
1284     if(!QT_LEAF_IS_FLAG(qt))
1285     return;
1286     }
1287     else
1288     if(!QT_IS_FLAG(qt))
1289     return;
1290     if(Display_lists[i][0])
1291     {
1292     glDeleteLists(Display_lists[i][0],1);
1293     Display_lists[i][0] = 0;
1294     }
1295     if(Display_lists[i][1])
1296     {
1297     glDeleteLists(Display_lists[i][1],1);
1298     Display_lists[i][1] = 0;
1299     }
1300     }
1301     else
1302     if(QT_IS_FLAG(qt))
1303     {
1304     /* Calculate the index for the first child given the values
1305     of the parent at the current level
1306     */
1307     i = ((i - level_i)<< 2) + level_i + leaf_cnt;
1308     level_i += leaf_cnt;
1309     leaf_cnt <<= 2;
1310     for(j=0; j < 4; j++)
1311     qtClear_dl(QT_NTH_CHILD(qt,j),i+j,level_i,level+1,max_level,
1312     leaf_cnt);
1313     }
1314     }
1315    
1316     /*
1317     * smInvalidate_view(sm,view) : Invalidate rendering representation for view
1318     * SM *sm; : mesh
1319     * VIEW *view; : current view
1320     *
1321     * Delete the existing display lists for geometry in the current
1322     * view frustum: Called when the geometry in the frustum has been changed
1323     */
1324     smInvalidate_view(sm,view)
1325     SM *sm;
1326     VIEW *view;
1327     {
1328     int i;
1329    
1330     if(SM_DL_LEVELS == 0)
1331     {
1332     if(Display_lists[0][0])
1333     {
1334     glDeleteLists(Display_lists[0][0],1);
1335     Display_lists[0][0] = 0;
1336     }
1337     return;
1338     }
1339     /* Mark qtree nodes/tris in frustum */
1340     smCull(sm,view,SM_DL_LEVELS);
1341    
1342     /* Invalidate display_lists in marked qtree nodes */
1343     for(i=0; i < ST_NUM_ROOT_NODES; i++)
1344     qtClear_dl(ST_ROOT_QT(SM_LOCATOR(sm),i),i,0,1,SM_DL_LEVELS,8);
1345    
1346     }
1347    
1348    
1349     /*
1350     * smRender(sm,view, qual): render OpenGL output geometry
1351     * SM *sm; : current mesh representation
1352     * VIEW *view; : desired view
1353     * int qual; : quality level (percentage on linear time scale)
1354     *
1355     * Render the current mesh:
1356     * recompute tone mapping if full redraw and specified:
1357     * if moving (i.e. qual < MAXQUALITY)
1358     * render the cached display lists, if quality drops
1359     * below threshold, render approximation instead
1360     * if stationary
1361     * render mesh geometry without display lists, unless up-to-date
1362     * display lists already exist.
1363     */
1364     smRender(sm,view,qual)
1365     SM *sm;
1366     VIEW *view;
1367     int qual;
1368     {
1369    
1370     /* Recompute tone mapping if specified */
1371     if( qual >= MAXQUALITY && smCompute_mapping)
1372     smUpdate_tm(sm);
1373    
1374     /* Unless quality > MAXQUALITY, render using display lists */
1375     if(qual <= MAXQUALITY)
1376     {
1377     /* If quality above threshold: render mesh*/
1378     if(qual > (MAXQUALITY*2/4))
1379     /* render stree using display lists */
1380     smRender_mesh_dl(sm,view);
1381     else
1382     /* If quality below threshold, use approximate rendering */
1383     smRender_approx(sm,qual,view);
1384     }
1385     else
1386     /* render stree without display lists */
1387     smRender_mesh(sm,view,TRUE);
1388     }
1389    
1390    
1391     /*
1392     * smUpdate(view, qual) : update OpenGL output geometry
1393 gwlarson 3.3 * VIEW *view; : desired view
1394 gwlarson 3.1 * int qual; : quality level (percentage on linear time scale)
1395     *
1396     * Draw new geometric representation using OpenGL calls. Assume that the
1397     * view has already been set up and the correct frame buffer has been
1398     * selected for drawing. The quality level is on a linear scale, where 100%
1399     * is full (final) quality. It is not necessary to redraw geometry that has
1400 gwlarson 3.14 * been output since the last call to smClean().(The last view drawn will
1401 gwlarson 3.3 * be view==&odev.v each time.)
1402 gwlarson 3.1 */
1403 gwlarson 3.3 smUpdate(view,qual)
1404     VIEW *view;
1405 gwlarson 3.1 int qual;
1406     {
1407 gwlarson 3.14 /* Is there anything to render? */
1408     if(!smMesh || SM_NUM_TRI(smMesh)<=0)
1409     return;
1410 gwlarson 3.3
1411 gwlarson 3.14 /* Is viewer MOVING?*/
1412     if(qual < MAXQUALITY)
1413     {
1414     /* Render mesh using display lists */
1415     smRender(smMesh,view,qual);
1416 gwlarson 3.13 return;
1417 gwlarson 3.14 }
1418 gwlarson 3.13
1419 gwlarson 3.14 /* Viewer is STATIONARY */
1420    
1421     /* Has view moved epsilon from canonical view? (epsilon= percentage
1422     (SM_VIEW_FRAC) of running average of the distance of the sample points
1423     from the canonical view */
1424     if(DIST(view->vp,SM_VIEW_CENTER(smMesh)) > SM_ALLOWED_VIEW_CHANGE(smMesh))
1425 gwlarson 3.1 {
1426 gwlarson 3.14 /* Must rebuild mesh with current view as new canonical view */
1427     smRebuild_mesh(smMesh,view);
1428     /* Existing display lists and tonemapping are no longer valid */
1429     clear_display_lists();
1430     smCompute_mapping = TRUE;
1431     /* Render all the triangles in the new mesh */
1432     smRender(smMesh,view,qual+1);
1433 gwlarson 3.1 }
1434 gwlarson 3.14 else
1435     /* Has a complete redraw been requested ?*/
1436     if(smClean_notify)
1437 gwlarson 3.3 {
1438 gwlarson 3.14 smIncremental = FALSE;
1439     smRender(smMesh,view,qual);
1440 gwlarson 3.3 }
1441     else
1442 gwlarson 3.14 {
1443     /* Viewer fixed and receiving new samples for the same view */
1444 gwlarson 3.8 if(!smNew_tri_cnt)
1445 gwlarson 3.14 return;
1446    
1447     /* If number of new triangles relatively small: do incremental update */
1448     if(smNew_tri_cnt < SM_SAMPLE_TRIS(smMesh)*SM_INC_PERCENT)
1449     {
1450     /* Mark Existing display lists in frustum invalid */
1451     if(!smIncremental)
1452     {
1453     smInvalidate_view(smMesh,view);
1454     smIncremental = TRUE;
1455     }
1456     smRender_inc(smMesh,view->vp);
1457     }
1458     else
1459     /* Otherwise render all of the active triangles */
1460     smRender(smMesh,view,qual+1);
1461 gwlarson 3.1 }
1462 gwlarson 3.14 /* This is our final update iff qual==MAXQUALITY and view==&odev.v */
1463     if( (qual >= MAXQUALITY) && (view == &(odev.v)))
1464 gwlarson 3.3 {
1465 gwlarson 3.14 /* reset rendering flags */
1466 gwlarson 3.3 smClean_notify = FALSE;
1467     smNew_tri_cnt = 0;
1468 gwlarson 3.6 smClear_flags(smMesh,T_NEW_FLAG);
1469 gwlarson 3.5 qtCache_init(0);
1470 gwlarson 3.3 }
1471    
1472 gwlarson 3.1 }