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.7 by gwlarson, Wed Sep 16 18:16:29 1998 UTC vs.
Revision 3.18 by schorsch, Mon Jul 21 22:30:18 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
15 < #include <gl/device.h>
16 < #include <GL/glu.h>
17 < #include <glut.h>
18 < #endif
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 int 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 */
# Line 42 | Line 63 | typedef struct {
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 < int
76 < mark_active_tris(qtptr,fptr,arg1,arg2)
77 < QUADTREE *qtptr;
78 < int *fptr,arg1,*arg2;
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   {
52  QUADTREE qt = *qtptr;
53  OBJECT *os,*optr;
54  register int i,t_id;
55
56  if (!QT_IS_LEAF(qt))
57    return(TRUE);
58  
59  if(!QT_FLAG_FILL_TRI(*fptr))
60     (*fptr)++;
61  /* For each triangle in the set, set the which flag*/
62  os = qtqueryset(qt);
63
64  for (i = QT_SET_CNT(os), optr = QT_SET_PTR(os); i > 0; i--)
65  {
66    t_id = QT_SET_NEXT_ELEM(optr);
67    /* Set the render flag */
68    if(SM_IS_NTH_T_BASE(smMesh,t_id))
69        continue;
70    SM_SET_NTH_T_ACTIVE(smMesh,t_id);
71    /* NOTE:Also set the LRU clock bit: MAY WANT TO CHANGE: */      
72    SM_SET_NTH_T_LRU(smMesh,t_id);
73  }
74  return(TRUE);
75 }
76
77 int
78 mark_active_interior(qtptr,q0,q1,q2,t0,t1,t2,n,arg1,arg2,arg3)
79 QUADTREE *qtptr;
80 FVECT q0,q1,q2;
81 FVECT t0,t1,t2;
82 int n;
83 int *arg1,arg2,*arg3;
84 {
85  QUADTREE qt = *qtptr;
86  OBJECT *os,*optr;
87  register int i,t_id;
88
89  if (!QT_IS_LEAF(qt))
90    return(TRUE);
91  /* For each triangle in the set, set the which flag*/
92  os = qtqueryset(qt);
93
94  for (i = QT_SET_CNT(os), optr = QT_SET_PTR(os); i > 0; i--)
95  {
96    t_id = QT_SET_NEXT_ELEM(optr);
97    /* Set the render flag */
98    if(SM_IS_NTH_T_BASE(smMesh,t_id))
99        continue;
100    SM_SET_NTH_T_ACTIVE(smMesh,t_id);
101    /* NOTE:Also set the LRU clock bit: MAY WANT TO CHANGE: */      
102    SM_SET_NTH_T_LRU(smMesh,t_id);
103  }
104  return(TRUE);
105 }
106
107 mark_tris_in_frustum(view)
108 VIEW *view;
109 {
110    FVECT nr[4],far[4];
111
112    /* Mark triangles in approx. view frustum as being active:set
113       LRU counter: for use in discarding samples when out
114       of space
115       Radiance often has no far clipping plane: but driver will set
116       dev_zmin,dev_zmax to satisfy OGL
117    */
118
119    /* First clear all the quadtree node and triangle active flags */
120    qtClearAllFlags();
121    smClear_flags(smMesh,T_ACTIVE_FLAG);
122
123    /* calculate the world space coordinates of the view frustum */
124    calculate_view_frustum(view->vp,view->hvec,view->vvec,view->horiz,
125                           view->vert, dev_zmin,dev_zmax,nr,far);
126
127    /* Project the view frustum onto the spherical quadtree */
128    /* For every cell intersected by the projection of the faces
129       of the frustum: mark all triangles in the cell as ACTIVE-
130       Also set the triangles LRU clock counter
131       */
132    /* Near face triangles */
133    smLocator_apply_func(smMesh,nr[0],nr[2],nr[3],mark_active_tris,
134                         mark_active_interior,NULL,NULL);
135    smLocator_apply_func(smMesh,nr[2],nr[0],nr[1],mark_active_tris,
136                         mark_active_interior,NULL,NULL);
137    /* Right face triangles */
138    smLocator_apply_func(smMesh,nr[0],far[3],far[0],mark_active_tris,
139                         mark_active_interior,NULL,NULL);
140    smLocator_apply_func(smMesh,far[3],nr[0],nr[3],mark_active_tris,
141                         mark_active_interior,NULL,NULL);
142    /* Left face triangles */
143    smLocator_apply_func(smMesh,nr[1],far[2],nr[2],mark_active_tris,
144                         mark_active_interior,NULL,NULL);
145    smLocator_apply_func(smMesh,far[2],nr[1],far[1],mark_active_tris,
146                         mark_active_interior,NULL,NULL);
147    /* Top face triangles */
148    smLocator_apply_func(smMesh,nr[0],far[0],nr[1],mark_active_tris,
149                         mark_active_interior,NULL,NULL);
150    smLocator_apply_func(smMesh,nr[1],far[0],far[1],mark_active_tris,
151                         mark_active_interior,NULL,NULL);
152    /* Bottom face triangles */
153    smLocator_apply_func(smMesh,nr[3],nr[2],far[3],mark_active_tris,
154                         mark_active_interior,NULL,NULL);
155    smLocator_apply_func(smMesh,nr[2],far[2],far[3],mark_active_tris,
156                         mark_active_interior,NULL,NULL);
157    /* Far face triangles */
158    smLocator_apply_func(smMesh,far[0],far[2],far[1],mark_active_tris,
159                         mark_active_interior,NULL,NULL);
160    
161    smLocator_apply_func(smMesh,far[2],far[0],far[3],mark_active_tris,
162                         mark_active_interior,NULL,NULL);
163 #ifdef TEST_DRIVER
164    VCOPY(FrustumFar[0],far[0]);
165    VCOPY(FrustumFar[1],far[1]);
166    VCOPY(FrustumFar[2],far[2]);
167    VCOPY(FrustumFar[3],far[3]);
168    VCOPY(FrustumNear[0],nr[0]);
169    VCOPY(FrustumNear[1],nr[1]);
170    VCOPY(FrustumNear[2],nr[2]);
171    VCOPY(FrustumNear[3],nr[3]);
172 #endif
173 }
174
175 /*
176 * smClean()            : display has been wiped clean
177 *
178 * Called after display has been effectively cleared, meaning that all
179 * geometry must be resent down the pipeline in the next call to smUpdate().
180 */
181 smClean()
182 {
85      smClean_notify = TRUE;
86 +    smCompute_mapping = tmflag;
87   }
88  
89   int
90   qtCache_init(nel)               /* initialize for at least nel elements */
91   int     nel;
92   {
93 <        static int  hsiztab[] = {
94 <                8191, 16381, 32749, 65521, 131071, 262139, 524287, 1048573, 0
95 <        };
96 <        register int  i;
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((char *)qt_htbl);
101 <                        qt_htbl = NULL;
102 <                        qt_hsiz = 0;
200 <                }
201 <                return(0);
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 <        nel += nel>>1;                  /* 66% occupancy */
105 <        for (i = 0; hsiztab[i]; i++)
106 <                if (hsiztab[i] > nel)
107 <                        break;
108 <        if (!(qt_hsiz = hsiztab[i]))
109 <                qt_hsiz = nel*2 + 1;            /* not always prime */
110 <        qt_htbl = (QT_LUENT *)calloc(qt_hsiz, sizeof(QT_LUENT));
111 <        if (qt_htbl == NULL)
112 <                qt_hsiz = 0;
113 <        for (i = qt_hsiz; i--; )
114 <                qt_htbl[i].qt = EMPTY;
115 <        return(qt_hsiz);
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   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;
124 >    int i, n;
125 >    register int        ndx;
126 >    register QT_LUENT   *le;
127  
128 <        if (qt_hsiz == 0 && !qtCache_init(1))
129 <                return(NULL);
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 <        }
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((char *)le);
152 <        goto tryagain;                  /* should happen only once! */
148 >    while (ndx--)
149 >       if (!QT_IS_EMPTY(le[ndx].qt))
150 >          *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 */
# Line 264 | Line 167 | register QUADTREE qt;
167      stCount_level_leaves(lcnt+1, QT_NTH_CHILD(qt,3));
168    }
169    else
170 <    lcnt[0]++;
170 >    if(QT_LEAF_IS_FLAG(qt))
171 >      lcnt[0]++;
172   }
173  
270
174   QTRAVG *
175   qtRender_level(qt,v0,v1,v2,sm,lvl)
176   QUADTREE qt;
# Line 284 | Line 187 | int lvl;
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,a,c,sm,lvl-1);
199 <    rc[1] = qtRender_level(QT_NTH_CHILD(qt,1),a,v1,b,sm,lvl-1);
200 <    rc[2] = qtRender_level(QT_NTH_CHILD(qt,2),c,b,v2,sm,lvl-1);
201 <    rc[3] = qtRender_level(QT_NTH_CHILD(qt,3),b,c,a,sm,lvl-1);
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! */
# Line 314 | Line 219 | int lvl;
219      }
220      else
221      {                                   /* from triangle set */
222 <      OBJECT *os;
223 <      int s0, s1, s2;
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 (n = os[0]; n; n--)
228 >      for (i = os[0]; i; i--)
229        {
230 <        tri = SM_NTH_TRI(sm,os[n]);
231 <        s0 = T_NTH_V(tri,0);
232 <        s1 = T_NTH_V(tri,1);
233 <        s2 = T_NTH_V(tri,2);
234 <        VCOPY(a,SM_NTH_WV(sm,s0));
235 <        VCOPY(b,SM_NTH_WV(sm,s1));
236 <        VCOPY(c,SM_NTH_WV(sm,s2));            
237 <        distsum += SM_BG_SAMPLE(sm,s0) ? dev_zmax
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
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];
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*os[0];
263 >      n *= 3;
264      }
265      if (!n)
266        return(NULL);
# Line 358 | Line 278 | int lvl;
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]);
361    /* NOTE: Triangle vertex order may change */
362    glVertex3d(c[0],c[1],c[2]);
363    glVertex3d(b[0],b[1],b[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 < smRender_stree_level(sm,lvl)
290 > smRender_approx_stree_level(sm,lvl)
291   SM *sm;
292   int lvl;
293   {
294 <  QUADTREE root;
294 >  QUADTREE qt;
295    int i;
296    FVECT t0,t1,t2;
297 <
298 <  if (lvl < 1)
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 < 4; i++)
305 >  for(i=0; i < ST_NUM_ROOT_NODES; i++)
306    {
307 <    root = ST_NTH_ROOT(SM_LOCATOR(sm),i);
308 <    stNth_base_verts(SM_LOCATOR(sm),i,t0,t1,t2);
309 <    qtRender_level(root,t0,t1,t2,sm,lvl-1);
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 <
316 < smRender_stree(sm, qual)        /* render some quadtree triangles */
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, ntarget;
333 >  int i, n,ntarget;
334    int lvlcnt[QT_MAX_LEVELS];
335 +  STREE *st;
336 +  int32 *active_flag;
337  
338    if (qual <= 0)
339      return;
340 +  smCull(sm,view,SM_ALL_LEVELS);
341                                  /* compute rendering target */
342    ntarget = 0;
343 <  SM_FOR_ALL_ACTIVE_TRIS(sm,i)
344 <    ntarget++;
345 <  ntarget = ntarget*qual/100;
343 >
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 >  ntarget = ntarget*qual/MAXQUALITY;
352    if (!ntarget)
353      return;
354    for (i = QT_MAX_LEVELS; i--; )
355      lvlcnt[i] = 0;
356 <  stCount_level_leaves(lvlcnt, SM_LOCATOR(sm)->root);
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_stree_level(sm,i);
365 >  smRender_approx_stree_level(sm,i);
366   }
367  
368  
369 < smRender_tri(sm,i,vp,clr)
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 > * 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 > 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 >  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_bg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
479   SM *sm;
423 int i;
480   FVECT vp;
481 < int clr;
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;
428  double ptr[3];
429  int j;
489  
490 <  tri = SM_NTH_TRI(sm,i);
432 <  if (clr) SM_CLEAR_NTH_T_NEW(sm,i);
490 >  glMatrixMode(GL_MODELVIEW);
491  
492 <  /* NOTE:Triangles are defined clockwise:historical relative to spherical
493 <     tris: could change
494 <     */
495 <  for(j=2; j>= 0; j--)
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 < #ifdef DEBUG
500 <    if(SM_BG_SAMPLE(sm,T_NTH_V(tri,j)))
441 <      eputs("SmRenderTri(): shouldnt have bg samples\n");
442 < #endif
443 <    glColor3ub(SM_NTH_RGB(sm,T_NTH_V(tri,j))[0],
444 <               SM_NTH_RGB(sm,T_NTH_V(tri,j))[1],
445 <               SM_NTH_RGB(sm,T_NTH_V(tri,j))[2]);
446 <    VCOPY(ptr,SM_T_NTH_WV(sm,tri,j));
447 <    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 < smRender_mixed_tri(sm,i,vp,clr)
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;
453 int i;
544   FVECT vp;
545 < int clr;
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;
458  double p[3],d;
459  int j,ids[3],cnt;
460  int rgb[3];
553  
554 <  tri = SM_NTH_TRI(sm,i);
463 <  if (clr) SM_CLEAR_NTH_T_NEW(sm,i);
554 >  glMatrixMode(GL_MODELVIEW);
555  
556 <  /* NOTE:Triangles are defined clockwise:historical relative to spherical
557 <     tris: could change
558 <     */
559 <  cnt = 0;
560 <  d = 0.0;
561 <  rgb[0] = rgb[1] = rgb[2] = 0;
471 <  for(j=0;j < 3;j++)
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 <      ids[j] = T_NTH_V(tri,j);
564 <      if(!SM_BG_SAMPLE(sm,ids[j]))
475 <      {
476 <          rgb[0] += SM_NTH_RGB(sm,ids[j])[0];
477 <          rgb[1] += SM_NTH_RGB(sm,ids[j])[1];
478 <          rgb[2] += SM_NTH_RGB(sm,ids[j])[2];
479 <          cnt++;
480 <          d += DIST(vp,SM_NTH_WV(sm,ids[j]));
481 <      }
563 >    d = (dev_zmin+dev_zmax)/2.0;
564 >    glScaled(d,d,d);
565    }
566 <  if(cnt > 1)
567 <  {
568 <    rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
569 <    d /= (double)cnt;
570 <  }
571 <  for(j=2; j>= 0; j--)
572 <  {
573 <    if(SM_BG_SAMPLE(sm,ids[j]))
574 <    {
575 <        glColor3ub(rgb[0],rgb[1],rgb[2]);
576 <        VSUB(p,SM_NTH_WV(sm,ids[j]),SM_VIEW_CENTER(sm));
577 <        p[0] *= d;
578 <        p[1] *= d;
579 <        p[2] *= d;
580 <        VADD(p,p,SM_VIEW_CENTER(sm));
581 <    }
582 <    else
583 <    {
584 <        glColor3ub(SM_NTH_RGB(sm,ids[j])[0],SM_NTH_RGB(sm,ids[j])[1],
585 <                   SM_NTH_RGB(sm,ids[j])[2]);
586 <        VCOPY(p,SM_NTH_WV(sm,ids[j]));
587 <    }
588 <    glVertex3d(p[0],p[1],p[2]);
589 <   }
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 < smRender_bg_tri(sm,i,vp,d,clr)
597 < SM *sm;
598 < int i;
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 < double d;
514 < int clr;
611 > int b0,b1,b2;
612   {
613 +  int cnt;
614 +  int rgb[3];
615 +  double d;
616    double p[3];
517  int j,id;
518  TRI *tri;
519  
520  tri = SM_NTH_TRI(sm,i);
521  if (clr) SM_CLEAR_NTH_T_NEW(sm,i);
617  
618 <  /* NOTE:Triangles are defined clockwise:historical relative to spherical
619 <     tris: could change
620 <     */
621 <  for(j=2; j>= 0; j--)
618 >  cnt = 0;
619 >  rgb[0] = rgb[1] = rgb[2] = 0;
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 <      id = T_NTH_V(tri,j);
629 <      glColor3ub(SM_NTH_RGB(sm,id)[0],SM_NTH_RGB(sm,id)[1],
630 <                 SM_NTH_RGB(sm,id)[2]);
531 <      VSUB(p,SM_NTH_WV(sm,id),SM_VIEW_CENTER(sm));
532 <      if(dev_zmin >= 0.99)
533 <       {
534 <           p[0] *= d;
535 <           p[1] *= d;
536 <           p[2] *= d;
537 <       }
538 <      VADD(p,p,vp);
539 <      glVertex3d(p[0],p[1],p[2]);
628 >    IADDV3(rgb,rgb0);
629 >    d += DIST(v0,vp);
630 >    cnt++;
631    }
632 +  if(!b1)
633 +  {
634 +    IADDV3(rgb,rgb1);
635 +    d += DIST(v1,vp);
636 +    cnt++;
637 +  }
638 +  if(!b2)
639 +  {
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,clr)
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 < int clr;
702 > int32  *t_flag,*bg_flag;
703 > SFLOAT (*wp)[3];
704 > BYTE  (*rgb)[3];
705   {
548  int i;
706    TRI *tri;
707 <  double ptr[3],d;
708 <  int j;
552 <
553 <  d = (dev_zmin+dev_zmax)/2.0;
554 <  glPushAttrib(GL_DEPTH_BUFFER_BIT);
707 >  int i,n,b0,b1,b2;
708 >  S_ID v0_id,v1_id,v2_id;
709    
556  /* First draw background polygons */
557
558  glDisable(GL_DEPTH_TEST);
710    glBegin(GL_TRIANGLES);
711 <  SM_FOR_ALL_ACTIVE_BG_TRIS(sm,i)
712 <     smRender_bg_tri(sm,i,vp,d,clr);
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();
563  
564  glEnable(GL_DEPTH_TEST);
565  glBegin(GL_TRIANGLES);
566  SM_FOR_ALL_ACTIVE_FG_TRIS(sm,i)
567  {
568      if(!SM_MIXED_TRI(sm,i))
569        smRender_tri(sm,i,vp,clr);
570     else
571        smRender_mixed_tri(sm,i,vp,clr);
572  }
573  glEnd();
732  
575  glPopAttrib();
733   }
734  
735 < smRender_tri_edges(sm,i)
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  
586
587  tri = SM_NTH_TRI(sm,i);
588
589  /* Triangles are defined clockwise:historical relative to spherical
590     tris: could change
591     */
592  for(j=2; j >=0; j--)
593  {
594    VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,j)));
595    glVertex3d(ptr[0],ptr[1],ptr[2]);
596    VCOPY(ptr,SM_NTH_WV(sm,T_NTH_V(tri,(j+1)%3)));
597    glVertex3d(ptr[0],ptr[1],ptr[2]);
598  }
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;
607  
788    if(d > 0.0)
789      return(1);
790    if(d < 0.0)
791      return(-1);
612  
792    return(0);
793   }
794  
795 < LIST
796 < *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   FVECT vp;
620 T_DEPTH *td;
809   {
810 <  int i,j,t_id,v;
810 >  T_DEPTH *td;
811 >  int n,i,j,tcnt,v,size;
812    TRI *tri;
813    double d,min_d;
814 <  LIST *tlist=NULL;
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(SM_BG_TRI(sm,t_id))
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 <        tlist = push_data(tlist,t_id);
927 <        continue;
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 < #ifdef DEBUG
945 <    if(i >= smNew_tri_cnt)
943 >    glEnd();
944 >    freebuf(td);
945 >  }
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 >  if(QT_IS_LEAF(qt) || level == max_level)
988 >  {
989 >    if(QT_IS_LEAF(qt))
990      {
991 <      eputs("smDepth_sort_tris():More tris than reported by smNew_tri_cnt\n");
992 <      break;
991 >      if(!QT_LEAF_IS_FLAG(qt))
992 >        return;
993      }
994 < #endif
995 <    td[i].tri = t_id;
996 <    min_d = -1;
997 <    for(j=0;j < 3;j++)
994 >    else
995 >      if(!QT_IS_FLAG(qt))
996 >        return;
997 >
998 >    if(!Display_lists[i][which])
999      {
1000 <        v = T_NTH_V(tri,j);
1001 <        if(!SM_BG_SAMPLE(sm,v))
1002 <        {
1003 <            d = DIST(vp,SM_NTH_WV(sm,v));
1004 <            if(min_d == -1 || d < min_d)
1005 <               min_d = d;
1006 <        }
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 <    td[i].depth = min_d;
1009 <    i++;
1008 >    else
1009 >    {
1010 >      glCallList(Display_lists[i][which]);
1011 >    }
1012    }
1013 <  td[i].tri = -1;
1014 <  if(i)
1015 <     qsort((void *)td,i,sizeof(T_DEPTH),compare_tri_depths);
1016 <  return(tlist);
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 < smUpdate_Rendered_mesh(sm,vp,clr)
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 + QUADTREE qt;
1040   FVECT vp;
1041 < int clr;
1041 > SFLOAT (*wp)[3];
1042 > BYTE  (*rgb)[3];
1043 > int which,cull;
1044   {
670  static T_DEPTH *td= NULL;
671  static int tsize = 0;
1045    int i;
1046 <  GLint depth_test;
1047 <  double d;
1048 <  LIST *bglist;
1049 <  /* For all of the NEW triangles (since last update): assume
1050 <     ACTIVE. Go through and sort on depth value (from vp). Turn
678 <     Depth Buffer test off and render back-front
679 <     */
680 <  /* NOTE: could malloc each time or hard code */
681 <  if(smNew_tri_cnt > tsize)
1046 >  
1047 >  if(QT_IS_EMPTY(qt))
1048 >    return;
1049 >
1050 >  if(QT_IS_LEAF(qt))
1051    {
1052 <    if(td)
1053 <      free((char *)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 <  bglist = 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  
1114 <  /* Turn Depth Test off -- using Painter's algorithm */
1114 >
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 <  d = (dev_zmin+dev_zmax)/2.0;
1147 <  /* Now render back-to front */
1148 <  /* First render bg triangles */
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 <  while(bglist)
1168 <     smRender_bg_tri(sm,pop_list(&bglist),vp,d,clr);
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 <  i=0;
1177 <  while(td[i].tri != -1)
709 <     if(!SM_MIXED_TRI(sm,td[i].tri))
710 <        smRender_tri(sm,td[i++].tri,vp,clr);
711 <     else
712 <        smRender_mixed_tri(sm,td[i++].tri,vp,clr);
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  
715  /* 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(view, qua)  : update OpenGL output geometry for view vp
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   *
# Line 725 | Line 1457 | int clr;
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().  (The last view drawn will
1460 > * been output since the last call to smClean().(The last view drawn will
1461   * be view==&odev.v each time.)
1462   */
1463   smUpdate(view,qual)
1464     VIEW *view;
1465     int qual;
1466   {
1467 <  double d;
1468 <  int last_update;
1469 <  int t;
1470 <
1471 <  /* If view has moved beyond epsilon from canonical: must rebuild -
1472 <     epsilon is calculated as running avg of distance of sample points
1473 <     from canonical view: m = 1/(AVG(1/r)): some fraction of this
742 <   */
743 <  d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
744 <  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 <      /* Re-build the mesh */
1476 < #ifdef TEST_DRIVER
1477 <    odev.v = *view;
1478 < #endif    
1479 <      smRebuild_mesh(smMesh,view->vp);
1475 >    if(smIncremental)
1476 >      smUpdate_tm(smMesh);
1477 >
1478 >    /* Render mesh using display lists */
1479 >    smRender(smMesh,view,qual);
1480 >    return;
1481    }
1482 <  /* This is our final update iff qual==100 and view==&odev.v */
1483 <  last_update = qual>=100 && view==&(odev.v);
1484 <  /* Check if we should draw ALL triangles in current frustum */
1485 <  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 <    if (SM_TONE_MAP(smMesh) < SM_NUM_SAMP(smMesh))
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 >  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 <                   tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
766 <                                SM_NUM_SAMP(smMesh)) != TM_E_OK)
767 <            return;
1501 >      if(smIncremental)
1502 >        smUpdate_tm(smMesh);
1503 >      smIncremental = FALSE;
1504 >      smRender(smMesh,view,qual);
1505      }
769 #endif
770    mark_tris_in_frustum(view);
771    if (qual <= 75)
772        smRender_stree(smMesh,qual);
1506      else
774        smRender_mesh(smMesh,view->vp,last_update);
775 #ifdef TEST_DRIVER
776    glFlush();
777    glutSwapBuffers();
778 #endif
779  }
780  /* Do an incremental update instead */
781  else
782  {  
783    if(!smNew_tri_cnt)
784      return;
785 #ifdef TEST_DRIVER
786    glDrawBuffer(GL_FRONT);
787 #else
788    t = SM_TONE_MAP(smMesh);
789    if(t == 0)
1507      {
1508 <        tmClearHisto();
1509 <        tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
1510 <        if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
1511 <           return;
1512 <    }
1513 <    if(tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
1514 <                   SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t) != TM_E_OK)
1515 <          return;
1516 < #endif    
800 <    smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
801 <    
802 < #ifdef TEST_DRIVER
803 <    glDrawBuffer(GL_BACK);
804 < #endif
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);
1519 <  if (last_update)
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 <    smNew_tri_cnt = 0;
1524 <    smClear_flags(smMesh,T_NEW_FLAG);
1523 >    if(smIncremental)
1524 >      smClear_flags(smMesh,T_NEW_FLAG);
1525      qtCache_init(0);
1526    }
1527  
1528   }
1529 +
1530 +
1531 +
1532 +
1533 +
1534 +
1535 +

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines