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.13 by gwlarson, Sun Jan 10 10:27:48 1999 UTC vs.
Revision 3.16 by greg, Sat Feb 22 02:07:25 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 <
68 > /* For DEPTH SORTING ********************************************************/
69   typedef struct _T_DEPTH {
70    int tri;
71    double depth;
72   }T_DEPTH;
73 + /**********************************************************************/
74  
75   /*
76    * smClean(tmflag)     : display has been wiped clean
# Line 63 | Line 83 | smClean(tmflag)
83     int tmflag;
84   {
85      smClean_notify = TRUE;
86 <    if(tmflag)
67 <       SM_TONE_MAP(smMesh) = 0;
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;
84 <                }
85 <                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 152 | Line 171 | register QUADTREE qt;
171        lcnt[0]++;
172   }
173  
155
174   QTRAVG *
175   qtRender_level(qt,v0,v1,v2,sm,lvl)
176   QUADTREE qt;
# Line 201 | 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 259 | 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 267 | Line 295 | int lvl;
295    int i;
296    FVECT t0,t1,t2;
297    STREE *st;
270
298    
299    if (lvl < 0)
300      return;
# Line 285 | 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, n,ntarget;
334    int lvlcnt[QT_MAX_LEVELS];
335    STREE *st;
336    int4 *active_flag;
337 +
338    if (qual <= 0)
339      return;
340 +  smCull(sm,view,SM_ALL_LEVELS);
341                                  /* compute rendering target */
342    ntarget = 0;
343  
# Line 320 | 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];
336 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;
397 <  int rgb[3];
398 <
343 <  /* NOTE:Triangles are defined clockwise:historical relative to spherical
344 <     tris: could change
345 <     */
346 <  if(bg0 && bg1 && bg2)
347 <    return;
348 <
395 >  double d,p[3];
396 >  int j,cnt,rgb[3];
397 >  
398 >  /* Average color from bg vertices */
399    cnt = 0;
400 <  d = 0.0;
401 <  rgb[0] = rgb[1] = rgb[2] = 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 <    rgb[0] += rgb0[0];
428 <    rgb[1] += rgb0[1];
429 <    rgb[2] += rgb0[2];
430 <    cnt++;
359 <    d += DIST(vp,v0);
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 <    rgb[0] += rgb1[0];
443 <    rgb[1] += rgb1[1];
444 <    rgb[2] += rgb1[2];
445 <    cnt++;
367 <    d += DIST(vp,v1);
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 <    rgb[0] += rgb2[0];
458 <    rgb[1] += rgb2[1];
459 <    rgb[2] += rgb2[2];
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 > * int4  *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 > int4 *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 > * int4  *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 > int4 *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 >
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 >    IADDV3(rgb,rgb0);
629 >    d += DIST(v0,vp);
630      cnt++;
375    d += DIST(vp,v2);
631    }
632 <  if(cnt > 1)
632 >  if(!b1)
633    {
634 <    rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
635 <    d /= (double)cnt;
636 <  }
637 <  if(bg0)
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 <    VSUB(p,v0,vc);
652 <    p[0] *= d;
653 <    p[1] *= d;
654 <    p[2] *= d;
389 <    VADD(p,p,vc);
390 <    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;
403 <    p[2] *= d;
404 <    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;
418 <    p[2] *= d;
419 <    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);
426 <   }
427 <
428 < }
429 <
430 < render_bg_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,d)
431 < float v0[3],v1[3],v2[3];
432 < BYTE rgb0[3],rgb1[3],rgb2[3];
433 < FVECT vp,vc;
434 < double d;
435 < {
436 <  double p[3];
437 <  
438 <  glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
439 <  VSUB(p,v0,vc);
440 <  if(dev_zmin >= 0.99)
441 <  {
442 <    p[0] *= d;
443 <    p[1] *= d;
444 <    p[2] *= d;
685 >    GLVERTEX3V(v2);
686    }
446  VADD(p,p,vp);
447  glVertex3dv(p);
448
449  glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
450  VSUB(p,v1,vc);
451  if(dev_zmin >= 0.99)
452  {
453    p[0] *= d;
454    p[1] *= d;
455    p[2] *= d;
456  }
457  VADD(p,p,vp);
458  glVertex3dv(p);
459
460
461  glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
462  VSUB(p,v2,vc);
463  if(dev_zmin >= 0.99)
464  {
465    p[0] *= d;
466    p[1] *= d;
467    p[2] *= d;
468  }
469  VADD(p,p,vp);
470  glVertex3dv(p);
471
687   }
688 <
689 < smRender_mesh(sm,vp)
688 > /*
689 > * smRender_fg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
690 > * SM *sm;                        : mesh
691 > * FVECT vp;                      : current viewpoint
692 > * int4  *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 + int4  *t_flag,*bg_flag;
703 + SFLOAT (*wp)[3];
704 + BYTE  (*rgb)[3];
705   {
478  int i,n,bg0,bg1,bg2;
479  double d;
480  int v0_id,v1_id,v2_id;
706    TRI *tri;
707 <  float (*wp)[3];
708 <  BYTE  (*rgb)[3];
484 <  int4  *active_flag,*bg_flag;
485 <
486 <  wp = SM_WP(sm);
487 <  rgb =SM_RGB(sm);
488 <  d = (dev_zmin+dev_zmax)/2.0;
489 <  glPushAttrib(GL_DEPTH_BUFFER_BIT);
707 >  int i,n,b0,b1,b2;
708 >  S_ID v0_id,v1_id,v2_id;
709    
491  /* First draw background polygons */
492  glDisable(GL_DEPTH_TEST);
710    glBegin(GL_TRIANGLES);
494
495  active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
496  bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
711    for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
712 <    if(active_flag[n] & bg_flag[n])
712 >    if(t_flag[n])
713        for(i=0; i < 32; i++)
714 <        if(active_flag[n] & bg_flag[n] & (1L << 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 <           render_bg_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
721 <                         rgb[v2_id],vp,SM_VIEW_CENTER(sm),d);
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();
732  
733 <  glEnable(GL_DEPTH_TEST);
733 > }
734 >
735 > /*
736 > * smRender_new_fg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb)
737 > * SM *sm;                        : mesh
738 > * FVECT vp;                      : current viewpoint
739 > * int4  *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 > int4  *new_flag,*active_flag,*bg_flag;
750 > SFLOAT (*wp)[3];
751 > BYTE  (*rgb)[3];
752 > {
753 >  TRI *tri;
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(active_flag[n])
759 >    if(new_flag[n] & active_flag[n])
760        for(i=0; i < 32; i++)
761 <        if((active_flag[n] & (1L << i)) && !(bg_flag[n] & (1L << 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 <           bg0 = SM_DIR_ID(sm,v0_id) || SM_BASE_ID(sm,v0_id);
768 <           bg1 = SM_DIR_ID(sm,v1_id) || SM_BASE_ID(sm,v1_id);
769 <           bg2 = SM_DIR_ID(sm,v2_id) || SM_BASE_ID(sm,v2_id);
770 <           if(!(bg0 || bg1 || bg2))
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])
528               else
529                 render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
530                  rgb[v1_id],rgb[v2_id],bg0,bg1,bg2,vp,SM_VIEW_CENTER(sm));
776           }
777    glEnd();
778  
534  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  
787    d = td2->depth-td1->depth;
543  
788    if(d > 0.0)
789      return(1);
790    if(d < 0.0)
791      return(-1);
548  
792    return(0);
550
793   }
794  
553 #ifdef DEBUG
554 #define freebuf(b)  tempbuf(-1)
555 #endif
795  
796 <
797 < char *
798 < tempbuf(len)                    /* get a temporary buffer */
799 < unsigned  len;
800 < {
801 <        extern char  *malloc(), *realloc();
802 <        static char  *tempbuf = NULL;
803 <        static unsigned  tempbuflen = 0;
804 <
805 < #ifdef DEBUG
806 <        static int in_use=FALSE;
568 <
569 <        if(len == -1)
570 <          {
571 <            in_use = FALSE;
572 <            return(NULL);
573 <          }
574 <        if(in_use)
575 <        {
576 <            eputs("Buffer in use:cannot allocate:tempbuf()\n");
577 <            return(NULL);
578 <        }
579 < #endif
580 <        if (len > tempbuflen) {
581 <                if (tempbuflen > 0)
582 <                        tempbuf = realloc(tempbuf, len);
583 <                else
584 <                        tempbuf = malloc(len);
585 <                tempbuflen = tempbuf==NULL ? 0 : len;
586 <        }
587 < #ifdef DEBUG
588 <        in_use = TRUE;
589 < #endif
590 <        return(tempbuf);
591 < }
592 <
593 < smOrder_new_tris(sm,vp,td)
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;
596 T_DEPTH *td;
809   {
810 <  int n,i,j,tcnt,v;
810 >  T_DEPTH *td;
811 >  int n,i,j,tcnt,v,size;
812    TRI *tri;
813    double d,min_d;
814    FVECT diff;
815 <  int4 *new_flag,*bg_flag;
815 >  int4 *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    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(new_flag[n] & ~bg_flag[n])
825 >    if(active_flag[n] & new_flag[n] & ~bg_flag[n])
826        for(i=0; i < 32; i++)
827 <        if(new_flag[n] & (1L << i) & ~bg_flag[n])
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 <               if(!SM_BG_SAMPLE(sm,v))
841 <                 {
842 <                   VSUB(diff,SM_NTH_WV(sm,v),vp);
843 <                   d = DOT(diff,diff);
622 <                   if(min_d == -1 || d < min_d)
623 <                     min_d = d;
624 <                 }
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 < smUpdate_Rendered_mesh(sm,vp,clr)
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;
637 int clr;
891   {
892 <  int i,n,v0_id,v1_id,v2_id,bg0,bg1,bg2;
893 <  GLint depth_test;
641 <  double d;
892 >  S_ID v0_id,v1_id,v2_id;
893 >  int i,n,b0,b1,b2;
894    TRI *tri;
895 <  float (*wp)[3];
895 >  SFLOAT (*wp)[3];
896    BYTE  (*rgb)[3];
897 <  int4  *new_flag,*bg_flag;
897 >  int4  *new_flag,*bg_flag,*active_flag;
898    T_DEPTH *td = NULL;
899 <  /* For all of the NEW triangles (since last update): assume
900 <     ACTIVE. Go through and sort on depth value (from vp). Turn
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 <     */
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 <  {
653 <    /* Must depth sort if view points do not coincide */
654 <    td = (T_DEPTH *)tempbuf(smNew_tri_cnt*sizeof(T_DEPTH));
655 < #ifdef DEBUG
656 <    if(!td)
657 <        eputs("Cant create list:wont depth sort:smUpdate_rendered_mesh\n");
658 < #endif
659 <    smOrder_new_tris(sm,vp,td);
660 <  }
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);
666  d = (dev_zmin+dev_zmax)/2.0;
917  
918 <  /* Now render back-to front */
669 <  /* First render bg triangles */
670 <  new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
671 <  bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
672 <  glBegin(GL_TRIANGLES);
673 <  for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
674 <    if(new_flag[n] & bg_flag[n])
675 <      for(i=0; i < 32; i++)
676 <        if(new_flag[n] & (1L << i) & bg_flag[n] )
677 <         {
678 <           tri = SM_NTH_TRI(sm,(n<<5)+i);
679 <           v0_id = T_NTH_V(tri,0);
680 <           v1_id = T_NTH_V(tri,1);
681 <           v2_id = T_NTH_V(tri,2);
682 <           render_bg_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
683 <                         rgb[v2_id],vp,SM_VIEW_CENTER(sm),d);
684 <         }
685 <  glEnd();
686 <
687 <
688 <  glBegin(GL_TRIANGLES);
918 >  smRender_new_bg_tris(sm,vp,new_flag,active_flag,bg_flag,wp,rgb);
919    if(!td)
920 <  {
691 <    for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
692 <     if(new_flag[n] & ~bg_flag[n])
693 <      for(i=0; i < 32; i++)
694 <        if(new_flag[n] & (1L << i) & ~bg_flag[n])
695 <         {
696 <           tri = SM_NTH_TRI(sm,(n<<5)+i);
697 <           /* Dont need to check for valid tri because flags are
698 <              cleared on delete
699 <            */
700 <           v0_id = T_NTH_V(tri,0);
701 <           v1_id = T_NTH_V(tri,1);
702 <           v2_id = T_NTH_V(tri,2);
703 <           bg0 = SM_DIR_ID(sm,v0_id) || SM_BASE_ID(sm,v0_id);
704 <           bg1 = SM_DIR_ID(sm,v1_id) || SM_BASE_ID(sm,v1_id);
705 <           bg2 = SM_DIR_ID(sm,v2_id) || SM_BASE_ID(sm,v2_id);
706 <           if(!(bg0 || bg1 || bg2))
707 <             render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
708 <                        rgb[v2_id])
709 <           else
710 <             render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
711 <                              rgb[v1_id],rgb[v2_id],bg0,bg1,bg2,vp,
712 <                              SM_VIEW_CENTER(sm));
713 <         }
714 <  }
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        tri = SM_NTH_TRI(sm,td[i].tri);
# Line 723 | Line 930 | int clr;
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 <      bg0 = SM_DIR_ID(sm,v0_id) || SM_BASE_ID(sm,v0_id);
934 <      bg1 = SM_DIR_ID(sm,v1_id) || SM_BASE_ID(sm,v1_id);
935 <      bg2 = SM_DIR_ID(sm,v2_id) || SM_BASE_ID(sm,v2_id);
936 <      if(!(bg0 || bg1 || bg2))
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])
732          else
733            render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
734                             rgb[v1_id],rgb[v2_id],bg0,bg1,bg2,vp,
735                             SM_VIEW_CENTER(sm));
942      }
943 < #ifdef DEBUG
943 >    glEnd();
944      freebuf(td);
739 #endif
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 +      if(!QT_LEAF_IS_FLAG(qt))
992 +        return;
993 +    }
994 +    else
995 +      if(!QT_IS_FLAG(qt))
996 +        return;
997 +
998 +    if(!Display_lists[i][which])
999 +    {
1000 +      Display_lists[i][which] = i+1 + which*SM_DL_LISTS;
1001 +      glNewList(Display_lists[i][which],GL_COMPILE_AND_EXECUTE);
1002 +      smClear_flags(sm,T_NEW_FLAG);
1003 +      glBegin(GL_TRIANGLES);
1004 +      smRender_qtree(sm,qt,vp,wp,rgb,which,FALSE);
1005 +      glEnd();
1006 +      glEndList();
1007 +    }
1008 +    else
1009 +    {
1010 +      glCallList(Display_lists[i][which]);
1011 +    }
1012 +  }
1013 +  else
1014 +    if(QT_IS_FLAG(qt))
1015 +    {
1016 +      i = ((i - level_i)<< 2) + level_i + leaf_cnt;
1017 +      level_i += leaf_cnt;
1018 +      leaf_cnt <<= 2;
1019 +      for(j=0; j < 4; j++)
1020 +        smRender_qtree_dl(sm,QT_NTH_CHILD(qt,j),vp,wp,rgb,
1021 +                        i+j,level_i,level+1,max_level,leaf_cnt,which);
1022 +    }
1023 +
1024 + }
1025 +
1026 + /*
1027 + * smRender_qtree(sm,qt,vp,wp,rgb,which,cull) : Render the tris stored in qtree
1028 + *  SM *sm;             : mesh
1029 + *  QUADTREE qt;        : quadtree base node
1030 + *  FVECT vp;           : current viewpoint
1031 + *  SFLOAT (*wp)[3]      : array of sample points
1032 + *  BYTE (*rgb)[3]      : array of RGB values for samples
1033 + *  int which;          : flag indicates whether to render fg or bg tris
1034 + *  int cull;           : if true, only traverse active (flagged) nodes
1035 + *
1036 + */
1037 + smRender_qtree(sm,qt,vp,wp,rgb,which,cull)
1038 + SM *sm;
1039 + 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 +  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 + /*
1116 + * smRender_mesh(sm,view,cull) : Render mesh Triangles
1117 + *   SM *sm;                   : mesh
1118 + *   VIEW *view;               : current view
1119 + *   int cull;                 : cull Flag
1120 + *
1121 + *   If cull is TRUE, first mark tris in current
1122 + *   frustum and only render them. Normally, cull will be FALSE only if
1123 + *   it is known that all tris lie in frustum, e.g. after a rebuild
1124 + *
1125 + */
1126 + smRender_mesh(sm,view,cull)
1127 + SM *sm;
1128 + VIEW *view;
1129 + int cull;
1130 + {
1131 +  SFLOAT (*wp)[3];
1132 +  BYTE  (*rgb)[3];
1133 +  int i;
1134 +  STREE *st= SM_LOCATOR(sm);
1135 +
1136 +  wp = SM_WP(sm);
1137 +  rgb =SM_RGB(sm);
1138 +
1139 +  smClear_flags(sm,T_NEW_FLAG);
1140 +
1141 +  if(cull)
1142 +    smCull(sm,view,SM_ALL_LEVELS);
1143 +
1144 +  glPushAttrib(GL_DEPTH_BUFFER_BIT);
1145 +  glDisable(GL_DEPTH_TEST);
1146 +  
1147 +  glMatrixMode(GL_MODELVIEW);
1148 +  glPushMatrix();
1149 +  /* move relative to the new view */
1150 +  glTranslated(view->vp[0],view->vp[1],view->vp[2]);
1151 +
1152 +  /* The points are a distance of 1 away from the origin: if necessary
1153 +     scale so that they fit in frustum and are therefore not clipped away
1154 +     */
1155 +  if(dev_zmin >= 0.99)
1156 +  {
1157 +    double d;
1158 +
1159 +    d = (dev_zmin+dev_zmax)/2.0;
1160 +    glScaled(d,d,d);
1161 +  }
1162 +  /* move points to unit sphere at origin */
1163 +  glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
1164 +               -SM_VIEW_CENTER(sm)[2]);
1165 +
1166 +  glBegin(GL_TRIANGLES);
1167 +  for(i=0; i < 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 <  /* Restore Depth Test */
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 +    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 >  int4  *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 753 | 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,t;
1469 <
766 <  if(!smMesh)
1467 >  
1468 >  /* Is there anything to render? */
1469 >  if(!smMesh || SM_NUM_TRI(smMesh)<=0)
1470      return;
1471 <
1472 <  /* If view has moved beyond epsilon from canonical: must rebuild -
1473 <     epsilon is calculated as running avg of distance of sample points
771 <     from canonical view: m = 1/(AVG(1/r)): some fraction of this
772 <   */
773 <  d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
774 <  if(qual >= MAXQUALITY  && 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);
782 <      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==MAXQUALITY and view==&odev.v */
1483 <  last_update = qual>=MAXQUALITY && 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 <       if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
1504 <         return;
798 <       tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
799 <                   SM_NUM_SAMP(smMesh));
1501 >      if(smIncremental)
1502 >        smUpdate_tm(smMesh);
1503 >      smIncremental = FALSE;
1504 >      smRender(smMesh,view,qual);
1505      }
801 #endif
802    mark_tris_in_frustum(view);
803    if (qual <= (MAXQUALITY*3/4))
804        smRender_stree(smMesh,qual);
1506      else
806        smRender_mesh(smMesh,view->vp);
807 #ifdef TEST_DRIVER
808    glFlush();
809    glutSwapBuffers();
810 #endif
811  }
812  /* Do an incremental update instead */
813  else
814  {
815      if(!smNew_tri_cnt)
816      return;
817 #ifdef TEST_DRIVER
818    glDrawBuffer(GL_FRONT);
819 #else
820    t = SM_TONE_MAP(smMesh);
821    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    
832 <    smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
833 <    
834 < #ifdef TEST_DRIVER
835 <    glDrawBuffer(GL_BACK);
836 < #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);
840 <
841 <  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   }
850
1529  
1530  
1531  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines