ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/hd/sm_ogl.c
(Generate patch)

Comparing ray/src/hd/sm_ogl.c (file contents):
Revision 3.8 by gwlarson, Tue Oct 6 18:16:54 1998 UTC vs.
Revision 3.15 by gwlarson, Thu Jun 10 15:22:23 1999 UTC

# Line 6 | Line 6 | static char SCCSid[] = "$SunId$ SGI";
6  
7   /*
8   * sm_ogl.c
9 + *
10 + *  Rendering routines for triangle mesh representation utilizing OpenGL
11   */
12   #include "standard.h"
13  
14   #include <GL/gl.h>
15  
14 #ifdef TEST_DRIVER
15 #include <gl/device.h>
16 #include <GL/glu.h>
17 #include <glut.h>
18 #endif
16   #include "sm_flag.h"
17   #include "sm_list.h"
18   #include "sm_geom.h"
22 #include "sm_qtree.h"
23 #include "sm_stree.h"
19   #include "sm.h"
20  
21 < #ifdef TEST_DRIVER
22 < #include "sm_draw.h"
23 < /*static char smClean_notify = TRUE;
24 < MAKE STATIC LATER: ui.c using for now;
25 < */
26 < char smClean_notify = TRUE;
27 < #else
28 < static int smClean_notify = TRUE;
29 < #endif
21 > int smClean_notify = TRUE;    /*If true:Do full redraw on next update*/
22 > 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 > #define MAX_NEW_TRIS 1000
26 > #define SM_RENDER_FG 0               /* Render foreground tris only*/
27 > #define SM_RENDER_BG 1               /* Render background tris only */
28 > #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 > /* 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  
38 + /* FOR APPROXIMATION RENDERING **********************************************/
39   typedef struct {
40          float   dist;           /* average distance */
41          BYTE    rgb[3];         /* average color */
# Line 45 | Line 48 | typedef struct {
48  
49   static QT_LUENT *qt_htbl = NULL;        /* quadtree cache */
50   static int      qt_hsiz = 0;            /* quadtree cache size */
51 + /****************************************************************************/
52  
53 + /* For DEPTH SORTING ********************************************************/
54 + typedef struct _T_DEPTH {
55 +  int tri;
56 +  double depth;
57 + }T_DEPTH;
58 + /**********************************************************************/
59  
60 <
61 < mark_active_tris(qtptr,fptr)
62 < QUADTREE *qtptr;
63 < int *fptr;
60 > /*
61 >  * smClean(tmflag)     : display has been wiped clean
62 >  *     int tmflag;
63 >  * 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 >  * If tmflag is set, tone-mapping should be performed
66 >  */
67 > smClean(tmflag)
68 >   int tmflag;
69   {
55  QUADTREE qt = *qtptr;
56  OBJECT *os,*optr;
57  register int i,t_id;
58  TRI *tri;
59
60
61  if(!QT_FLAG_FILL_TRI(*fptr))
62     (*fptr)++;
63
64  if(QT_IS_EMPTY(qt) || QT_LEAF_IS_FLAG(qt))
65    return;
66  /* For each triangle in the set, set the which flag*/
67  os = qtqueryset(qt);
68
69  for (i = QT_SET_CNT(os), optr = QT_SET_PTR(os); i > 0; i--)
70  {
71    t_id = QT_SET_NEXT_ELEM(optr);
72    /* Set the render flag */
73    tri = SM_NTH_TRI(smMesh,t_id);
74    if(!T_IS_VALID(tri) || SM_IS_NTH_T_BASE(smMesh,t_id))
75        continue;
76    SM_SET_NTH_T_ACTIVE(smMesh,t_id);
77    /* Set the Active bits of the Vertices */
78    S_SET_FLAG(T_NTH_V(tri,0));
79    S_SET_FLAG(T_NTH_V(tri,1));
80    S_SET_FLAG(T_NTH_V(tri,2));
81
82  }
83 }
84
85 #define mark_active_interior mark_active_tris
86
87 mark_tris_in_frustum(view)
88 VIEW *view;
89 {
90    FVECT nr[4],far[4];
91    FPEQ peq;
92    int debug=0;
93    /* Mark triangles in approx. view frustum as being active:set
94       LRU counter: for use in discarding samples when out
95       of space
96       Radiance often has no far clipping plane: but driver will set
97       dev_zmin,dev_zmax to satisfy OGL
98    */
99
100    /* First clear all the quadtree node and triangle active flags */
101    qtClearAllFlags();
102    smClear_flags(smMesh,T_ACTIVE_FLAG);
103    /* Clear all of the active sample flags*/
104    sClear_all_flags(smMesh->samples);
105
106
107    /* calculate the world space coordinates of the view frustum */
108    calculate_view_frustum(view->vp,view->hvec,view->vvec,view->horiz,
109                           view->vert, dev_zmin,dev_zmax,nr,far);
110
111 #ifdef TEST_DRIVER
112    VCOPY(FrustumFar[0],far[0]);
113    VCOPY(FrustumFar[1],far[1]);
114    VCOPY(FrustumFar[2],far[2]);
115    VCOPY(FrustumFar[3],far[3]);
116    VCOPY(FrustumNear[0],nr[0]);
117    VCOPY(FrustumNear[1],nr[1]);
118    VCOPY(FrustumNear[2],nr[2]);
119    VCOPY(FrustumNear[3],nr[3]);
120 #endif
121    /* Project the view frustum onto the spherical quadtree */
122    /* For every cell intersected by the projection of the faces
123
124       of the frustum: mark all triangles in the cell as ACTIVE-
125       Also set the triangles LRU clock counter
126       */
127    
128    if(EQUAL_VEC3(view->vp,SM_VIEW_CENTER(smMesh)))
129    {/* Near face triangles */
130      smLocator_apply_func(smMesh,nr[3],nr[2],nr[0],mark_active_tris,
131                         mark_active_interior,NULL);
132      smLocator_apply_func(smMesh,nr[1],nr[0],nr[2],mark_active_tris,
133                         mark_active_interior,NULL);
134      return;
135    }
136
137    /* Test the view against the planes: and swap orientation if inside:*/
138    tri_plane_equation(nr[0],nr[2],nr[3], &peq,FALSE);
139    if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
140    {/* Near face triangles */
141      smLocator_apply_func(smMesh,nr[3],nr[2],nr[0],mark_active_tris,
142                           mark_active_interior,NULL);
143      smLocator_apply_func(smMesh,nr[1],nr[0],nr[2],mark_active_tris,
144                         mark_active_interior,NULL);
145    }
146    else
147    {/* Near face triangles */
148      smLocator_apply_func(smMesh,nr[0],nr[2],nr[3],mark_active_tris,
149                           mark_active_interior,NULL);
150      smLocator_apply_func(smMesh,nr[2],nr[0],nr[1],mark_active_tris,
151                         mark_active_interior,NULL);
152    }
153    tri_plane_equation(nr[0],far[3],far[0], &peq,FALSE);
154    if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
155    { /* Right face triangles */
156      smLocator_apply_func(smMesh,far[0],far[3],nr[0],mark_active_tris,
157                           mark_active_interior,NULL);
158      smLocator_apply_func(smMesh,nr[3],nr[0],far[3],mark_active_tris,
159                           mark_active_interior,NULL);
160    }
161    else
162    {/* Right face triangles */
163      smLocator_apply_func(smMesh,nr[0],far[3],far[0],mark_active_tris,
164                           mark_active_interior,NULL);
165      smLocator_apply_func(smMesh,far[3],nr[0],nr[3],mark_active_tris,
166                           mark_active_interior,NULL);
167    }
168
169    tri_plane_equation(nr[1],far[2],nr[2], &peq,FALSE);
170    if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
171    { /* Left face triangles */
172      smLocator_apply_func(smMesh,nr[2],far[2],nr[1],mark_active_tris,
173                           mark_active_interior,NULL);
174      smLocator_apply_func(smMesh,far[1],nr[1],far[2],mark_active_tris,
175                           mark_active_interior,NULL);  
176    }
177    else
178    { /* Left face triangles */
179      smLocator_apply_func(smMesh,nr[1],far[2],nr[2],mark_active_tris,
180                           mark_active_interior,NULL);
181      smLocator_apply_func(smMesh,far[2],nr[1],far[1],mark_active_tris,
182                   mark_active_interior,NULL);
183
184    }
185    tri_plane_equation(nr[0],far[0],nr[1], &peq,FALSE);
186    if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
187    {/* Top face triangles */
188      smLocator_apply_func(smMesh,nr[1],far[0],nr[0],mark_active_tris,
189                           mark_active_interior,NULL);
190      smLocator_apply_func(smMesh,far[1],far[0],nr[1],mark_active_tris,
191                           mark_active_interior,NULL);
192    }
193    else
194    {/* Top face triangles */
195      smLocator_apply_func(smMesh,nr[0],far[0],nr[1],mark_active_tris,
196                           mark_active_interior,NULL);
197      smLocator_apply_func(smMesh,nr[1],far[0],far[1],mark_active_tris,
198                           mark_active_interior,NULL);
199    }
200    tri_plane_equation(nr[3],nr[2],far[3], &peq,FALSE);
201    if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
202    {/* Bottom face triangles */
203      smLocator_apply_func(smMesh,far[3],nr[2],nr[3],mark_active_tris,
204                           mark_active_interior,NULL);
205      smLocator_apply_func(smMesh,far[3],far[2],nr[2],mark_active_tris,
206                           mark_active_interior,NULL);
207    }
208    else
209    { /* Bottom face triangles */
210      smLocator_apply_func(smMesh,nr[3],nr[2],far[3],mark_active_tris,
211                           mark_active_interior,NULL);
212      smLocator_apply_func(smMesh,nr[2],far[2],far[3],mark_active_tris,
213                           mark_active_interior,NULL);
214    }
215     tri_plane_equation(far[2],far[0],far[1], &peq,FALSE);
216    if(PT_ON_PLANE(SM_VIEW_CENTER(smMesh),peq) > 0.0)
217    {/* Far face triangles */
218      smLocator_apply_func(smMesh,far[0],far[2],far[1],mark_active_tris,
219                           mark_active_interior,NULL);
220      smLocator_apply_func(smMesh,far[2],far[0],far[3],mark_active_tris,
221                           mark_active_interior,NULL);
222    }
223    else
224    {/* Far face triangles */
225      smLocator_apply_func(smMesh,far[1],far[2],far[0],mark_active_tris,
226                           mark_active_interior,NULL);
227      smLocator_apply_func(smMesh,far[3],far[0],far[2],mark_active_tris,
228                           mark_active_interior,NULL);
229    }
230
231 }
232
233 /*
234 * smClean()            : display has been wiped clean
235 *
236 * Called after display has been effectively cleared, meaning that all
237 * geometry must be resent down the pipeline in the next call to smUpdate().
238 */
239 smClean()
240 {
70      smClean_notify = TRUE;
71 +    if(tmflag)
72 +       smCompute_mapping = TRUE;
73   }
74  
75   int
# Line 322 | Line 153 | register QUADTREE qt;
153      stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,3));
154    }
155    else
156 <    lcnt[0]++;
156 >    if(QT_LEAF_IS_FLAG(qt))
157 >      lcnt[0]++;
158   }
159  
328
160   QTRAVG *
161   qtRender_level(qt,v0,v1,v2,sm,lvl)
162   QUADTREE qt;
# Line 342 | Line 173 | int lvl;
173      return(NULL);
174    if (QT_IS_TREE(qt) && !QT_IS_FLAG(qt))        /* not in our frustum */
175      return(NULL);
176 +  if(QT_IS_LEAF(qt)  && !QT_LEAF_IS_FLAG(qt))   /* not in our frustum */
177 +    return(NULL);
178                                          /* else look up node */
179    if ((le = qtCache_find(qt)) == NULL)
180      error(SYSTEM, "out of memory in qtRender_level");
181    if (QT_IS_TREE(qt) && (QT_IS_EMPTY(le->qt) || lvl > 0))
182    {                                     /* compute children */
183      qtSubdivide_tri(v0,v1,v2,a,b,c);
184 <    rc[0] = qtRender_level(QT_NTH_CHILD(qt,0),v0,a,c,sm,lvl-1);
185 <    rc[1] = qtRender_level(QT_NTH_CHILD(qt,1),a,v1,b,sm,lvl-1);
186 <    rc[2] = qtRender_level(QT_NTH_CHILD(qt,2),c,b,v2,sm,lvl-1);
187 <    rc[3] = qtRender_level(QT_NTH_CHILD(qt,3),b,c,a,sm,lvl-1);
184 >    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    }
189    if (QT_IS_EMPTY(le->qt))
190    {                                     /* let's make some data! */
# Line 373 | Line 206 | int lvl;
206      else
207      {                                   /* from triangle set */
208        OBJECT *os;
209 <      int s0, s1, s2;
209 >      int s0, s1, s2,s_id,t_id;
210 >      TRI *tri,*t;
211  
212        os = qtqueryset(qt);
213 <      for (n = os[0]; n; n--)
213 >      for (i = os[0]; i; i--)
214        {
215 <        tri = SM_NTH_TRI(sm,os[n]);
216 <        if(!T_IS_VALID(tri))
217 <          continue;
218 <
219 <        s0 = T_NTH_V(tri,0);
220 <        s1 = T_NTH_V(tri,1);
221 <        s2 = T_NTH_V(tri,2);
222 <        VCOPY(a,SM_NTH_WV(sm,s0));
223 <        VCOPY(b,SM_NTH_WV(sm,s1));
224 <        VCOPY(c,SM_NTH_WV(sm,s2));            
225 <        distsum += SM_BG_SAMPLE(sm,s0) ? dev_zmax
215 >        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                                  : sqrt(dist2(a,SM_VIEW_CENTER(sm)));
231 <        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
231 >            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                                  : sqrt(dist2(c,SM_VIEW_CENTER(sm)));
235 <        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];
235 >            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        }
248 <      n = 3*os[0];
248 >      n *= 3;
249      }
250      if (!n)
251        return(NULL);
# Line 419 | Line 263 | int lvl;
263      VSUM(c,SM_VIEW_CENTER(sm),c,le->av.dist);
264                                          /* draw triangle */
265      glColor3ub(le->av.rgb[0],le->av.rgb[1],le->av.rgb[2]);
422    /* NOTE: Triangle vertex order may change */
423    glVertex3d(c[0],c[1],c[2]);
424    glVertex3d(b[0],b[1],b[2]);
266      glVertex3d(a[0],a[1],a[2]);
267 +    glVertex3d(b[0],b[1],b[2]);
268 +    glVertex3d(c[0],c[1],c[2]);
269 +
270    }
271    return(&le->av);
272   }
273  
274  
275 < smRender_stree_level(sm,lvl)
275 >
276 >
277 > smRender_approx_stree_level(sm,lvl)
278   SM *sm;
279   int lvl;
280   {
281 <  QUADTREE root;
281 >  QUADTREE qt;
282    int i;
283    FVECT t0,t1,t2;
284    STREE *st;
285  
286    
287 <  if (lvl < 1)
287 >  if (lvl < 0)
288      return;
289    st = SM_LOCATOR(sm);
290    glPushAttrib(GL_LIGHTING_BIT);
# Line 446 | Line 292 | int lvl;
292    glBegin(GL_TRIANGLES);
293    for(i=0; i < ST_NUM_ROOT_NODES; i++)
294    {
295 <    root = ST_NTH_ROOT(st,i);
296 <    qtRender_level(root,ST_NTH_V(st,i,0),ST_NTH_V(st,i,1),ST_NTH_V(st,i,2),
297 <                   sm,lvl-1);
295 >    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 >                   sm,lvl);
298    }
299    glEnd();
300    glPopAttrib();
301   }
302  
303 <
304 < smRender_stree(sm, qual)        /* render some quadtree triangles */
303 > /*
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   SM *sm;
318   int qual;
319 + VIEW *view;
320   {
321 <  int i, ntarget;
321 >  int i, n,ntarget;
322    int lvlcnt[QT_MAX_LEVELS];
323 +  STREE *st;
324 +  int4 *active_flag;
325  
326    if (qual <= 0)
327      return;
328 +  smCull(sm,view,SM_ALL_LEVELS);
329                                  /* compute rendering target */
330    ntarget = 0;
331 <  SM_FOR_ALL_ACTIVE_TRIS(sm,i)
332 <    ntarget++;
333 <  ntarget = ntarget*qual/100;
331 >
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    if (!ntarget)
341      return;
342    for (i = QT_MAX_LEVELS; i--; )
343      lvlcnt[i] = 0;
344 <  stCount_level_leaves(lvlcnt, ST_TOP_ROOT(SM_LOCATOR(sm)));
345 <  stCount_level_leaves(lvlcnt, ST_BOTTOM_ROOT(SM_LOCATOR(sm)));  
344 >  
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    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 <  smRender_stree_level(sm,i);
353 >  smRender_approx_stree_level(sm,i);
354   }
355  
356 + #ifndef LORES
357 + #define GLVERTEX3V(v) glVertex3dv(v)
358 + #else
359 + #define GLVERTEX3V(v) glVertex3fv(v)
360 + #endif
361  
362 < smRender_tri(sm,i,vp,clr)
362 > #define render_tri(v0,v1,v2,rgb0,rgb1,rgb2) \
363 >  {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 >
367 > /*
368 > * render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,b0,b1,b2)
369 > *  SFLOAT v0[3],v1[3],v2[3];      : triangle vertex coordinates
370 > *  BYTE rgb0[3],rgb1[3],rgb2[3]; : vertex RGBs
371 > *  int b0,b1,b2;                 : background or base vertex flag
372 > *  
373 > *  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 > */
379 > render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,bg0,bg1,bg2)
380 > SFLOAT v0[3],v1[3],v2[3];
381 > BYTE rgb0[3],rgb1[3],rgb2[3];
382 > FVECT vp,vc;
383 > int bg0,bg1,bg2;
384 > {
385 >  double d,p[3];
386 >  int j,cnt,rgb[3];
387 >  
388 >  /* Average color from bg vertices */
389 >  cnt = 0;
390 >  if(bg0 == BASE || bg1==BASE || bg2 == BASE)
391 >  {
392 >    rgb[0] = rgb[1] = rgb[2] = 0;
393 >    if(bg0 != BASE)
394 >      {
395 >        IADDV3(rgb,rgb0);
396 >        cnt++;
397 >      }
398 >    if(bg1 != BASE)
399 >      {
400 >        IADDV3(rgb,rgb1);
401 >        cnt++;
402 >      }
403 >    if(bg2 != BASE)
404 >      {
405 >        IADDV3(rgb,rgb2);
406 >        cnt++;
407 >      }
408 >    IDIVV3(rgb,cnt);
409 >  }
410 >  if(bg0 == BASE)
411 >    glColor3i(rgb[0],rgb[1],rgb[2]);
412 >  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 >    GLVERTEX3V(v0);
424 >
425 >  if(bg1 == BASE)
426 >    glColor3i(rgb[0],rgb[1],rgb[2]);
427 >  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 >    GLVERTEX3V(v1);
439 >
440 >  if(bg2 == BASE)
441 >    glColor3i(rgb[0],rgb[1],rgb[2]);
442 >  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 >    GLVERTEX3V(v2);
454 > }
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 > * SFLOAT (*wp)[3];BYTE  (*rgb)[3]; : arrays of sample points and RGB colors
463 > *
464 > * Sequentially traverses triangle list and renders all valid tris who
465 > * 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;
488 int i;
470   FVECT vp;
471 < int clr;
471 > int4 *t_flag,*bg_flag;
472 > SFLOAT (*wp)[3];
473 > 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;
493  double ptr[3];
494  int j;
479  
480 <  tri = SM_NTH_TRI(sm,i);
497 <  if (clr) SM_CLR_NTH_T_NEW(sm,i);
480 >  glMatrixMode(GL_MODELVIEW);
481  
482 <  /* NOTE:Triangles are defined clockwise:historical relative to spherical
483 <     tris: could change
484 <     */
485 <  for(j=2; j>= 0; j--)
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 < #ifdef DEBUG
490 <    if(SM_BG_SAMPLE(sm,T_NTH_V(tri,j)))
506 <      eputs("SmRenderTri(): shouldnt have bg samples\n");
507 < #endif
508 <    glColor3ub(SM_NTH_RGB(sm,T_NTH_V(tri,j))[0],
509 <               SM_NTH_RGB(sm,T_NTH_V(tri,j))[1],
510 <               SM_NTH_RGB(sm,T_NTH_V(tri,j))[2]);
511 <    VCOPY(ptr,SM_T_NTH_WV(sm,tri,j));
512 <    glVertex3d(ptr[0],ptr[1],ptr[2]);
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 +              rgb[v1_id],rgb[v2_id],vp,SM_VIEW_CENTER(sm),bg0,bg1,bg2);
515 +         }
516 +  glEnd();
517 +
518 +  glPopMatrix();
519 +
520   }
521 + /*
522 + * 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_mixed_tri(sm,i,vp,clr)
533 > smRender_new_bg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb)
534   SM *sm;
518 int i;
535   FVECT vp;
536 < int clr;
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;
523  double p[3],d;
524  int j,ids[3],cnt;
525  int rgb[3];
544  
545 <  tri = SM_NTH_TRI(sm,i);
528 <  if (clr) SM_CLR_NTH_T_NEW(sm,i);
545 >  glMatrixMode(GL_MODELVIEW);
546  
547 <  /* NOTE:Triangles are defined clockwise:historical relative to spherical
548 <     tris: could change
549 <     */
550 <  cnt = 0;
551 <  d = 0.0;
552 <  rgb[0] = rgb[1] = rgb[2] = 0;
536 <  for(j=0;j < 3;j++)
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 <      ids[j] = T_NTH_V(tri,j);
555 <      if(!SM_BG_SAMPLE(sm,ids[j]))
540 <      {
541 <          rgb[0] += SM_NTH_RGB(sm,ids[j])[0];
542 <          rgb[1] += SM_NTH_RGB(sm,ids[j])[1];
543 <          rgb[2] += SM_NTH_RGB(sm,ids[j])[2];
544 <          cnt++;
545 <          d += DIST(vp,SM_NTH_WV(sm,ids[j]));
546 <      }
554 >    d = (dev_zmin+dev_zmax)/2.0;
555 >    glScaled(d,d,d);
556    }
557 <  if(cnt > 1)
558 <  {
559 <    rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
560 <    d /= (double)cnt;
561 <  }
562 <  for(j=2; j>= 0; j--)
563 <  {
564 <    if(SM_BG_SAMPLE(sm,ids[j]))
565 <    {
566 <        glColor3ub(rgb[0],rgb[1],rgb[2]);
567 <        VSUB(p,SM_NTH_WV(sm,ids[j]),SM_VIEW_CENTER(sm));
568 <        p[0] *= d;
569 <        p[1] *= d;
570 <        p[2] *= d;
571 <        VADD(p,p,SM_VIEW_CENTER(sm));
572 <    }
573 <    else
574 <    {
575 <        glColor3ub(SM_NTH_RGB(sm,ids[j])[0],SM_NTH_RGB(sm,ids[j])[1],
576 <                   SM_NTH_RGB(sm,ids[j])[2]);
577 <        VCOPY(p,SM_NTH_WV(sm,ids[j]));
578 <    }
579 <    glVertex3d(p[0],p[1],p[2]);
580 <   }
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 < smRender_bg_tri(sm,i,vp,d,clr)
588 < SM *sm;
589 < int i;
587 > /*
588 > * render_base_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,b0,b1,b2)
589 > *  SFLOAT v0[3],v1[3],v2[3];       : triangle vertex coordinates
590 > *  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 > SFLOAT v0[3],v1[3],v2[3];
600 > BYTE rgb0[3],rgb1[3],rgb2[3];
601   FVECT vp;
602 < double d;
579 < int clr;
602 > int b0,b1,b2;
603   {
604 +  int cnt;
605 +  int rgb[3];
606 +  double d;
607    double p[3];
582  int j,id;
583  TRI *tri;
584  
585  tri = SM_NTH_TRI(sm,i);
586  if (clr) SM_CLR_NTH_T_NEW(sm,i);
608  
609 <  /* NOTE:Triangles are defined clockwise:historical relative to spherical
610 <     tris: could change
611 <     */
612 <  for(j=2; j>= 0; j--)
609 >  cnt = 0;
610 >  rgb[0] = rgb[1] = rgb[2] = 0;
611 >  d = 0.0;
612 >
613 >  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    {
619 <      id = T_NTH_V(tri,j);
620 <      glColor3ub(SM_NTH_RGB(sm,id)[0],SM_NTH_RGB(sm,id)[1],
621 <                 SM_NTH_RGB(sm,id)[2]);
596 <      VSUB(p,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
597 <      if(dev_zmin >= 0.99)
598 <       {
599 <           p[0] *= d;
600 <           p[1] *= d;
601 <           p[2] *= d;
602 <       }
603 <      VADD(p,p,vp);
604 <      glVertex3d(p[0],p[1],p[2]);
619 >    IADDV3(rgb,rgb0);
620 >    d += DIST(v0,vp);
621 >    cnt++;
622    }
623 +  if(!b1)
624 +  {
625 +    IADDV3(rgb,rgb1);
626 +    d += DIST(v1,vp);
627 +    cnt++;
628 +  }
629 +  if(!b2)
630 +  {
631 +    IADDV3(rgb,rgb2);
632 +    d += DIST(v2,vp);
633 +    cnt++;
634 +  }
635 +  IDIVV3(rgb,cnt);
636 +  d /= (double)cnt;
637 +  
638 +  /* Now render triangle */
639 +  if(b0)
640 +  {
641 +    glColor3ub(rgb[0],rgb[1],rgb[2]);
642 +    SUBV3(p,v0,vp);
643 +    ISCALEV3(p,d);
644 +    IADDV3(p,vp);
645 +    glVertex3dv(p);    
646 +  }
647 +  else
648 +  {
649 +    glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
650 +    GLVERTEX3V(v0);
651 +  }
652 +  if(b1)
653 +  {
654 +    glColor3ub(rgb[0],rgb[1],rgb[2]);
655 +    SUBV3(p,v1,vp);
656 +    ISCALEV3(p,d);
657 +    IADDV3(p,vp);
658 +    glVertex3dv(p);
659 +  }
660 +  else
661 +  {
662 +    glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
663 +    GLVERTEX3V(v1);
664 +  }
665 +  if(b2)
666 +  {
667 +    glColor3ub(rgb[0],rgb[1],rgb[2]);
668 +    SUBV3(p,v2,vp);
669 +    ISCALEV3(p,d);
670 +    IADDV3(p,vp);
671 +    glVertex3dv(p);
672 +  }
673 +  else
674 +  {
675 +    glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
676 +    GLVERTEX3V(v2);
677 +  }
678   }
679 <
680 < smRender_mesh(sm,vp,clr)
679 > /*
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 > * SFLOAT (*wp)[3];BYTE (*rgb)[3]; : arrays of sample points and RGB colors
686 > *
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   SM *sm;
692   FVECT vp;
693 < int clr;
693 > int4  *t_flag,*bg_flag;
694 > SFLOAT (*wp)[3];
695 > BYTE  (*rgb)[3];
696   {
613  int i;
697    TRI *tri;
698 <  double ptr[3],d;
699 <  int j;
617 <
618 <  d = (dev_zmin+dev_zmax)/2.0;
619 <  glPushAttrib(GL_DEPTH_BUFFER_BIT);
698 >  int i,n,b0,b1,b2;
699 >  int v0_id,v1_id,v2_id;
700    
621  /* First draw background polygons */
622  glDisable(GL_DEPTH_TEST);
701    glBegin(GL_TRIANGLES);
702 <  SM_FOR_ALL_ACTIVE_BG_TRIS(sm,i)
703 <     smRender_bg_tri(sm,i,vp,d,clr);
702 >  for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
703 >    if(t_flag[n])
704 >      for(i=0; i < 32; i++)
705 >        if(t_flag[n] & (1L << i) & ~bg_flag[n])
706 >         {
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 >           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 >             render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
719 >                        rgb[v2_id])
720 >
721 >         }
722    glEnd();
627  glEnable(GL_DEPTH_TEST);
628  glBegin(GL_TRIANGLES);
629  SM_FOR_ALL_ACTIVE_FG_TRIS(sm,i)
630  {
631      if(SM_BG_TRI(sm,i))
632         continue;
633      if(!SM_MIXED_TRI(sm,i))
634        smRender_tri(sm,i,vp,clr);
635   else
636        smRender_mixed_tri(sm,i,vp,clr);
637  }
638  glEnd();
723  
640  glPopAttrib();
724   }
725  
726 < smRender_tri_edges(sm,i)
726 > /*
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 < int i;
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 j;
746 <  double ptr[3];
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  
768 +         }
769 +  glEnd();
770  
652  tri = SM_NTH_TRI(sm,i);
653
654  /* Triangles are defined clockwise:historical relative to spherical
655     tris: could change
656     */
657  for(j=2; j >=0; j--)
658  {
659    VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,j)));
660    glVertex3d(ptr[0],ptr[1],ptr[2]);
661    VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,(j+1)%3)));
662    glVertex3d(ptr[0],ptr[1],ptr[2]);
663  }
771   }
772  
773 +
774   int
775   compare_tri_depths(T_DEPTH *td1,T_DEPTH *td2)
776   {
777    double d;
778  
779    d = td2->depth-td1->depth;
672  
780    if(d > 0.0)
781      return(1);
782    if(d < 0.0)
783      return(-1);
677  
784    return(0);
785   }
786  
787 < LIST
788 < *smDepth_sort_tris(sm,vp,td)
787 >
788 > /*
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 > T_DEPTH
798 > *smOrder_new_tris(sm,vp)
799   SM *sm;
800   FVECT vp;
685 T_DEPTH *td;
801   {
802 <  int i,j,t_id,v;
802 >  T_DEPTH *td;
803 >  int n,i,j,tcnt,v,size;
804    TRI *tri;
805    double d,min_d;
806 <  LIST *tlist=NULL;
806 >  FVECT diff;
807 >  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  
812 <  i = 0;
813 <  SM_FOR_ALL_NEW_TRIS(sm,t_id)
812 >  tcnt=0;
813 >  new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
814 >  bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
815 >  active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
816 >  for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
817 >    if(active_flag[n] & new_flag[n] & ~bg_flag[n])
818 >      for(i=0; i < 32; i++)
819 >        if(active_flag[n] & new_flag[n] & (1L << i) & ~bg_flag[n])
820 >         {
821 >           tri = SM_NTH_TRI(sm,(n<<5)+i);
822 >           if(tcnt+1 >= size)
823 >           {
824 >             size += 100;
825 >             td = (T_DEPTH *)tempbuf(size*sizeof(T_DEPTH),TRUE);
826 >           }
827 >           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 >               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 >             }
837 >           td[tcnt++].depth = min_d;
838 >  }
839 >  td[tcnt].tri = -1;
840 >  if(tcnt)
841 >      qsort((void *)td,tcnt,sizeof(T_DEPTH),compare_tri_depths);
842 >  return(td);
843 > }
844 >
845 > /*
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 >
855 >  if(t==0 || smCompute_mapping)
856    {
857 <    if(SM_BG_TRI(sm,t_id))
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 > SM *sm;
882 > FVECT vp;
883 > {
884 >  int i,n,v0_id,v1_id,v2_id,b0,b1,b2;
885 >  TRI *tri;
886 >  SFLOAT (*wp)[3];
887 >  BYTE  (*rgb)[3];
888 >  int4  *new_flag,*bg_flag,*active_flag;
889 >  T_DEPTH *td = NULL;
890 >
891 >
892 >  /* 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 >
897 >  /* Must depth sort if view points do not coincide */
898 >  if(!EQUAL_VEC3(SM_VIEW_CENTER(sm),vp))
899 >    td =  smOrder_new_tris(sm,vp);
900 >  wp = SM_WP(sm);
901 >  rgb =SM_RGB(sm);
902 >  new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
903 >  active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
904 >  bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
905 >  /* Turn Depth Test off -- using Painter's algorithm */
906 >  glPushAttrib(GL_DEPTH_BUFFER_BIT);
907 >  glDepthFunc(GL_ALWAYS);
908 >
909 >  smRender_new_bg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb);
910 >  if(!td)
911 >    smRender_new_fg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb);
912 >  else
913 >  {
914 >    glBegin(GL_TRIANGLES);
915 >    for(i=0; td[i].tri != -1;i++)
916      {
917 <        tlist = push_data(tlist,t_id);
918 <        continue;
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 >      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 >        render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
932 >                   rgb[v2_id])
933      }
934 <    tri = SM_NTH_TRI(sm,t_id);
935 < #ifdef DEBUG
936 <    if(i >= smNew_tri_cnt)
934 >    glEnd();
935 >    freebuf(td);
936 >  }
937 >  /* 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 > *  SFLOAT (*wp)[3];      : array of sample points
947 > *  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 > SFLOAT (*wp)[3];
969 > 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 <      eputs("smDepth_sort_tris():More tris than reported by smNew_tri_cnt\n");
983 <      break;
982 >      if(!QT_LEAF_IS_FLAG(qt))
983 >        return;
984      }
985 < #endif
986 <    td[i].tri = t_id;
987 <    min_d = -1;
988 <    for(j=0;j < 3;j++)
985 >    else
986 >      if(!QT_IS_FLAG(qt))
987 >        return;
988 >
989 >    if(!Display_lists[i][which])
990      {
991 <        v = T_NTH_V(tri,j);
992 <        if(!SM_BG_SAMPLE(sm,v))
993 <        {
994 <            d = DIST(vp,SM_NTH_WV(sm,v));
995 <            if(min_d == -1 || d < min_d)
996 <               min_d = d;
997 <        }
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 <    td[i].depth = min_d;
1000 <    i++;
999 >    else
1000 >    {
1001 >      glCallList(Display_lists[i][which]);
1002 >    }
1003    }
1004 <  td[i].tri = -1;
1005 <  if(i)
1006 <     qsort((void *)td,i,sizeof(T_DEPTH),compare_tri_depths);
1007 <  return(tlist);
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 < smUpdate_Rendered_mesh(sm,vp,clr)
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 > *  SFLOAT (*wp)[3]      : array of sample points
1023 > *  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 < int clr;
1032 > SFLOAT (*wp)[3];
1033 > BYTE  (*rgb)[3];
1034 > int which,cull;
1035   {
735  static T_DEPTH *td= NULL;
736  static int tsize = 0;
1036    int i;
1037 <  GLint depth_test;
1038 <  double d;
1039 <  LIST *bglist;
1040 <  /* For all of the NEW triangles (since last update): assume
1041 <     ACTIVE. Go through and sort on depth value (from vp). Turn
743 <     Depth Buffer test off and render back-front
744 <     */
745 <  /* NOTE: could malloc each time or hard code */
746 <  if(smNew_tri_cnt > tsize)
1037 >  
1038 >  if(QT_IS_EMPTY(qt))
1039 >    return;
1040 >
1041 >  if(QT_IS_LEAF(qt))
1042    {
1043 <    if(td)
1044 <      free((char *)td);
1045 <    td = (T_DEPTH *)malloc(smNew_tri_cnt*sizeof(T_DEPTH));
1046 <    tsize = smNew_tri_cnt;
1043 >    TRI *t,*tri;
1044 >    OBJECT *optr;
1045 >    int v0_id,v1_id,v2_id,bg0,bg1,bg2;
1046 >    int t_id,s_id;
1047 >
1048 >    if(cull && !QT_LEAF_IS_FLAG(qt))
1049 >      return;
1050 >
1051 >    optr = qtqueryset(qt);
1052 >    for (i = QT_SET_CNT(optr);i > 0; i--)
1053 >    {
1054 >      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 >      {
1059 >       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 >    }
1099    }
1100 <  if(!td)
1101 <  {
1102 <    error(SYSTEM,"smUpdate_Rendered_mesh:Cannot allocate memory\n");
1103 <  }
1104 <  bglist = smDepth_sort_tris(sm,vp,td);
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 <  /* Turn Depth Test off -- using Painter's algorithm */
1106 >
1107 > /*
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 >  SFLOAT (*wp)[3];
1124 >  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 >
1135 >  if(cull)
1136 >    smCull(sm,view,SM_ALL_LEVELS);
1137 >
1138 >
1139    glPushAttrib(GL_DEPTH_BUFFER_BIT);
1140    glDisable(GL_DEPTH_TEST);
1141 <  d = (dev_zmin+dev_zmax)/2.0;
1142 <  /* Now render back-to front */
1143 <  /* First render bg triangles */
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 <  while(bglist)
1164 <     smRender_bg_tri(sm,pop_list(&bglist),vp,d,clr);
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    glEnd();
1166  
1167 +  glPopMatrix();
1168  
1169 +  glEnable(GL_DEPTH_TEST);
1170 +
1171    glBegin(GL_TRIANGLES);
1172 <  i=0;
1173 <  while(td[i].tri != -1)
774 <     if(!SM_MIXED_TRI(sm,td[i].tri))
775 <        smRender_tri(sm,td[i++].tri,vp,clr);
776 <     else
777 <        smRender_mixed_tri(sm,td[i++].tri,vp,clr);
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  
780  /* Restore Depth Test */
1176    glPopAttrib();
1177   }
1178  
1179 + /*
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 +  SFLOAT (*wp)[3];
1189 +  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 +  smClear_flags(sm,T_NEW_FLAG);
1208 +
1209 +  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   /*
1254 < * smUpdate(view, qua)  : update OpenGL output geometry for view vp
1254 > * 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 >  SFLOAT (*wp)[3];
1269 >  BYTE  (*rgb)[3];
1270 >
1271 >  wp = SM_WP(sm);
1272 >  rgb = SM_RGB(sm);
1273 >  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 >    if(qual > (MAXQUALITY*2/4) )
1431 >      /* render stree using display lists */
1432 >      smRender_mesh_dl(sm,view);
1433 >    else
1434 >    {
1435 >      /* If quality below threshold, use approximate rendering */
1436 >      smRender_approx(sm,qual,view);
1437 >    }
1438 >  }
1439 >  else
1440 >  {
1441 >    /* render stree without display lists */
1442 >      smRender_mesh(sm,view,TRUE);
1443 >  }
1444 > }
1445 >
1446 >
1447 > /*
1448 > * smUpdate(view, qual) : update OpenGL output geometry
1449   * VIEW *view;          : desired view
1450   * int  qual;           : quality level (percentage on linear time scale)
1451   *
# Line 790 | Line 1453 | int clr;
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 < * been output since the last call to smClean().  (The last view drawn will
1456 > * been output since the last call to smClean().(The last view drawn will
1457   * be view==&odev.v each time.)
1458   */
1459   smUpdate(view,qual)
1460     VIEW *view;
1461     int qual;
1462   {
1463 <  double d;
1464 <  int last_update;
802 <  int t;
803 <
804 <  /* If view has moved beyond epsilon from canonical: must rebuild -
805 <     epsilon is calculated as running avg of distance of sample points
806 <     from canonical view: m = 1/(AVG(1/r)): some fraction of this
807 <   */
808 <
809 <  if(!smMesh)
1463 >  /* Is there anything to render? */
1464 >  if(!smMesh || SM_NUM_TRI(smMesh)<=0)
1465      return;
1466 <  d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
1467 <  if(qual >= 100 && d > SM_ALLOWED_VIEW_CHANGE(smMesh))
1466 >
1467 >  /* Is viewer MOVING?*/
1468 >  if(qual < MAXQUALITY)
1469    {
1470 <      /* Re-build the mesh */
1471 < #ifdef TEST_DRIVER
1472 <    odev.v = *view;
1473 < #endif  
1474 <      mark_tris_in_frustum(view);
1475 <      smRebuild_mesh(smMesh,view);
1470 >    if(smIncremental)
1471 >      smUpdate_tm(smMesh);
1472 >    smIncremental = FALSE;
1473 >    /* Render mesh using display lists */
1474 >    smRender(smMesh,view,qual);
1475 >    return;
1476    }
1477 <  /* This is our final update iff qual==100 and view==&odev.v */
1478 <  last_update = qual>=100 && view==&(odev.v);
1479 <  /* Check if we should draw ALL triangles in current frustum */
1480 <  if(smClean_notify || smNew_tri_cnt > SM_SAMPLE_TRIS(smMesh)*SM_INC_PERCENT)
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    {
1483 < #ifdef TEST_DRIVER
1484 <    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1485 < #else
1486 <    if ( SM_TONE_MAP(smMesh) < SM_NUM_SAMP(smMesh))
1483 >    /* Must rebuild mesh with current view as new canonical view  */
1484 >    smRebuild(smMesh,view);
1485 >    /* Existing display lists and tonemapping are no longer valid */
1486 >    clear_display_lists();
1487 >    smCompute_mapping = FALSE;
1488 >    smUpdate_tm(smMesh);
1489 >    /* Render all the triangles in the new mesh */
1490 >    smRender(smMesh,view,qual+1);
1491 >  }
1492 >  else
1493 >    /* Has a complete redraw been requested ?*/
1494 >    if(smClean_notify)
1495      {
1496 <       tmClearHisto();
1497 <       tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
1498 <       if(tmComputeMapping(0.,0.,0.) != TM_E_OK ||
1499 <                   tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
835 <                                SM_NUM_SAMP(smMesh)) != TM_E_OK)
836 <            return;
1496 >      if(smIncremental)
1497 >        smUpdate_tm(smMesh);
1498 >      smIncremental = FALSE;
1499 >      smRender(smMesh,view,qual);
1500      }
838 #endif
839    mark_tris_in_frustum(view);
840    if (qual <= 75)
841        smRender_stree(smMesh,qual);
1501      else
843        smRender_mesh(smMesh,view->vp,last_update);
844 #ifdef TEST_DRIVER
845    glFlush();
846    glutSwapBuffers();
847 #endif
848  }
849  /* Do an incremental update instead */
850  else
851  {
852      if(!smNew_tri_cnt)
853      return;
854 #ifdef TEST_DRIVER
855    glDrawBuffer(GL_FRONT);
856 #else
857    t = SM_TONE_MAP(smMesh);
858    if(t == 0)
1502      {
1503 <        tmClearHisto();
1504 <        tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
1505 <        if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
1506 <           return;
1507 <    }
1508 <    if(tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
1509 <                   SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t) != TM_E_OK)
1510 <          return;
1511 < #endif    
869 <    smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
870 <    
871 < #ifdef TEST_DRIVER
872 <    glDrawBuffer(GL_BACK);
873 < #endif
1503 >      smUpdate_tm(smMesh);
1504 >      /* If number of new triangles relatively small: do incremental update */
1505 >      /* 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    }
1513 <  SM_TONE_MAP(smMesh) = SM_NUM_SAMP(smMesh);
1514 <  if (last_update)
1513 >  /* This is our final update iff qual==MAXQUALITY and view==&odev.v */
1514 >  if( (qual >= MAXQUALITY) && (view == &(odev.v)))
1515    {
1516 +    /* reset rendering flags */
1517      smClean_notify = FALSE;
1518 <    smNew_tri_cnt = 0;
1519 <    smClear_flags(smMesh,T_NEW_FLAG);
1518 >    if(smIncremental)
1519 >      smClear_flags(smMesh,T_NEW_FLAG);
1520      qtCache_init(0);
1521    }
1522  
1523   }
1524 +
1525 +
1526 +
1527 +
1528 +
1529 +

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines