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.14 by gwlarson, Fri Mar 5 16:33:32 1999 UTC

# Line 6 | Line 6 | static char SCCSid[] = "$SunId$ SGI";
6  
7   /*
8   * sm_ogl.c
9 + *
10 + *  Rendering routines for triangle mesh representation utilizing OpenGL
11   */
12   #include "standard.h"
13  
14   #include <GL/gl.h>
15  
14 #ifdef TEST_DRIVER
15 #include <gl/device.h>
16 #include <GL/glu.h>
17 #include <glut.h>
18 #endif
16   #include "sm_flag.h"
17   #include "sm_list.h"
18   #include "sm_geom.h"
# Line 23 | Line 20 | static char SCCSid[] = "$SunId$ SGI";
20   #include "sm_stree.h"
21   #include "sm.h"
22  
23 < #ifdef TEST_DRIVER
24 < #include "sm_draw.h"
25 < /*static char smClean_notify = TRUE;
26 < MAKE STATIC LATER: ui.c using for now;
27 < */
28 < char smClean_notify = TRUE;
29 < #else
30 < static int smClean_notify = TRUE;
31 < #endif
23 > static int smClean_notify = TRUE;    /*If true:Do full redraw on next update*/
24 > static int smCompute_mapping = TRUE;/*If true:re-tonemap on next update */
25 > static int smIncremental = FALSE;    /*If true: there has been incremental
26 >                                       rendering since last full draw */
27 > #define SM_RENDER_FG 0               /* Render foreground tris only*/
28 > #define SM_RENDER_BG 1               /* Render background tris only */
29 > #define SM_RENDER_MIXED 4               /* Render mixed tris only */
30 > #define SM_RENDER_CULL 8          /* Perform view frustum culling */
31 > #define BASE 1
32 > #define DIR 2
33 > /* FOR DISPLAY LIST RENDERING: **********************************************/
34 > #define  SM_DL_LEVELS 2 /* # of levels down to create display lists */
35 > #define SM_DL_LISTS   42  /* # of qtree nodes in tree at above level:
36 >                           should be 2*(4^(SM_DL_LEVELS+1)-1)/(4-1) */
37 > static GLuint Display_lists[SM_DL_LISTS][2] = {0};
38 > /****************************************************************************/
39  
40 + /* FOR APPROXIMATION RENDERING **********************************************/
41   typedef struct {
42          float   dist;           /* average distance */
43          BYTE    rgb[3];         /* average color */
# Line 45 | Line 50 | typedef struct {
50  
51   static QT_LUENT *qt_htbl = NULL;        /* quadtree cache */
52   static int      qt_hsiz = 0;            /* quadtree cache size */
53 + /****************************************************************************/
54  
55 + /* For DEPTH SORTING ********************************************************/
56 + typedef struct _T_DEPTH {
57 +  int tri;
58 +  double depth;
59 + }T_DEPTH;
60 + /**********************************************************************/
61  
62 +
63   /*
64 <  * smClean()           : display has been wiped clean
65 <  *
64 >  * smClean(tmflag)     : display has been wiped clean
65 >  *     int tmflag;
66    * Called after display has been effectively cleared, meaning that all
67    * geometry must be resent down the pipeline in the next call to smUpdate().
68 +  * If tmflag is set, tone-mapping should be performed
69    */
70 < smClean()
70 > smClean(tmflag)
71 >   int tmflag;
72   {
73      smClean_notify = TRUE;
74 +    if(tmflag)
75 +       smCompute_mapping = TRUE;
76   }
77  
78   int
# Line 250 | Line 267 | int lvl;
267   }
268  
269  
270 < smRender_stree_level(sm,lvl)
270 > smRender_approx_stree_level(sm,lvl)
271   SM *sm;
272   int lvl;
273   {
# Line 276 | Line 293 | int lvl;
293    glPopAttrib();
294   }
295  
296 <
297 < smRender_stree(sm, qual)        /* render some quadtree triangles */
296 > /*
297 > * smRender_approx(sm,qual,view)
298 > * SM *sm;                : mesh
299 > * int qual;              : quality level
300 > * VIEW *view;            : current view
301 > *
302 > *  Renders an approximation to the current mesh based on the quadtree
303 > *  subdivision. The quadtree is traversed to a level (based upon the quality:
304 > *  the lower the quality, the fewer levels visited, and the coarser, and
305 > *  faster, the approximation). The quadtree triangles are drawn relative to
306 > *  the current viewpoint, with a depth and color averaged from all of the
307 > *  triangles that lie beneath the node.
308 > */
309 > smRender_approx(sm, qual,view)  
310   SM *sm;
311   int qual;
312 + VIEW *view;
313   {
314 <  int i, ntarget;
314 >  int i, n,ntarget;
315    int lvlcnt[QT_MAX_LEVELS];
316    STREE *st;
317 +  int4 *active_flag;
318  
319    if (qual <= 0)
320      return;
321 +  smCull(sm,view,SM_ALL_LEVELS);
322                                  /* compute rendering target */
323    ntarget = 0;
324 <  SM_FOR_ALL_ACTIVE_TRIS(sm,i)
325 <    ntarget++;
326 <  ntarget = ntarget*qual/100;
324 >
325 >  active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
326 >  for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
327 >    if(active_flag[n])
328 >      for(i=0; i < 32; i++)
329 >        if(active_flag[n] & (1L << i))
330 >          ntarget++;
331 >
332 >  ntarget = ntarget*qual/MAXQUALITY;
333    if (!ntarget)
334      return;
335    for (i = QT_MAX_LEVELS; i--; )
# Line 305 | Line 343 | int qual;
343      if (ntarget < lvlcnt[i+1])
344        break;
345                                  /* compute and render target level */
346 <  smRender_stree_level(sm,i);
346 >  smRender_approx_stree_level(sm,i);
347   }
348  
311
312
349   #define render_tri(v0,v1,v2,rgb0,rgb1,rgb2) \
350    {glColor3ub(rgb0[0],rgb0[1],rgb0[2]);  glVertex3fv(v0); \
351    glColor3ub(rgb1[0],rgb1[1],rgb1[2]);  glVertex3fv(v1); \
352 <  glColor3ub(rgb2[0],rgb2[1],rgb2[2]);  glVertex3fv(v2);} \
352 >  glColor3ub(rgb2[0],rgb2[1],rgb2[2]);  glVertex3fv(v2);}
353  
354 < render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,bg0,bg1,bg2,vp,vc)
354 >
355 > render_bg_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,d)
356 > float v0[3],v1[3],v2[3];
357 > BYTE rgb0[3],rgb1[3],rgb2[3];
358 > FVECT vp,vc;
359 > double d;
360 > {
361 >   double p[3];
362 >  
363 >   glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
364 >   VSUB(p,v0,vc);
365 >   if(dev_zmin >= 0.99)
366 >   {
367 >     p[0] *= d;
368 >     p[1] *= d;
369 >     p[2] *= d;
370 >   }
371 >   VADD(p,p,vp);
372 >   glVertex3dv(p);
373 >
374 >   glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
375 >   VSUB(p,v1,vc);
376 >   if(dev_zmin >= 0.99)
377 >   {
378 >     p[0] *= d;
379 >     p[1] *= d;
380 >     p[2] *= d;
381 >   }
382 >   VADD(p,p,vp);
383 >   glVertex3dv(p);
384 >
385 >
386 >   glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
387 >   VSUB(p,v2,vc);
388 >   if(dev_zmin >= 0.99)
389 >   {
390 >     p[0] *= d;
391 >     p[1] *= d;
392 >     p[2] *= d;
393 >    VADD(p,p,vp);
394 >    glVertex3dv(p);
395 >   }
396 > }
397 >
398 >
399 > /*
400 > * render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,b0,b1,b2)
401 > *  float v0[3],v1[3],v2[3];      : triangle vertex coordinates
402 > *  BYTE rgb0[3],rgb1[3],rgb2[3]; : vertex RGBs
403 > *  int b0,b1,b2;                 : background or base vertex flag
404 > *  
405 > *  render foreground or base vertex color as average of the background
406 > *  vertex RGBs.
407 > */
408 > render_mixed_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,bg0,bg1,bg2)
409   float v0[3],v1[3],v2[3];
410   BYTE rgb0[3],rgb1[3],rgb2[3];
321 int bg0,bg1,bg2;
411   FVECT vp,vc;
412 + int bg0,bg1,bg2;
413   {
414 <  double p[3],d;
415 <  int j,ids[3],cnt;
414 >  double d,p[3];
415 >  int j,cnt,rgb[3],base;
416 >  
417 >  base = bg0==BASE || bg1==BASE || bg2==BASE;
418 >
419 >  if(base)
420 >  {
421 >    cnt = 0;
422 >    rgb[0] = rgb[1] = rgb[2] = 0;
423 >    if(bg0 != BASE)
424 >    {
425 >      IADDV3(rgb,rgb0);
426 >      cnt++;
427 >    }
428 >    if(bg1 !=BASE)
429 >    {
430 >      IADDV3(rgb,rgb1);
431 >      cnt++;
432 >    }
433 >    if(bg2 != BASE)
434 >    {
435 >      IADDV3(rgb,rgb2);
436 >      cnt++;
437 >    }
438 >    IDIVV3(rgb,cnt);
439 >  }
440 >
441 >  if(bg0== BASE)
442 >    glColor3ub(rgb[0],rgb[1],rgb[2]);
443 >  else
444 >    glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
445 >
446 >  if(!bg0)
447 >  {
448 >    VSUB(p,v0,vp);
449 >    normalize(p);
450 >    IADDV3(p,vc);
451 >    glVertex3dv(p);
452 >  }
453 >  else
454 >    glVertex3fv(v0);
455 >
456 >  if(bg1== BASE)
457 >    glColor3ub(rgb[0],rgb[1],rgb[2]);
458 >  else
459 >    glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
460 >
461 >  if(!bg1)
462 >  {
463 >    VSUB(p,v1,vp);
464 >    normalize(p);
465 >    IADDV3(p,vc);
466 >    glVertex3dv(p);
467 >  }
468 >  else
469 >    glVertex3fv(v1);
470 >
471 >  if(bg2== BASE)
472 >    glColor3ub(rgb[0],rgb[1],rgb[2]);
473 >  else
474 >    glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
475 >
476 >  if(!bg2)
477 >  {
478 >    VSUB(p,v2,vp);
479 >    normalize(p);
480 >    IADDV3(p,vc);
481 >    glVertex3dv(p);
482 >  }
483 >  else
484 >    glVertex3fv(v2);
485 > }
486 >
487 > /*
488 > * smRender_bg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
489 > * SM *sm;                         : mesh
490 > * FVECT vp;                       : current viewpoint
491 > * int4  *t_flag,*bg_flag;         : triangle flags: t_flag is generic,
492 > *                                   and bg_flag indicates if background tri;
493 > * float (*wp)[3];BYTE  (*rgb)[3]; : arrays of sample points and RGB colors
494 > *
495 > * Sequentially gos through triangle list and renders all valid tris who
496 > * have t_flag set, and bg_flag set.
497 > */
498 >
499 > smRender_bg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
500 > SM *sm;
501 > FVECT vp;
502 > int4 *t_flag,*bg_flag;
503 > float (*wp)[3];
504 > BYTE  (*rgb)[3];
505 > {
506 >  double d;
507 >  int v0_id,v1_id,v2_id;
508 >  int i,n,bg0,bg1,bg2;
509 >  TRI *tri;
510 >
511 >  glMatrixMode(GL_MODELVIEW);
512 >
513 >  glPushMatrix();
514 >  glTranslated(vp[0],vp[1],vp[2]);
515 >  /* The points are a distance of 1 away from the origin: if necessary scale
516 >     so that they fit in frustum and are therefore not clipped away
517 >   */
518 >  if(dev_zmin >= 0.99)
519 >  {
520 >    d = (dev_zmin+dev_zmax)/2.0;
521 >    glScaled(d,d,d);
522 >  }
523 >  /* move relative to the new view */
524 >  /* move points to unit sphere at origin */
525 >  glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
526 >               -SM_VIEW_CENTER(sm)[2]);
527 >  glBegin(GL_TRIANGLES);
528 >  for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
529 >    if(t_flag[n] & bg_flag[n])
530 >      for(i=0; i < 32; i++)
531 >        if(t_flag[n] & bg_flag[n] & (1L << i))
532 >         {
533 >           tri = SM_NTH_TRI(sm,(n<<5)+i);
534 >           v0_id = T_NTH_V(tri,0);
535 >           v1_id = T_NTH_V(tri,1);
536 >           v2_id = T_NTH_V(tri,2);
537 >           bg0 = SM_DIR_ID(sm,v0_id)?DIR:SM_BASE_ID(sm,v0_id)?BASE:0;
538 >           bg1 = SM_DIR_ID(sm,v1_id)?DIR:SM_BASE_ID(sm,v1_id)?BASE:0;
539 >           bg2 = SM_DIR_ID(sm,v2_id)?DIR:SM_BASE_ID(sm,v2_id)?BASE:0;
540 >           if(bg0==DIR && bg1==DIR && bg2==DIR)
541 >             render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
542 >                rgb[v2_id])
543 >           else
544 >             render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
545 >                      rgb[v1_id],rgb[v2_id],vp,SM_VIEW_CENTER(sm),bg0,bg1,bg2);
546 >         }
547 >  glEnd();
548 >
549 >  glPopMatrix();
550 >
551 > }
552 > /*
553 > * render_base_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,b0,b1,b2)
554 > *  float v0[3],v1[3],v2[3];       : triangle vertex coordinates
555 > *  BYTE rgb0[3],rgb1[3],rgb2[3];  : vertex RGBs
556 > *  FVECT vp;                      : current viewpoint
557 > *  int b0,b1,b2;                  : vertex base flag
558 > *  
559 > *  render base vertex color as average of the non-base vertex RGBs. The
560 > *  base vertex coordinate is taken as the stored vector, scaled out by
561 > *  the average distance to the non-base vertices
562 > */
563 > render_base_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,b0,b1,b2)
564 > float v0[3],v1[3],v2[3];
565 > BYTE rgb0[3],rgb1[3],rgb2[3];
566 > FVECT vp;
567 > int b0,b1,b2;
568 > {
569 >  int cnt;
570    int rgb[3];
571 +  double d;
572 +  double p[3];
573  
328  /* NOTE:Triangles are defined clockwise:historical relative to spherical
329     tris: could change
330     */
574    cnt = 0;
332  d = 0.0;
575    rgb[0] = rgb[1] = rgb[2] = 0;
576 +  d = 0.0;
577  
578 <  if(bg0 && bg1 && bg2)
578 >  if(b0&&b1&&b2)
579      return;
580 <
581 <  if(!bg0)
580 >  /* First calculate color and coordinates
581 >     for base vertices based on world space vertices*/
582 >  if(!b0)
583    {
584 <    rgb[0] += rgb0[0];
585 <    rgb[1] += rgb0[1];
342 <    rgb[2] += rgb0[2];
584 >    IADDV3(rgb,rgb0);
585 >    d += DIST(v0,vp);
586      cnt++;
344    d += DIST(vp,v0);
587    }
588 <  if(!bg1)
588 >  if(!b1)
589    {
590 <    rgb[0] += rgb1[0];
591 <    rgb[1] += rgb1[1];
350 <    rgb[2] += rgb1[2];
590 >    IADDV3(rgb,rgb1);
591 >    d += DIST(v1,vp);
592      cnt++;
352    d += DIST(vp,v1);
593    }
594 <  if(!bg2)
594 >  if(!b2)
595    {
596 <    rgb[0] += rgb2[0];
597 <    rgb[1] += rgb2[1];
358 <    rgb[2] += rgb2[2];
596 >    IADDV3(rgb,rgb2);
597 >    d += DIST(v2,vp);
598      cnt++;
360    d += DIST(vp,v2);
599    }
600 <  if(cnt > 1)
600 >  IDIVV3(rgb,cnt);
601 >  d /= (double)cnt;
602 >  
603 >  /* Now render triangle */
604 >  if(b0)
605    {
364    rgb[0]/=cnt; rgb[1]/=cnt; rgb[2]/=cnt;
365    d /= (double)cnt;
366  }
367  if(bg0)
368  {
606      glColor3ub(rgb[0],rgb[1],rgb[2]);
607 <    VSUB(p,v0,vc);
608 <    p[0] *= d;
609 <    p[1] *= d;
610 <    p[2] *= d;
374 <    VADD(p,p,vc);
375 <    glVertex3dv(p);
607 >    SUBV3(p,v0,vp);
608 >    ISCALEV3(p,d);
609 >    IADDV3(p,vp);
610 >    glVertex3dv(p);    
611    }
612    else
613    {
614      glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
615      glVertex3fv(v0);
616 <   }
617 <  if(bg1)
616 >  }
617 >  if(b1)
618    {
619      glColor3ub(rgb[0],rgb[1],rgb[2]);
620 <    VSUB(p,v1,vc);
621 <    p[0] *= d;
622 <    p[1] *= d;
388 <    p[2] *= d;
389 <    VADD(p,p,vc);
620 >    SUBV3(p,v1,vp);
621 >    ISCALEV3(p,d);
622 >    IADDV3(p,vp);
623      glVertex3dv(p);
624    }
625    else
626    {
627      glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
628      glVertex3fv(v1);
629 <   }
630 <  if(bg2)
629 >  }
630 >  if(b2)
631    {
632      glColor3ub(rgb[0],rgb[1],rgb[2]);
633 <    VSUB(p,v2,vc);
634 <    p[0] *= d;
635 <    p[1] *= d;
403 <    p[2] *= d;
404 <    VADD(p,p,vc);
633 >    SUBV3(p,v2,vp);
634 >    ISCALEV3(p,d);
635 >    IADDV3(p,vp);
636      glVertex3dv(p);
637    }
638    else
639    {
640      glColor3ub(rgb2[0],rgb2[1],rgb2[2]);
641      glVertex3fv(v2);
411   }
412
413 }
414
415 render_bg_tri(v0,v1,v2,rgb0,rgb1,rgb2,vp,vc,d)
416 float v0[3],v1[3],v2[3];
417 BYTE rgb0[3],rgb1[3],rgb2[3];
418 FVECT vp,vc;
419 double d;
420 {
421  double p[3];
422  
423  glColor3ub(rgb0[0],rgb0[1],rgb0[2]);
424  VSUB(p,v0,vc);
425  if(dev_zmin >= 0.99)
426  {
427    p[0] *= d;
428    p[1] *= d;
429    p[2] *= d;
642    }
431  VADD(p,p,vp);
432  glVertex3dv(p);
433
434  glColor3ub(rgb1[0],rgb1[1],rgb1[2]);
435  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);
444
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
643   }
644 <
645 < smRender_mesh(sm,vp,clr)
644 > /*
645 > * smRender_fg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
646 > * SM *sm;                        : mesh
647 > * FVECT vp;                      : current viewpoint
648 > * int4  *t_flag,*bg_flag;        : triangle flags: t_flag is generic,bg_flag
649 > *                                  indicates if background tri;
650 > * float (*wp)[3];BYTE (*rgb)[3]; : arrays of sample points and RGB colors
651 > *
652 > * Sequentially gos through triangle list and renders all valid tris who
653 > * have t_flag set, and NOT bg_flag set.
654 > */
655 > smRender_fg_tris(sm,vp,t_flag,bg_flag,wp,rgb)
656   SM *sm;
657   FVECT vp;
658 < int clr;
658 > int4  *t_flag,*bg_flag;
659 > float (*wp)[3];
660 > BYTE  (*rgb)[3];
661   {
464  int i,bg0,bg1,bg2;
465  double d;
466  int v0_id,v1_id,v2_id;
662    TRI *tri;
663 <  float (*wp)[3];
664 <  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);
663 >  int i,n,b0,b1,b2;
664 >  int v0_id,v1_id,v2_id;
665    
476  /* First draw background polygons */
477  glDisable(GL_DEPTH_TEST);
666    glBegin(GL_TRIANGLES);
667 <  /* Maintain a list? */
668 <  SM_FOR_ALL_ACTIVE_BG_TRIS(sm,i)
669 <  {
670 <    if (clr)
671 <      SM_CLR_NTH_T_NEW(sm,i);
672 <    tri = SM_NTH_TRI(sm,i);
673 <    v0_id = T_NTH_V(tri,0);
674 <    v1_id = T_NTH_V(tri,1);
675 <    v2_id = T_NTH_V(tri,2);
676 <    render_bg_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
677 <                   rgb[v2_id],vp,SM_VIEW_CENTER(sm),d);
678 <  }
667 >  for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
668 >    if(t_flag[n])
669 >      for(i=0; i < 32; i++)
670 >        if(t_flag[n] & (1L << i) & ~bg_flag[n])
671 >         {
672 >           tri = SM_NTH_TRI(sm,(n<<5)+i);
673 >           v0_id = T_NTH_V(tri,0);
674 >           v1_id = T_NTH_V(tri,1);
675 >           v2_id = T_NTH_V(tri,2);
676 >           b0 = SM_BASE_ID(sm,v0_id);
677 >           b1 = SM_BASE_ID(sm,v1_id);
678 >           b2 = SM_BASE_ID(sm,v2_id);
679 >           if(b0 || b1 || b2)
680 >             render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
681 >             rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),b0,b1,b2);
682 >           else
683 >             render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
684 >                        rgb[v2_id])
685 >         }
686    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();
687  
514  glPopAttrib();
688   }
689  
690 +
691   int
692   compare_tri_depths(T_DEPTH *td1,T_DEPTH *td2)
693   {
694    double d;
695  
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
696    d = td2->depth-td1->depth;
533  
697    if(d > 0.0)
698      return(1);
699    if(d < 0.0)
700      return(-1);
538  
701    return(0);
702 +
703   }
704  
705 < int
706 < compare_tri_depths_old(T_DEPTH *td1,T_DEPTH *td2)
705 > #ifdef DEBUG
706 > #define freebuf(b)  tempbuf(-1)
707 > #endif
708 >
709 > char *
710 > tempbuf(len)                    /* get a temporary buffer */
711 > unsigned  len;
712   {
713 <  double d;
713 >  extern char  *malloc(), *realloc();
714 >  static char  *tempbuf = NULL;
715 >  static unsigned  tempbuflen = 0;
716  
717 <  d = td2->depth-td1->depth;
718 <  
719 <  if(d > 0.0)
720 <    return(1);
721 <  if(d < 0.0)
722 <    return(-1);
723 <  
724 <  return(0);
717 > #ifdef DEBUG
718 >        static int in_use=FALSE;
719 >
720 >        if(len == -1)
721 >          {
722 >            in_use = FALSE;
723 >            return(NULL);
724 >          }
725 >        if(in_use)
726 >        {
727 >            eputs("Buffer in use:cannot allocate:tempbuf()\n");
728 >            return(NULL);
729 >        }
730 > #endif
731 >        if (len > tempbuflen) {
732 >                if (tempbuflen > 0)
733 >                        tempbuf = realloc(tempbuf, len);
734 >                else
735 >                        tempbuf = malloc(len);
736 >                tempbuflen = tempbuf==NULL ? 0 : len;
737 >        }
738 > #ifdef DEBUG
739 >        in_use = TRUE;
740 > #endif
741 >        return(tempbuf);
742   }
743  
744 < LIST
745 < *smDepth_sort_tris(sm,vp,td)
744 > /*
745 > * smOrder_new_tris(sm,vp,td)
746 > * SM *sm;      : mesh
747 > * FVECT vp;    : current viewpoint
748 > * T_DEPTH *td; : holds returned list of depth sorted tris
749 > *
750 > * Creates list of all new tris, with their distance from the current
751 > * viewpoint, and sorts the list based on this distance
752 > */
753 > smOrder_new_tris(sm,vp,td)
754   SM *sm;
755   FVECT vp;
756   T_DEPTH *td;
757   {
758 <  int i,j,t_id,v;
758 >  int n,i,j,tcnt,v;
759    TRI *tri;
760    double d,min_d;
566  LIST *tlist=NULL;
761    FVECT diff;
762 +  int4 *new_flag,*bg_flag;
763  
764 <  i = 0;
765 <  SM_FOR_ALL_NEW_TRIS(sm,t_id)
766 <  {
767 <    if(SM_BG_TRI(sm,t_id))
768 <    {
769 <        tlist = push_data(tlist,t_id);
770 <        continue;
771 <    }
772 <    tri = SM_NTH_TRI(sm,t_id);
773 <    td[i].tri = t_id;
774 <    min_d = -1;
775 <    for(j=0;j < 3;j++)
776 <    {
777 <        v = T_NTH_V(tri,j);
778 <        if(!SM_BG_SAMPLE(sm,v))
779 <        {
780 <            VSUB(diff,SM_NTH_WV(sm,v),vp);
781 <            d = DOT(diff,diff);
782 <            if(min_d == -1 || d < min_d)
783 <               min_d = d;
589 <        }
590 <    }
591 <    td[i].depth = min_d;
592 <    i++;
764 >  tcnt=0;
765 >  new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
766 >  bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
767 >  for(n=((SM_NUM_TRI(sm)+31)>>5) +1; --n;)
768 >    if(new_flag[n] & ~bg_flag[n])
769 >      for(i=0; i < 32; i++)
770 >        if(new_flag[n] & (1L << i) & ~bg_flag[n])
771 >         {
772 >           tri = SM_NTH_TRI(sm,(n<<5)+i);
773 >           td[tcnt].tri = (n << 5)+i;
774 >           min_d = -1;
775 >           for(j=0;j < 3;j++)
776 >             {
777 >               v = T_NTH_V(tri,j);
778 >               VSUB(diff,SM_NTH_WV(sm,v),vp);
779 >               d = DOT(diff,diff);
780 >               if(min_d == -1 || d < min_d)
781 >                 min_d = d;
782 >             }
783 >           td[tcnt++].depth = min_d;
784    }
785 <  td[i].tri = -1;
786 <  if(i)
787 <     qsort((void *)td,i,sizeof(T_DEPTH),compare_tri_depths);
597 <  return(tlist);
785 >  td[tcnt].tri = -1;
786 >  if(tcnt)
787 >      qsort((void *)td,tcnt,sizeof(T_DEPTH),compare_tri_depths);
788   }
789  
790 + /*
791 + * smUpdate_tm(sm)   : Update the tone-mapping
792 + * SM *sm;           : mesh
793 + *
794 + */
795 + smUpdate_tm(sm)
796 + SM *sm;
797 + {
798 +  int t = SM_TONE_MAP(sm);
799  
800 +  if(t==0 || smCompute_mapping)
801 +  {
802 +    tmClearHisto();
803 +    tmAddHisto(SM_BRT(sm),SM_NUM_SAMP(sm),1);
804 +    if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
805 +      return;
806 +    t = 0;
807 +    smCompute_mapping = FALSE;
808 +  }
809 +  tmMapPixels(SM_NTH_RGB(sm,t),&SM_NTH_BRT(sm,t),SM_NTH_CHR(sm,t),
810 +              SM_NUM_SAMP(sm)-t);
811 +  SM_TONE_MAP(sm) = SM_NUM_SAMP(sm);
812 + }
813  
814 < LIST
815 < *smOrder_new_tris(sm,vp,td,sort)
814 > /*
815 > *   smRender_inc(sm,vp)      : Incremental update of mesh
816 > *    SM * sm;                : mesh
817 > *    FVECT vp;               : current view point
818 > *
819 > *  If a relatively small number of new triangles have been created,
820 > *  do an incremental update. Render new triangles with depth buffering
821 > *  turned off, if the current viewpoint is not the same as canonical view-
822 > *  point, must use painter's approach to resolve visibility:first depth sort
823 > *  triangles, then render back-to-front.  
824 > */
825 > smRender_inc(sm,vp)
826   SM *sm;
827   FVECT vp;
606 T_DEPTH *td;
607 int sort;
828   {
829 <  int i,j,t_id,v;
829 >  int i,n,v0_id,v1_id,v2_id,b0,b1,b2;
830    TRI *tri;
831 <  double d,min_d;
832 <  LIST *tlist=NULL;
833 <  FVECT diff;
831 >  float (*wp)[3];
832 >  BYTE  (*rgb)[3];
833 >  int4  *new_flag,*bg_flag;
834 >  T_DEPTH *td = NULL;
835  
836 <  i = 0;
837 <  for(i=0; i < smNew_tri_cnt;i++)
836 >  smUpdate_tm(sm);
837 >
838 >  /* For all of the NEW triangles (since last update): assume
839 >     ACTIVE. Go through and sort on depth value (from vp). Turn
840 >     Depth Buffer test off and render back-front
841 >     */
842 >  if(!EQUAL_VEC3(SM_VIEW_CENTER(sm),vp))
843    {
844 <    t_id = smNew_tris[i].tri;
844 >    /* Must depth sort if view points do not coincide */
845 >    td = (T_DEPTH *)tempbuf(smNew_tri_cnt*sizeof(T_DEPTH));
846 >    if(td)
847 >      smOrder_new_tris(sm,vp,td);
848 > #ifdef DEBUG
849 >    else
850 >        eputs("Cant create list:wont depth sort:smUpdate_incremental\n");
851 > #endif
852 >  }
853 >  wp = SM_WP(sm);
854 >  rgb =SM_RGB(sm);
855 >  new_flag = SM_NTH_FLAGS(sm,T_NEW_FLAG);
856 >  bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
857 >  /* Turn Depth Test off -- using Painter's algorithm */
858 >  glPushAttrib(GL_DEPTH_BUFFER_BIT);
859 >  glDepthFunc(GL_ALWAYS);
860  
861 <    tri = SM_NTH_TRI(sm,t_id);
862 <    if(!T_IS_VALID(tri))
861 >  smRender_bg_tris(sm,vp,new_flag,bg_flag,wp,rgb);
862 >  if(!td)
863 >    smRender_fg_tris(sm,vp,new_flag,bg_flag,wp,rgb);
864 >  else
865 >  {
866 >    glBegin(GL_TRIANGLES);
867 >    for(i=0; td[i].tri != -1;i++)
868      {
869 <      smNew_tris[i].tri = -1;
870 <      continue;
869 >      tri = SM_NTH_TRI(sm,td[i].tri);
870 >      /* Dont need to check for valid tri because flags are
871 >         cleared on delete
872 >         */
873 >      v0_id = T_NTH_V(tri,0);
874 >      v1_id = T_NTH_V(tri,1);
875 >      v2_id = T_NTH_V(tri,2);
876 >      b0 = SM_BASE_ID(sm,v0_id);
877 >      b1 = SM_BASE_ID(sm,v1_id);
878 >      b2 = SM_BASE_ID(sm,v2_id);
879 >      if(b0 || b1 || b2)
880 >        render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
881 >                        rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),b0,b1,b2);
882 >      else
883 >        render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
884 >                   rgb[v2_id])
885      }
886 <    if(SM_BG_TRI(sm,t_id))
886 >    glEnd();
887 >    freebuf(td);
888 >  }
889 >  /* Restore Depth Test */
890 >  glPopAttrib();
891 > }
892 >
893 > /*
894 > * smRender_qtree_dl(sm,qt,vp,wp,rgb,i,level_i,max_level,leaf_cnt,which)
895 > *  SM *sm;              : mesh
896 > *  QUADTREE qt;         : quadtree base node
897 > *  FVECT vp;            : current viewpoint
898 > *  float (*wp)[3];      : array of sample points
899 > *  BYTE (*rgb)[3];      : array of RGB values for samples
900 > *  int i,level_i,level,max_level,leaf_cnt;
901 > *                       : variables to keep track of where
902 > *         we are in the quadtree traversal in order to map nodes to
903 > *         corresponding array locations, where nodes are stored in breadth-
904 > *         first order. i is the index of the current node,level_i is the
905 > *         index of the first node on the current quadtree level, max_level is
906 > *         the maximum number of levels to traverse, and leaf_cnt is the number
907 > *         of leaves on the current level
908 > *  int which;          flag indicates whether to render fg or bg tris
909 > *
910 > *
911 > *    Render the tris stored in qtree using display lists. For each node at
912 > *   the leaf or max_level, call the display_list if it exists, else traverse
913 > *   down the subtree and render the nodes into a new display list which is
914 > *   stored for future use.
915 > */
916 > smRender_qtree_dl(sm,qt,vp,wp,rgb,i,level_i,level,max_level,leaf_cnt,which)
917 > SM *sm;
918 > QUADTREE qt;
919 > FVECT vp;
920 > float (*wp)[3];
921 > BYTE  (*rgb)[3];
922 > int i,level_i,level,max_level,leaf_cnt;
923 > int which;
924 > {
925 >  int j;
926 >  
927 >  if(QT_IS_EMPTY(qt))
928 >    return;
929 >
930 >  if(QT_IS_LEAF(qt) || level == max_level)
931 >  {
932 >    if(QT_IS_LEAF(qt))
933      {
934 <        tlist = push_data(tlist,t_id);
935 <        smNew_tris[i].tri = -1;
630 <        continue;
934 >      if(!QT_LEAF_IS_FLAG(qt))
935 >        return;
936      }
937 <    if(!sort)
938 <      continue;
939 <    min_d = -1;
940 <    for(j=0;j < 3;j++)
937 >    else
938 >      if(!QT_IS_FLAG(qt))
939 >        return;
940 >
941 >    if(!Display_lists[i][which])
942      {
943 <        v = T_NTH_V(tri,j);
944 <        if(!SM_BG_SAMPLE(sm,v))
945 <        {
946 <            VSUB(diff,SM_NTH_WV(sm,v),vp);
947 <            d = DOT(diff,diff);
948 <            if(min_d == -1 || d < min_d)
949 <               min_d = d;
644 <        }
943 >      Display_lists[i][which] = i+1 + which*SM_DL_LISTS;
944 >      glNewList(Display_lists[i][which],GL_COMPILE_AND_EXECUTE);
945 >      smClear_flags(sm,T_NEW_FLAG);
946 >      glBegin(GL_TRIANGLES);
947 >      smRender_qtree(sm,qt,vp,wp,rgb,which,FALSE);
948 >      glEnd();
949 >      glEndList();
950      }
951 <    td[i].depth = min_d;
951 >    else
952 >    {
953 >      glCallList(Display_lists[i][which]);
954 >    }
955    }
956 <  if(!sort)
957 <    return(tlist);
958 <  qsort((void *)td,smNew_tri_cnt,sizeof(T_DEPTH),compare_tri_depths);
959 <  return(tlist);
956 >  else
957 >    if(QT_IS_FLAG(qt))
958 >    {
959 >      i = ((i - level_i)<< 2) + level_i + leaf_cnt;
960 >      level_i += leaf_cnt;
961 >      leaf_cnt <<= 2;
962 >      for(j=0; j < 4; j++)
963 >        smRender_qtree_dl(sm,QT_NTH_CHILD(qt,j),vp,wp,rgb,
964 >                        i+j,level_i,level+1,max_level,leaf_cnt,which);
965 >    }
966 >
967   }
968  
969 <
970 < smUpdate_Rendered_mesh(sm,vp,clr)
969 > /*
970 > * smRender_qtree(sm,qt,vp,wp,rgb,which,cull) : Render the tris stored in qtree
971 > *  SM *sm;             : mesh
972 > *  QUADTREE qt;        : quadtree base node
973 > *  FVECT vp;           : current viewpoint
974 > *  float (*wp)[3]      : array of sample points
975 > *  BYTE (*rgb)[3]      : array of RGB values for samples
976 > *  int which;          : flag indicates whether to render fg or bg tris
977 > *  int cull;           : if true, only traverse active (flagged) nodes
978 > *
979 > */
980 > smRender_qtree(sm,qt,vp,wp,rgb,which,cull)
981   SM *sm;
982 + QUADTREE qt;
983   FVECT vp;
984 < int clr;
984 > float (*wp)[3];
985 > BYTE  (*rgb)[3];
986 > int which,cull;
987   {
988 <  static T_DEPTH *td= NULL;
989 <  static int tsize = 0;
990 <  int i,v0_id,v1_id,v2_id,bg0,bg1,bg2;
991 <  GLint depth_test;
992 <  double d;
993 <  LIST *bglist;
994 <  TRI *tri;
988 >  int i;
989 >  
990 >  if(QT_IS_EMPTY(qt))
991 >    return;
992 >
993 >  if(QT_IS_LEAF(qt))
994 >  {
995 >    TRI *t;
996 >    OBJECT *optr;
997 >    int t_id,v0_id,v1_id,v2_id,bg0,bg1,bg2;
998 >
999 >    if(cull && !QT_LEAF_IS_FLAG(qt))
1000 >      return;
1001 >
1002 >    optr = qtqueryset(qt);
1003 >    for (i = QT_SET_CNT(optr),optr = QT_SET_PTR(optr);i > 0; i--)
1004 >    {
1005 >      t_id = QT_SET_NEXT_ELEM(optr);
1006 >      t = SM_NTH_TRI(sm,t_id);
1007 >      if(!T_IS_VALID(t) || (cull &&!SM_IS_NTH_T_ACTIVE(sm,t_id)) ||
1008 >         SM_IS_NTH_T_NEW(sm,t_id))
1009 >        continue;
1010 >      
1011 >      bg0 = SM_IS_NTH_T_BG(sm,t_id);
1012 >      if((which== SM_RENDER_FG && bg0) || (which== SM_RENDER_BG && !bg0))
1013 >        continue;
1014 >
1015 >      v0_id = T_NTH_V(t,0);
1016 >      v1_id = T_NTH_V(t,1);
1017 >      v2_id = T_NTH_V(t,2);
1018 >      if(bg0)
1019 >      {
1020 >        bg0 = SM_DIR_ID(sm,v0_id)?DIR:SM_BASE_ID(sm,v0_id)?BASE:0;
1021 >        bg1 = SM_DIR_ID(sm,v1_id)?DIR:SM_BASE_ID(sm,v1_id)?BASE:0;
1022 >        bg2 = SM_DIR_ID(sm,v2_id)?DIR:SM_BASE_ID(sm,v2_id)?BASE:0;
1023 >        SM_SET_NTH_T_NEW(sm,t_id);  
1024 >        if(bg0==DIR && bg1==DIR && bg2==DIR)
1025 >          render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1026 >                  rgb[v2_id])
1027 >         else
1028 >           render_mixed_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
1029 >                 rgb[v1_id],rgb[v2_id],vp,SM_VIEW_CENTER(sm),bg0,bg1,bg2);
1030 >      }
1031 >      else
1032 >      {
1033 >        SM_SET_NTH_T_NEW(sm,t_id);  
1034 >        bg0 = SM_BASE_ID(sm,v0_id);
1035 >        bg1 = SM_BASE_ID(sm,v1_id);
1036 >        bg2 = SM_BASE_ID(sm,v2_id);
1037 >        if(bg0 || bg1 || bg2)
1038 >          render_base_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],
1039 >             rgb[v1_id],rgb[v2_id],SM_VIEW_CENTER(sm),bg0,bg1,bg2);
1040 >        else
1041 >          render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1042 >                   rgb[v2_id])
1043 >      }
1044 >    }
1045 >  }
1046 >  else
1047 >    if(!cull  || QT_IS_FLAG(qt))
1048 >      for(i=0; i < 4; i++)
1049 >        smRender_qtree(sm,QT_NTH_CHILD(qt,i),vp,wp,rgb,which,cull);
1050 > }
1051 >
1052 > /*
1053 > * smRender_mesh(sm,view,cull) : Render mesh Triangles
1054 > *   SM *sm;                   : mesh
1055 > *   VIEW *view;               : current view
1056 > *   int cull;                 : cull Flag
1057 > *
1058 > *   If cull is TRUE, first mark tris in current
1059 > *   frustum and only render them. Normally, cull will be FALSE only if
1060 > *   it is known that all tris lie in frustum, e.g. after a rebuild
1061 > *
1062 > */
1063 > smRender_mesh(sm,view,cull)
1064 > SM *sm;
1065 > VIEW *view;
1066 > int cull;
1067 > {
1068    float (*wp)[3];
1069    BYTE  (*rgb)[3];
1070 +  int i;
1071 +  STREE *st= SM_LOCATOR(sm);
1072  
1073 <  /* For all of the NEW triangles (since last update): assume
1074 <     ACTIVE. Go through and sort on depth value (from vp). Turn
1075 <     Depth Buffer test off and render back-front
1073 >  smUpdate_tm(sm);
1074 >
1075 >  wp = SM_WP(sm);
1076 >  rgb =SM_RGB(sm);
1077 >
1078 >  smClear_flags(sm,T_NEW_FLAG);
1079 >
1080 >  if(cull)
1081 >    smCull(sm,view,SM_ALL_LEVELS);
1082 >
1083 >
1084 >  glPushAttrib(GL_DEPTH_BUFFER_BIT);
1085 >  glDisable(GL_DEPTH_TEST);
1086 >  
1087 >  glMatrixMode(GL_MODELVIEW);
1088 >  glPushMatrix();
1089 >  /* move relative to the new view */
1090 >  glTranslated(view->vp[0],view->vp[1],view->vp[2]);
1091 >
1092 >
1093 >  /* The points are a distance of 1 away from the origin: if necessary
1094 >     scale so that they fit in frustum and are therefore not clipped away
1095       */
1096 <  /* NOTE: could malloc each time or hard code */
675 < #if 0
676 <  if(smNew_tri_cnt > tsize)
1096 >  if(dev_zmin >= 0.99)
1097    {
1098 <    if(td)
1099 <      free((char *)td);
1100 <    td = (T_DEPTH *)malloc(smNew_tri_cnt*sizeof(T_DEPTH));
1101 <    tsize = smNew_tri_cnt;
1098 >    double d;
1099 >
1100 >    d = (dev_zmin+dev_zmax)/2.0;
1101 >    glScaled(d,d,d);
1102    }
1103 <  if(!td)
1103 >  /* move points to unit sphere at origin */
1104 >  glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
1105 >               -SM_VIEW_CENTER(sm)[2]);
1106 >
1107 >  glBegin(GL_TRIANGLES);
1108 >  for(i=0; i < ST_NUM_ROOT_NODES; i++)
1109 >      smRender_qtree(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,SM_RENDER_BG,cull);
1110 >  glEnd();
1111 >
1112 >  glPopMatrix();
1113 >
1114 >  glEnable(GL_DEPTH_TEST);
1115 >
1116 >  glBegin(GL_TRIANGLES);
1117 >  for(i=0; i < ST_NUM_ROOT_NODES; i++)
1118 >    smRender_qtree(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,SM_RENDER_FG,cull);
1119 >  glEnd();
1120 >
1121 >  glPopAttrib();
1122 > }
1123 >
1124 > /*
1125 > * smRender_mesh_dl(sm,view) : Render stree utilizing display lists
1126 > * SM *sm;                   : mesh
1127 > * VIEW *view;               : current view
1128 > */
1129 > smRender_mesh_dl(sm,view)
1130 > SM *sm;
1131 > VIEW *view;
1132 > {
1133 >  float (*wp)[3];
1134 >  BYTE  (*rgb)[3];
1135 >  STREE *st;
1136 >  int i;
1137 >
1138 >  if(SM_DL_LEVELS == 0)
1139    {
1140 <    error(SYSTEM,"smUpdate_Rendered_mesh:Cannot allocate memory\n");
1141 <  }
1142 <  bglist = smDepth_sort_tris(sm,vp,td);
1143 < #else
1144 <  td = smNew_tris;
1145 <  if(!EQUAL_VEC3(SM_VIEW_CENTER(sm),vp))
1146 <    bglist = smOrder_new_tris(sm,vp,td,1);
1147 <  else
1148 <    bglist = smOrder_new_tris(sm,vp,td,0);
1149 < #endif
1140 >    if(!Display_lists[0][0])
1141 >    {
1142 >      Display_lists[0][0] = 1;
1143 >      glNewList(Display_lists[0][0],GL_COMPILE_AND_EXECUTE);
1144 >      smRender_mesh(sm,view,FALSE);
1145 >      glEndList();
1146 >    }
1147 >    else
1148 >      glCallList(Display_lists[0][0]);
1149 >
1150 >    return;
1151 >  }    
1152 >  smCull(sm,view,SM_DL_LEVELS);
1153 >
1154 >  st = SM_LOCATOR(sm);
1155 >
1156    wp = SM_WP(sm);
1157    rgb =SM_RGB(sm);
1158 <  /* Turn Depth Test off -- using Painter's algorithm */
1158 >
1159 >    /* For all active quadtree nodes- first render bg tris, then fg */
1160 >    /* If display list exists, use otherwise create/display list */
1161 >   glPushAttrib(GL_DEPTH_BUFFER_BIT);
1162 >   glDisable(GL_DEPTH_TEST);
1163 >
1164 >   glMatrixMode(GL_MODELVIEW);
1165 >   glPushMatrix();
1166 >
1167 >   /* move relative to the new view */
1168 >   glTranslated(view->vp[0],view->vp[1],view->vp[2]);
1169 >
1170 >   /* The points are a distance of 1 away from the origin: if necessary
1171 >      scale so that they fit in frustum and are therefore not clipped away
1172 >      */
1173 >   if(dev_zmin >= 0.99)
1174 >   {
1175 >     double d;
1176 >     d = (dev_zmin+dev_zmax)/2.0;
1177 >     glScaled(d,d,d);
1178 >   }
1179 >    /* move points to unit sphere at origin */
1180 >   glTranslated(-SM_VIEW_CENTER(sm)[0],-SM_VIEW_CENTER(sm)[1],
1181 >                   -SM_VIEW_CENTER(sm)[2]);
1182 >   for(i=0; i < ST_NUM_ROOT_NODES; i++)
1183 >     smRender_qtree_dl(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,i,0,1,
1184 >                       SM_DL_LEVELS,8,SM_RENDER_BG);
1185 >   glPopMatrix();
1186 >
1187 >   glEnable(GL_DEPTH_TEST);
1188 >   for(i=0; i < ST_NUM_ROOT_NODES; i++)
1189 >     smRender_qtree_dl(sm,ST_ROOT_QT(st,i),view->vp,wp,rgb,i,0,1,
1190 >                        SM_DL_LEVELS,8,SM_RENDER_FG);
1191 >   glPopAttrib();
1192 > }
1193 >
1194 >
1195 >
1196 > /*
1197 > * smRender_tris(sm,view,render_flag)  : Render all of the mesh triangles
1198 > *  SM *sm             : current geometry
1199 > *  VIEW *view         : current view
1200 > *  int render_flag    : if render_flag & SM_RENDER_CULL: do culling first
1201 > *
1202 > * Renders mesh by traversing triangle list and drawing all active tris-
1203 > * background tris first, then foreground and mixed tris
1204 > */
1205 > smRender_tris(sm,view,render_flag)
1206 > SM *sm;
1207 > VIEW *view;
1208 > int render_flag;
1209 > {
1210 >  int4  *active_flag,*bg_flag;
1211 >  float (*wp)[3];
1212 >  BYTE  (*rgb)[3];
1213 >
1214 >  wp = SM_WP(sm);
1215 >  rgb =SM_RGB(sm);
1216 >  active_flag = SM_NTH_FLAGS(sm,T_ACTIVE_FLAG);
1217 >  bg_flag = SM_NTH_FLAGS(sm,T_BG_FLAG);
1218 >
1219 >  if(render_flag & SM_RENDER_CULL)
1220 >    smCull(sm,view,SM_ALL_LEVELS);
1221 >  
1222 >  /* Render triangles made up of points at infinity by turning off
1223 >     depth-buffering and projecting the points onto a sphere around the view*/
1224    glPushAttrib(GL_DEPTH_BUFFER_BIT);
1225 <  glDepthFunc(GL_ALWAYS);
1226 <  d = (dev_zmin+dev_zmax)/2.0;
1227 <  /* Now render back-to front */
1228 <  /* First render bg triangles */
1229 <  glBegin(GL_TRIANGLES);
1230 <  while(bglist)
1225 >  glDisable(GL_DEPTH_TEST);
1226 >  smRender_bg_tris(sm,view->vp,active_flag,bg_flag,wp,rgb);
1227 >
1228 >  /* Render triangles containing world-space points */
1229 >  glEnable(GL_DEPTH_TEST);
1230 >  smRender_fg_tris(sm,view->vp,active_flag,bg_flag,wp,rgb);
1231 >
1232 >  glPopAttrib();
1233 >
1234 > }
1235 >
1236 > /* Clear all of the display lists */
1237 > clear_display_lists()
1238 > {
1239 >  int i;
1240 >  for(i=0; i< SM_DL_LISTS; i++)
1241    {
1242 <    i = pop_list(&bglist);
1243 <    if (clr)
1244 <      SM_CLR_NTH_T_NEW(sm,i);
1245 <    tri = SM_NTH_TRI(sm,i);
1246 <    v0_id = T_NTH_V(tri,0);
1247 <    v1_id = T_NTH_V(tri,1);
1248 <    v2_id = T_NTH_V(tri,2);
1249 <    render_bg_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1250 <                   rgb[v2_id],vp,SM_VIEW_CENTER(sm),d);
1242 >    if(Display_lists[i][0])
1243 >    { /* Clear the foreground display list */
1244 >      glDeleteLists(Display_lists[i][0],1);
1245 >      Display_lists[i][0] = 0;
1246 >    }
1247 >    if(Display_lists[i][1])
1248 >    { /* Clear the background display list */
1249 >      glDeleteLists(Display_lists[i][1],1);
1250 >      Display_lists[i][1] = 0;
1251 >    }
1252    }
1253 <  glEnd();
1253 > }
1254  
1255 + /*
1256 + * qtClear_dl(qt,i,level_i,level,max_level,leaf_cnt) :clear display lists
1257 + * QUADTREE *qt;               : Quadtree node  
1258 + * int i;                      : index into list of display lists for this node
1259 + * int level_i;                : index for first node at this level
1260 + * int level,max_level;        : current level, maximum level to descend
1261 + * int leaf_cnt;               : number of leaves at this level
1262 + *
1263 + *  For each node under this node that has its flag set: delete all
1264 + *  existing display lists. Display lists are stored in an array indexed as
1265 + *  if the quadtree was traversed in a breadth first order (indices 0-7 are
1266 + *  the 8 quadtree roots, indices 8-11 the first level children of root 0,
1267 + *  indices 12-15 the children of root 1, etc). It is assumes that the display
1268 + *  lists will only be stored for a small number of levels: if this is not
1269 + *  true, a hashing scheme would work better for storing/retrieving the
1270 + *  display lists
1271 + */
1272 + qtClear_dl(qt,i,level_i,level,max_level,leaf_cnt)
1273 + QUADTREE qt;
1274 + int i,level_i,level,max_level,leaf_cnt;
1275 + {
1276 +  int j;
1277  
1278 <  glBegin(GL_TRIANGLES);
1279 <  i=0;
1280 <  while(i != smNew_tri_cnt)
1278 >  if(QT_IS_EMPTY(qt))
1279 >    return;
1280 >  if(QT_IS_LEAF(qt) || level== max_level)
1281    {
1282 <    if(td[i].tri == -1)
1283 <      {
1284 <        i++;
1285 <        continue;
1286 <      }
1287 <    if (clr)
1288 <      SM_CLR_NTH_T_NEW(sm,td[i].tri);
1289 <    tri = SM_NTH_TRI(sm,td[i].tri);
1290 <    v0_id = T_NTH_V(tri,0);
1291 <    v1_id = T_NTH_V(tri,1);
1292 <    v2_id = T_NTH_V(tri,2);
1293 <    bg0 = SM_DIR_ID(sm,v0_id) || SM_BASE_ID(sm,v0_id);
1294 <    bg1 = SM_DIR_ID(sm,v1_id) || SM_BASE_ID(sm,v1_id);
1295 <    bg2 = SM_DIR_ID(sm,v2_id) || SM_BASE_ID(sm,v2_id);
1296 <    if(!(bg0 || bg1 || bg2))
1297 <      render_tri(wp[v0_id],wp[v1_id],wp[v2_id],rgb[v0_id],rgb[v1_id],
1298 <                 rgb[v2_id])
1299 <   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++;
1282 >    if(QT_IS_LEAF(qt))
1283 >    {
1284 >      if(!QT_LEAF_IS_FLAG(qt))
1285 >        return;
1286 >    }
1287 >    else
1288 >      if(!QT_IS_FLAG(qt))
1289 >        return;
1290 >    if(Display_lists[i][0])
1291 >    {
1292 >      glDeleteLists(Display_lists[i][0],1);
1293 >      Display_lists[i][0] = 0;
1294 >    }
1295 >    if(Display_lists[i][1])
1296 >    {
1297 >      glDeleteLists(Display_lists[i][1],1);
1298 >      Display_lists[i][1] = 0;
1299 >    }
1300    }
1301 <  glEnd();
1301 >  else
1302 >    if(QT_IS_FLAG(qt))
1303 >    {
1304 >      /* Calculate the index for the first child given the values
1305 >         of the parent at  the current level
1306 >       */
1307 >      i = ((i - level_i)<< 2) + level_i + leaf_cnt;
1308 >      level_i += leaf_cnt;
1309 >      leaf_cnt <<= 2;
1310 >      for(j=0; j < 4; j++)
1311 >        qtClear_dl(QT_NTH_CHILD(qt,j),i+j,level_i,level+1,max_level,
1312 >                            leaf_cnt);
1313 >    }
1314 > }
1315  
1316 <  /* Restore Depth Test */
1317 <  glPopAttrib();
1316 > /*
1317 > * smInvalidate_view(sm,view) : Invalidate rendering representation for view
1318 > * SM *sm;                    : mesh
1319 > * VIEW *view;                : current view
1320 > *
1321 > * Delete the existing display lists for geometry in the current
1322 > * view frustum: Called when the geometry in the frustum has been changed
1323 > */
1324 > smInvalidate_view(sm,view)
1325 > SM *sm;
1326 > VIEW *view;
1327 > {
1328 >  int i;
1329 >
1330 >  if(SM_DL_LEVELS == 0)
1331 >  {
1332 >    if(Display_lists[0][0])
1333 >    {
1334 >      glDeleteLists(Display_lists[0][0],1);
1335 >      Display_lists[0][0] = 0;
1336 >    }
1337 >    return;
1338 >  }    
1339 >  /* Mark qtree nodes/tris in frustum */
1340 >  smCull(sm,view,SM_DL_LEVELS);
1341 >
1342 >  /* Invalidate display_lists in marked qtree nodes */
1343 >   for(i=0; i < ST_NUM_ROOT_NODES; i++)
1344 >     qtClear_dl(ST_ROOT_QT(SM_LOCATOR(sm),i),i,0,1,SM_DL_LEVELS,8);
1345 >
1346   }
1347  
1348 +
1349   /*
1350 < * smUpdate(view, qua)  : update OpenGL output geometry for view vp
1350 > * smRender(sm,view, qual): render OpenGL output geometry
1351 > * SM *sm;                : current mesh representation
1352 > * VIEW *view;            : desired view
1353 > * int  qual;             : quality level (percentage on linear time scale)
1354 > *
1355 > * Render the current mesh:
1356 > * recompute tone mapping if full redraw and specified:
1357 > * if moving (i.e. qual < MAXQUALITY)
1358 > *     render the cached display lists, if quality drops
1359 > *     below threshold, render approximation instead
1360 > *  if stationary
1361 > *     render mesh geometry without display lists, unless up-to-date
1362 > *     display lists already exist.
1363 > */
1364 > smRender(sm,view,qual)
1365 > SM *sm;
1366 > VIEW *view;
1367 > int qual;
1368 > {
1369 >
1370 >  /* Recompute tone mapping if specified */
1371 >  if( qual >= MAXQUALITY && smCompute_mapping)
1372 >    smUpdate_tm(sm);
1373 >
1374 >  /* Unless quality > MAXQUALITY, render using display lists */
1375 >  if(qual <= MAXQUALITY)
1376 >  {
1377 >    /* If quality above threshold: render mesh*/
1378 >    if(qual > (MAXQUALITY*2/4))
1379 >      /* render stree using display lists */
1380 >      smRender_mesh_dl(sm,view);
1381 >    else
1382 >      /* If quality below threshold, use approximate rendering */
1383 >      smRender_approx(sm,qual,view);
1384 >  }
1385 >  else
1386 >      /* render stree without display lists */
1387 >      smRender_mesh(sm,view,TRUE);
1388 > }
1389 >
1390 >
1391 > /*
1392 > * smUpdate(view, qual) : update OpenGL output geometry
1393   * VIEW *view;          : desired view
1394   * int  qual;           : quality level (percentage on linear time scale)
1395   *
# Line 757 | Line 1397 | int clr;
1397   * view has already been set up and the correct frame buffer has been
1398   * selected for drawing.  The quality level is on a linear scale, where 100%
1399   * is full (final) quality.  It is not necessary to redraw geometry that has
1400 < * been output since the last call to smClean().  (The last view drawn will
1400 > * been output since the last call to smClean().(The last view drawn will
1401   * be view==&odev.v each time.)
1402   */
1403   smUpdate(view,qual)
1404     VIEW *view;
1405     int qual;
1406   {
1407 <  double d;
1408 <  int last_update;
769 <  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)
1407 >  /* Is there anything to render? */
1408 >  if(!smMesh || SM_NUM_TRI(smMesh)<=0)
1409      return;
1410  
1411 <  d = DIST(view->vp,SM_VIEW_CENTER(smMesh));
1412 <  if(qual >= 100 && d > SM_ALLOWED_VIEW_CHANGE(smMesh))
1411 >  /* Is viewer MOVING?*/
1412 >  if(qual < MAXQUALITY)
1413    {
1414 <      /* Re-build the mesh */
1415 < #ifdef TEST_DRIVER
1416 <    odev.v = *view;
785 < #endif  
786 <      mark_tris_in_frustum(view);
787 <      smRebuild_mesh(smMesh,view);
788 <      smClean_notify = TRUE;
1414 >    /* Render mesh using display lists */
1415 >    smRender(smMesh,view,qual);
1416 >    return;
1417    }
1418 <  /* This is our final update iff qual==100 and view==&odev.v */
1419 <  last_update = qual>=100 && view==&(odev.v);
1420 <  /* Check if we should draw ALL triangles in current frustum */
1421 <  if(smClean_notify || smNew_tri_cnt > SM_SAMPLE_TRIS(smMesh)*SM_INC_PERCENT)
1418 >
1419 >  /* Viewer is STATIONARY */
1420 >
1421 >  /* Has view moved epsilon from canonical view? (epsilon= percentage
1422 >     (SM_VIEW_FRAC) of running average of the distance of the sample points
1423 >     from the canonical view */
1424 >  if(DIST(view->vp,SM_VIEW_CENTER(smMesh)) > SM_ALLOWED_VIEW_CHANGE(smMesh))
1425    {
1426 < #ifdef TEST_DRIVER
1427 <    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1428 < #else
1429 <    if ( SM_TONE_MAP(smMesh) < SM_NUM_SAMP(smMesh))
1426 >    /* Must rebuild mesh with current view as new canonical view  */
1427 >    smRebuild_mesh(smMesh,view);
1428 >    /* Existing display lists and tonemapping are no longer valid */
1429 >    clear_display_lists();
1430 >    smCompute_mapping = TRUE;
1431 >    /* Render all the triangles in the new mesh */
1432 >    smRender(smMesh,view,qual+1);
1433 >  }
1434 >  else
1435 >    /* Has a complete redraw been requested ?*/
1436 >    if(smClean_notify)
1437      {
1438 <       tmClearHisto();
1439 <       tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
802 <       tmComputeMapping(0.,0.,0.);
803 <       tmMapPixels(SM_RGB(smMesh),SM_BRT(smMesh),SM_CHR(smMesh),
804 <                   SM_NUM_SAMP(smMesh));
1438 >      smIncremental = FALSE;
1439 >      smRender(smMesh,view,qual);
1440      }
806 #endif
807    mark_tris_in_frustum(view);
808    if (qual <= 75)
809        smRender_stree(smMesh,qual);
1441      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)
1442      {
1443 <        tmClearHisto();
1444 <        tmAddHisto(SM_BRT(smMesh),SM_NUM_SAMP(smMesh),1);
1445 <        if(tmComputeMapping(0.,0.,0.) != TM_E_OK)
831 <           return;
832 <    }
833 <    tmMapPixels(SM_NTH_RGB(smMesh,t),&SM_NTH_BRT(smMesh,t),
834 <                   SM_NTH_CHR(smMesh,t), SM_NUM_SAMP(smMesh)-t);
835 <        
836 < #endif    
837 <    smUpdate_Rendered_mesh(smMesh,view->vp,last_update);
838 <    
839 < #ifdef TEST_DRIVER
840 <    glDrawBuffer(GL_BACK);
841 < #endif
842 <  }
1443 >      /* Viewer fixed and receiving new samples for the same view */
1444 >      if(!smNew_tri_cnt)
1445 >        return;
1446  
1447 <  SM_TONE_MAP(smMesh) = SM_NUM_SAMP(smMesh);
1448 <
1449 <  if (last_update)
1447 >      /* If number of new triangles relatively small: do incremental update */
1448 >      if(smNew_tri_cnt < SM_SAMPLE_TRIS(smMesh)*SM_INC_PERCENT)
1449 >        {
1450 >          /* Mark Existing display lists in frustum invalid */
1451 >          if(!smIncremental)
1452 >          {
1453 >            smInvalidate_view(smMesh,view);
1454 >            smIncremental = TRUE;
1455 >          }
1456 >          smRender_inc(smMesh,view->vp);
1457 >        }
1458 >      else
1459 >        /* Otherwise render all of the active triangles */
1460 >          smRender(smMesh,view,qual+1);
1461 >  }
1462 >  /* This is our final update iff qual==MAXQUALITY and view==&odev.v */
1463 >  if( (qual >= MAXQUALITY) && (view == &(odev.v)))
1464    {
1465 +    /* reset rendering flags */
1466      smClean_notify = FALSE;
1467      smNew_tri_cnt = 0;
850 #if 0  
1468      smClear_flags(smMesh,T_NEW_FLAG);
852 #endif
1469      qtCache_init(0);
1470    }
1471  

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines