462 lines
15 KiB
C++
462 lines
15 KiB
C++
//-----------------------------------------------------------------------------
|
|
// File: npipe.cpp
|
|
//
|
|
// Desc: Normal pipes code
|
|
//
|
|
// Copyright (c) 1994-2000 Microsoft Corporation
|
|
//-----------------------------------------------------------------------------
|
|
#include "stdafx.h"
|
|
|
|
|
|
static void align_notch( int newDir, int notch );
|
|
static void align_plusy( int oldDir, int newDir );
|
|
|
|
// defCylNotch shows where the notch for the default cylinder will be,
|
|
// in absolute coords, once we do an align_plusz
|
|
static int defCylNotch[NUM_DIRS] =
|
|
{ PLUS_Y, PLUS_Y, MINUS_Z, PLUS_Z, PLUS_Y, PLUS_Y };
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: NORMAL_PIPE constructor
|
|
// Desc:
|
|
//-----------------------------------------------------------------------------
|
|
NORMAL_PIPE::NORMAL_PIPE( STATE *pState ) : PIPE( pState )
|
|
{
|
|
m_type = TYPE_NORMAL;
|
|
m_pNState = pState->m_pNState;
|
|
|
|
// choose weighting of going straight
|
|
if( ! CPipesScreensaver::iRand( 20 ) )
|
|
m_weightStraight = CPipesScreensaver::iRand2( MAX_WEIGHT_STRAIGHT/4, MAX_WEIGHT_STRAIGHT );
|
|
else
|
|
m_weightStraight = 1 + CPipesScreensaver::iRand( 4 );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Start
|
|
// Desc: Start drawing a new normal pipe
|
|
// - Draw a start cap and short pipe in new direction
|
|
//-----------------------------------------------------------------------------
|
|
void NORMAL_PIPE::Start()
|
|
{
|
|
int newDir;
|
|
|
|
// Set start position
|
|
if( !SetStartPos() )
|
|
{
|
|
m_status = PIPE_OUT_OF_NODES;
|
|
return;
|
|
}
|
|
|
|
// set a material
|
|
ChooseMaterial();
|
|
|
|
m_pState->m_pd3dDevice->SetTexture( 0, m_pState->m_textureInfo[0].pTexture );
|
|
m_pState->m_pd3dDevice->SetMaterial( m_pMat );
|
|
|
|
// push matrix that has initial zTrans and rotation
|
|
m_pWorldMatrixStack->Push();
|
|
|
|
// Translate to current position
|
|
TranslateToCurrentPosition();
|
|
|
|
// Pick a random lastDir
|
|
m_lastDir = CPipesScreensaver::iRand( NUM_DIRS );
|
|
|
|
newDir = ChooseNewDirection();
|
|
|
|
if( newDir == DIR_NONE )
|
|
{
|
|
// pipe is stuck at the start node, draw nothing
|
|
m_status = PIPE_STUCK;
|
|
m_pWorldMatrixStack->Pop();
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
m_status = PIPE_ACTIVE;
|
|
}
|
|
|
|
// set initial notch vector
|
|
m_notchVec = defCylNotch[newDir];
|
|
|
|
DrawStartCap( newDir );
|
|
|
|
// move ahead 1.0*r to draw pipe
|
|
m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
|
|
|
|
// draw short pipe
|
|
align_notch( newDir, m_notchVec );
|
|
m_pNState->m_pShortPipe->Draw( m_pWorldMatrixStack->GetTop() );
|
|
|
|
m_pWorldMatrixStack->Pop();
|
|
|
|
UpdateCurrentPosition( newDir );
|
|
|
|
m_lastDir = newDir;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: Draw
|
|
// Desc: - if turning, draws a joint and a short cylinder, otherwise
|
|
// draws a long cylinder.
|
|
// - the 'current node' is set as the one we draw thru the NEXT
|
|
// time around.
|
|
//-----------------------------------------------------------------------------
|
|
void NORMAL_PIPE::Draw()
|
|
{
|
|
int newDir;
|
|
|
|
m_pState->m_pd3dDevice->SetTexture( 0, m_pState->m_textureInfo[0].pTexture );
|
|
m_pState->m_pd3dDevice->SetMaterial( m_pMat );
|
|
|
|
newDir = ChooseNewDirection();
|
|
|
|
if( newDir == DIR_NONE )
|
|
{
|
|
// no empty nodes - nowhere to go
|
|
DrawEndCap();
|
|
m_status = PIPE_STUCK;
|
|
return;
|
|
}
|
|
|
|
// push matrix that has initial zTrans and rotation
|
|
m_pWorldMatrixStack->Push();
|
|
|
|
// Translate to current position
|
|
TranslateToCurrentPosition();
|
|
|
|
// draw joint if necessary, and pipe
|
|
if( newDir != m_lastDir )
|
|
{
|
|
// turning! - we have to draw joint
|
|
DrawJoint( newDir );
|
|
|
|
// draw short pipe
|
|
align_notch( newDir, m_notchVec );
|
|
m_pNState->m_pShortPipe->Draw( m_pWorldMatrixStack->GetTop() );
|
|
}
|
|
else
|
|
{
|
|
// no turn -- draw long pipe, from point 1.0*r back
|
|
align_plusz( newDir );
|
|
align_notch( newDir, m_notchVec );
|
|
m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, -m_radius );
|
|
m_pNState->m_pLongPipe->Draw( m_pWorldMatrixStack->GetTop() );
|
|
}
|
|
|
|
m_pWorldMatrixStack->Pop();
|
|
|
|
UpdateCurrentPosition( newDir );
|
|
|
|
m_lastDir = newDir;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DrawStartCap
|
|
// Desc: Cap the start of the pipe with a ball
|
|
//-----------------------------------------------------------------------------
|
|
void NORMAL_PIPE::DrawStartCap( int newDir )
|
|
{
|
|
if( m_pState->m_bUseTexture )
|
|
{
|
|
align_plusz( newDir );
|
|
m_pNState->m_pBallCap->Draw( m_pWorldMatrixStack->GetTop() );
|
|
}
|
|
else
|
|
{
|
|
// draw big ball in default orientation
|
|
m_pNState->m_pBigBall->Draw( m_pWorldMatrixStack->GetTop() );
|
|
align_plusz( newDir );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DrawEndCap():
|
|
// Desc: - Draws a ball, used to cap end of a pipe
|
|
//-----------------------------------------------------------------------------
|
|
void NORMAL_PIPE::DrawEndCap()
|
|
{
|
|
m_pWorldMatrixStack->Push();
|
|
|
|
// Translate to current position
|
|
TranslateToCurrentPosition();
|
|
|
|
if( m_pState->m_bUseTexture )
|
|
{
|
|
align_plusz( m_lastDir );
|
|
align_notch( m_lastDir, m_notchVec );
|
|
m_pNState->m_pBallCap->Draw( m_pWorldMatrixStack->GetTop() );
|
|
}
|
|
else
|
|
{
|
|
m_pNState->m_pBigBall->Draw( m_pWorldMatrixStack->GetTop() );
|
|
}
|
|
|
|
m_pWorldMatrixStack->Pop();
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name:
|
|
// Desc: this array supplies the sequence of elbow notch vectors, given
|
|
// oldDir and newDir (0's are don't cares)
|
|
// it is also used to determine the ending notch of an elbow
|
|
//-----------------------------------------------------------------------------
|
|
static int notchElbDir[NUM_DIRS][NUM_DIRS][4] =
|
|
{
|
|
// oldDir = +x
|
|
iXX, iXX, iXX, iXX,
|
|
iXX, iXX, iXX, iXX,
|
|
PLUS_Y, MINUS_Z, MINUS_Y, PLUS_Z,
|
|
MINUS_Y, PLUS_Z, PLUS_Y, MINUS_Z,
|
|
PLUS_Z, PLUS_Y, MINUS_Z, MINUS_Y,
|
|
MINUS_Z, MINUS_Y, PLUS_Z, PLUS_Y,
|
|
// oldDir = -x
|
|
iXX, iXX, iXX, iXX,
|
|
iXX, iXX, iXX, iXX,
|
|
PLUS_Y, PLUS_Z, MINUS_Y, MINUS_Z,
|
|
MINUS_Y, MINUS_Z, PLUS_Y, PLUS_Z,
|
|
PLUS_Z, MINUS_Y, MINUS_Z, PLUS_Y,
|
|
MINUS_Z, PLUS_Y, PLUS_Z, MINUS_Y,
|
|
|
|
// oldDir = +y
|
|
PLUS_X, PLUS_Z, MINUS_X, MINUS_Z,
|
|
MINUS_X, MINUS_Z, PLUS_X, PLUS_Z,
|
|
iXX, iXX, iXX, iXX,
|
|
iXX, iXX, iXX, iXX,
|
|
PLUS_Z, MINUS_X, MINUS_Z, PLUS_X,
|
|
MINUS_Z, PLUS_X, PLUS_Z, MINUS_X,
|
|
// oldDir = -y
|
|
PLUS_X, MINUS_Z, MINUS_X, PLUS_Z,
|
|
MINUS_X, PLUS_Z, PLUS_X, MINUS_Z,
|
|
iXX, iXX, iXX, iXX,
|
|
iXX, iXX, iXX, iXX,
|
|
PLUS_Z, PLUS_X, MINUS_Z, MINUS_X,
|
|
MINUS_Z, MINUS_X, PLUS_Z, PLUS_X,
|
|
|
|
// oldDir = +z
|
|
PLUS_X, MINUS_Y, MINUS_X, PLUS_Y,
|
|
MINUS_X, PLUS_Y, PLUS_X, MINUS_Y,
|
|
PLUS_Y, PLUS_X, MINUS_Y, MINUS_X,
|
|
MINUS_Y, MINUS_X, PLUS_Y, PLUS_X,
|
|
iXX, iXX, iXX, iXX,
|
|
iXX, iXX, iXX, iXX,
|
|
// oldDir = -z
|
|
PLUS_X, PLUS_Y, MINUS_X, MINUS_Y,
|
|
MINUS_X, MINUS_Y, PLUS_X, PLUS_Y,
|
|
PLUS_Y, MINUS_X, MINUS_Y, PLUS_X,
|
|
MINUS_Y, PLUS_X, PLUS_Y, MINUS_X,
|
|
iXX, iXX, iXX, iXX,
|
|
iXX, iXX, iXX, iXX
|
|
};
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: ChooseElbow
|
|
// Desc: - Decides which elbow to draw
|
|
// - The beginning of each elbow is aligned along +y, and we have
|
|
// to choose the one with the notch in correct position
|
|
// - The 'primary' start notch (elbow[0]) is in same direction as
|
|
// newDir, and successive elbows rotate this notch CCW around +y
|
|
//-----------------------------------------------------------------------------
|
|
int NORMAL_PIPE::ChooseElbow( int oldDir, int newDir )
|
|
{
|
|
int i;
|
|
|
|
// precomputed table supplies correct elbow orientation
|
|
for( i=0; i<4; i++ )
|
|
{
|
|
if( notchElbDir[oldDir][newDir][i] == m_notchVec )
|
|
return i;
|
|
}
|
|
|
|
// we shouldn't arrive here
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: DrawJoint
|
|
// Desc: Draw a joint between 2 pipes
|
|
//-----------------------------------------------------------------------------
|
|
void NORMAL_PIPE::DrawJoint( int newDir )
|
|
{
|
|
int jointType;
|
|
int iBend;
|
|
|
|
jointType = m_pNState->ChooseJointType();
|
|
#if PIPES_DEBUG
|
|
if( newDir == oppositeDir[lastDir] )
|
|
OutputDebugString( "Warning: opposite dir chosen!\n" );
|
|
#endif
|
|
|
|
switch( jointType )
|
|
{
|
|
case BALL_JOINT:
|
|
{
|
|
if( m_pState->m_bUseTexture )
|
|
{
|
|
// use special texture-friendly ballJoints
|
|
align_plusz( newDir );
|
|
m_pWorldMatrixStack->Push();
|
|
|
|
align_plusy( m_lastDir, newDir );
|
|
|
|
// translate forward 1.0*r along +z to get set for drawing elbow
|
|
m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
|
|
|
|
// decide which elbow orientation to use
|
|
iBend = ChooseElbow( m_lastDir, newDir );
|
|
m_pNState->m_pBallJoints[iBend]->Draw( m_pWorldMatrixStack->GetTop() );
|
|
|
|
m_pWorldMatrixStack->Pop();
|
|
}
|
|
else
|
|
{
|
|
// draw big ball in default orientation
|
|
m_pNState->m_pBigBall->Draw( m_pWorldMatrixStack->GetTop() );
|
|
align_plusz( newDir );
|
|
}
|
|
|
|
// move ahead 1.0*r to draw pipe
|
|
m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
|
|
break;
|
|
}
|
|
|
|
case ELBOW_JOINT:
|
|
default:
|
|
{
|
|
align_plusz( newDir );
|
|
|
|
// the align_plusy() here will mess up
|
|
// our notch calcs, so we push-pop
|
|
m_pWorldMatrixStack->Push();
|
|
|
|
align_plusy( m_lastDir, newDir );
|
|
|
|
// translate forward 1.0*r along +z to get set for drawing elbow
|
|
m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
|
|
|
|
// decide which elbow orientation to use
|
|
iBend = ChooseElbow( m_lastDir, newDir );
|
|
if( iBend == -1 )
|
|
{
|
|
#if PIPES_DEBUG
|
|
OutputDebugString( "Bad result from ChooseElbow()\n" );
|
|
#endif
|
|
iBend = 0; // recover
|
|
}
|
|
m_pNState->m_pElbows[iBend]->Draw( m_pWorldMatrixStack->GetTop() );
|
|
|
|
m_pWorldMatrixStack->Pop();
|
|
|
|
m_pWorldMatrixStack->TranslateLocal( 0.0f, 0.0f, m_radius );
|
|
break;
|
|
}
|
|
}
|
|
|
|
// update the current notch vector
|
|
m_notchVec = notchTurn[m_lastDir][newDir][m_notchVec];
|
|
|
|
#if PIPES_DEBUG
|
|
if( m_notchVec == iXX )
|
|
OutputDebugString( "notchTurn gave bad value\n" );
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: align_plusy
|
|
// Desc: - Assuming +z axis is already aligned with newDir, align
|
|
// +y axis BACK along lastDir
|
|
//-----------------------------------------------------------------------------
|
|
void NORMAL_PIPE::align_plusy( int oldDir, int newDir )
|
|
{
|
|
static D3DXVECTOR3 zAxis = D3DXVECTOR3(0.0f,0.0f,1.0f);
|
|
static float RotZ[NUM_DIRS][NUM_DIRS] =
|
|
{
|
|
0.0f, 0.0f, 90.0f, 90.0f, 90.0f, -90.0f,
|
|
0.0f, 0.0f, -90.0f, -90.0f, -90.0f, 90.0f,
|
|
180.0f, 180.0f, 0.0f, 0.0f, 180.0f, 180.0f,
|
|
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
|
|
-90.0f, 90.0f, 0.0f, 180.0f, 0.0f, 0.0f,
|
|
90.0f, -90.0f, 180.0f, 0.0f, 0.0f, 0.0f
|
|
};
|
|
|
|
float rotz = RotZ[oldDir][newDir];
|
|
if( rotz != 0.0f )
|
|
m_pWorldMatrixStack->RotateAxisLocal( &zAxis, SS_DEG_TO_RAD(rotz) );
|
|
}
|
|
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Name: align_notch
|
|
// Desc: - a cylinder is notched, and we have to line this up
|
|
// with the previous primitive's notch which is maintained as
|
|
// notchVec.
|
|
// - this adds a rotation around z to achieve this
|
|
//-----------------------------------------------------------------------------
|
|
void NORMAL_PIPE::align_notch( int newDir, int notch )
|
|
{
|
|
float rotz;
|
|
int curNotch;
|
|
|
|
// figure out where notch is presently after +z alignment
|
|
curNotch = defCylNotch[newDir];
|
|
// (don't need this now we have lut)
|
|
|
|
// given a dir, determine how much to rotate cylinder around z to match notches
|
|
// format is [newDir][notchVec]
|
|
static float alignNotchRot[NUM_DIRS][NUM_DIRS] =
|
|
{
|
|
fXX, fXX, 0.0f, 180.0f, 90.0f, -90.0f,
|
|
fXX, fXX, 0.0f, 180.0f, -90.0f, 90.0f,
|
|
-90.0f, 90.0f, fXX, fXX, 180.0f, 0.0f,
|
|
-90.0f, 90.0f, fXX, fXX, 0.0f, 180.0f,
|
|
-90.0f, 90.0f, 0.0f, 180.0f, fXX, fXX,
|
|
90.0f, -90.0f, 0.0f, 180.0f, fXX, fXX
|
|
};
|
|
|
|
// look up rotation value in table
|
|
rotz = alignNotchRot[newDir][notch];
|
|
|
|
#if PIPES_DEBUG
|
|
if( rotz == fXX )
|
|
{
|
|
printf( "align_notch(): unexpected value\n" );
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
static D3DXVECTOR3 zAxis = D3DXVECTOR3(0.0f,0.0f,1.0f);
|
|
if( rotz != 0.0f )
|
|
m_pWorldMatrixStack->RotateAxisLocal( &zAxis, SS_DEG_TO_RAD(rotz) );
|
|
}
|
|
|