windows-nt/Source/XPSP1/NT/multimedia/opengl/glu/nurbs/clients/glsurfev.cxx
2020-09-26 16:20:57 +08:00

767 lines
17 KiB
C++

/**************************************************************************
* *
* 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);
}
}