Edit

IABSD.fr/xenocara/lib/libGLU/src/libnurbs/interface/glsurfeval.cc

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2013-09-01 03:51:12
    Hash : 729f7da4
    Message : Update to GLU 9.0.0, GLU was previously part of Mesa but is now seperate. tested in a ports bulk build by landry@, ok matthieu@

  • lib/libGLU/src/libnurbs/interface/glsurfeval.cc
  • /*
    ** License Applicability. Except to the extent portions of this file are
    ** made subject to an alternative license as permitted in the SGI Free
    ** Software License B, Version 1.1 (the "License"), the contents of this
    ** file are subject only to the provisions of the License. You may not use
    ** this file except in compliance with the License. You may obtain a copy
    ** of the License at Silicon Graphics, Inc., attn: Legal Services, 1600
    ** Amphitheatre Parkway, Mountain View, CA 94043-1351, or at:
    **
    ** http://oss.sgi.com/projects/FreeB
    **
    ** Note that, as provided in the License, the Software is distributed on an
    ** "AS IS" basis, with ALL EXPRESS AND IMPLIED WARRANTIES AND CONDITIONS
    ** DISCLAIMED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED WARRANTIES AND
    ** CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY, FITNESS FOR A
    ** PARTICULAR PURPOSE, AND NON-INFRINGEMENT.
    **
    ** Original Code. The Original Code is: OpenGL Sample Implementation,
    ** Version 1.2.1, released January 26, 2000, developed by Silicon Graphics,
    ** Inc. The Original Code is Copyright (c) 1991-2000 Silicon Graphics, Inc.
    ** Copyright in any portions created by third parties is as indicated
    ** elsewhere herein. All Rights Reserved.
    **
    ** Additional Notice Provisions: The application programming interfaces
    ** established by SGI in conjunction with the Original Code are The
    ** OpenGL(R) Graphics System: A Specification (Version 1.2.1), released
    ** April 1, 1999; The OpenGL(R) Graphics System Utility Library (Version
    ** 1.3), released November 4, 1998; and OpenGL(R) Graphics with the X
    ** Window System(R) (Version 1.3), released October 19, 1998. This software
    ** was created using the OpenGL(R) version 1.2.1 Sample Implementation
    ** published by SGI, but has not been independently verified as being
    ** compliant with the OpenGL(R) version 1.2.1 Specification.
    */
    
    /*
     * glsurfeval.c++
     *
     */
    
    /* Polynomial Evaluator Interface */
    #include "gluos.h"
    #include <stdio.h>
    #include "glimports.h"
    #include "glrenderer.h"
    #include "glsurfeval.h"
    #include "nurbsconsts.h"
    #include "bezierPatchMesh.h"
    
    
    //extern int surfcount;
    //int surfcount=0;
    
    /*#define USE_INTERNAL_EVAL*/ //use internal evaluator
    
    /*whether do evaluation or not*/
    /*#define NO_EVALUATION*/
    
    //#define USE_LOD //for LOD test, have to turn on USE_LOD in insurfeval.c++ too
    
    /*for statistics*/
    //#define STATISTICS
    #ifdef STATISTICS
    static int STAT_num_of_triangles=0;
    static int STAT_num_of_eval_vertices=0;
    static int STAT_num_of_quad_strips=0;
    #endif
    
    /*for output triangles*/
    /*#define OUTPUT_TRIANGLES*/
    
    
    /*#define FOR_CHRIS*/
    #ifdef FOR_CHRIS
    extern "C"  {  void                evalUStripExt(int n_upper, REAL v_upper, REAL* upper_val,
    				   int n_lower, REAL v_lower, REAL* lower_val);}
    
    extern "C" {   void                evalVStripExt(int n_left, REAL u_left, REAL* left_val,
    				   int n_right, REAL u_right, REAL* right_val);
    	     }
    #endif
    
    
    /**************begin for LOD_eval_list***********/
    void OpenGLSurfaceEvaluator::LOD_eval_list(int level)
    {
      if(level == 0)
        LOD_eval_level = 1;
      else if(level == 1)
        LOD_eval_level = 2;
      else if(level == 2)
        LOD_eval_level = 4;
      else
        LOD_eval_level = 8;
    
      inBPMListEvalEM(global_bpm);
    }
    
    
    OpenGLSurfaceEvaluator::OpenGLSurfaceEvaluator()
    {
        int i;
    
        for (i=0; i<VERTEX_CACHE_SIZE; i++) {
    	vertexCache[i] = new StoredVertex;
        }
        tmeshing = 0;
        which = 0;
        vcount = 0;
    
        global_uorder = 0;
        global_vorder = 0;
        global_uprime = -1.0;
        global_vprime = -1.0;
        global_vprime_BV = -1.0;
        global_uprime_BU = -1.0;
        global_uorder_BU = 0;
        global_vorder_BU = 0;
        global_uorder_BV = 0;
        global_vorder_BV = 0;
        global_baseData = NULL;
            
        global_bpm = NULL;
        output_triangles = 0; //don't output triangles by default
    
        //no default callback functions
        beginCallBackN = NULL;
        endCallBackN = NULL;
        vertexCallBackN = NULL;
        normalCallBackN = NULL;
        colorCallBackN = NULL;
        texcoordCallBackN = NULL;
        beginCallBackData = NULL;
        endCallBackData = NULL;
        vertexCallBackData = NULL;
        normalCallBackData = NULL;
        colorCallBackData = NULL;
        texcoordCallBackData = NULL;
    
        userData = NULL;
    
        auto_normal_flag = 0;
        callback_auto_normal = 0; //default of GLU_CALLBACK_AUTO_NORMAL is 0
        vertex_flag = 0;
        normal_flag = 0;
        color_flag = 0;
        texcoord_flag = 0;
    
        em_vertex.uprime = -1.0;
        em_vertex.vprime = -1.0;
        em_normal.uprime = -1.0;
        em_normal.vprime = -1.0;
        em_color.uprime = -1.0;
        em_color.vprime = -1.0;
        em_texcoord.uprime = -1.0;
        em_texcoord.vprime = -1.0;
    
    #ifdef USE_LOD
        LOD_eval_level = 1;
    #endif
    }
    
    OpenGLSurfaceEvaluator::~OpenGLSurfaceEvaluator()
    {
       for (int ii= 0; ii< VERTEX_CACHE_SIZE; ii++) {
          delete vertexCache[ii];
          vertexCache[ii]= 0;
       }
    }
    
    /*---------------------------------------------------------------------------
     * disable - turn off a map
     *---------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::disable(long type)
    {
        glDisable((GLenum) type);
    }
    
    /*---------------------------------------------------------------------------
     * enable - turn on a map
     *---------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::enable(long type)
    {
        glEnable((GLenum) type);
    }
    
    /*-------------------------------------------------------------------------
     * mapgrid2f - define a lattice of points with origin and offset
     *-------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::mapgrid2f(long nu, REAL u0, REAL u1, long nv, REAL v0, REAL v1)
    {
    #ifdef USE_INTERNAL_EVAL
      inMapGrid2f((int) nu, (REAL) u0, (REAL) u1, (int) nv,
    	      (REAL) v0, (REAL) v1);
    #else
    
      if(output_triangles)  
        {
          global_grid_u0 = u0;
          global_grid_u1 = u1;
          global_grid_nu = nu;
          global_grid_v0 = v0;
          global_grid_v1 = v1;
          global_grid_nv = nv;
        }
      else
        glMapGrid2d((GLint) nu, (GLdouble) u0, (GLdouble) u1, (GLint) nv,
    	    (GLdouble) v0, (GLdouble) v1);
    
    #endif
    }
    
    void
    OpenGLSurfaceEvaluator::polymode(long style)
    {
      if(! output_triangles)
        {
          switch(style) {
          default:
          case N_MESHFILL:
            
    	glPolygonMode((GLenum) GL_FRONT_AND_BACK, (GLenum) GL_FILL);
    	break;
          case N_MESHLINE:
    	glPolygonMode((GLenum) GL_FRONT_AND_BACK, (GLenum) GL_LINE);
    	break;
          case N_MESHPOINT:
    	glPolygonMode((GLenum) GL_FRONT_AND_BACK, (GLenum) GL_POINT);
    	break;
          }
        }
    }
    
    void
    OpenGLSurfaceEvaluator::bgnline(void)
    {
      if(output_triangles)
        bezierPatchMeshBeginStrip(global_bpm, GL_LINE_STRIP);
      else
        glBegin((GLenum) GL_LINE_STRIP);
    }
    
    void
    OpenGLSurfaceEvaluator::endline(void)
    {
      if(output_triangles)
        bezierPatchMeshEndStrip(global_bpm);
      else
        glEnd();
    }
    
    void
    OpenGLSurfaceEvaluator::range2f(long type, REAL *from, REAL *to)
    {
    }
    
    void
    OpenGLSurfaceEvaluator::domain2f(REAL ulo, REAL uhi, REAL vlo, REAL vhi)
    {
    }
    
    void
    OpenGLSurfaceEvaluator::bgnclosedline(void)
    {
      if(output_triangles)
        bezierPatchMeshBeginStrip(global_bpm, GL_LINE_LOOP);
      else
        glBegin((GLenum) GL_LINE_LOOP);
    }
    
    void
    OpenGLSurfaceEvaluator::endclosedline(void)
    {
      if(output_triangles)
        bezierPatchMeshEndStrip(global_bpm);
      else
        glEnd();
    }
    
    
    
    
    
    void
    OpenGLSurfaceEvaluator::bgntmesh(void)
    {
    
        tmeshing = 1;
        which = 0;
        vcount = 0;
    
        if(output_triangles)
          bezierPatchMeshBeginStrip(global_bpm, GL_TRIANGLES);
        else
          glBegin((GLenum) GL_TRIANGLES);
    
    }
    
    void
    OpenGLSurfaceEvaluator::swaptmesh(void)
    {
        which = 1 - which;
    
    }
    
    void
    OpenGLSurfaceEvaluator::endtmesh(void)
    {
        tmeshing = 0;
    
    
        if(output_triangles)
          bezierPatchMeshEndStrip(global_bpm);
        else
          glEnd();
    }
    
    void
    OpenGLSurfaceEvaluator::bgntfan(void)
    {
    
      if(output_triangles)
        bezierPatchMeshBeginStrip(global_bpm, GL_TRIANGLE_FAN);
      else
        glBegin((GLenum) GL_TRIANGLE_FAN);
    
    }
    void
    OpenGLSurfaceEvaluator::endtfan(void)
    {
      if(output_triangles)
    	bezierPatchMeshEndStrip(global_bpm);
      else
        glEnd();
    }
    
    void
    OpenGLSurfaceEvaluator::evalUStrip(int n_upper, REAL v_upper, REAL* upper_val, int n_lower, REAL v_lower, REAL* lower_val)
    {
    #ifdef USE_INTERNAL_EVAL
      inEvalUStrip(n_upper, v_upper, upper_val,
    	n_lower, v_lower, lower_val);
    #else
    
    #ifdef FOR_CHRIS
      evalUStripExt(n_upper, v_upper, upper_val,
    		 n_lower, v_lower, lower_val);
      return;
    
    #endif
      int i,j,k,l;
      REAL leftMostV[2];
    
      /*
       *the algorithm works by scanning from left to right.
       *leftMostV: the left most of the remaining verteces (on both upper and lower).
       *	       it could an element of upperVerts or lowerVerts.
       *i: upperVerts[i] is the first vertex to the right of leftMostV on upper line
       *j: lowerVerts[j] is the first vertex to the right of leftMostV on lower line
       */
    
      /*initialize i,j,and leftMostV
       */
      if(upper_val[0] <= lower_val[0])
        {
          i=1;
          j=0;
    
          leftMostV[0] = upper_val[0];
          leftMostV[1] = v_upper;
        }
      else
        {
          i=0;
          j=1;
    
          leftMostV[0] = lower_val[0];
          leftMostV[1] = v_lower;
    
        }
    
      /*the main loop.
       *the invariance is that:
       *at the beginning of each loop, the meaning of i,j,and leftMostV are
       *maintained
       */
      while(1)
        {
          if(i >= n_upper) /*case1: no more in upper*/
    	{
    	  if(j<n_lower-1) /*at least two vertices in lower*/
    	    {
    	      bgntfan();
    	      coord2f(leftMostV[0], leftMostV[1]);
    //	      glNormal3fv(leftMostNormal);
    //		glVertex3fv(leftMostXYZ);
    
    	      while(j<n_lower){
    		coord2f(lower_val[j], v_lower);
    //		glNormal3fv(lowerNormal[j]);
    //		glVertex3fv(lowerXYZ[j]);
    		j++;
    
    	      }
    	      endtfan();
    	    }
    	  break; /*exit the main loop*/
    	}
          else if(j>= n_lower) /*case2: no more in lower*/
    	{
    	  if(i<n_upper-1) /*at least two vertices in upper*/
    	    {
    	      bgntfan();
    	      coord2f(leftMostV[0], leftMostV[1]);
    //	      glNormal3fv(leftMostNormal);
    //	      glVertex3fv(leftMostXYZ);
            
    	      for(k=n_upper-1; k>=i; k--) /*reverse order for two-side lighting*/
    		{
    		  coord2f(upper_val[k], v_upper);
    //		  glNormal3fv(upperNormal[k]);
    //		  glVertex3fv(upperXYZ[k]);
    		}
    
    	      endtfan();
    	    }
    	  break; /*exit the main loop*/
    	}
          else /* case3: neither is empty, plus the leftMostV, there is at least one triangle to output*/
    	{
    	  if(upper_val[i] <= lower_val[j])
    	    {
    	      bgntfan();
    	      coord2f(lower_val[j], v_lower);
    //	      glNormal3fv(lowerNormal[j]);
    //	      glVertex3fv(lowerXYZ[j]);
    
    	      /*find the last k>=i such that
    	       *upperverts[k][0] <= lowerverts[j][0]
    	       */
    	      k=i;
    
    	      while(k<n_upper)
    		{
    		  if(upper_val[k] > lower_val[j])
    		    break;
    		  k++;
    
    		}
    	      k--;
    
    
    	      for(l=k; l>=i; l--)/*the reverse is for two-side lighting*/
    		{
    		  coord2f(upper_val[l], v_upper);
    //		  glNormal3fv(upperNormal[l]);
    //		  glVertex3fv(upperXYZ[l]);
    
    		}
    	      coord2f(leftMostV[0], leftMostV[1]);
    //	      glNormal3fv(leftMostNormal);
    //	      glVertex3fv(leftMostXYZ);
    
    	      endtfan();
    
    	      /*update i and leftMostV for next loop
    	       */
    	      i = k+1;
    
    	      leftMostV[0] = upper_val[k];
    	      leftMostV[1] = v_upper;
    //	      leftMostNormal = upperNormal[k];
    //	      leftMostXYZ = upperXYZ[k];
    	    }
    	  else /*upperVerts[i][0] > lowerVerts[j][0]*/
    	    {
    	      bgntfan();
    	      coord2f(upper_val[i], v_upper);
    //	      glNormal3fv(upperNormal[i]);
    //	      glVertex3fv(upperXYZ[i]);
            
    	      coord2f(leftMostV[0], leftMostV[1]);
    //		glNormal3fv(leftMostNormal);
    //	      glVertex3fv(leftMostXYZ);
            
    
    	      /*find the last k>=j such that
    	       *lowerverts[k][0] < upperverts[i][0]
    	       */
    	      k=j;
    	      while(k< n_lower)
    		{
    		  if(lower_val[k] >= upper_val[i])
    		    break;
    		  coord2f(lower_val[k], v_lower);
    //		  glNormal3fv(lowerNormal[k]);
    //		  glVertex3fv(lowerXYZ[k]);
    
    		  k++;
    		}
    	      endtfan();
    
    	      /*update j and leftMostV for next loop
    	       */
    	      j=k;
    	      leftMostV[0] = lower_val[j-1];
    	      leftMostV[1] = v_lower;
    
    //	      leftMostNormal = lowerNormal[j-1];
    //	      leftMostXYZ = lowerXYZ[j-1];
    	    }
    	}
        }
      //clean up
    //  free(upperXYZ);
    //  free(lowerXYZ);
    //  free(upperNormal);
    //  free(lowerNormal);
    #endif
    
    }
    
    
    void
    OpenGLSurfaceEvaluator::evalVStrip(int n_left, REAL u_left, REAL* left_val, int n_right, REAL u_right, REAL* right_val)
    {
    #ifdef USE_INTERNAL_EVAL
    	inEvalVStrip(n_left, u_left, left_val,
    	n_right, u_right, right_val);
    #else
    
    #ifdef FOR_CHRIS
    	evalVStripExt(n_left, u_left, left_val,
    		      n_right, u_right, right_val);
    	return;
    
    #endif
    
      int i,j,k,l;
      REAL botMostV[2];
      /*
       *the algorithm works by scanning from bot to top.
       *botMostV: the bot most of the remaining verteces (on both left and right).
       *	       it could an element of leftVerts or rightVerts.
       *i: leftVerts[i] is the first vertex to the top of botMostV on left line
       *j: rightVerts[j] is the first vertex to the top of botMostV on rightline
       */
    
      /*initialize i,j,and botMostV
       */
      if(left_val[0] <= right_val[0])
        {
          i=1;
          j=0;
    
          botMostV[0] = u_left;
          botMostV[1] = left_val[0];
        }
      else
        {
          i=0;
          j=1;
    
          botMostV[0] = u_right;
          botMostV[1] = right_val[0];
        }
    
      /*the main loop.
       *the invariance is that:
       *at the beginning of each loop, the meaning of i,j,and botMostV are
       *maintained
       */
      while(1)
        {
          if(i >= n_left) /*case1: no more in left*/
    	{
    	  if(j<n_right-1) /*at least two vertices in right*/
    	    {
    	      bgntfan();
    	      coord2f(botMostV[0], botMostV[1]);
    	      while(j<n_right){
    		coord2f(u_right, right_val[j]);
    //		glNormal3fv(rightNormal[j]);
    //		glVertex3fv(rightXYZ[j]);
    		j++;
    
    	      }
    	      endtfan();
    	    }
    	  break; /*exit the main loop*/
    	}
          else if(j>= n_right) /*case2: no more in right*/
    	{
    	  if(i<n_left-1) /*at least two vertices in left*/
    	    {
    	      bgntfan();
    	      coord2f(botMostV[0], botMostV[1]);
    //	      glNormal3fv(botMostNormal);
    //	      glVertex3fv(botMostXYZ);
            
    	      for(k=n_left-1; k>=i; k--) /*reverse order for two-side lighting*/
    		{
    		  coord2f(u_left, left_val[k]);
    //		  glNormal3fv(leftNormal[k]);
    //		  glVertex3fv(leftXYZ[k]);
    		}
    
    	      endtfan();
    	    }
    	  break; /*exit the main loop*/
    	}
          else /* case3: neither is empty, plus the botMostV, there is at least one triangle to output*/
    	{
    	  if(left_val[i] <= right_val[j])
    	    {
    	      bgntfan();
    	      coord2f(u_right, right_val[j]);
    //	      glNormal3fv(rightNormal[j]);
    //	      glVertex3fv(rightXYZ[j]);
    
    	      /*find the last k>=i such that
    	       *leftverts[k][0] <= rightverts[j][0]
    	       */
    	      k=i;
    
    	      while(k<n_left)
    		{
    		  if(left_val[k] > right_val[j])
    		    break;
    		  k++;
    
    		}
    	      k--;
    
    
    	      for(l=k; l>=i; l--)/*the reverse is for two-side lighting*/
    		{
    		  coord2f(u_left, left_val[l]);
    //		  glNormal3fv(leftNormal[l]);
    //		  glVertex3fv(leftXYZ[l]);
    
    		}
    	      coord2f(botMostV[0], botMostV[1]);
    //	      glNormal3fv(botMostNormal);
    //	      glVertex3fv(botMostXYZ);
    
    	      endtfan();
    
    	      /*update i and botMostV for next loop
    	       */
    	      i = k+1;
    
    	      botMostV[0] = u_left;
    	      botMostV[1] = left_val[k];
    //	      botMostNormal = leftNormal[k];
    //	      botMostXYZ = leftXYZ[k];
    	    }
    	  else /*left_val[i] > right_val[j])*/
    	    {
    	      bgntfan();
    	      coord2f(u_left, left_val[i]);
    //	      glNormal3fv(leftNormal[i]);
    //	      glVertex3fv(leftXYZ[i]);
            
    	      coord2f(botMostV[0], botMostV[1]);
    //	      glNormal3fv(botMostNormal);
    //	      glVertex3fv(botMostXYZ);
            
    
    	      /*find the last k>=j such that
    	       *rightverts[k][0] < leftverts[i][0]
    	       */
    	      k=j;
    	      while(k< n_right)
    		{
    		  if(right_val[k] >= left_val[i])
    		    break;
    		  coord2f(u_right, right_val[k]);
    //		  glNormal3fv(rightNormal[k]);
    //		  glVertex3fv(rightXYZ[k]);
    
    		  k++;
    		}
    	      endtfan();
    
    	      /*update j and botMostV for next loop
    	       */
    	      j=k;
    	      botMostV[0] = u_right;
    	      botMostV[1] = right_val[j-1];
    
    //	      botMostNormal = rightNormal[j-1];
    //	      botMostXYZ = rightXYZ[j-1];
    	    }
    	}
        }
      //clean up
    //  free(leftXYZ);
    //  free(leftNormal);
    //  free(rightXYZ);
    //  free(rightNormal);
    #endif
    }
    
    
    void
    OpenGLSurfaceEvaluator::bgnqstrip(void)
    {
      if(output_triangles)
        bezierPatchMeshBeginStrip(global_bpm, GL_QUAD_STRIP);
      else
        glBegin((GLenum) GL_QUAD_STRIP);
    
    #ifdef STATISTICS
    	STAT_num_of_quad_strips++;
    #endif
    }
    
    void
    OpenGLSurfaceEvaluator::endqstrip(void)
    {
      if(output_triangles)
        bezierPatchMeshEndStrip(global_bpm);
      else
        glEnd();
    
    }
    
    /*-------------------------------------------------------------------------
     * bgnmap2f - preamble to surface definition and evaluations
     *-------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::bgnmap2f(long)
    {
      if(output_triangles)
        {
          /*deallocate the space which may has been
           *allocated by global_bpm previously
           */
          if(global_bpm != NULL) {
    	bezierPatchMeshListDelete(global_bpm);
    	global_bpm = NULL;
          }
    
    
          /*
    	auto_normal_flag = 1; //always output normal in callback mode.
    			      //we could have used the following code,
    			      //but Inspector doesn't have gl context
    			      //before it calls tessellator.
    			      //this way is temporary.
    	*/
          //NEWCALLBACK
          //if one of the two normal callback functions are set,
          //then set
          if(normalCallBackN != NULL ||
    	 normalCallBackData != NULL)
    	auto_normal_flag = 1;
          else
    	auto_normal_flag = 0;
    
          //initialize so that no maps initially
          vertex_flag = 0;
          normal_flag = 0;
          color_flag = 0;
          texcoord_flag = 0;
    
          /*
          if(glIsEnabled(GL_AUTO_NORMAL) == GL_TRUE)
    	auto_normal_flag = 1;
          else if (callback_auto_normal == 1)
    	auto_normal_flag = 1;
          else
    	auto_normal_flag = 0;
    	*/
    	  glPushAttrib((GLbitfield) GL_EVAL_BIT);
    
        }
      else
        {
          glPushAttrib((GLbitfield) GL_EVAL_BIT);
    
          /*to avoid side effect, we restor the opengl state for GL_POLYGON_MODE
           */       
          glGetIntegerv(GL_POLYGON_MODE, gl_polygon_mode);
        }
    
    }
    
    /*-------------------------------------------------------------------------
     * endmap2f - postamble to a map
     *-------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::endmap2f(void)
    {
    
      if(output_triangles)
        {
          //bezierPatchMeshListDelDeg(global_bpm);
    
          //    bezierPatchMeshListEval(global_bpm);
    
          //surfcount++;
          //printf("surfcount=%i\n", surfcount);
          //if(surfcount == 8) exit(0);
    
          inBPMListEvalEM(global_bpm);
    
    
    
    /*
        global_bpm = bezierPatchMeshListReverse(global_bpm);
        {
          float *vertex_array;
          float *normal_array;
          int *length_array;
          int *type_array;
          int num_strips;
          bezierPatchMeshListCollect(global_bpm, &vertex_array, &normal_array, &length_array, &type_array, &num_strips);
          drawStrips(vertex_array, normal_array, length_array, type_array, num_strips);
          free(vertex_array);
          free(normal_array);
          free(length_array);
          free(type_array);
        }
    */
    
        //bezierPatchMeshListPrint(global_bpm);
        //bezierPatchMeshListDraw(global_bpm);
    
    //	  printf("num triangles=%i\n", bezierPatchMeshListNumTriangles(global_bpm));
    
    #ifdef USE_LOD
    #else
        bezierPatchMeshListDelete(global_bpm);
        global_bpm = NULL;
    #endif
    	glPopAttrib();
      }
    else
      {
    #ifndef USE_LOD
        glPopAttrib();
    #endif
    
    #ifdef STATISTICS
        fprintf(stderr, "num_vertices=%i,num_triangles=%i,num_quads_strips=%i\n", STAT_num_of_eval_vertices,STAT_num_of_triangles,STAT_num_of_quad_strips);
    #endif
    
        /*to restore the gl_polygon_mode
         */
    #ifndef USE_LOD
        glPolygonMode( GL_FRONT, (GLenum) gl_polygon_mode[0]);
        glPolygonMode( GL_BACK,  (GLenum) gl_polygon_mode[1]);
    #endif
    }
    
    }
    
    /*-------------------------------------------------------------------------
     * map2f - pass a desription of a surface map
     *-------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::map2f(
        long _type,
        REAL _ulower,	/* u lower domain coord 	*/
        REAL _uupper,	/* u upper domain coord 	*/
        long _ustride,	/* interpoint distance		*/
        long _uorder,	/* parametric order		*/
        REAL _vlower,	/* v lower domain coord 	*/
        REAL _vupper,	/* v upper domain coord 	*/
        long _vstride,	/* interpoint distance		*/
        long _vorder,	/* parametric order		*/
        REAL *pts)	/* control points		*/
    {
    #ifdef USE_INTERNAL_EVAL
       inMap2f((int) _type, (REAL) _ulower, (REAL) _uupper,
    	    (int) _ustride, (int) _uorder, (REAL) _vlower,
    	    (REAL) _vupper, (int) _vstride, (int) _vorder,
    	    (REAL *) pts);
    #else
    
    
    
       if(output_triangles)
         {
           if(global_bpm == NULL)
    	 global_bpm = bezierPatchMeshMake2(10,10);
           if(
    	  (global_bpm->bpatch == NULL &&
    	  (_type == GL_MAP2_VERTEX_3 || _type == GL_MAP2_VERTEX_4))
    	  ||
    	  (global_bpm->bpatch_normal == NULL &&
    	   (_type == GL_MAP2_NORMAL))
    	  ||
    	  (global_bpm->bpatch_color == NULL &&
    	   (_type == GL_MAP2_INDEX || _type == GL_MAP2_COLOR_4))
    	  ||
    	  (global_bpm->bpatch_texcoord == NULL &&
    	   (_type == GL_MAP2_TEXTURE_COORD_1 ||
    	    _type == GL_MAP2_TEXTURE_COORD_2 ||
    	    _type == GL_MAP2_TEXTURE_COORD_3 ||
    	    _type == GL_MAP2_TEXTURE_COORD_4 )
    	   ))
    	 {
    	   bezierPatchMeshPutPatch(global_bpm, (int) _type, _ulower, _uupper,(int)  _ustride,(int) _uorder,_vlower, _vupper, (int) _vstride, (int) _vorder, pts);
    	 }
           else /*new surface patch (with multiple maps) starts*/
    	 {
    	   bezierPatchMesh *temp = bezierPatchMeshMake2(10,10);
    	   bezierPatchMeshPutPatch(temp, (int) _type, _ulower, _uupper,(int)  _ustride,(int) _uorder,_vlower, _vupper, (int) _vstride, (int) _vorder, pts);
    	   global_bpm = bezierPatchMeshListInsert(global_bpm, temp);
    
    	   /*
    	   global_bpm = bezierPatchMeshListInsert(global_bpm,
    						  bezierPatchMeshMake(
    								      (int) _type, _ulower, _uupper,(int)  _ustride, (int) _uorder, _vlower, _vupper, (int) _vstride, (int) _vorder, pts, 10, 10));
    	   */
    	 }
         }
       else /*not output triangles*/
         {
           glMap2f((GLenum) _type, (GLfloat) _ulower, (GLfloat) _uupper,
    	       (GLint) _ustride, (GLint) _uorder, (GLfloat) _vlower,
    	       (GLfloat) _vupper, (GLint) _vstride, (GLint) _vorder,
    	       (const GLfloat *) pts);
         }
    
    #endif
    }
    
    
    /*-------------------------------------------------------------------------
     * mapmesh2f - evaluate a mesh of points on lattice
     *-------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::mapmesh2f(long style, long umin, long umax, long vmin, long vmax)
    {
    #ifdef NO_EVALUATION
    return;
    #endif
    
    #ifdef USE_INTERNAL_EVAL
        inEvalMesh2((int)umin, (int)vmin, (int)umax, (int)vmax);
    #else
    
    
    
    if(output_triangles)
    {
    #ifdef USE_LOD
      bezierPatchMeshBeginStrip(global_bpm, GL_POLYGON);
      bezierPatchMeshInsertUV(global_bpm, global_grid_u0, global_grid_v0);
      bezierPatchMeshInsertUV(global_bpm, global_grid_u1, global_grid_v1);
      bezierPatchMeshInsertUV(global_bpm, (REAL)global_grid_nu, (REAL)global_grid_nv);
      bezierPatchMeshInsertUV(global_bpm, (REAL)umin, (REAL)vmin);
      bezierPatchMeshInsertUV(global_bpm, (REAL)umax, (REAL)vmax);
      bezierPatchMeshEndStrip(global_bpm);
    
    #else
    
      REAL du, dv;
      long i,j;
      if(global_grid_nu == 0 || global_grid_nv == 0)
        return; /*no points need to be output*/
      du = (global_grid_u1 - global_grid_u0) / (REAL)global_grid_nu;
      dv = (global_grid_v1 - global_grid_v0) / (REAL)global_grid_nv;
    
      if(global_grid_nu >= global_grid_nv){
    
        for(i=umin; i<umax; i++){
          REAL u1 = (i==global_grid_nu)? global_grid_u1:(global_grid_u0 + i*du);
          REAL u2 = ((i+1) == global_grid_nu)? global_grid_u1: (global_grid_u0+(i+1)*du);
    
          bgnqstrip();
          for(j=vmax; j>=vmin; j--){
    	REAL v1 = (j == global_grid_nv)? global_grid_v1: (global_grid_v0 +j*dv);
            
    	coord2f(u1, v1);
    	coord2f(u2, v1);
          }
          endqstrip();
        }
      }
      else{
    
        for(i=vmin; i<vmax; i++){
          REAL v1 = (i==global_grid_nv)? global_grid_v1:(global_grid_v0 + i*dv);
          REAL v2 = ((i+1) == global_grid_nv)? global_grid_v1: (global_grid_v0+(i+1)*dv);
    
          bgnqstrip();
          for(j=umax; j>=umin; j--){
    	REAL u1 = (j == global_grid_nu)? global_grid_u1: (global_grid_u0 +j*du);        
    	coord2f(u1, v2);
    	coord2f(u1, v1);
          }
          endqstrip();
        }
      }
    #endif
    }
    else
    {
        switch(style) {
        default:
        case N_MESHFILL:
    	glEvalMesh2((GLenum) GL_FILL, (GLint) umin, (GLint) umax,
    		(GLint) vmin, (GLint) vmax);
    	break;
        case N_MESHLINE:
    	glEvalMesh2((GLenum) GL_LINE, (GLint) umin, (GLint) umax,
    		(GLint) vmin, (GLint) vmax);
    	break;
        case N_MESHPOINT:
    	glEvalMesh2((GLenum) GL_POINT, (GLint) umin, (GLint) umax,
    		(GLint) vmin, (GLint) vmax);
    	break;
        }
      }
    
    #endif
    
    #ifdef STATISTICS
    	STAT_num_of_quad_strips += (umax-umin)*(vmax-vmin);
    #endif
    }
    
    /*-------------------------------------------------------------------------
     * evalcoord2f - evaluate a point on a surface
     *-------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::evalcoord2f(long, REAL u, REAL v)
    {
    
    
    #ifdef NO_EVALUATION
    return;
    #endif
    
    
        newtmeshvert(u, v);
    }
    
    /*-------------------------------------------------------------------------
     * evalpoint2i - evaluate a grid point
     *-------------------------------------------------------------------------
     */
    void
    OpenGLSurfaceEvaluator::evalpoint2i(long u, long v)
    {
    #ifdef NO_EVALUATION
    return;
    #endif
    
        newtmeshvert(u, v);
    }
    
    void
    OpenGLSurfaceEvaluator::point2i( long u, long v )
    {
    #ifdef NO_EVALUATION
    return;
    #else
    
    #ifdef USE_INTERNAL_EVAL
        inEvalPoint2( (int)u,  (int)v);
    #else
    
    
    if(output_triangles)
    {
    
      REAL du, dv;
      REAL fu,fv;
      du = (global_grid_u1 - global_grid_u0) / (REAL)global_grid_nu;
      dv = (global_grid_v1 - global_grid_v0) / (REAL)global_grid_nv;
      fu = (u==global_grid_nu)? global_grid_u1:(global_grid_u0 + u*du);
      fv = (v == global_grid_nv)? global_grid_v1: (global_grid_v0 +v*dv);
      coord2f(fu,fv);
    }
    else
        glEvalPoint2((GLint) u, (GLint) v);
    
    
    #endif
    
    #ifdef STATISTICS
      STAT_num_of_eval_vertices++;
    #endif
    
    #endif
    
    }
    
    void
    OpenGLSurfaceEvaluator::coord2f( REAL u, REAL v )
    {
    #ifdef NO_EVALUATION
    return;
    #else
    
    #ifdef USE_INTERNAL_EVAL
        inEvalCoord2f( u, v);
    #else
    
    
    if(output_triangles)
        bezierPatchMeshInsertUV(global_bpm, u,v);
    else
        glEvalCoord2f((GLfloat) u, (GLfloat) v);
    
    
    #endif
    
    
    #ifdef STATISTICS
      STAT_num_of_eval_vertices++;
    #endif
    
    #endif
    }
    
    void
    OpenGLSurfaceEvaluator::newtmeshvert( long u, long v )
    {
    #ifdef NO_EVALUATION
    return;
    #else
    
        if (tmeshing) {
    
    	if (vcount == 2) {
    	    vertexCache[0]->invoke(this);
    	    vertexCache[1]->invoke(this);
    	    point2i( u,  v);
    
    	} else {
    	    vcount++;
    	}
    
    	vertexCache[which]->saveEvalPoint(u, v);
    	which = 1 - which;
        } else {
    	point2i( u,  v);
        }
    #endif
    }
    
    void
    OpenGLSurfaceEvaluator::newtmeshvert( REAL u, REAL v )
    {
    #ifdef NO_EVALUATION
    return;
    #else
        if (tmeshing) {
    
    
    	if (vcount == 2) {
    	    vertexCache[0]->invoke(this);
    	    vertexCache[1]->invoke(this);
    	    coord2f(u,v);
    
    	} else {
    	    vcount++;
    	}
    
    	vertexCache[which]->saveEvalCoord(u, v);
    	which = 1 - which;
        } else {
    
    	coord2f( u,  v);
        }
    #endif
    
    }
    
    #ifdef _WIN32
    void OpenGLSurfaceEvaluator::putCallBack(GLenum which, void (GLAPIENTRY *fn)() )
    #else
    void OpenGLSurfaceEvaluator::putCallBack(GLenum which, _GLUfuncptr fn )
    #endif
    {
      switch(which)
        {
        case GLU_NURBS_BEGIN:
          beginCallBackN = (void (GLAPIENTRY *) (GLenum)) fn;
          break;
        case GLU_NURBS_END:
          endCallBackN = (void (GLAPIENTRY *) (void)) fn;
          break;
        case GLU_NURBS_VERTEX:
          vertexCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
          break;
        case GLU_NURBS_NORMAL:
          normalCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
          break;
        case GLU_NURBS_COLOR:
          colorCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
          break;
        case GLU_NURBS_TEXTURE_COORD:
          texcoordCallBackN = (void (GLAPIENTRY *) (const GLfloat*)) fn;
          break;
        case GLU_NURBS_BEGIN_DATA:
          beginCallBackData = (void (GLAPIENTRY *) (GLenum, void*)) fn;
          break;
        case GLU_NURBS_END_DATA:
          endCallBackData = (void (GLAPIENTRY *) (void*)) fn;
          break;
        case GLU_NURBS_VERTEX_DATA:
          vertexCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
          break;
        case GLU_NURBS_NORMAL_DATA:
          normalCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
          break;
        case GLU_NURBS_COLOR_DATA:
          colorCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
          break;
        case GLU_NURBS_TEXTURE_COORD_DATA:
          texcoordCallBackData = (void (GLAPIENTRY *) (const GLfloat*, void*)) fn;
          break;
    
        }
    }
    
    
    void
    OpenGLSurfaceEvaluator::beginCallBack(GLenum which, void *data)
    {
      if(beginCallBackData)
        beginCallBackData(which, data);
      else if(beginCallBackN)
        beginCallBackN(which);
    }
    
    void
    OpenGLSurfaceEvaluator::endCallBack(void *data)
    {
      if(endCallBackData)
        endCallBackData(data);
      else if(endCallBackN)
        endCallBackN();
    }
    
    void
    OpenGLSurfaceEvaluator::vertexCallBack(const GLfloat *vert, void* data)
    {
      if(vertexCallBackData)
        vertexCallBackData(vert, data);
      else if(vertexCallBackN)
        vertexCallBackN(vert);
    }
    
    
    void
    OpenGLSurfaceEvaluator::normalCallBack(const GLfloat *normal, void* data)
    {
      if(normalCallBackData)
        normalCallBackData(normal, data);
      else if(normalCallBackN)
        normalCallBackN(normal);
    }
    
    void
    OpenGLSurfaceEvaluator::colorCallBack(const GLfloat *color, void* data)
    {
      if(colorCallBackData)
        colorCallBackData(color, data);
      else if(colorCallBackN)
        colorCallBackN(color);
    }
    
    void
    OpenGLSurfaceEvaluator::texcoordCallBack(const GLfloat *texcoord, void* data)
    {
      if(texcoordCallBackData)
        texcoordCallBackData(texcoord, data);
      else if(texcoordCallBackN)
        texcoordCallBackN(texcoord);
    }