ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
Revision: 3.15
Committed: Thu Jun 10 15:22:23 1999 UTC (24 years, 10 months ago) by gwlarson
Content type: text/plain
Branch: MAIN
Changes since 3.14: +321 -264 lines
Log Message:
Implemented sample quadtree in place of triangle quadtree
Made geometric predicates more robust
Added #define LORES which utilizes a single precision floating point
  sample array, the default is a double sample array
Added topology DEBUG commands (for DEBUG > 1)
Made code optimizations

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