565 lines
15 KiB
C++
565 lines
15 KiB
C++
/******************************Module*Header*******************************\
|
|
* Module Name: eval.cxx
|
|
*
|
|
* Evaluator stuff
|
|
*
|
|
* Copyright (c) 1994 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <sys/types.h>
|
|
#include <time.h>
|
|
#include <windows.h>
|
|
#include <GL/gl.h>
|
|
#include <GL/glu.h>
|
|
#include <GL/glaux.h>
|
|
|
|
#include "sscommon.h"
|
|
#include "sspipes.h"
|
|
#include "eval.h"
|
|
|
|
//#define EVAL_DBG 1
|
|
|
|
typedef enum {
|
|
X_PLANE = 0,
|
|
Y_PLANE,
|
|
Z_PLANE
|
|
};
|
|
|
|
#define EVAL_VSIZE 3 // vertex size in floats
|
|
|
|
#define TMAJOR_ORDER 2
|
|
#define TMINOR_ORDER 2
|
|
|
|
#define VDIM 3
|
|
#define TDIM 2
|
|
|
|
//forwards
|
|
#if EVAL_DBG
|
|
static void DrawPoints( int num, POINT3D *pts );
|
|
#endif
|
|
static void RotatePointSet( POINT3D *inPts, int numPts, float angle, int dir,
|
|
float radius, POINT3D *outPts );
|
|
static void ExtrudePointSetDir( POINT3D *inPts, int numPts, float *acPts,
|
|
int dir, POINT3D *outPts );
|
|
|
|
|
|
/**************************************************************************\
|
|
* EVAL
|
|
*
|
|
* Evaluator constructor
|
|
*
|
|
\**************************************************************************/
|
|
|
|
EVAL::EVAL( BOOL bTex )
|
|
{
|
|
bTexture = bTex;
|
|
|
|
// Allocate points buffer
|
|
|
|
//mf: might want to use less than max in some cases
|
|
int size = MAX_USECTIONS * MAX_UORDER * MAX_VORDER * sizeof(POINT3D);
|
|
pts = (POINT3D *) LocalAlloc( LMEM_FIXED, size );
|
|
SS_ASSERT( pts != NULL, "EVAL constructor\n" );
|
|
|
|
// Alloc texture points buffer
|
|
|
|
if( bTexture ) {
|
|
size = MAX_USECTIONS * TEX_ORDER * TEX_ORDER * sizeof(TEX_POINT2D);
|
|
texPts = (TEX_POINT2D *) LocalAlloc( LMEM_FIXED, size );
|
|
SS_ASSERT( texPts != NULL, "EVAL constructor\n" );
|
|
}
|
|
|
|
ResetEvaluator( bTexture );
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* ~EVAL
|
|
*
|
|
* Evaluator destructor
|
|
*
|
|
* Frees up memory
|
|
*
|
|
\**************************************************************************/
|
|
|
|
EVAL::~EVAL( )
|
|
{
|
|
LocalFree( pts );
|
|
if( bTexture )
|
|
LocalFree( texPts );
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* Reset
|
|
*
|
|
* Reset evaluator to generate 3d vertices and vertex normals
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
ResetEvaluator( BOOL bTexture )
|
|
{
|
|
if( bTexture ) {
|
|
glEnable( GL_MAP2_TEXTURE_COORD_2 );
|
|
}
|
|
glEnable( GL_MAP2_VERTEX_3 );
|
|
glEnable( GL_AUTO_NORMAL );
|
|
glFrontFace( GL_CW ); // cuz
|
|
//mf: !!! if mixing Normal and Flex, have to watch out for this, cuz normal
|
|
// needs CCW
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* SetTextureControlPoints
|
|
*
|
|
* Set texture control point net
|
|
*
|
|
* This sets up 'numSections' sets of texture coordinate control points, based
|
|
* on starting and ending s and t values.
|
|
*
|
|
* s coords run along pipe direction, t coords run around circumference
|
|
*
|
|
* History
|
|
* July 17, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
EVAL::SetTextureControlPoints( float s_start, float s_end,
|
|
float t_start, float t_end )
|
|
{
|
|
int i;
|
|
TEX_POINT2D *ptexPts = texPts;
|
|
GLfloat t_delta = (t_end - t_start) / numSections;
|
|
GLfloat t = t_start;
|
|
|
|
// calc ctrl pts for each quadrant
|
|
for( i = 0; i < numSections; i++, ptexPts += (TDIM*TDIM) ) {
|
|
// s, t coords
|
|
ptexPts[0].t = ptexPts[2].t = t;
|
|
t += t_delta;
|
|
ptexPts[1].t = ptexPts[3].t = t;
|
|
ptexPts[0].s = ptexPts[1].s = s_start;
|
|
ptexPts[2].s = ptexPts[3].s = s_end;
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* SetVertexCtrlPtsXCTranslate
|
|
*
|
|
* Builds 3D control eval control net from 2 xcObjs displaced along the
|
|
* z-axis by 'length'.
|
|
*
|
|
* First xc used to generate points in z=0 plane.
|
|
* Second xc generates points in z=length plane.
|
|
* ! Replicates the last point around each u.
|
|
*
|
|
* July 27, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
EVAL::SetVertexCtrlPtsXCTranslate( POINT3D *pts, float length,
|
|
XC *xcStart, XC *xcEnd )
|
|
{
|
|
int i;
|
|
POINT2D *ptsStart, *ptsEnd;
|
|
POINT3D *pts1, *pts2;
|
|
int numPts = xcStart->numPts;
|
|
|
|
numPts++; // due to last point replication
|
|
|
|
ptsStart = xcStart->pts;
|
|
ptsEnd = xcEnd->pts;
|
|
pts1 = pts;
|
|
pts2 = pts + numPts;
|
|
|
|
for( i = 0; i < (numPts-1); i++, pts1++, pts2++ ) {
|
|
// copy over x,y from each xc
|
|
*( (POINT2D *) pts1) = *ptsStart++;
|
|
*( (POINT2D *) pts2) = *ptsEnd++;
|
|
// set z for each
|
|
pts1->z = 0.0f;
|
|
pts2->z = length;
|
|
}
|
|
|
|
// Replicate last point in each u-band
|
|
*pts1 = *pts;
|
|
*pts2 = *(pts + numPts);
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* ProcessXCPrimLinear
|
|
*
|
|
* Processes a prim according to evaluator data
|
|
*
|
|
* - Only valid for colinear xc's (along z)
|
|
* - XC's may be identical (extrusion). If not identical, may have
|
|
* discontinuities at each end.
|
|
* - Converts 2D XC pts to 3D pts
|
|
*
|
|
* July 27, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
EVAL::ProcessXCPrimLinear( XC *xcStart, XC *xcEnd, float length )
|
|
{
|
|
if( length <= 0.0f )
|
|
// nuttin' to do
|
|
return;
|
|
|
|
// Build a vertex control net from 2 xcObj's a distance 'length' apart
|
|
// this will displace the end xcObj a distance 'length' down the z-axis
|
|
SetVertexCtrlPtsXCTranslate( pts, length, xcStart, xcEnd );
|
|
|
|
Evaluate( );
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* ProcessXCPrimBendSimple
|
|
*
|
|
* Processes a prim by bending along dir from xcCur
|
|
*
|
|
* - dir is relative from xc in x-y plane
|
|
* - adds C2 continuity at ends
|
|
*
|
|
* July 27, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
EVAL::ProcessXCPrimBendSimple( XC *xcCur, int dir, float radius )
|
|
{
|
|
POINT3D *ptsSrc, *ptsDst;
|
|
static float acPts[MAX_XC_PTS+1];
|
|
int ptSetStride = xcCur->numPts + 1; // pt stride for output pts buffer
|
|
|
|
// We will be creating 4 cross-sectional control point sets here.
|
|
|
|
// Convert 2D pts in xcCur to 3D pts at z=0 for 1st point set
|
|
xcCur->ConvertPtsZ( pts, 0.0f );
|
|
|
|
// Calc 4th point set by rotating 1st set as per dir
|
|
ptsDst = pts + 3*ptSetStride;
|
|
RotatePointSet( pts, ptSetStride, 90.0f, dir, radius, ptsDst );
|
|
|
|
// angles != 90, hard, cuz not easy to extrude 3rd set from 4th
|
|
|
|
// Next, have to figure out ac values. Need to extend each xc's points
|
|
// into bend to generate ac net. For circular bend (and later for general
|
|
// case elliptical bend), need to know ac distance from xc for each point.
|
|
// This is based on the point's turn radius - a function of its distance
|
|
// from the 'hinge' of the turn.
|
|
|
|
// Can take advantage of symmetry here. Figure for one xc, good for 2nd.
|
|
// This assumes 90 deg turn. (also,last point replicated)
|
|
xcCur->CalcArcACValues90( dir, radius, acPts );
|
|
|
|
// 2) extrude each point's ac from xcCur (extrusion in +z)
|
|
// apply values to 1st to get 2nd
|
|
// MINUS_Z, cuz subtracts *back* from dir
|
|
ExtrudePointSetDir( pts, ptSetStride, acPts, MINUS_Z,
|
|
pts + ptSetStride );
|
|
|
|
// 3) extrude each point's ac from xcEnd (extrusion in -dir)
|
|
ptsSrc = pts + 3*ptSetStride;
|
|
ptsDst = pts + 2*ptSetStride;
|
|
ExtrudePointSetDir( ptsSrc, ptSetStride, acPts, dir, ptsDst );
|
|
|
|
Evaluate();
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* eval_ProcessXCPrimSingularity
|
|
*
|
|
* Processes a prim by joining singularity to an xc
|
|
*
|
|
* - Used for closing or opening the pipe
|
|
* - If bOpening is true, starts with singularity, otherwise ends with one
|
|
* - the xc side is always in z=0 plane
|
|
* - singularity side is radius on either side of xc
|
|
* - adds C2 continuity at ends (perpendicular to +z at singularity end)
|
|
*
|
|
* July 29, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
EVAL::ProcessXCPrimSingularity( XC *xcCur, float length, BOOL bOpening )
|
|
{
|
|
POINT3D *ptsSing, *ptsXC;
|
|
static float acPts[MAX_XC_PTS+1];
|
|
float zSing; // z-value at singularity
|
|
int ptSetStride = xcCur->numPts + 1; // pt stride for output pts buffer
|
|
int i;
|
|
XC xcSing(xcCur);
|
|
|
|
// create singularity xc - which is an extremely scaled-down version
|
|
// of xcCur (this prevents any end-artifacts, unless of course we were
|
|
// to zoom it ultra-large).
|
|
|
|
xcSing.Scale( .0005f );
|
|
|
|
// We will be creating 4 cross-sectional control point sets here.
|
|
// mf: 4 is like hard coded; what about for different xc component levels ?
|
|
|
|
if( bOpening ) {
|
|
ptsSing = pts;
|
|
ptsXC = pts + 3*ptSetStride;
|
|
} else {
|
|
ptsSing = pts + 3*ptSetStride;
|
|
ptsXC = pts;
|
|
}
|
|
|
|
// Convert 2D pts in xcCur to 3D pts at 'xc' point set
|
|
xcCur->ConvertPtsZ( ptsXC, 0.0f );
|
|
|
|
// Set z-value for singularity point set
|
|
zSing = bOpening ? -length : length;
|
|
xcSing.ConvertPtsZ( ptsSing, zSing );
|
|
|
|
// The arc control for each point is based on a radius value that is
|
|
// each xc point's distance from the xc center
|
|
xcCur->CalcArcACValuesByDistance( acPts );
|
|
|
|
// Calculate point set near xc
|
|
if( bOpening )
|
|
ExtrudePointSetDir( ptsXC, ptSetStride, acPts, PLUS_Z,
|
|
ptsXC - ptSetStride );
|
|
else
|
|
ExtrudePointSetDir( ptsXC, ptSetStride, acPts, MINUS_Z,
|
|
ptsXC + ptSetStride );
|
|
|
|
// Point set near singularity is harder, as the points must generate
|
|
// a curve between the singularity and each xc point
|
|
// No, easier, just scale each point by universal arc controller !
|
|
POINT3D *ptsDst = pts;
|
|
ptsDst = bOpening ? ptsSing + ptSetStride : ptsSing - ptSetStride;
|
|
for( i = 0; i < ptSetStride; i ++, ptsDst++ ) {
|
|
ptsDst->x = EVAL_CIRC_ARC_CONTROL * ptsXC[i].x;
|
|
ptsDst->y = EVAL_CIRC_ARC_CONTROL * ptsXC[i].y;
|
|
ptsDst->z = zSing;
|
|
}
|
|
|
|
Evaluate();
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* Evaluate
|
|
*
|
|
* Evaluates the EVAL object
|
|
*
|
|
* - There may be 1 or more lengthwise sections around an xc
|
|
* - u is minor, v major
|
|
* - u,t run around circumference, v,s lengthwise
|
|
* - Texture maps are 2x2 for each section
|
|
* - ! uDiv is per section !
|
|
*
|
|
* History
|
|
* July 21, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
\**************************************************************************/
|
|
|
|
void
|
|
EVAL::Evaluate( )
|
|
{
|
|
int i;
|
|
POINT3D *ppts = pts;
|
|
TEX_POINT2D *ptexPts = texPts;
|
|
// total # pts in cross-section:
|
|
int xcPointCount = (uOrder-1)*numSections + 1;
|
|
|
|
for( i = 0; i < numSections; i ++,
|
|
ppts += (uOrder-1),
|
|
ptexPts += (TEX_ORDER*TEX_ORDER) ) {
|
|
|
|
// map texture coords
|
|
|
|
if( bTexture ) {
|
|
glMap2f(GL_MAP2_TEXTURE_COORD_2,
|
|
0.0f, 1.0f, TDIM, TEX_ORDER,
|
|
0.0f, 1.0f, TEX_ORDER*TDIM, TEX_ORDER,
|
|
(GLfloat *) ptexPts );
|
|
}
|
|
|
|
// map vertices
|
|
|
|
glMap2f(GL_MAP2_VERTEX_3,
|
|
0.0f, 1.0f, VDIM, uOrder,
|
|
0.0f, 1.0f, xcPointCount*VDIM, vOrder,
|
|
(GLfloat *) ppts );
|
|
|
|
// evaluate
|
|
|
|
glMapGrid2f(uDiv, 0.0f, 1.0f, vDiv, 0.0f, 1.0f);
|
|
glEvalMesh2( GL_FILL, 0, uDiv, 0, vDiv);
|
|
}
|
|
}
|
|
|
|
#if EVAL_DBG
|
|
/**************************************************************************\
|
|
* DrawPoints
|
|
*
|
|
* draw control points
|
|
*
|
|
\**************************************************************************/
|
|
static
|
|
void DrawPoints( int num, POINT3D *pts )
|
|
{
|
|
GLint i;
|
|
|
|
// draw green pts for now
|
|
glColor3f(0.0f, 1.0f, 0.0f);
|
|
glPointSize(2);
|
|
|
|
glBegin(GL_POINTS);
|
|
for (i = 0; i < num; i++, pts++) {
|
|
glVertex3fv( (GLfloat *) pts );
|
|
}
|
|
glEnd();
|
|
}
|
|
#endif
|
|
|
|
/**************************************************************************\
|
|
* ExtrudePointSetDir
|
|
*
|
|
* Extrude a point set back from the current direction
|
|
*
|
|
* Generates C2 continuity at the supplied point set xc, by generating another
|
|
* point set back of the first, using supplied subtraction values.
|
|
*
|
|
* July 28, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
\**************************************************************************/
|
|
|
|
static void
|
|
ExtrudePointSetDir( POINT3D *inPts, int numPts, float *acPts, int dir,
|
|
POINT3D *outPts )
|
|
{
|
|
int i;
|
|
float sign;
|
|
int offset;
|
|
|
|
switch( dir ) {
|
|
case PLUS_X:
|
|
offset = 0;
|
|
sign = -1.0f;
|
|
break;
|
|
case MINUS_X:
|
|
offset = 0;
|
|
sign = 1.0f;
|
|
break;
|
|
case PLUS_Y:
|
|
offset = 1;
|
|
sign = -1.0f;
|
|
break;
|
|
case MINUS_Y:
|
|
offset = 1;
|
|
sign = 1.0f;
|
|
break;
|
|
case PLUS_Z:
|
|
offset = 2;
|
|
sign = -1.0f;
|
|
break;
|
|
case MINUS_Z:
|
|
offset = 2;
|
|
sign = 1.0f;
|
|
break;
|
|
}
|
|
|
|
for( i = 0; i < numPts; i++, inPts++, outPts++, acPts++ ) {
|
|
*outPts = *inPts;
|
|
((float *)outPts)[offset] = ((float *)inPts)[offset] + (sign * (*acPts));
|
|
}
|
|
}
|
|
|
|
/**************************************************************************\
|
|
* RotatePointSet
|
|
*
|
|
* Rotate point set by angle, according to dir and radius
|
|
*
|
|
* - Put points in supplied outPts buffer
|
|
*
|
|
* July 28, 95 : [marcfo]
|
|
* - Wrote it
|
|
*
|
|
\**************************************************************************/
|
|
|
|
static void
|
|
RotatePointSet( POINT3D *inPts, int numPts, float angle, int dir,
|
|
float radius, POINT3D *outPts )
|
|
{
|
|
MATRIX matrix1, matrix2, matrix3;
|
|
int i;
|
|
POINT3D rot = {0.0f};
|
|
POINT3D anchor = {0.0f};
|
|
|
|
/* dir rot
|
|
+x 90 y
|
|
-x -90 y
|
|
+y -90 x
|
|
-y 90 x
|
|
*/
|
|
|
|
// convert angle to radians
|
|
//mf: as noted in objects.c, we have to take negative angle to make
|
|
// it work in familiar 'CCW rotation is positive' mode. The ss_* rotate
|
|
// routines must work in the 'CW is +'ve' mode, as axis pointing at you.
|
|
angle = SS_DEG_TO_RAD(-angle);
|
|
|
|
// set axis rotation and anchor point
|
|
|
|
switch( dir ) {
|
|
case PLUS_X:
|
|
rot.y = angle;
|
|
anchor.x = radius;
|
|
break;
|
|
case MINUS_X:
|
|
rot.y = -angle;
|
|
anchor.x = -radius;
|
|
break;
|
|
case PLUS_Y:
|
|
rot.x = -angle;
|
|
anchor.y = radius;
|
|
break;
|
|
case MINUS_Y:
|
|
rot.x = angle;
|
|
anchor.y = -radius;
|
|
break;
|
|
}
|
|
|
|
// translate anchor point to origin
|
|
ss_matrixIdent( &matrix1 );
|
|
ss_matrixTranslate( &matrix1, -anchor.x, -anchor.y, -anchor.z );
|
|
|
|
// rotate
|
|
ss_matrixIdent( &matrix2 );
|
|
ss_matrixRotate( &matrix2, (double) rot.x, rot.y, rot.z );
|
|
|
|
// concat these 2
|
|
ss_matrixMult( &matrix3, &matrix2, &matrix1 );
|
|
|
|
// translate back
|
|
ss_matrixIdent( &matrix2 );
|
|
ss_matrixTranslate( &matrix2, anchor.x, anchor.y, anchor.z );
|
|
|
|
// concat these 2
|
|
ss_matrixMult( &matrix1, &matrix2, &matrix3 );
|
|
|
|
for( i = 0; i < numPts; i ++, outPts++, inPts++ ) {
|
|
ss_xformPoint( outPts, inPts, &matrix1 );
|
|
}
|
|
}
|