|
|
/**************************************************************************
* * * Copyright (C) 1991, Silicon Graphics, Inc. * * * * These coded instructions, statements, and computer programs contain * * unpublished proprietary information of Silicon Graphics, Inc., and * * are protected by Federal copyright law. They may not be disclosed * * to third parties or copied or duplicated in any form, in whole or * * in part, without the prior written consent of Silicon Graphics, Inc. * * * **************************************************************************/
/*
* glsurfeval.c++ - surface evaluator * * $Revision: 1.5 $ */
/* Polynomial Evaluator Interface */
#include <glos.h>
#include <GL/gl.h>
#include "glimport.h"
#include "glrender.h"
#include "glsurfev.h"
#include "nurbscon.h"
/*#define USE_INTERNAL_EVAL*/ //use internal evaluator
/*whether do evaluation or not*/ /*#define NO_EVALUATION*/
/*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
OpenGLSurfaceEvaluator::OpenGLSurfaceEvaluator() { int i;
for (i=0; i<VERTEX_CACHE_SIZE; i++) { vertexCache[i] = new StoredVertex; } tmeshing = 0; which = 0; vcount = 0;
}
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
glMapGrid2d((GLint) nu, (GLdouble) u0, (GLdouble) u1, (GLint) nv, (GLdouble) v0, (GLdouble) v1); #endif
}
void OpenGLSurfaceEvaluator::polymode(long style) { 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) { glBegin((GLenum) GL_LINE_STRIP); }
void OpenGLSurfaceEvaluator::endline(void) { 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) { glBegin((GLenum) GL_LINE_LOOP); }
void OpenGLSurfaceEvaluator::endclosedline(void) { glEnd(); }
void OpenGLSurfaceEvaluator::bgntmesh(void) {
tmeshing = 1; which = 0; vcount = 0;
glBegin((GLenum) GL_TRIANGLES);
}
void OpenGLSurfaceEvaluator::swaptmesh(void) { which = 1 - which;
}
void OpenGLSurfaceEvaluator::endtmesh(void) { tmeshing = 0;
glEnd(); }
void OpenGLSurfaceEvaluator::bgntfan(void) { glBegin((GLenum) GL_TRIANGLE_FAN); } void OpenGLSurfaceEvaluator::endtfan(void) { 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
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
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) { glBegin((GLenum) GL_QUAD_STRIP); #ifdef STATISTICS
STAT_num_of_quad_strips++; #endif
}
void OpenGLSurfaceEvaluator::endqstrip(void) { glEnd(); }
/*-------------------------------------------------------------------------
* bgnmap2f - preamble to surface definition and evaluations *------------------------------------------------------------------------- */ void OpenGLSurfaceEvaluator::bgnmap2f(long) {
glPushAttrib((GLbitfield) GL_EVAL_BIT);
}
/*-------------------------------------------------------------------------
* endmap2f - postamble to a map *------------------------------------------------------------------------- */ void OpenGLSurfaceEvaluator::endmap2f(void) {
glPopAttrib();
#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
}
/*-------------------------------------------------------------------------
* 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
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
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 USE_INTERNAL_EVAL
inEvalPoint2( (int)u, (int)v); #else
glEvalPoint2((GLint) u, (GLint) v); #endif
#ifdef STATISTICS
STAT_num_of_eval_vertices++; #endif
}
void OpenGLSurfaceEvaluator::coord2f( REAL u, REAL v ) { #ifdef USE_INTERNAL_EVAL
inEvalCoord2f( u, v); #else
glEvalCoord2f((GLfloat) u, (GLfloat) v); #endif
#ifdef STATISTICS
STAT_num_of_eval_vertices++; #endif
}
void OpenGLSurfaceEvaluator::newtmeshvert( long u, long v ) { 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); } }
void OpenGLSurfaceEvaluator::newtmeshvert( REAL u, REAL v ) {
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); } }
|