windows-nt/Source/XPSP1/NT/multimedia/opengl/client/eval.c
2020-09-26 16:20:57 +08:00

2135 lines
64 KiB
C

/******************************Module*Header*******************************\
* Module Name: eval.c
*
* OpenGL Evaluator functions on the client side.
*
* Created:
* Author:
*
* Copyright (c) 1993 Microsoft Corporation
\**************************************************************************/
#include "precomp.h"
#pragma hdrstop
#include "glsbcltu.h"
#include "glclt.h"
#include "compsize.h"
#include "glsize.h"
#include "context.h"
#include "global.h"
#include "attrib.h"
#include "imports.h"
////////////////////////////////////////////////////////////////////
// Stuff needed for PA_EvalMesh2 ///////////////////////////////////
////////////////////////////////////////////////////////////////////
#define MV_VERTEX3 0x0001
#define MV_VERTEX4 0x0002
#define MV_NORMAL 0x0004
#define MV_COLOR 0x0008
#define MV_INDEX 0x0010
#define MV_TEXTURE1 0x0020
#define MV_TEXTURE2 0x0040
#define MV_TEXTURE3 0x0080
#define MV_TEXTURE4 0x0100
// Assumption: U is moving, left to right. V is moving top to bottom
#define MV_TOP 0x0001
#define MV_LEFT 0x0002
typedef struct {
__GLcoord vertex;
__GLcoord normal;
__GLcoord texture;
__GLcolor color;
} MESHVERTEX;
#define MAX_MESH_VERTICES MAX_U_SIZE*MAX_V_SIZE
#define MAX_U_SIZE 16
#define MAX_V_SIZE 16
GLubyte *dBufFill; //fill only
GLuint totFillPts;
GLubyte *dBufTopLeft; //for mv_left
GLuint totTopLeftPts;
GLubyte *dBufTopRight; //for non mv_left
GLuint totTopRightPts;
//////////////////////////////////////////////////////////////////////
/// Function Prototypes //////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
void FASTCALL PADoEval1(__GLcontext *, __GLfloat);
void FASTCALL PADoEval2(__GLcontext *, __GLfloat, __GLfloat);
void FASTCALL PADoEval2VArray(__GLcontext *, __GLfloat, __GLfloat,
MESHVERTEX *, GLuint *);
static void PreEvaluate(GLint , __GLfloat , __GLfloat *);
static void PreEvaluateWithDeriv(GLint, __GLfloat, __GLfloat *, __GLfloat *);
void DoDomain2(__GLevaluatorMachine *, __GLfloat, __GLfloat,
__GLevaluator2 *, __GLfloat *, __GLfloat *);
void DoDomain2WithDerivs(__GLevaluatorMachine *, __GLfloat, __GLfloat,
__GLevaluator2 *, __GLfloat *, __GLfloat *,
__GLfloat *, __GLfloat *);
int FASTCALL genMeshElts (GLenum, GLuint, GLint, GLint, GLubyte *);
void FASTCALL PA_EvalMesh2Fast(__GLcontext *, GLint, GLint, GLint,
GLint, GLint, GLenum, GLuint);
void glcltColor4fv_Eval (__GLfloat *c4);
void glcltIndexf_Eval (__GLfloat ci);
void glcltNormal3fv_Eval(__GLfloat *n3);
void glcltTexCoord1fv_Eval(__GLfloat *t1);
void glcltTexCoord2fv_Eval(__GLfloat *t2);
void glcltTexCoord3fv_Eval(__GLfloat *t3);
void glcltTexCoord4fv_Eval(__GLfloat *t4);
/************************************************************************/
/********************** Client-side entry points ************************/
/********************** for 1-D Evaluators ************************/
/************************************************************************/
void APIENTRY
glcltEvalMesh1 ( IN GLenum mode, IN GLint u1, IN GLint u2 )
{
__GL_SETUP ();
POLYARRAY *pa;
GLenum primType;
GLint i;
WORD flags = (WORD) GET_EVALSTATE (gc);
__GLfloat u;
__GLfloat du;
__GLevaluatorGrid *gu;
// Not allowed in begin/end.
pa = GLTEB_CLTPOLYARRAY();
if (pa->flags & POLYARRAY_IN_BEGIN)
{
GLSETERROR(GL_INVALID_OPERATION);
return;
}
switch(mode)
{
case GL_LINE:
primType = GL_LINE_STRIP;
break;
case GL_POINT:
primType = GL_POINTS;
break;
default:
GLSETERROR(GL_INVALID_ENUM);
return;
}
// if there are any pending API calls that affect the Evaluator state
// then flush the message buffer
if (flags & (__EVALS_AFFECTS_1D_EVAL|
__EVALS_AFFECTS_ALL_EVAL))
glsbAttention();
gu = &gc->state.evaluator.u1;
//du = (gu->finish - gu->start)/(__GLfloat)gu->n;
du = gu->step;
// Call Begin/End.
glcltBegin(primType);
for (i = u1; i <= u2; i++)
{
u = (i == gu->n) ? gu->finish : (gu->start + i * du);
PADoEval1(gc, u);
}
glcltEnd();
}
void APIENTRY
glcltEvalPoint1 ( IN GLint i )
{
__GL_SETUP ();
POLYARRAY *pa;
__GLfloat u;
__GLfloat du;
__GLevaluatorGrid *gu;
// This call has no effect outside begin/end
// (unless it is being compiled).
pa = GLTEB_CLTPOLYARRAY();
if (!(pa->flags & POLYARRAY_IN_BEGIN))
{
return;
}
gu = &gc->state.evaluator.u1;
du = gu->step;
//du = (gu->finish - gu->start)/(__GLfloat)gu->n;
u = (i == gu->n) ? gu->finish : (gu->start + i * du);
PADoEval1(gc, u);
}
void APIENTRY
glcltEvalCoord1f ( IN GLfloat u )
{
__GL_SETUP ();
POLYARRAY *pa;
// This call has no effect outside begin/end
// (unless it is being compiled).
pa = GLTEB_CLTPOLYARRAY();
// If not in Begin-End block, return without doing anything
if (!(pa->flags & POLYARRAY_IN_BEGIN))
{
return;
}
PADoEval1(gc, u);
}
void APIENTRY
glcltEvalCoord1d ( IN GLdouble u )
{
glcltEvalCoord1f((GLfloat) u);
}
void APIENTRY
glcltEvalCoord1dv ( IN const GLdouble u[1] )
{
glcltEvalCoord1f((GLfloat) u[0]);
}
void APIENTRY
glcltEvalCoord1fv ( IN const GLfloat u[1] )
{
glcltEvalCoord1f((GLfloat) u[0]);
}
void APIENTRY
glcltMapGrid1d ( IN GLint un, IN GLdouble u1, IN GLdouble u2 )
{
glcltMapGrid1f(un, (GLfloat) u1, (GLfloat) u2);
}
void APIENTRY
glcltMapGrid1f ( IN GLint un, IN GLfloat u1, IN GLfloat u2 )
{
POLYARRAY *pa;
__GL_SETUP ();
WORD flags = (WORD) GET_EVALSTATE (gc);
// Check if it is called inside a Begin-End block
// If we are already in the begin/end bracket, return an error.
pa = GLTEB_CLTPOLYARRAY();
if (pa->flags & POLYARRAY_IN_BEGIN)
{
GLSETERROR(GL_INVALID_OPERATION);
return;
}
// if there are any pending API calls that affect the Evaluator state
// then flush the message buffer
if (flags & (__EVALS_PUSH_EVAL_ATTRIB | __EVALS_POP_EVAL_ATTRIB))
glsbAttention ();
#ifdef NT
if (un <= 0)
{
__glSetError(GL_INVALID_VALUE);
return;
}
#endif
gc->state.evaluator.u1.start = (__GLfloat)u1;
gc->state.evaluator.u1.finish = (__GLfloat)u2;
gc->state.evaluator.u1.n = un;
gc->state.evaluator.u1.step = ((__GLfloat)u2 - (__GLfloat)u1)/(__GLfloat)un;
}
void APIENTRY
glcltMap1d ( IN GLenum target, IN GLdouble u1, IN GLdouble u2, IN GLint stride, IN GLint order, IN const GLdouble points[] )
{
__GLevaluator1 *ev;
__GLfloat *data;
POLYARRAY *pa;
__GL_SETUP ();
// Check if it is called inside a Begin-End block
// If we are already in the begin/end bracket, return an error.
pa = GLTEB_CLTPOLYARRAY();
if (pa->flags & POLYARRAY_IN_BEGIN)
{
GLSETERROR(GL_INVALID_OPERATION);
return;
}
ev = __glSetUpMap1(gc, target, order, u1, u2);
if (ev == 0) {
return;
}
if (stride < ev->k) {
__glSetError(GL_INVALID_VALUE);
return;
}
data = gc->eval.eval1Data[__GL_EVAL1D_INDEX(target)];
__glFillMap1d(ev->k, order, stride, points, data);
}
void APIENTRY
glcltMap1f ( IN GLenum target, IN GLfloat u1, IN GLfloat u2, IN GLint stride, IN GLint order, IN const GLfloat points[] )
{
__GLevaluator1 *ev;
__GLfloat *data;
POLYARRAY *pa;
__GL_SETUP ();
// Check if it is called inside a Begin-End block
// If we are already in the begin/end bracket, return an error.
pa = GLTEB_CLTPOLYARRAY();
if (pa->flags & POLYARRAY_IN_BEGIN)
{
GLSETERROR(GL_INVALID_OPERATION);
return;
}
ev = __glSetUpMap1(gc, target, order, u1, u2);
if (ev == 0) {
return;
}
if (stride < ev->k) {
__glSetError(GL_INVALID_VALUE);
return;
}
data = gc->eval.eval1Data[__GL_EVAL1D_INDEX(target)];
__glFillMap1f(ev->k, order, stride, points, data);
}
/************************************************************************/
/********************** Client-side entry points ************************/
/********************** for 2-D Evaluators ************************/
/************************************************************************/
void APIENTRY
glcltEvalMesh2 ( IN GLenum mode, IN GLint u1, IN GLint u2, IN GLint v1, IN GLint v2 )
{
POLYARRAY *pa;
GLint i, j, meshSize;
__GL_SETUP();
GLboolean done_v, done_u;
GLint v_beg, v_end, u_beg, u_end, u_len;
GLuint sides;
WORD flags = (WORD) GET_EVALSTATE (gc);
// Flush the command buffer before we start. We need to access the
// latest evaluator states in this function.
// if there are any pending API calls that affect the Evaluator state
// then flush the message buffer
if (flags & (__EVALS_AFFECTS_2D_EVAL|
__EVALS_AFFECTS_ALL_EVAL))
glsbAttention ();
// Not allowed in begin/end.
pa = gc->paTeb;
if (pa->flags & POLYARRAY_IN_BEGIN)
{
GLSETERROR(GL_INVALID_OPERATION);
return;
}
// If vertex map is not enabled, this is a noop.
if (!(gc->state.enables.eval2 & (__GL_MAP2_VERTEX_4_ENABLE |
__GL_MAP2_VERTEX_3_ENABLE)))
return;
// Make sure that the mesh is not empty.
if (u1 > u2 || v1 > v2)
return;
if (mode == GL_FILL && dBufFill == NULL)
{
if (!(dBufFill = (GLubyte *) ALLOC (
4 * MAX_U_SIZE * MAX_V_SIZE * sizeof (GLubyte))))
{
GLSETERROR(GL_OUT_OF_MEMORY);
return;
}
totFillPts = genMeshElts (GL_FILL, MV_TOP | MV_LEFT, MAX_U_SIZE,
MAX_V_SIZE, dBufFill);
}
if (mode == GL_LINE && dBufTopLeft == NULL)
{
if (!(dBufTopLeft = (GLubyte *) ALLOC (
2 * 4 * MAX_U_SIZE * MAX_V_SIZE * sizeof (GLubyte))))
{
GLSETERROR(GL_OUT_OF_MEMORY);
return;
}
dBufTopRight = &dBufTopLeft[4 * MAX_U_SIZE * MAX_V_SIZE];
totTopLeftPts = genMeshElts (GL_LINE, MV_TOP | MV_LEFT, MAX_U_SIZE,
MAX_V_SIZE, dBufTopLeft);
totTopRightPts = genMeshElts (GL_LINE, MV_TOP, MAX_U_SIZE, MAX_V_SIZE,
dBufTopRight);
}
switch(mode)
{
case GL_POINT:
glcltBegin(GL_POINTS);
for (i = v1; i <= v2; i++)
for (j = u1; j <= u2; j++)
glcltEvalPoint2(j, i);
glcltEnd();
break ;
case GL_LINE:
case GL_FILL: // the sides argument in the fastcall is ignored
meshSize = (u2 - u1 + 1)*(v2 - v1 + 1);
if (meshSize <= MAX_MESH_VERTICES)
PA_EvalMesh2Fast(gc, u1, u2, v1, v2, meshSize, mode,
(GLubyte) 15);
else {
u_beg = u1;
u_end = u_beg + MAX_U_SIZE - 1;
done_u = GL_FALSE;
while (!done_u) { //Along U side
if(u_end >= u2) {
u_end = u2;
done_u = GL_TRUE;
}
u_len = u_end - u_beg + 1;
v_beg = v1;
v_end = v_beg + MAX_V_SIZE - 1;
done_v = GL_FALSE;
while(!done_v) { //Along V side
if(v_end >= v2) {
v_end = v2;
done_v = GL_TRUE;
}
meshSize = u_len*(v_end - v_beg + 1);
sides = 0;
if (u_beg == u1)
sides |= MV_LEFT;
if (v_beg == v1)
sides |= MV_TOP;
PA_EvalMesh2Fast(gc, u_beg, u_end,
v_beg, v_end, meshSize, mode, sides);
v_beg = v_end;
v_end = v_beg+MAX_V_SIZE-1;
}
u_beg = u_end;
u_end = u_beg + MAX_U_SIZE - 1;
}
}
break ;
default:
GLSETERROR(GL_INVALID_ENUM);
return;
}
}
void APIENTRY
glcltEvalCoord2f ( IN GLfloat u, IN GLfloat v )
{
__GL_SETUP ();
POLYARRAY *pa;
// This call has no effect outside begin/end
// (unless it is being compiled).
pa = GLTEB_CLTPOLYARRAY();
if (!(pa->flags & POLYARRAY_IN_BEGIN))
{
return;
}
PADoEval2(gc, u, v);
}
void APIENTRY
glcltEvalCoord2d ( IN GLdouble u, IN GLdouble v )
{
glcltEvalCoord2f((GLfloat) u, (GLfloat) v);
}
void APIENTRY
glcltEvalCoord2dv ( IN const GLdouble u[2] )
{
glcltEvalCoord2f((GLfloat) u[0], (GLfloat) u[1]);
}
void APIENTRY
glcltEvalCoord2fv ( IN const GLfloat u[2] )
{
glcltEvalCoord2f((GLfloat) u[0], (GLfloat) u[1]);
}
void APIENTRY
glcltEvalPoint2 ( IN GLint i, IN GLint j )
{
__GL_SETUP ();
POLYARRAY *pa;
__GLfloat u, v;
__GLfloat du, dv;
__GLevaluatorGrid *gu;
__GLevaluatorGrid *gv;
// This call has no effect outside begin/end
// (unless it is being compiled).
pa = GLTEB_CLTPOLYARRAY();
if (!(pa->flags & POLYARRAY_IN_BEGIN))
{
return;
}
gu = &gc->state.evaluator.u2;
gv = &gc->state.evaluator.v2;
du = gu->step;
dv = gv->step;
//du = (gu->finish - gu->start)/(__GLfloat)gu->n;
//dv = (gv->finish - gv->start)/(__GLfloat)gv->n;
u = (i == gu->n) ? gu->finish : (gu->start + i * du);
v = (j == gv->n) ? gv->finish : (gv->start + j * dv);
PADoEval2 (gc, u, v);
}
void APIENTRY
glcltMapGrid2d ( IN GLint un, IN GLdouble u1, IN GLdouble u2, IN GLint vn, IN GLdouble v1, IN GLdouble v2 )
{
glcltMapGrid2f(un, (GLfloat) u1, (GLfloat) u2, vn, (GLfloat) v1, (GLfloat) v2);
}
void APIENTRY
glcltMapGrid2f ( IN GLint un, IN GLfloat u1, IN GLfloat u2, IN GLint vn, IN GLfloat v1, IN GLfloat v2 )
{
POLYARRAY *pa;
__GL_SETUP ();
WORD flags = (WORD) GET_EVALSTATE (gc);
// Check if it is called inside a Begin-End block
// If we are already in the begin/end bracket, return an error.
pa = GLTEB_CLTPOLYARRAY();
if (pa->flags & POLYARRAY_IN_BEGIN)
{
GLSETERROR(GL_INVALID_OPERATION);
return;
}
// if there are any pending API calls that affect the Evaluator state
// then flush the message buffer
if (flags & (__EVALS_PUSH_EVAL_ATTRIB|
__EVALS_POP_EVAL_ATTRIB))
glsbAttention ();
#ifdef NT
if (un <= 0 || vn <= 0)
{
__glSetError(GL_INVALID_VALUE);
return;
}
#endif
gc->state.evaluator.u2.start = (__GLfloat)u1;
gc->state.evaluator.u2.finish = (__GLfloat)u2;
gc->state.evaluator.u2.n = un;
gc->state.evaluator.u2.step = ((__GLfloat)u2 - (__GLfloat)u1)/(__GLfloat)un;
gc->state.evaluator.v2.start = (__GLfloat)v1;
gc->state.evaluator.v2.finish = (__GLfloat)v2;
gc->state.evaluator.v2.n = vn;
gc->state.evaluator.v2.step = ((__GLfloat)v2 - (__GLfloat)v1)/(__GLfloat)vn;
}
void APIENTRY
glcltMap2d ( IN GLenum target, IN GLdouble u1, IN GLdouble u2, IN GLint ustride, IN GLint uorder, IN GLdouble v1, IN GLdouble v2, IN GLint vstride, IN GLint vorder, IN const GLdouble points[] )
{
__GLevaluator2 *ev;
__GLfloat *data;
POLYARRAY *pa;
__GL_SETUP ();
// Check if it is called inside a Begin-End block
// If we are already in the begin/end bracket, return an error.
pa = GLTEB_CLTPOLYARRAY();
if (pa->flags & POLYARRAY_IN_BEGIN)
{
GLSETERROR(GL_INVALID_OPERATION);
return;
}
ev = __glSetUpMap2(gc, target, uorder, vorder, u1, u2, v1, v2);
if (ev == 0) {
return;
}
if (ustride < ev->k) {
__glSetError(GL_INVALID_VALUE);
return;
}
if (vstride < ev->k) {
__glSetError(GL_INVALID_VALUE);
return;
}
data = gc->eval.eval2Data[__GL_EVAL2D_INDEX(target)];
__glFillMap2d(ev->k, uorder, vorder, ustride, vstride,
points, data);
}
void APIENTRY
glcltMap2f ( IN GLenum target, IN GLfloat u1, IN GLfloat u2, IN GLint ustride, IN GLint uorder, IN GLfloat v1, IN GLfloat v2, IN GLint vstride, IN GLint vorder, IN const GLfloat points[] )
{
__GLevaluator2 *ev;
__GLfloat *data;
POLYARRAY *pa;
__GL_SETUP ();
// Check if it is called inside a Begin-End block
// If we are already in the begin/end bracket, return an error.
pa = GLTEB_CLTPOLYARRAY();
if (pa->flags & POLYARRAY_IN_BEGIN)
{
GLSETERROR(GL_INVALID_OPERATION);
return;
}
ev = __glSetUpMap2(gc, target, uorder, vorder, u1, u2, v1, v2);
if (ev == 0) {
return;
}
if (ustride < ev->k) {
__glSetError(GL_INVALID_VALUE);
return;
}
if (vstride < ev->k) {
__glSetError(GL_INVALID_VALUE);
return;
}
data = gc->eval.eval2Data[__GL_EVAL2D_INDEX(target)];
__glFillMap2f(ev->k, uorder, vorder, ustride, vstride,
points, data);
}
/************************************************************************/
/********************** Evaluator helper functions **********************/
/********************** taken from so_eval.c **********************/
/************************************************************************/
GLint FASTCALL __glEvalComputeK(GLenum target)
{
switch(target) {
case GL_MAP1_VERTEX_4:
case GL_MAP1_COLOR_4:
case GL_MAP1_TEXTURE_COORD_4:
case GL_MAP2_VERTEX_4:
case GL_MAP2_COLOR_4:
case GL_MAP2_TEXTURE_COORD_4:
return 4;
case GL_MAP1_VERTEX_3:
case GL_MAP1_TEXTURE_COORD_3:
case GL_MAP1_NORMAL:
case GL_MAP2_VERTEX_3:
case GL_MAP2_TEXTURE_COORD_3:
case GL_MAP2_NORMAL:
return 3;
case GL_MAP1_TEXTURE_COORD_2:
case GL_MAP2_TEXTURE_COORD_2:
return 2;
case GL_MAP1_TEXTURE_COORD_1:
case GL_MAP2_TEXTURE_COORD_1:
case GL_MAP1_INDEX:
case GL_MAP2_INDEX:
return 1;
default:
return -1;
}
}
void ComputeNormal2(__GLcontext *gc, __GLfloat *n, __GLfloat *pu,
__GLfloat *pv)
{
n[0] = pu[1]*pv[2] - pu[2]*pv[1];
n[1] = pu[2]*pv[0] - pu[0]*pv[2];
n[2] = pu[0]*pv[1] - pu[1]*pv[0];
#ifdef NT
// Only need to normalize auto normals if normalization is not enabled!
if (!(gc->state.enables.general & __GL_NORMALIZE_ENABLE))
#endif
__glNormalize(n, n);
}
void ComputeFirstPartials(__GLfloat *p, __GLfloat *pu, __GLfloat *pv)
{
pu[0] = pu[0]*p[3] - pu[3]*p[0];
pu[1] = pu[1]*p[3] - pu[3]*p[1];
pu[2] = pu[2]*p[3] - pu[3]*p[2];
pv[0] = pv[0]*p[3] - pv[3]*p[0];
pv[1] = pv[1]*p[3] - pv[3]*p[1];
pv[2] = pv[2]*p[3] - pv[3]*p[2];
}
/*
** define a one dimensional map
*/
__GLevaluator1 *__glSetUpMap1(__GLcontext *gc, GLenum type,
GLint order, __GLfloat u1, __GLfloat u2)
{
__GLevaluator1 *ev;
__GLfloat **evData;
__GLfloat *pevData;
switch (type)
{
case GL_MAP1_COLOR_4:
case GL_MAP1_INDEX:
case GL_MAP1_NORMAL:
case GL_MAP1_TEXTURE_COORD_1:
case GL_MAP1_TEXTURE_COORD_2:
case GL_MAP1_TEXTURE_COORD_3:
case GL_MAP1_TEXTURE_COORD_4:
case GL_MAP1_VERTEX_3:
case GL_MAP1_VERTEX_4:
ev = &gc->eval.eval1[__GL_EVAL1D_INDEX(type)];
evData = &gc->eval.eval1Data[__GL_EVAL1D_INDEX(type)];
break;
default:
__glSetError(GL_INVALID_ENUM);
return 0;
}
if (u1 == u2 || order < 1 || order > gc->constants.maxEvalOrder)
{
__glSetError(GL_INVALID_VALUE);
return 0;
}
pevData = (__GLfloat *)
GCREALLOC(gc, *evData,
(__glMap1_size(ev->k, order) * sizeof(__GLfloat)));
if (!pevData)
{
__glSetError(GL_OUT_OF_MEMORY);
return 0;
}
*evData = pevData;
ev->order = order;
ev->u1 = u1;
ev->u2 = u2;
return ev;
}
/*
** define a two dimensional map
*/
__GLevaluator2 *__glSetUpMap2(__GLcontext *gc, GLenum type,
GLint majorOrder, GLint minorOrder,
__GLfloat u1, __GLfloat u2,
__GLfloat v1, __GLfloat v2)
{
__GLevaluator2 *ev;
__GLfloat **evData;
__GLfloat *pevData;
switch (type) {
case GL_MAP2_COLOR_4:
case GL_MAP2_INDEX:
case GL_MAP2_NORMAL:
case GL_MAP2_TEXTURE_COORD_1:
case GL_MAP2_TEXTURE_COORD_2:
case GL_MAP2_TEXTURE_COORD_3:
case GL_MAP2_TEXTURE_COORD_4:
case GL_MAP2_VERTEX_3:
case GL_MAP2_VERTEX_4:
ev = &gc->eval.eval2[__GL_EVAL2D_INDEX(type)];
evData = &gc->eval.eval2Data[__GL_EVAL2D_INDEX(type)];
break;
default:
__glSetError(GL_INVALID_ENUM);
return 0;
}
if (minorOrder < 1 || minorOrder > gc->constants.maxEvalOrder ||
majorOrder < 1 || majorOrder > gc->constants.maxEvalOrder ||
u1 == u2 || v1 == v2)
{
__glSetError(GL_INVALID_VALUE);
return 0;
}
pevData = (__GLfloat *)
GCREALLOC(gc, *evData,
(__glMap2_size(ev->k, majorOrder, minorOrder)
* sizeof(__GLfloat)));
if (!pevData)
{
__glSetError(GL_OUT_OF_MEMORY);
return 0;
}
*evData = pevData;
ev->majorOrder = majorOrder;
ev->minorOrder = minorOrder;
ev->u1 = u1;
ev->u2 = u2;
ev->v1 = v1;
ev->v2 = v2;
return ev;
}
/*
** Fill our data from user data
*/
void APIPRIVATE __glFillMap1f(GLint k, GLint order, GLint stride,
const GLfloat *points, __GLfloat *data)
{
int i,j;
#ifndef __GL_DOUBLE
/* Optimization always hit during display list execution */
if (k == stride)
{
__GL_MEMCOPY(data, points,
__glMap1_size(k, order) * sizeof(__GLfloat));
return;
}
#endif
for (i=0; i<order; i++)
{
for (j=0; j<k; j++)
{
data[j] = points[j];
}
points += stride;
data += k;
}
}
void APIPRIVATE __glFillMap1d(GLint k, GLint order, GLint stride,
const GLdouble *points, __GLfloat *data)
{
int i,j;
for (i=0; i<order; i++)
{
for (j=0; j<k; j++)
{
data[j] = points[j];
}
points += stride;
data += k;
}
}
void APIPRIVATE __glFillMap2f(GLint k, GLint majorOrder, GLint minorOrder,
GLint majorStride, GLint minorStride,
const GLfloat *points, __GLfloat *data)
{
int i,j,x;
#ifndef __GL_DOUBLE
/* Optimization always hit during display list execution */
if (k == minorStride && majorStride == k * minorOrder)
{
__GL_MEMCOPY(data, points,
__glMap2_size(k, majorOrder, minorOrder) * sizeof(__GLfloat));
return;
}
#endif
for (i=0; i<majorOrder; i++)
{
for (j=0; j<minorOrder; j++)
{
for (x=0; x<k; x++)
{
data[x] = points[x];
}
points += minorStride;
data += k;
}
points += majorStride - minorStride * minorOrder;
}
}
void APIPRIVATE __glFillMap2d(GLint k, GLint majorOrder, GLint minorOrder,
GLint majorStride, GLint minorStride,
const GLdouble *points, __GLfloat *data)
{
int i,j,x;
for (i=0; i<majorOrder; i++)
{
for (j=0; j<minorOrder; j++)
{
for (x=0; x<k; x++)
{
data[x] = points[x];
}
points += minorStride;
data += k;
}
points += majorStride - minorStride * minorOrder;
}
}
#define TYPE_COEFF_AND_DERIV 1
#define TYPE_COEFF 2
void DoDomain1(__GLevaluatorMachine *em, __GLfloat u, __GLevaluator1 *e,
__GLfloat *v, __GLfloat *baseData)
{
GLint j, row;
__GLfloat uprime;
__GLfloat *data;
GLint k;
#ifdef NT
ASSERTOPENGL(e->u2 != e->u1, "Assert in DoDomain1 failed\n");
// assert(e->u2 != e->u1);
#else
if(e->u2 == e->u1)
return;
#endif
uprime = (u - e->u1) / (e->u2 - e->u1);
/* Use already cached values if possible */
if (em->uvalue != uprime || em->uorder != e->order)
{
/* Compute coefficients for values */
PreEvaluate(e->order, uprime, em->ucoeff);
em->utype = TYPE_COEFF;
em->uorder = e->order;
em->uvalue = uprime;
}
k=e->k;
for (j = 0; j < k; j++)
{
data=baseData+j;
v[j] = 0;
for (row = 0; row < e->order; row++)
{
v[j] += em->ucoeff[row] * (*data);
data += k;
}
}
}
// Helper Macro used in PADoEval1 and PADoEval2
#ifdef __NO_OPTIMIZE_FOR_DLIST
#define PropagateToNextPolyData (eval, pa) \
{ \
if ((gc)->eval.accFlags & EVAL_COLOR_VALID) \
{ \
(pa)->pdNextVertex->flags &= ~POLYDATA_EVAL_COLOR; \
if ((gc)->modes.colorIndexMode) \
glcltIndexf_InCI((gc)->eval.color.r); \
else \
glcltColor4f_InRGBA ((gc)->eval.color.r, \
(gc)->eval.color.g, \
(gc)->eval.color.b, \
(gc)->eval.color.a); \
} \
\
if ((gc)->eval.accFlags & EVAL_NORMAL_VALID) \
{ \
(pa)->pdNextVertex->flags &= ~POLYDATA_EVAL_NORMAL; \
glcltNormal3f ((gc)->eval.normal.x, \
(gc)->eval.normal.y, \
(gc)->eval.normal.z); \
} \
\
if ((gc)->eval.accFlags & EVAL_TEXTURE_VALID) \
{ \
(pa)->pdNextVertex->flags &= ~POLYDATA_EVAL_TEXCOORD; \
if (__GL_FLOAT_COMPARE_PONE((gc)->eval.texture.w, !=)) \
glcltTexCoord4f ((gc)->eval.texture.x, \
(gc)->eval.texture.y, \
(gc)->eval.texture.z, \
(gc)->eval.texture.w); \
else if (__GL_FLOAT_NEZ((gc)->eval.texture.z)) \
glcltTexCoord3f ((gc)->eval.texture.x, \
(gc)->eval.texture.y, \
(gc)->eval.texture.z); \
else if (__GL_FLOAT_NEZ((gc)->eval.texture.y)) \
glcltTexCoord2f ((gc)->eval.texture.x, \
(gc)->eval.texture.y); \
else \
glcltTexCoord1f ((gc)->eval.texture.x); \
} \
}
#else
#define PropagateToNextPolyData(eval,pa) \
\
if ((gc)->eval.accFlags & EVAL_COLOR_VALID) \
{ \
(pa)->pdNextVertex->flags &= ~POLYDATA_EVAL_COLOR; \
if ((gc)->modes.colorIndexMode) \
glcltIndexf_InCI((gc)->eval.color.r); \
else \
glcltColor4f_InRGBA ((gc)->eval.color.r, \
(gc)->eval.color.g, \
(gc)->eval.color.b, \
(gc)->eval.color.a); \
} \
\
if ((gc)->eval.accFlags & EVAL_NORMAL_VALID) \
{ \
(pa)->pdNextVertex->flags &= ~POLYDATA_EVAL_NORMAL; \
glcltNormal3f ((gc)->eval.normal.x, \
(gc)->eval.normal.y, \
(gc)->eval.normal.z); \
} \
\
if ((gc)->eval.accFlags & EVAL_TEXTURE_VALID) \
{ \
(pa)->pdNextVertex->flags &= ~POLYDATA_EVAL_TEXCOORD; \
glcltTexCoord4f ((gc)->eval.texture.x, \
(gc)->eval.texture.y, \
(gc)->eval.texture.z, \
(gc)->eval.texture.w); \
}
#endif
//////////////////////////////////////////////////////
// Assuming that the latest State is available here //
//////////////////////////////////////////////////////
void FASTCALL PADoEval1(__GLcontext *gc, __GLfloat u)
{
__GLevaluator1 *eval;
__GLfloat **evalData;
__GLevaluatorMachine em;
__GLfloat v4[4];
__GLfloat n3[3];
__GLfloat t4[4];
__GLfloat c4[4];
__GLfloat ci;
POLYARRAY *pa;
pa = gc->paTeb;
eval = gc->eval.eval1;
evalData = gc->eval.eval1Data;
em = gc->eval;
// Initialize the flag
gc->eval.accFlags = 0;
// Evaluated color, index, normal and texture coords are ignored
// in selection
if ((gc->renderMode != GL_SELECT) &&
(gc->state.enables.eval1 & (__GL_MAP1_VERTEX_4_ENABLE |
__GL_MAP1_VERTEX_3_ENABLE ))
)
{
if (gc->modes.colorIndexMode)
{
if (!(gc->state.enables.general & __GL_LIGHTING_ENABLE))
{
if (gc->state.enables.eval1 & __GL_MAP1_INDEX_ENABLE)
{
DoDomain1(&em, u, &eval[__GL_I], &ci, evalData[__GL_I]);
glcltIndexf_Eval(ci);
}
}
}
else
{
if (gc->state.enables.eval1 & __GL_MAP1_COLOR_4_ENABLE)
{
// NOTE: In OpenGL 1.0, color material does not apply to
// evaluated colors.
// In OpenGL 1.1, this behavior was changed.
// This (1.1) code assumes that ColorMaterial applies to
// evaluated colors to simplify the graphics pipeline.
// Otherwise, the evaluated colors have no effect when
// lighting is enabled.
DoDomain1(&em, u, &eval[__GL_C4], c4, evalData[__GL_C4]);
// If some color is set in the current polydata, then
// Save it in a temporary buffer and call glcltColor later
// Also make sure that the current-color pointer is updated
// appropriately
glcltColor4fv_Eval(c4);
}
if (gc->state.enables.eval1 & __GL_MAP1_TEXTURE_COORD_4_ENABLE)
{
DoDomain1(&em, u, &eval[__GL_T4], t4, evalData[__GL_T4]);
glcltTexCoord4fv_Eval(t4);
}
else if (gc->state.enables.eval1 &
__GL_MAP1_TEXTURE_COORD_3_ENABLE)
{
DoDomain1(&em, u, &eval[__GL_T3], t4, evalData[__GL_T3]);
glcltTexCoord3fv_Eval(t4);
}
else if (gc->state.enables.eval1 &
__GL_MAP1_TEXTURE_COORD_2_ENABLE)
{
DoDomain1(&em, u, &eval[__GL_T2], t4, evalData[__GL_T2]);
glcltTexCoord2fv_Eval(t4);
}
else if (gc->state.enables.eval1 &
__GL_MAP1_TEXTURE_COORD_1_ENABLE)
{
DoDomain1(&em, u, &eval[__GL_T1], t4, evalData[__GL_T1]);
glcltTexCoord1fv_Eval(t4);
}
}
if (gc->state.enables.eval1 & __GL_MAP1_NORMAL_ENABLE)
{
DoDomain1(&em, u, &eval[__GL_N3], n3, evalData[__GL_N3]);
glcltNormal3fv_Eval(n3);
}
}
/* Vertex */
if (gc->state.enables.eval1 & __GL_MAP1_VERTEX_4_ENABLE)
{
DoDomain1(&em, u, &eval[__GL_V4], v4, evalData[__GL_V4]);
glcltVertex4fv (v4);
}
else if (gc->state.enables.eval1 & __GL_MAP1_VERTEX_3_ENABLE)
{
DoDomain1(&em, u, &eval[__GL_V3], v4, evalData[__GL_V3]);
glcltVertex3fv (v4);
}
// If there are any prior glcltColor, glcltIndex, glcltTexCoord
// or glcltNormal calls. The values are saved in gc->eval. Use
// these and propagate them, to the next PolyData
PropagateToNextPolyData (eval, pa);
}
// Compute the color, texture, normal, vertex based upon u and v.
//
// NOTE: This function is called by the client side EvalMesh2 functions.
// If you modify it, make sure that you modify the callers too!
//////////////////////////////////////////////////////
// Assuming that the latest State is available here //
//////////////////////////////////////////////////////
void FASTCALL PADoEval2(__GLcontext *gc, __GLfloat u, __GLfloat v)
{
__GLevaluator2 *eval = gc->eval.eval2;
__GLfloat **evalData = gc->eval.eval2Data;
__GLevaluatorMachine em = gc->eval;
__GLfloat v4[4];
__GLfloat n3[3];
__GLfloat t4[4];
__GLfloat c4[4];
__GLfloat ci;
POLYARRAY *pa;
pa = gc->paTeb;
// Mark this PolyArray to indicate that it has a Evaluator vertex
// pa->flags |= POLYARRAY_EVALCOORD;
// Evaluated colors, normals and texture coords are ignored in selection.
if (gc->renderMode == GL_SELECT)
{
if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_4_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_V4], v4, evalData[__GL_V4]);
glcltVertex4fv (v4);
}
else if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_3_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_V3], v4, evalData[__GL_V3]);
glcltVertex3fv (v4);
}
return;
}
if (gc->state.enables.eval2 & (__GL_MAP2_VERTEX_3_ENABLE |
__GL_MAP2_VERTEX_4_ENABLE))
{
if (gc->modes.colorIndexMode)
{
if (!(gc->state.enables.general & __GL_LIGHTING_ENABLE))
{
if (gc->state.enables.eval2 & __GL_MAP2_INDEX_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_I], &ci, evalData[__GL_I]);
glcltIndexf_Eval(ci);
}
}
}
else
{
if (gc->state.enables.eval2 & __GL_MAP2_COLOR_4_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_C4], c4, evalData[__GL_C4]);
glcltColor4fv_Eval(c4);
}
if (gc->state.enables.eval2 & __GL_MAP2_TEXTURE_COORD_4_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_T4], t4, evalData[__GL_T4]);
glcltTexCoord4fv_Eval(t4);
}
else if (gc->state.enables.eval2 &
__GL_MAP2_TEXTURE_COORD_3_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_T3], t4, evalData[__GL_T3]);
glcltTexCoord3fv_Eval(t4);
}
else if (gc->state.enables.eval2 &
__GL_MAP2_TEXTURE_COORD_2_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_T2], t4, evalData[__GL_T2]);
glcltTexCoord2fv_Eval(t4);
}
else if (gc->state.enables.eval2 &
__GL_MAP2_TEXTURE_COORD_1_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_T1], t4, evalData[__GL_T1]);
glcltTexCoord1fv_Eval(t4);
}
}
if (gc->state.enables.general & __GL_AUTO_NORMAL_ENABLE)
{
if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_4_ENABLE)
{
__GLfloat du[4];
__GLfloat dv[4];
DoDomain2WithDerivs(&em, u, v, &eval[__GL_V4], v4, du, dv,
evalData[__GL_V4]);
ComputeFirstPartials(v4, du, dv);
ComputeNormal2(gc, n3, du, dv);
glcltNormal3fv_Eval(n3);
glcltVertex4fv(v4);
}
else if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_3_ENABLE)
{
__GLfloat du[3];
__GLfloat dv[3];
DoDomain2WithDerivs(&em, u, v, &eval[__GL_V3], v4, du, dv,
evalData[__GL_V3]);
ComputeNormal2(gc, n3, du, dv);
glcltNormal3fv_Eval(n3);
glcltVertex3fv(v4);
}
}
else
{
if (gc->state.enables.eval2 & __GL_MAP2_NORMAL_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_N3], n3, evalData[__GL_N3]);
glcltNormal3fv_Eval(n3);
}
if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_4_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_V4], v4, evalData[__GL_V4]);
glcltVertex4fv(v4);
}
else if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_3_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_V3], v4, evalData[__GL_V3]);
glcltVertex3fv(v4);
}
}
}
// If there are any prior glcltColor, glcltIndex, glcltTexCoord
// or glcltNormal calls. The values are saved in gc->eval. Use
// these and propagate them, to the next PolyData
PropagateToNextPolyData (eval, pa);
}
#define COPYMESHVERTEX(m,v) \
{ \
(m)->vertex.x = (v)[0]; \
(m)->vertex.y = (v)[1]; \
(m)->vertex.z = (v)[2]; \
(m)->vertex.w = (v)[3]; \
}
#define COPYMESHNORMAL(m,n) \
{ \
(m)->normal.x = (n)[0]; \
(m)->normal.y = (n)[1]; \
(m)->normal.z = (n)[2]; \
}
#define COPYMESHCOLOR(m,c) \
{ \
(m)->color.r = (c)[0]; \
(m)->color.g = (c)[1]; \
(m)->color.b = (c)[2]; \
(m)->color.a = (c)[3]; \
}
#define COPYMESHTEXTURE(m,t) \
{ \
(m)->texture.x = (t)[0]; \
(m)->texture.y = (t)[1]; \
(m)->texture.z = (t)[2]; \
(m)->texture.w = (t)[3]; \
}
//////////////////////////////////////////////////////
// Assuming that the latest State is available here //
//////////////////////////////////////////////////////
void FASTCALL PADoEval2VArray(__GLcontext *gc, __GLfloat u, __GLfloat v,
MESHVERTEX *mv, GLuint *flags)
{
__GLevaluator2 *eval = gc->eval.eval2;
__GLfloat **evalData = gc->eval.eval2Data;
__GLevaluatorMachine em = gc->eval;
__GLfloat v4[4];
__GLfloat n3[3];
__GLfloat t4[4];
__GLfloat c4[4];
__GLfloat ci;
// Evaluated colors, normals and texture coords are ignored in selection.
if (gc->renderMode == GL_SELECT)
{
if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_4_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_V4], v4, evalData[__GL_V4]);
*flags = *flags | MV_VERTEX4;
}
else if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_3_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_V3], v4, evalData[__GL_V3]);
*flags = *flags | MV_VERTEX3;
}
COPYMESHVERTEX (mv, v4);
return;
}
if (gc->state.enables.general & __GL_AUTO_NORMAL_ENABLE)
{
if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_4_ENABLE)
{
__GLfloat du[4];
__GLfloat dv[4];
DoDomain2WithDerivs(&em, u, v, &eval[__GL_V4], v4, du, dv,
evalData[__GL_V4]);
ComputeFirstPartials(v4, du, dv);
ComputeNormal2(gc, n3, du, dv);
*flags = *flags | MV_VERTEX4 | MV_NORMAL;
}
else if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_3_ENABLE)
{
__GLfloat du[3];
__GLfloat dv[3];
DoDomain2WithDerivs(&em, u, v, &eval[__GL_V3], v4, du, dv,
evalData[__GL_V3]);
ComputeNormal2(gc, n3, du, dv);
*flags = *flags | MV_VERTEX3 | MV_NORMAL;
}
COPYMESHNORMAL (mv, n3);
COPYMESHVERTEX (mv, v4);
}
else
{
if (gc->state.enables.eval2 & __GL_MAP2_NORMAL_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_N3], n3, evalData[__GL_N3]);
COPYMESHNORMAL (mv, n3);
*flags = *flags | MV_NORMAL;
}
if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_4_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_V4], v4, evalData[__GL_V4]);
COPYMESHVERTEX (mv, v4);
*flags = *flags | MV_VERTEX4;
}
else if (gc->state.enables.eval2 & __GL_MAP2_VERTEX_3_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_V3], v4, evalData[__GL_V3]);
COPYMESHVERTEX (mv, v4);
*flags = *flags | MV_VERTEX3;
}
}
if (gc->modes.colorIndexMode)
{
if (!(gc->state.enables.general & __GL_LIGHTING_ENABLE))
{
if (gc->state.enables.eval2 & __GL_MAP2_INDEX_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_I], &(mv->color.r),
evalData[__GL_I]);
*flags = *flags | MV_INDEX;
}
}
}
else
{
if (gc->state.enables.eval2 & __GL_MAP2_COLOR_4_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_C4], c4, evalData[__GL_C4]);
COPYMESHCOLOR (mv, c4);
*flags = *flags | MV_COLOR;
}
if (gc->state.enables.eval2 & __GL_MAP2_TEXTURE_COORD_4_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_T4], t4, evalData[__GL_T4]);
COPYMESHTEXTURE (mv, t4);
*flags = *flags | MV_TEXTURE4;
}
else if (gc->state.enables.eval2 & __GL_MAP2_TEXTURE_COORD_3_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_T3], t4, evalData[__GL_T3]);
COPYMESHTEXTURE (mv, t4);
*flags = *flags | MV_TEXTURE3;
}
else if (gc->state.enables.eval2 & __GL_MAP2_TEXTURE_COORD_2_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_T2], t4, evalData[__GL_T2]);
COPYMESHTEXTURE (mv, t4);
*flags = *flags | MV_TEXTURE2;
}
else if (gc->state.enables.eval2 & __GL_MAP2_TEXTURE_COORD_1_ENABLE)
{
DoDomain2(&em, u, v, &eval[__GL_T1], t4, evalData[__GL_T1]);
COPYMESHTEXTURE (mv, t4);
*flags = *flags | MV_TEXTURE1;
}
}
}
/*
** Optimization to precompute coefficients for polynomial evaluation.
*/
static void PreEvaluate(GLint order, __GLfloat vprime, __GLfloat *coeff)
{
GLint i, j;
__GLfloat oldval, temp;
__GLfloat oneMinusvprime;
/*
** Minor optimization
** Compute orders 1 and 2 outright, and set coeff[0], coeff[1] to
** their i==1 loop values to avoid the initialization and the i==1 loop.
*/
if (order == 1)
{
coeff[0] = ((__GLfloat) 1.0);
return;
}
oneMinusvprime = 1-vprime;
coeff[0] = oneMinusvprime;
coeff[1] = vprime;
if (order == 2) return;
for (i = 2; i < order; i++)
{
oldval = coeff[0] * vprime;
coeff[0] = oneMinusvprime * coeff[0];
for (j = 1; j < i; j++)
{
temp = oldval;
oldval = coeff[j] * vprime;
coeff[j] = temp + oneMinusvprime * coeff[j];
}
coeff[j] = oldval;
}
}
/*
** Optimization to precompute coefficients for polynomial evaluation.
*/
static void PreEvaluateWithDeriv(GLint order, __GLfloat vprime,
__GLfloat *coeff, __GLfloat *coeffDeriv)
{
GLint i, j;
__GLfloat oldval, temp;
__GLfloat oneMinusvprime;
oneMinusvprime = 1-vprime;
/*
** Minor optimization
** Compute orders 1 and 2 outright, and set coeff[0], coeff[1] to
** their i==1 loop values to avoid the initialization and the i==1 loop.
*/
if (order == 1)
{
coeff[0] = ((__GLfloat) 1.0);
coeffDeriv[0] = __glZero;
return;
}
else if (order == 2)
{
coeffDeriv[0] = __glMinusOne;
coeffDeriv[1] = ((__GLfloat) 1.0);
coeff[0] = oneMinusvprime;
coeff[1] = vprime;
return;
}
coeff[0] = oneMinusvprime;
coeff[1] = vprime;
for (i = 2; i < order - 1; i++)
{
oldval = coeff[0] * vprime;
coeff[0] = oneMinusvprime * coeff[0];
for (j = 1; j < i; j++)
{
temp = oldval;
oldval = coeff[j] * vprime;
coeff[j] = temp + oneMinusvprime * coeff[j];
}
coeff[j] = oldval;
}
coeffDeriv[0] = -coeff[0];
/*
** Minor optimization:
** Would make this a "for (j=1; j<order-1; j++)" loop, but it is always
** executed at least once, so this is more efficient.
*/
j=1;
do
{
coeffDeriv[j] = coeff[j-1] - coeff[j];
j++;
} while (j < order - 1);
coeffDeriv[j] = coeff[j-1];
oldval = coeff[0] * vprime;
coeff[0] = oneMinusvprime * coeff[0];
for (j = 1; j < i; j++)
{
temp = oldval;
oldval = coeff[j] * vprime;
coeff[j] = temp + oneMinusvprime * coeff[j];
}
coeff[j] = oldval;
}
void DoDomain2(__GLevaluatorMachine *em, __GLfloat u, __GLfloat v,
__GLevaluator2 *e, __GLfloat *r, __GLfloat *baseData)
{
GLint j, row, col;
__GLfloat uprime;
__GLfloat vprime;
__GLfloat p;
__GLfloat *data;
GLint k;
#ifdef NT
ASSERTOPENGL((e->u2 != e->u1) && (e->v2 != e->v1), "In DoDomain2\n");
// assert((e->u2 != e->u1) && (e->v2 != e->v1));
#else
if((e->u2 == e->u1) || (e->v2 == e->v1))
return;
#endif
uprime = (u - e->u1) / (e->u2 - e->u1);
vprime = (v - e->v1) / (e->v2 - e->v1);
/* Compute coefficients for values */
/* Use already cached values if possible */
if (em->uvalue != uprime || em->uorder != e->majorOrder)
{
PreEvaluate(e->majorOrder, uprime, em->ucoeff);
em->utype = TYPE_COEFF;
em->uorder = e->majorOrder;
em->uvalue = uprime;
}
if (em->vvalue != vprime || em->vorder != e->minorOrder)
{
PreEvaluate(e->minorOrder, vprime, em->vcoeff);
em->vtype = TYPE_COEFF;
em->vorder = e->minorOrder;
em->vvalue = vprime;
}
k=e->k;
for (j = 0; j < k; j++)
{
data=baseData+j;
r[j] = 0;
for (row = 0; row < e->majorOrder; row++)
{
/*
** Minor optimization.
** The col == 0 part of the loop is extracted so we don't
** have to initialize p to 0.
*/
p=em->vcoeff[0] * (*data);
data += k;
for (col = 1; col < e->minorOrder; col++)
{
p += em->vcoeff[col] * (*data);
data += k;
}
r[j] += em->ucoeff[row] * p;
}
}
}
void DoDomain2WithDerivs(__GLevaluatorMachine *em, __GLfloat u,
__GLfloat v, __GLevaluator2 *e, __GLfloat *r,
__GLfloat *du, __GLfloat *dv, __GLfloat *baseData)
{
GLint j, row, col;
__GLfloat uprime;
__GLfloat vprime;
__GLfloat p;
__GLfloat pdv;
__GLfloat n[3];
__GLfloat *data;
GLint k;
#ifdef NT
ASSERTOPENGL((e->u2 != e->u1) && (e->v2 != e->v1),
"In Dodomain2WithDerivs\n");
// assert((e->u2 != e->u1) && (e->v2 != e->v1));
#else
if((e->u2 == e->u1) || (e->v2 == e->v1))
return;
#endif
uprime = (u - e->u1) / (e->u2 - e->u1);
vprime = (v - e->v1) / (e->v2 - e->v1);
/* Compute coefficients for values and derivs */
/* Use already cached values if possible */
if (em->uvalue != uprime || em->utype != TYPE_COEFF_AND_DERIV ||
em->uorder != e->majorOrder)
{
PreEvaluateWithDeriv(e->majorOrder, uprime, em->ucoeff,
em->ucoeffDeriv);
em->utype = TYPE_COEFF_AND_DERIV;
em->uorder = e->majorOrder;
em->uvalue = uprime;
}
if (em->vvalue != vprime || em->vtype != TYPE_COEFF_AND_DERIV ||
em->vorder != e->minorOrder)
{
PreEvaluateWithDeriv(e->minorOrder, vprime, em->vcoeff,
em->vcoeffDeriv);
em->vtype = TYPE_COEFF_AND_DERIV;
em->vorder = e->minorOrder;
em->vvalue = vprime;
}
k=e->k;
for (j = 0; j < k; j++)
{
data=baseData+j;
r[j] = du[j] = dv[j] = __glZero;
for (row = 0; row < e->majorOrder; row++)
{
/*
** Minor optimization.
** The col == 0 part of the loop is extracted so we don't
** have to initialize p and pdv to 0.
*/
p = em->vcoeff[0] * (*data);
pdv = em->vcoeffDeriv[0] * (*data);
data += k;
for (col = 1; col < e->minorOrder; col++)
{
/* Incrementally build up p, pdv value */
p += em->vcoeff[col] * (*data);
pdv += em->vcoeffDeriv[col] * (*data);
data += k;
}
/* Use p, pdv value to incrementally add up r, du, dv */
r[j] += em->ucoeff[row] * p;
du[j] += em->ucoeffDeriv[row] * p;
dv[j] += em->ucoeff[row] * pdv;
}
}
}
int FASTCALL genMeshElts (GLenum mode, GLuint sides, GLint nu, GLint nv,
GLubyte *buff)
{
GLint start;
GLint i, j, k;
// Compute the DrawElements Indices
switch(mode) {
case GL_LINE :
// Draw lines along U direction
start = 1;
k = 0;
if (sides & MV_TOP)
start = 0 ;
for (i=start; i<nv; i++)
for(j=0; j<nu-1; j++) {
buff[k++] = i*nu+j;
buff[k++] = i*nu+j+1;
}
// Draw lines along V direction
start = 1 ;
if (sides & MV_LEFT)
start = 0;
for (i=start; i<nu; i++)
for (j=0; j<nv-1; j++) {
buff[k++] = j*nu+i;
buff[k++] = (j+1)*nu+i;
}
break ;
case GL_FILL :
for (i=0, k=0; i<nv-1; i++)
for (j=0; j<nu-1; j++) {
buff[k++] = i*nu+j;
buff[k++] = (i+1)*nu+j;
buff[k++] = (i+1)*nu+j+1;
buff[k++] = i*nu+j+1;
}
break ;
}
return k; //the total number of points
}
void FASTCALL PA_EvalMesh2Fast(__GLcontext *gc, GLint u1, GLint u2, GLint v1,
GLint v2, GLint meshSize, GLenum mode,
GLuint sides)
{
GLint i, j, k, nu, nv;
__GLcolor currentColor;
__GLcoord currentNormal, currentTexture;
GLboolean currentEdgeFlag;
MESHVERTEX *mv, mvBuf[MAX_U_SIZE*MAX_V_SIZE];
GLuint mflags = 0;
GLuint stride;
GLubyte *disBuf;
__GLvertexArray currentVertexInfo;
GLuint texSize = 0, start, totalPts;
GLubyte dBufSmall[4*MAX_U_SIZE*MAX_V_SIZE]; //small
__GLfloat u, v;
__GLfloat du, dv;
__GLevaluatorGrid *gu;
__GLevaluatorGrid *gv;
// Now build the mesh vertex array [0..u2-u1, 0..v2-v1]
gu = &gc->state.evaluator.u2;
gv = &gc->state.evaluator.v2;
du = gu->step;
dv = gv->step;
//du = (gu->finish - gu->start)/(__GLfloat)gu->n;
//dv = (gv->finish - gv->start)/(__GLfloat)gv->n;
mv = &mvBuf[0];
nu = u2 - u1 + 1;
nv = v2 - v1 + 1;
for (i = v1; i < nv+v1; i++) //along V
{
for (j = u1; j < nu+u1; j++) //along U
{
u = (j == gu->n) ? gu->finish : (gu->start + j * du);
v = (i == gv->n) ? gv->finish : (gv->start + i * dv);
PADoEval2VArray(gc, u, v, mv, &mflags);
mv++;
}
}
if ((nv != MAX_V_SIZE) || (nu != MAX_U_SIZE)) {
disBuf = dBufSmall;
totalPts = genMeshElts (mode, sides, nu, nv, disBuf);
} else {
if (mode == GL_FILL) {
disBuf = dBufFill;
totalPts = totFillPts;
} else
switch (sides) {
case (MV_TOP | MV_LEFT):
disBuf = dBufTopLeft;
totalPts = totTopLeftPts;
break;
case (MV_TOP):
disBuf = dBufTopRight;
totalPts = totTopRightPts;
break;
case (MV_LEFT):
disBuf = &dBufTopLeft [(MAX_U_SIZE - 1) * 2];
totalPts = totTopLeftPts - (MAX_U_SIZE - 1) * 2;
break;
default : //NONE
disBuf = &dBufTopRight [(MAX_V_SIZE - 1) * 2];
totalPts = totTopRightPts - (MAX_V_SIZE - 1) * 2;
break;
}
}
if (mflags & MV_TEXTURE4)
texSize = 4;
else if (mflags & MV_TEXTURE3)
texSize = 3;
else if (mflags & MV_TEXTURE2)
texSize = 2;
else if (mflags & MV_TEXTURE1)
texSize = 1;
// Save current values.
if (mflags & MV_NORMAL)
currentNormal = gc->state.current.normal;
if (mflags & MV_INDEX)
currentColor.r = gc->state.current.userColorIndex;
else if (mflags & MV_COLOR)
currentColor = gc->state.current.userColor;
if (texSize)
currentTexture = gc->state.current.texture;
// Always force edge flag on in GL_FILL mode. The spec uses QUAD_STRIP
// which implies that edge flag is on for the evaluated mesh.
currentEdgeFlag = gc->state.current.edgeTag;
gc->state.current.edgeTag = GL_TRUE;
currentVertexInfo = gc->vertexArray;
//Enable the appropriate arrays
// Disable the arrays followed by enabling each individual array.
gc->vertexArray.flags |= __GL_VERTEX_ARRAY_DIRTY;
gc->vertexArray.mask &= ~(VAMASK_VERTEX_ENABLE_MASK |
VAMASK_NORMAL_ENABLE_MASK |
VAMASK_COLOR_ENABLE_MASK |
VAMASK_INDEX_ENABLE_MASK |
VAMASK_TEXCOORD_ENABLE_MASK |
VAMASK_EDGEFLAG_ENABLE_MASK);
stride = sizeof(MESHVERTEX);
if (mflags & MV_NORMAL)
{
gc->vertexArray.mask |= VAMASK_NORMAL_ENABLE_MASK;
glcltNormalPointer(GL_FLOAT, stride, &(mvBuf[0].normal.x));
}
if (mflags & MV_INDEX) {
gc->vertexArray.mask |= VAMASK_INDEX_ENABLE_MASK;
glcltIndexPointer(GL_FLOAT, stride, &(mvBuf[0].color.r));
} else if (mflags & MV_COLOR) {
gc->vertexArray.mask |= VAMASK_COLOR_ENABLE_MASK;
glcltColorPointer(3, GL_FLOAT, stride, &(mvBuf[0].color.r));
}
if (texSize)
{
glcltTexCoordPointer(texSize, GL_FLOAT, stride,
&(mvBuf[0].texture.x));
gc->vertexArray.mask |= VAMASK_TEXCOORD_ENABLE_MASK;
}
if (mflags & MV_VERTEX3)
glcltVertexPointer(3, GL_FLOAT, stride, &(mvBuf[0].vertex.x));
else
glcltVertexPointer(4, GL_FLOAT, stride, &(mvBuf[0].vertex.x));
gc->vertexArray.mask |= VAMASK_VERTEX_ENABLE_MASK;
if (mode == GL_FILL)
glcltDrawElements(GL_QUADS, totalPts, GL_UNSIGNED_BYTE, disBuf);
else
glcltDrawElements(GL_LINES, totalPts, GL_UNSIGNED_BYTE, disBuf);
// Execute the command now.
// Otherwise, the current states will be messed up.
glsbAttention();
// Restore current values.
if (mflags & MV_NORMAL)
gc->state.current.normal = currentNormal;
if (mflags & MV_INDEX)
gc->state.current.userColorIndex = currentColor.r;
else if (mflags & MV_COLOR)
gc->state.current.userColor = currentColor;
if (texSize)
gc->state.current.texture = currentTexture;
gc->state.current.edgeTag = currentEdgeFlag;
gc->vertexArray = currentVertexInfo ;
}
void glcltColor4fv_Eval (__GLfloat *c4)
{
__GL_SETUP ();
POLYARRAY *pa;
POLYDATA *pd;
// POLYDATA *pdNext;
pa = gc->paTeb;
pd = pa->pdNextVertex;
// We are in RGBA mode.
ASSERTOPENGL (!gc->modes.colorIndexMode, "We should be in RGBA mode\n");
// Do not update the CurColor pointer
// If the color has already been set by a previous glcltColor call,
// simply, push this color to the next POLYDATA.
// This is a COLOR and not an INDEX.
if ((pd->flags & POLYDATA_COLOR_VALID) &&
!(pd->flags & POLYDATA_EVAL_COLOR))
{
gc->eval.color.r = pd->colors[0].r;
gc->eval.color.g = pd->colors[0].g;
gc->eval.color.b = pd->colors[0].b;
gc->eval.color.a = pd->colors[0].a;
gc->eval.accFlags |= EVAL_COLOR_VALID;
}
__GL_SCALE_AND_CHECK_CLAMP_RGBA(pd->colors[0].r,
pd->colors[0].g,
pd->colors[0].b,
pd->colors[0].a,
gc, pa->flags,
c4[0], c4[1], c4[2], c4[3]);
pd->flags |= (POLYDATA_COLOR_VALID | POLYDATA_DLIST_COLOR_4 |
POLYDATA_EVAL_COLOR) ;
pa->pdLastEvalColor = pd;
}
void glcltIndexf_Eval (__GLfloat ci)
{
__GL_SETUP ();
POLYARRAY *pa;
POLYDATA *pd;
pa = gc->paTeb;
pd = pa->pdNextVertex;
// We are in CI mode.
ASSERTOPENGL (gc->modes.colorIndexMode, "We should be in CI mode\n");
// Do not update the CurColor pointer
// If the index has already been set by a previous glcltIndex call,
// simply, push this color to the next POLYDATA.
// This is an INDEX and not a COLOR.
if ((pd->flags & POLYDATA_COLOR_VALID) &&
!(pd->flags & POLYDATA_EVAL_COLOR))
{
gc->eval.color.r = pd->colors[0].r;
gc->eval.accFlags |= EVAL_COLOR_VALID;
}
__GL_CHECK_CLAMP_CI(pd->colors[0].r, gc, pa->flags, ci);
pd->flags |= (POLYDATA_COLOR_VALID | POLYDATA_EVAL_COLOR) ;
pa->pdLastEvalColor = pd;
}
void glcltTexCoord1fv_Eval (__GLfloat *t1)
{
__GL_SETUP ();
POLYARRAY *pa;
POLYDATA *pd;
pa = GLTEB_CLTPOLYARRAY();
pa->flags |= POLYARRAY_TEXTURE1;
pd = pa->pdNextVertex;
// Do not update the CurTexture pointer
if (pd->flags & POLYDATA_TEXTURE_VALID)
{
ASSERTOPENGL (!(pd->flags & POLYDATA_EVAL_TEXCOORD),
"This cannot have been generated by an evaluator\n");
gc->eval.texture.x = pd->texture.x;
gc->eval.texture.y = pd->texture.y;
gc->eval.texture.z = pd->texture.z;
gc->eval.texture.w = pd->texture.w;
gc->eval.accFlags |= EVAL_TEXTURE_VALID;
}
pd->texture.x = t1[0];
pd->texture.y = __glZero;
pd->texture.z = __glZero;
pd->texture.w = __glOne;
pd->flags |= (POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE1 |
POLYDATA_EVAL_TEXCOORD);
pa->pdLastEvalTexture = pd;
}
void glcltTexCoord2fv_Eval (__GLfloat *t2)
{
__GL_SETUP ();
POLYARRAY *pa;
POLYDATA *pd;
pa = GLTEB_CLTPOLYARRAY();
pa->flags |= POLYARRAY_TEXTURE2;
pd = pa->pdNextVertex;
// Do not update the CurTexture pointer
if (pd->flags & POLYDATA_TEXTURE_VALID)
{
ASSERTOPENGL (!(pd->flags & POLYDATA_EVAL_TEXCOORD),
"This cannot have been generated by an evaluator\n");
gc->eval.texture.x = pd->texture.x;
gc->eval.texture.y = pd->texture.y;
gc->eval.texture.z = pd->texture.z;
gc->eval.texture.w = pd->texture.w;
gc->eval.accFlags |= EVAL_TEXTURE_VALID;
}
pd->texture.x = t2[0];
pd->texture.y = t2[1];
pd->texture.z = __glZero;
pd->texture.w = __glOne;
pd->flags |= (POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE2 |
POLYDATA_EVAL_TEXCOORD);
pa->pdLastEvalTexture = pd;
}
void glcltTexCoord3fv_Eval (__GLfloat *t3)
{
__GL_SETUP ();
POLYARRAY *pa;
POLYDATA *pd;
pa = GLTEB_CLTPOLYARRAY();
pa->flags |= POLYARRAY_TEXTURE3;
pd = pa->pdNextVertex;
if (pd->flags & POLYDATA_TEXTURE_VALID)
{
ASSERTOPENGL (!(pd->flags & POLYDATA_EVAL_TEXCOORD),
"This cannot have been generated by an evaluator\n");
gc->eval.texture.x = pd->texture.x;
gc->eval.texture.y = pd->texture.y;
gc->eval.texture.z = pd->texture.z;
gc->eval.texture.w = pd->texture.w;
gc->eval.accFlags |= EVAL_TEXTURE_VALID;
}
pd->texture.x = t3[0];
pd->texture.y = t3[1];
pd->texture.z = t3[2];
pd->texture.w = __glOne;
pd->flags |= (POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE3 |
POLYDATA_EVAL_TEXCOORD) ;
pa->pdLastEvalTexture = pd;
}
// Do not update the CurTexture pointer
void glcltTexCoord4fv_Eval (__GLfloat *t4)
{
__GL_SETUP ();
POLYARRAY *pa;
POLYDATA *pd;
pa = GLTEB_CLTPOLYARRAY();
pa->flags |= POLYARRAY_TEXTURE4;
pd = pa->pdNextVertex;
if (pd->flags & POLYDATA_TEXTURE_VALID)
{
ASSERTOPENGL (!(pd->flags & POLYDATA_EVAL_TEXCOORD),
"This cannot have been generated by an evaluator\n");
gc->eval.texture.x = pd->texture.x;
gc->eval.texture.y = pd->texture.y;
gc->eval.texture.z = pd->texture.z;
gc->eval.texture.w = pd->texture.w;
gc->eval.accFlags |= EVAL_TEXTURE_VALID;
}
pd->texture.x = t4[0];
pd->texture.y = t4[1];
pd->texture.z = t4[2];
pd->texture.w = t4[4];
pd->flags |= (POLYDATA_TEXTURE_VALID | POLYDATA_DLIST_TEXTURE4 |
POLYDATA_EVAL_TEXCOORD);
pa->pdLastEvalTexture = pd;
}
// We do not update the CurNormal pointer here
void glcltNormal3fv_Eval (__GLfloat *n3)
{
__GL_SETUP ();
POLYARRAY *pa;
POLYDATA *pd;
pa = GLTEB_CLTPOLYARRAY();
pd = pa->pdNextVertex;
// If the existing normal is not from an evaluator, store it
// so that it can be set later.
if (pd->flags & POLYDATA_NORMAL_VALID)
{
ASSERTOPENGL (!(pd->flags & POLYDATA_EVAL_NORMAL),
"This cannot have been generated by an evaluator\n");
gc->eval.normal.x = pd->normal.x;
gc->eval.normal.y = pd->normal.y;
gc->eval.normal.z = pd->normal.z;
gc->eval.accFlags |= EVAL_NORMAL_VALID;
}
pd->normal.x = n3[0];
pd->normal.y = n3[1];
pd->normal.z = n3[2];
pd->flags |= (POLYDATA_NORMAL_VALID | POLYDATA_EVAL_NORMAL);
pa->pdLastEvalNormal = pd;
}