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.1 by gwlarson, Wed Aug 19 17:45:24 1998 UTC vs.
Revision 3.17 by greg, Fri Jun 20 00:25:49 2003 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines