PIPE.CXX

/******************************Module*Header*******************************\ 
* Module Name: pipe.cxx
*
* - Pipe base class stuff
*
* Copyright 1995 - 1998 Microsoft Corporation
*
\**************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <time.h>
#include <windows.h>

#include "sspipes.h"
#include "state.h"
#include "pipe.h"

/******************************Public*Routine******************************\
* PIPE constructor
\**************************************************************************/

PIPE::PIPE( STATE *state )
{
pState = state;
bTexture = pState->bTexture;
radius = pState->radius;
// default direction choosing is random
chooseDirMethod = CHOOSE_DIR_RANDOM_WEIGHTED;
chooseStartPosMethod = CHOOSE_STARTPOS_RANDOM;
weightStraight = 1;
}

/******************************Public*Routine******************************\
* ChooseMaterial
*
\**************************************************************************/

void
PIPE::ChooseMaterial( )
{
if( bTexture )
ss_RandomTexMaterial( TRUE );
else
ss_RandomTeaMaterial( TRUE );
}

/**************************************************************************\
*
* DrawTeapot
*
\**************************************************************************/

extern void ResetEvaluator( BOOL bTexture );

void
PIPE::DrawTeapot( )
{
glFrontFace( GL_CW );
glEnable( GL_NORMALIZE );
auxSolidTeapot(2.5 * radius);
glDisable( GL_NORMALIZE );
glFrontFace( GL_CCW );
if( type != TYPE_NORMAL ) {
// Re-init flex's evaluator state (teapot uses evaluators as well,
// and messes up the state).
ResetEvaluator( bTexture );
}
}

/******************************Public*Routine******************************\
* SetChooseDirectionMethod
\**************************************************************************/

void
PIPE::SetChooseDirectionMethod( int method )
{
chooseDirMethod = method;
}


/**************************************************************************\
*
* ChooseNewDirection
*
* Call direction-finding function based on current method
* This is a generic entry point that is used by some pipe types
*
\**************************************************************************/

int
PIPE::ChooseNewDirection()
{
NODE_ARRAY *nodes = pState->nodes;
int bestDirs[NUM_DIRS], nBestDirs;

// figger out which fn to call
switch( chooseDirMethod ) {
case CHOOSE_DIR_CHASE:
if( nBestDirs = GetBestDirsForChase( bestDirs ) )
return nodes->ChoosePreferredDirection( &curPos, lastDir,
bestDirs, nBestDirs );
// else lead pipe must have died, so fall thru:
case CHOOSE_DIR_RANDOM_WEIGHTED :
default:
return nodes->ChooseRandomDirection( &curPos, lastDir, weightStraight );
}
}

/**************************************************************************\
*
* GetBestDirsForChase
*
* Find the best directions to take to close in on the lead pipe in chase mode.
*
\**************************************************************************/

int
PIPE::GetBestDirsForChase( int *bestDirs )
{
// Figure out best dirs to close in on leadPos

//mf: will have to 'protect' leadPos with GetLeadPos() for multi-threading
IPOINT3D *leadPos = &pState->pLeadPipe->curPos;
IPOINT3D delta;
int numDirs = 0;

delta.x = leadPos->x - curPos.x;
delta.y = leadPos->y - curPos.y;
delta.z = leadPos->z - curPos.z;

if( delta.x ) {
numDirs++;
*bestDirs++ = delta.x > 0 ? PLUS_X : MINUS_X;
}
if( delta.y ) {
numDirs++;
*bestDirs++ = delta.y > 0 ? PLUS_Y : MINUS_Y;
}
if( delta.z ) {
numDirs++;
*bestDirs++ = delta.z > 0 ? PLUS_Z : MINUS_Z;
}
// It should be impossible for numDirs = 0 (all deltas = 0), as this
// means curPos = leadPos
return numDirs;
}

/******************************Public*Routine******************************\
* SetChooseStartPosMethod
\**************************************************************************/

void
PIPE::SetChooseStartPosMethod( int method )
{
chooseStartPosMethod = method;
}

/******************************Public*Routine******************************\
* PIPE::SetStartPos
*
* - Find an empty node to start the pipe on
*
\**************************************************************************/

BOOL
PIPE::SetStartPos()
{
NODE_ARRAY *nodes = pState->nodes;

switch( chooseStartPosMethod ) {

case CHOOSE_STARTPOS_RANDOM:
default:
if( !nodes->FindRandomEmptyNode( &curPos ) ) {
return FALSE;
}
return TRUE;

case CHOOSE_STARTPOS_FURTHEST:
// find node furthest away from curPos
IPOINT3D refPos, numNodes;
nodes->GetNodeCount( &numNodes );
refPos.x = (curPos.x >= (numNodes.x / 2)) ? 0 : numNodes.x - 1;
refPos.y = (curPos.y >= (numNodes.y / 2)) ? 0 : numNodes.y - 1;
refPos.z = (curPos.z >= (numNodes.z / 2)) ? 0 : numNodes.z - 1;

if( !nodes->TakeClosestEmptyNode( &curPos, &refPos ) ) {
return FALSE;
}
return TRUE;
}
}

/******************************Public*Routine******************************\
* PIPE::IsStuck
\**************************************************************************/

BOOL
PIPE::IsStuck()
{
return status == PIPE_STUCK;
}

/******************************Public*Routine******************************\
* PIPE::TranslateToCurrentPosition
*
\**************************************************************************/

void
PIPE::TranslateToCurrentPosition()
{
IPOINT3D numNodes;

float divSize = pState->view.divSize;
// this requires knowing the size of the node array
pState->nodes->GetNodeCount( &numNodes );
glTranslatef( (curPos.x - (numNodes.x - 1)/2.0f )*divSize,
(curPos.y - (numNodes.y - 1)/2.0f )*divSize,
(curPos.z - (numNodes.z - 1)/2.0f )*divSize );
}

/**************************************************************************\
*
* UpdateCurrentPosition
*
* Increment current position according to direction taken
\**************************************************************************/

void
PIPE::UpdateCurrentPosition( int newDir )
{
switch( newDir ) {
case PLUS_X:
curPos.x += 1;
break;
case MINUS_X:
curPos.x -= 1;
break;
case PLUS_Y:
curPos.y += 1;
break;
case MINUS_Y:
curPos.y -= 1;
break;
case PLUS_Z:
curPos.z += 1;
break;
case MINUS_Z:
curPos.z -= 1;
break;
}
}

/******************************Public*Routine******************************\
* align_plusz
*
* - Aligns the z axis along specified direction
* - Used for all types of pipes
*
\**************************************************************************/


void align_plusz( int newDir )
{
// align +z along new direction
switch( newDir ) {
case PLUS_X:
glRotatef( 90.0f, 0.0f, 1.0f, 0.0f);
break;
case MINUS_X:
glRotatef( -90.0f, 0.0f, 1.0f, 0.0f);
break;
case PLUS_Y:
glRotatef( -90.0f, 1.0f, 0.0f, 0.0f);
break;
case MINUS_Y:
glRotatef( 90.0f, 1.0f, 0.0f, 0.0f);
break;
case PLUS_Z:
glRotatef( 0.0f, 0.0f, 1.0f, 0.0f);
break;
case MINUS_Z:
glRotatef( 180.0f, 0.0f, 1.0f, 0.0f);
break;
}

}

/**************************************************************************\
* this array tells you which way the notch will be once you make
* a turn
* format: notchTurn[oldDir][newDir][notchVec]
*
\**************************************************************************/

GLint notchTurn[NUM_DIRS][NUM_DIRS][NUM_DIRS] = {
// oldDir = +x
iXX, iXX, iXX, iXX, iXX, iXX,
iXX, iXX, iXX, iXX, iXX, iXX,
iXX, iXX, MINUS_X,PLUS_X, PLUS_Z, MINUS_Z,
iXX, iXX, PLUS_X, MINUS_X,PLUS_Z, MINUS_Z,
iXX, iXX, PLUS_Y, MINUS_Y,MINUS_X,PLUS_X,
iXX, iXX, PLUS_Y, MINUS_Y,PLUS_X, MINUS_X,
// oldDir = -x
iXX, iXX, iXX, iXX, iXX, iXX,
iXX, iXX, iXX, iXX, iXX, iXX,
iXX, iXX, PLUS_X, MINUS_X,PLUS_Z, MINUS_Z,
iXX, iXX, MINUS_X,PLUS_X, PLUS_Z, MINUS_Z,
iXX, iXX, PLUS_Y, MINUS_Y,PLUS_X, MINUS_X,
iXX, iXX, PLUS_Y, MINUS_Y,MINUS_X,PLUS_X,
// oldDir = +y
MINUS_Y,PLUS_Y, iXX, iXX, PLUS_Z, MINUS_Z,
PLUS_Y, MINUS_Y,iXX, iXX, PLUS_Z, MINUS_Z,
iXX, iXX, iXX, iXX, iXX, iXX,
iXX, iXX, iXX, iXX, iXX, iXX,
PLUS_X, MINUS_X,iXX, iXX, MINUS_Y,PLUS_Y,
PLUS_X, MINUS_X,iXX, iXX, PLUS_Y, MINUS_Y,
// oldDir = -y
PLUS_Y, MINUS_Y,iXX, iXX, PLUS_Z, MINUS_Z,
MINUS_Y,PLUS_Y, iXX, iXX, PLUS_Z, MINUS_Z,
iXX, iXX, iXX, iXX, iXX, iXX,
iXX, iXX, iXX, iXX, iXX, iXX,
PLUS_X, MINUS_X,iXX, iXX, PLUS_Y, MINUS_Y,
PLUS_X, MINUS_X,iXX, iXX, MINUS_Y,PLUS_Y,
// oldDir = +z
MINUS_Z,PLUS_Z, PLUS_Y, MINUS_Y,iXX, iXX,
PLUS_Z, MINUS_Z,PLUS_Y, MINUS_Y,iXX, iXX,
PLUS_X, MINUS_X,MINUS_Z,PLUS_Z, iXX, iXX,
PLUS_X, MINUS_X,PLUS_Z, MINUS_Z,iXX, iXX,
iXX, iXX, iXX, iXX, iXX, iXX,
iXX, iXX, iXX, iXX, iXX, iXX,
// oldDir = -z
PLUS_Z, MINUS_Z,PLUS_Y, MINUS_Y,iXX, iXX,
MINUS_Z,PLUS_Z, PLUS_Y, MINUS_Y,iXX, iXX,
PLUS_X, MINUS_X,PLUS_Z, MINUS_Z,iXX, iXX,
PLUS_X, MINUS_X,MINUS_Z,PLUS_Z, iXX, iXX,
iXX, iXX, iXX, iXX, iXX, iXX,
iXX, iXX, iXX, iXX, iXX, iXX
};