#include "gluos.h"
#include <stdio.h>
#include "glimports.h"
#include "glrenderer.h"
#include "glsurfeval.h"
#include "nurbsconsts.h"
#include "bezierPatchMesh.h"
#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
#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
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;
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; 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;
}
}
void
OpenGLSurfaceEvaluator::disable(long type)
{
glDisable((GLenum) type);
}
void
OpenGLSurfaceEvaluator::enable(long type)
{
glEnable((GLenum) type);
}
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];
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;
}
while(1)
{
if(i >= n_upper)
{
if(j<n_lower-1)
{
bgntfan();
coord2f(leftMostV[0], leftMostV[1]);
while(j<n_lower){
coord2f(lower_val[j], v_lower);
j++;
}
endtfan();
}
break;
}
else if(j>= n_lower)
{
if(i<n_upper-1)
{
bgntfan();
coord2f(leftMostV[0], leftMostV[1]);
for(k=n_upper-1; k>=i; k--)
{
coord2f(upper_val[k], v_upper);
}
endtfan();
}
break;
}
else
{
if(upper_val[i] <= lower_val[j])
{
bgntfan();
coord2f(lower_val[j], v_lower);
k=i;
while(k<n_upper)
{
if(upper_val[k] > lower_val[j])
break;
k++;
}
k--;
for(l=k; l>=i; l--)
{
coord2f(upper_val[l], v_upper);
}
coord2f(leftMostV[0], leftMostV[1]);
endtfan();
i = k+1;
leftMostV[0] = upper_val[k];
leftMostV[1] = v_upper;
}
else
{
bgntfan();
coord2f(upper_val[i], v_upper);
coord2f(leftMostV[0], leftMostV[1]);
k=j;
while(k< n_lower)
{
if(lower_val[k] >= upper_val[i])
break;
coord2f(lower_val[k], v_lower);
k++;
}
endtfan();
j=k;
leftMostV[0] = lower_val[j-1];
leftMostV[1] = v_lower;
}
}
}
#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];
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];
}
while(1)
{
if(i >= n_left)
{
if(j<n_right-1)
{
bgntfan();
coord2f(botMostV[0], botMostV[1]);
while(j<n_right){
coord2f(u_right, right_val[j]);
j++;
}
endtfan();
}
break;
}
else if(j>= n_right)
{
if(i<n_left-1)
{
bgntfan();
coord2f(botMostV[0], botMostV[1]);
for(k=n_left-1; k>=i; k--)
{
coord2f(u_left, left_val[k]);
}
endtfan();
}
break;
}
else
{
if(left_val[i] <= right_val[j])
{
bgntfan();
coord2f(u_right, right_val[j]);
k=i;
while(k<n_left)
{
if(left_val[k] > right_val[j])
break;
k++;
}
k--;
for(l=k; l>=i; l--)
{
coord2f(u_left, left_val[l]);
}
coord2f(botMostV[0], botMostV[1]);
endtfan();
i = k+1;
botMostV[0] = u_left;
botMostV[1] = left_val[k];
}
else
{
bgntfan();
coord2f(u_left, left_val[i]);
coord2f(botMostV[0], botMostV[1]);
k=j;
while(k< n_right)
{
if(right_val[k] >= left_val[i])
break;
coord2f(u_right, right_val[k]);
k++;
}
endtfan();
j=k;
botMostV[0] = u_right;
botMostV[1] = right_val[j-1];
}
}
}
#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();
}
void
OpenGLSurfaceEvaluator::bgnmap2f(long)
{
if(output_triangles)
{
if(global_bpm != NULL) {
bezierPatchMeshListDelete(global_bpm);
global_bpm = NULL;
}
if(normalCallBackN != NULL ||
normalCallBackData != NULL)
auto_normal_flag = 1;
else
auto_normal_flag = 0;
vertex_flag = 0;
normal_flag = 0;
color_flag = 0;
texcoord_flag = 0;
glPushAttrib((GLbitfield) GL_EVAL_BIT);
}
else
{
glPushAttrib((GLbitfield) GL_EVAL_BIT);
glGetIntegerv(GL_POLYGON_MODE, gl_polygon_mode);
}
}
void
OpenGLSurfaceEvaluator::endmap2f(void)
{
if(output_triangles)
{
inBPMListEvalEM(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
#ifndef USE_LOD
glPolygonMode( GL_FRONT, (GLenum) gl_polygon_mode[0]);
glPolygonMode( GL_BACK, (GLenum) gl_polygon_mode[1]);
#endif
}
}
void
OpenGLSurfaceEvaluator::map2f(
long _type,
REAL _ulower,
REAL _uupper,
long _ustride,
long _uorder,
REAL _vlower,
REAL _vupper,
long _vstride,
long _vorder,
REAL *pts)
{
#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
{
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);
}
}
else
{
glMap2f((GLenum) _type, (GLfloat) _ulower, (GLfloat) _uupper,
(GLint) _ustride, (GLint) _uorder, (GLfloat) _vlower,
(GLfloat) _vupper, (GLint) _vstride, (GLint) _vorder,
(const GLfloat *) pts);
}
#endif
}
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;
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
}
void
OpenGLSurfaceEvaluator::evalcoord2f(long, REAL u, REAL v)
{
#ifdef NO_EVALUATION
return;
#endif
newtmeshvert(u, v);
}
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);
}