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.12 by gwlarson, Tue Jan 5 16:52:38 1999 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  
14 #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"
22 #include "sm_qtree.h"
23 #include "sm_stree.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 45 | 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   /*
76 <  * smClean()           : display has been wiped clean
77 <  *
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()
82 > smClean(tmflag)
83 >   int tmflag;
84   {
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;
75 <                }
76 <                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 >          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 */
# Line 143 | Line 171 | register QUADTREE qt;
171        lcnt[0]++;
172   }
173  
146
174   QTRAVG *
175   qtRender_level(qt,v0,v1,v2,sm,lvl)
176   QUADTREE qt;
# Line 192 | Line 219 | int lvl;
219      }
220      else
221      {                                   /* from triangle set */
222 <      OBJECT *os;
223 <      int s0, s1, s2;
224 <      
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 <        if(SM_IS_NTH_T_BASE(sm,os[i]))
231 <           continue;
232 <        tri = SM_NTH_TRI(sm,os[i]);
233 <        if(!T_IS_VALID(tri))
234 <          continue;
235 <        n++;
236 <        s0 = T_NTH_V(tri,0);
237 <        s1 = T_NTH_V(tri,1);
238 <        s2 = T_NTH_V(tri,2);
239 <        VCOPY(a,SM_NTH_WV(sm,s0));
240 <        VCOPY(b,SM_NTH_WV(sm,s1));
241 <        VCOPY(c,SM_NTH_WV(sm,s2));            
242 <        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;
264      }
# Line 250 | Line 287 | int lvl;
287   }
288  
289  
290 < smRender_stree_level(sm,lvl)
290 > smRender_approx_stree_level(sm,lvl)
291   SM *sm;
292   int lvl;
293   {
# Line 258 | Line 295 | int lvl;
295    int i;
296    FVECT t0,t1,t2;
297    STREE *st;
261
298    
299    if (lvl < 0)
300      return;
# Line 276 | Line 312 | int lvl;
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--; )
# Line 305 | Line 362 | int qual;
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 + #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]);  glVertex3fv(v0); \
374 <  glColor3ub(rgb1[0],rgb1[1],rgb1[2]);  glVertex3fv(v1); \
375 <  glColor3ub(rgb2[0],rgb2[1],rgb2[2]);  glVertex3fv(v2);} \
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 < render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,bg0,bg1,bg2,vp,vc)
378 < float v0[3],v1[3],v2[3];
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];
321 int bg0,bg1,bg2;
392   FVECT vp,vc;
393 + int bg0,bg1,bg2;
394   {
395 <  double p[3],d;
396 <  int j,ids[3],cnt;
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;
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;
489 >
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 >    d = (dev_zmin+dev_zmax)/2.0;
500 >    glScaled(d,d,d);
501 >  }
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 >  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;
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;
553 >
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  
328  /* NOTE:Triangles are defined clockwise:historical relative to spherical
329     tris: could change
330     */
618    cnt = 0;
332  d = 0.0;
619    rgb[0] = rgb[1] = rgb[2] = 0;
620 <
621 <  if(bg0 && bg1 && bg2)
620 >  d = 0.0;
621 >  /* If all vertices are base: don't render */
622 >  if(b0&&b1&&b2)
623      return;
624 <
625 <  if(!bg0)
624 >  /* First calculate color and coordinates
625 >     for base vertices based on world space vertices*/
626 >  if(!b0)
627    {
628 <    rgb[0] += rgb0[0];
629 <    rgb[1] += rgb0[1];
342 <    rgb[2] += rgb0[2];
628 >    IADDV3(rgb,rgb0);
629 >    d += DIST(v0,vp);
630      cnt++;
344    d += DIST(vp,v0);
631    }
632 <  if(!bg1)
632 >  if(!b1)
633    {
634 <    rgb[0] += rgb1[0];
635 <    rgb[1] += rgb1[1];
350 <    rgb[2] += rgb1[2];
634 >    IADDV3(rgb,rgb1);
635 >    d += DIST(v1,vp);
636      cnt++;
352    d += DIST(vp,v1);
637    }
638 <  if(!bg2)
638 >  if(!b2)
639    {
640 <    rgb[0] += rgb2[0];
641 <    rgb[1] += rgb2[1];
358 <    rgb[2] += rgb2[2];
640 >    IADDV3(rgb,rgb2);
641 >    d += DIST(v2,vp);
642      cnt++;
360    d += DIST(vp,v2);
643    }
644 <  if(cnt > 1)
644 >  IDIVV3(rgb,cnt);
645 >  d /= (double)cnt;
646 >  
647 >  /* Now render triangle */
648 >  if(b0)
649    {
364    rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
365    d /= (double)cnt;
366  }
367  if(bg0)
368  {
650      glColor3ub(rgb[0],rgb[1],rgb[2]);
651 <    VSUB(p,v0,vc);
652 <    p[0] *= d;
653 <    p[1] *= d;
654 <    p[2] *= d;
374 <    VADD(p,p,vc);
375 <    glVertex3dv(p);
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 <    glVertex3fv(v0);
660 <   }
661 <  if(bg1)
659 >    GLVERTEX3V(v0);
660 >  }
661 >  if(b1)
662    {
663      glColor3ub(rgb[0],rgb[1],rgb[2]);
664 <    VSUB(p,v1,vc);
665 <    p[0] *= d;
666 <    p[1] *= d;
388 <    p[2] *= d;
389 <    VADD(p,p,vc);
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 <    glVertex3fv(v1);
673 <   }
674 <  if(bg2)
672 >    GLVERTEX3V(v1);
673 >  }
674 >  if(b2)
675    {
676      glColor3ub(rgb[0],rgb[1],rgb[2]);
677 <    VSUB(p,v2,vc);
678 <    p[0] *= d;
679 <    p[1] *= d;
403 <    p[2] *= d;
404 <    VADD(p,p,vc);
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 <    glVertex3fv(v2);
686 <   }
412 <
685 >    GLVERTEX3V(v2);
686 >  }
687   }
688 <
689 < render_bg_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,d)
690 < float v0[3],v1[3],v2[3];
691 < BYTE rgb0[3],rgb1[3],rgb2[3];
692 < FVECT vp,vc;
693 < double d;
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   {
706 <  double p[3];
706 >  TRI *tri;
707 >  int i,n,b0,b1,b2;
708 >  S_ID v0_id,v1_id,v2_id;
709    
710 <  glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
711 <  VSUB(p,v0,vc);
712 <  if(dev_zmin >= 0.99)
713 <  {
714 <    p[0] *= d;
715 <    p[1] *= d;
716 <    p[2] *= d;
717 <  }
718 <  VADD(p,p,vp);
719 <  glVertex3dv(p);
710 >  glBegin(GL_TRIANGLES);
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 <  glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
731 <  VSUB(p,v1,vc);
436 <  if(dev_zmin >= 0.99)
437 <  {
438 <    p[0] *= d;
439 <    p[1] *= d;
440 <    p[2] *= d;
441 <  }
442 <  VADD(p,p,vp);
443 <  glVertex3dv(p);
730 >         }
731 >  glEnd();
732  
445
446  glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
447  VSUB(p,v2,vc);
448  if(dev_zmin >= 0.99)
449  {
450    p[0] *= d;
451    p[1] *= d;
452    p[2] *= d;
453  }
454  VADD(p,p,vp);
455  glVertex3dv(p);
456
733   }
734  
735 < smRender_mesh(sm,vp,clr)
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   FVECT vp;
749 < int clr;
749 > int32  *new_flag,*active_flag,*bg_flag;
750 > SFLOAT (*wp)[3];
751 > BYTE  (*rgb)[3];
752   {
464  int i,bg0,bg1,bg2;
465  double d;
466  int v0_id,v1_id,v2_id;
753    TRI *tri;
754 <  float (*wp)[3];
755 <  BYTE  (*rgb)[3];
470 <
471 <  wp = SM_WP(sm);
472 <  rgb =SM_RGB(sm);
473 <  d = (dev_zmin+dev_zmax)/2.0;
474 <  glPushAttrib(GL_DEPTH_BUFFER_BIT);
754 >  int i,n,b0,b1,b2;
755 >  S_ID v0_id,v1_id,v2_id;
756    
476  /* First draw background polygons */
477  glDisable(GL_DEPTH_TEST);
757    glBegin(GL_TRIANGLES);
758 <  /* Maintain a list? */
759 <  SM_FOR_ALL_ACTIVE_BG_TRIS(sm,i)
760 <  {
761 <    if (clr)
762 <      SM_CLR_NTH_T_NEW(sm,i);
763 <    tri = SM_NTH_TRI(sm,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 <    render_bg_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
768 <                   rgb[v2_id],vp,SM_VIEW_CENTER(sm),d);
769 <  }
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();
492  glEnable(GL_DEPTH_TEST);
493  glBegin(GL_TRIANGLES);
494  SM_FOR_ALL_ACTIVE_FG_TRIS(sm,i)
495  {
496    if (clr)
497      SM_CLR_NTH_T_NEW(sm,i);
498    tri = SM_NTH_TRI(sm,i);
499    v0_id = T_NTH_V(tri,0);
500    v1_id = T_NTH_V(tri,1);
501    v2_id = T_NTH_V(tri,2);
502    bg0 = SM_DIR_ID(sm,v0_id) || SM_BASE_ID(sm,v0_id);
503    bg1 = SM_DIR_ID(sm,v1_id) || SM_BASE_ID(sm,v1_id);
504    bg2 = SM_DIR_ID(sm,v2_id) || SM_BASE_ID(sm,v2_id);
505    if(!(bg0 || bg1 || bg2))
506        render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
507                   rgb[v2_id])
508   else
509        render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
510           rgb[v2_id],bg0,bg1,bg2,vp,SM_VIEW_CENTER(sm));
511  }
512  glEnd();
778  
514  glPopAttrib();
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  
522  if(td1->tri==-1)
523    {
524      if(td2->tri==-1)
525        return(0);
526      else
527        return(-1);
528    }
529  if(td2->tri==-1)
530    return(1);
531
787    d = td2->depth-td1->depth;
533  
788    if(d > 0.0)
789      return(1);
790    if(d < 0.0)
791      return(-1);
538  
792    return(0);
793   }
794  
542 int
543 compare_tri_depths_old(T_DEPTH *td1,T_DEPTH *td2)
544 {
545  double d;
795  
796 <  d = td2->depth-td1->depth;
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;
809 > {
810 >  T_DEPTH *td;
811 >  int n,i,j,tcnt,v,size;
812 >  TRI *tri;
813 >  double d,min_d;
814 >  FVECT diff;
815 >  int32 *new_flag,*bg_flag,*active_flag;
816    
817 <  if(d > 0.0)
818 <    return(1);
819 <  if(d < 0.0)
820 <    return(-1);
821 <  
822 <  return(0);
817 > td = (T_DEPTH *)tempbuf(NEW_TRI_CNT*sizeof(T_DEPTH),FALSE);
818 > size = NEW_TRI_CNT;
819 >
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 < LIST
854 < *smDepth_sort_tris(sm,vp,td)
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 +    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;
561 T_DEPTH *td;
891   {
892 <  int i,j,t_id,v;
892 >  S_ID v0_id,v1_id,v2_id;
893 >  int i,n,b0,b1,b2;
894    TRI *tri;
895 <  double d,min_d;
896 <  LIST *tlist=NULL;
897 <  FVECT diff;
895 >  SFLOAT (*wp)[3];
896 >  BYTE  (*rgb)[3];
897 >  int32  *new_flag,*bg_flag,*active_flag;
898 >  T_DEPTH *td = NULL;
899  
900 <  i = 0;
901 <  SM_FOR_ALL_NEW_TRIS(sm,t_id)
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 <    if(SM_BG_TRI(sm,t_id))
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 <    td[i].tri = t_id;
579 <    min_d = -1;
580 <    for(j=0;j < 3;j++)
581 <    {
582 <        v = T_NTH_V(tri,j);
583 <        if(!SM_BG_SAMPLE(sm,v))
584 <        {
585 <            VSUB(diff,SM_NTH_WV(sm,v),vp);
586 <            d = DOT(diff,diff);
587 <            if(min_d == -1 || d < min_d)
588 <               min_d = d;
589 <        }
590 <    }
591 <    td[i].depth = min_d;
592 <    i++;
943 >    glEnd();
944 >    freebuf(td);
945    }
946 <  td[i].tri = -1;
947 <  if(i)
596 <     qsort((void *)td,i,sizeof(T_DEPTH),compare_tri_depths);
597 <  return(tlist);
946 >  /* Restore Depth Test */
947 >  glPopAttrib();
948   }
949  
950 <
951 <
952 < LIST
953 < *smOrder_new_tris(sm,vp,td,sort)
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 < T_DEPTH *td;
978 < int sort;
977 > SFLOAT (*wp)[3];
978 > BYTE  (*rgb)[3];
979 > int i,level_i,level,max_level,leaf_cnt;
980 > int which;
981   {
982 <  int i,j,t_id,v;
983 <  TRI *tri;
984 <  double d,min_d;
985 <  LIST *tlist=NULL;
613 <  FVECT diff;
982 >  int j;
983 >  
984 >  if(QT_IS_EMPTY(qt))
985 >    return;
986  
987 <  i = 0;
616 <  for(i=0; i < smNew_tri_cnt;i++)
987 >  if(QT_IS_LEAF(qt) || level == max_level)
988    {
989 <    t_id = smNew_tris[i].tri;
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 <    tri = SM_NTH_TRI(sm,t_id);
621 <    if(!T_IS_VALID(tri))
998 >    if(!Display_lists[i][which])
999      {
1000 <      smNew_tris[i].tri = -1;
1001 <      continue;
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 <    if(SM_BG_TRI(sm,t_id))
1008 >    else
1009      {
1010 <        tlist = push_data(tlist,t_id);
629 <        smNew_tris[i].tri = -1;
630 <        continue;
1010 >      glCallList(Display_lists[i][which]);
1011      }
1012 <    if(!sort)
1013 <      continue;
1014 <    min_d = -1;
635 <    for(j=0;j < 3;j++)
1012 >  }
1013 >  else
1014 >    if(QT_IS_FLAG(qt))
1015      {
1016 <        v = T_NTH_V(tri,j);
1017 <        if(!SM_BG_SAMPLE(sm,v))
1018 <        {
1019 <            VSUB(diff,SM_NTH_WV(sm,v),vp);
1020 <            d = DOT(diff,diff);
1021 <            if(min_d == -1 || d < min_d)
643 <               min_d = d;
644 <        }
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 <    td[i].depth = min_d;
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 > QUADTREE qt;
1040 > FVECT vp;
1041 > SFLOAT (*wp)[3];
1042 > BYTE  (*rgb)[3];
1043 > int which,cull;
1044 > {
1045 >  int i;
1046 >  
1047 >  if(QT_IS_EMPTY(qt))
1048 >    return;
1049 >
1050 >  if(QT_IS_LEAF(qt))
1051 >  {
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(!sort)
1109 <    return(tlist);
1110 <  qsort((void *)td,smNew_tri_cnt,sizeof(T_DEPTH),compare_tri_depths);
1111 <  return(tlist);
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  
1115 < smUpdate_Rendered_mesh(sm,vp,clr)
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 < FVECT vp;
1129 < int clr;
1128 > VIEW *view;
1129 > int cull;
1130   {
1131 <  static T_DEPTH *td= NULL;
661 <  static int tsize = 0;
662 <  int i,v0_id,v1_id,v2_id,bg0,bg1,bg2;
663 <  GLint depth_test;
664 <  double d;
665 <  LIST *bglist;
666 <  TRI *tri;
667 <  float (*wp)[3];
1131 >  SFLOAT (*wp)[3];
1132    BYTE  (*rgb)[3];
1133 +  int i;
1134 +  STREE *st= SM_LOCATOR(sm);
1135  
1136 <  /* For all of the NEW triangles (since last update): assume
1137 <     ACTIVE. Go through and sort on depth value (from vp). Turn
1138 <     Depth Buffer test off and render back-front
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 <  /* NOTE: could malloc each time or hard code */
675 < #if 0
676 <  if(smNew_tri_cnt > tsize)
1155 >  if(dev_zmin >= 0.99)
1156    {
1157 <    if(td)
1158 <      free((char *)td);
1159 <    td = (T_DEPTH *)malloc(smNew_tri_cnt*sizeof(T_DEPTH));
1160 <    tsize = smNew_tri_cnt;
1157 >    double d;
1158 >
1159 >    d = (dev_zmin+dev_zmax)/2.0;
1160 >    glScaled(d,d,d);
1161    }
1162 <  if(!td)
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 < 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 < 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 >
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 <    error(SYSTEM,"smUpdate_Rendered_mesh:Cannot allocate memory\n");
1200 <  }
1201 <  bglist = smDepth_sort_tris(sm,vp,td);
1202 < #else
1203 <  td = smNew_tris;
1204 <  if(!EQUAL_VEC3(SM_VIEW_CENTER(sm),vp))
1205 <    bglist = smOrder_new_tris(sm,vp,td,1);
1206 <  else
1207 <    bglist = smOrder_new_tris(sm,vp,td,0);
1208 < #endif
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 <  /* Turn Depth Test off -- using Painter's algorithm */
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 > * 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 <  glDepthFunc(GL_ALWAYS);
1287 <  d = (dev_zmin+dev_zmax)/2.0;
1288 <  /* Now render back-to front */
1289 <  /* First render bg triangles */
1290 <  glBegin(GL_TRIANGLES);
1291 <  while(bglist)
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 <    i = pop_list(&bglist);
1304 <    if (clr)
1305 <      SM_CLR_NTH_T_NEW(sm,i);
1306 <    tri = SM_NTH_TRI(sm,i);
1307 <    v0_id = T_NTH_V(tri,0);
1308 <    v1_id = T_NTH_V(tri,1);
1309 <    v2_id = T_NTH_V(tri,2);
1310 <    render_bg_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1311 <                   rgb[v2_id],vp,SM_VIEW_CENTER(sm),d);
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 <  glEnd();
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 <  glBegin(GL_TRIANGLES);
1340 <  i=0;
1341 <  while(i != smNew_tri_cnt)
1339 >  if(QT_IS_EMPTY(qt))
1340 >    return;
1341 >  if(QT_IS_LEAF(qt) || level== max_level)
1342    {
1343 <    if(td[i].tri == -1)
1344 <      {
1345 <        i++;
1346 <        continue;
1347 <      }
1348 <    if (clr)
1349 <      SM_CLR_NTH_T_NEW(sm,td[i].tri);
1350 <    tri = SM_NTH_TRI(sm,td[i].tri);
1351 <    v0_id = T_NTH_V(tri,0);
1352 <    v1_id = T_NTH_V(tri,1);
1353 <    v2_id = T_NTH_V(tri,2);
1354 <    bg0 = SM_DIR_ID(sm,v0_id) || SM_BASE_ID(sm,v0_id);
1355 <    bg1 = SM_DIR_ID(sm,v1_id) || SM_BASE_ID(sm,v1_id);
1356 <    bg2 = SM_DIR_ID(sm,v2_id) || SM_BASE_ID(sm,v2_id);
1357 <    if(!(bg0 || bg1 || bg2))
1358 <      render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1359 <                 rgb[v2_id])
1360 <   else
741 <     render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
742 <                      rgb[v2_id],bg0,bg1,bg2,vp,SM_VIEW_CENTER(sm));
743 <    i++;
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 <  glEnd();
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 <  /* Restore Depth Test */
1378 <  glPopAttrib();
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 < * smUpdate(view, qua)  : update OpenGL output geometry for view vp
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 757 | 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;
770 <
771 <  /* If view has moved beyond epsilon from canonical: must rebuild -
772 <     epsilon is calculated as running avg of distance of sample points
773 <     from canonical view: m = 1/(AVG(1/r)): some fraction of this
774 <   */
775 <
776 <  if(!smMesh)
1467 >  
1468 >  /* Is there anything to render? */
1469 >  if(!smMesh || SM_NUM_TRI(smMesh)<=0)
1470      return;
1471 <
1472 <  d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
1473 <  if(qual >= 100 && d > SM_ALLOWED_VIEW_CHANGE(smMesh))
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 <      mark_tris_in_frustum(view);
1480 <      smRebuild_mesh(smMesh,view);
788 <      smClean_notify = TRUE;
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_SAMPLE_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 <       tmComputeMapping(0.,0.,0.);
1504 <       tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
804 <                   SM_NUM_SAMP(smMesh));
1501 >      if(smIncremental)
1502 >        smUpdate_tm(smMesh);
1503 >      smIncremental = FALSE;
1504 >      smRender(smMesh,view,qual);
1505      }
806 #endif
807    mark_tris_in_frustum(view);
808    if (qual <= 75)
809        smRender_stree(smMesh,qual);
1506      else
811        smRender_mesh(smMesh,view->vp,last_update);
812 #ifdef TEST_DRIVER
813    glFlush();
814    glutSwapBuffers();
815 #endif
816  }
817  /* Do an incremental update instead */
818  else
819  {
820      if(!smNew_tri_cnt)
821      return;
822 #ifdef TEST_DRIVER
823    glDrawBuffer(GL_FRONT);
824 #else
825    t = SM_TONE_MAP(smMesh);
826    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 <    tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
1514 <                   SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t);
1515 <        
1516 < #endif    
837 <    smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
838 <    
839 < #ifdef TEST_DRIVER
840 <    glDrawBuffer(GL_BACK);
841 < #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 <
1519 <  SM_TONE_MAP(smMesh) = SM_NUM_SAMP(smMesh);
845 <
846 <  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 < #if 0  
851 <    smClear_flags(smMesh,T_NEW_FLAG);
852 < #endif
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