|
|
/******************************Module*Header*******************************\
* Module Name: npipe.cxx * * Normal pipes code * * Copyright (c) 1995 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 "npipe.h"
#include "state.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 GLint defCylNotch[NUM_DIRS] = { PLUS_Y, PLUS_Y, MINUS_Z, PLUS_Z, PLUS_Y, PLUS_Y };
/**************************************************************************\
* NORMAL_PIPE constructor * * \**************************************************************************/
NORMAL_PIPE::NORMAL_PIPE( STATE *pState ) : PIPE( pState ) { int choice;
type = TYPE_NORMAL; pNState = pState->pNState;
// choose weighting of going straight
if( ! ss_iRand( 20 ) ) weightStraight = ss_iRand2( MAX_WEIGHT_STRAIGHT/4, MAX_WEIGHT_STRAIGHT ); else weightStraight = 1 + ss_iRand( 4 ); }
/**************************************************************************\
* Start * * Start drawing a new normal pipe * * - Draw a start cap and short pipe in new direction * * History * July 27, 95 : [marcfo] * - Wrote it * \**************************************************************************/
void NORMAL_PIPE::Start( ) { int newDir;
// Set start position
if( !SetStartPos() ) { status = PIPE_OUT_OF_NODES; return; }
// set a material
ChooseMaterial();
// push matrix that has initial zTrans and rotation
glPushMatrix();
// Translate to current position
TranslateToCurrentPosition();
// Pick a random lastDir
lastDir = ss_iRand( NUM_DIRS );
newDir = ChooseNewDirection();
if( newDir == DIR_NONE ) { // pipe is stuck at the start node, draw something
status = PIPE_STUCK; DrawTeapot(); glPopMatrix(); return; } else status = PIPE_ACTIVE;
// set initial notch vector
notchVec = defCylNotch[newDir];
DrawStartCap( newDir );
// move ahead 1.0*r to draw pipe
glTranslatef( 0.0f, 0.0f, radius ); // draw short pipe
align_notch( newDir, notchVec ); pNState->shortPipe->Draw();
glPopMatrix();
UpdateCurrentPosition( newDir );
lastDir = newDir; }
/**************************************************************************\
* Draw * * - 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;
newDir = ChooseNewDirection();
if( newDir == DIR_NONE ) { // no empty nodes - nowhere to go
DrawEndCap(); status = PIPE_STUCK; return; }
// push matrix that has initial zTrans and rotation
glPushMatrix();
// Translate to current position
TranslateToCurrentPosition();
// draw joint if necessary, and pipe
if( newDir != lastDir ) { // turning! - we have to draw joint
DrawJoint( newDir );
// draw short pipe
align_notch( newDir, notchVec ); pNState->shortPipe->Draw(); } else { // no turn
// draw long pipe, from point 1.0*r back
align_plusz( newDir ); align_notch( newDir, notchVec ); glTranslatef( 0.0f, 0.0f, -radius ); pNState->longPipe->Draw(); }
glPopMatrix();
UpdateCurrentPosition( newDir );
lastDir = newDir; }
/**************************************************************************\
* DrawStartCap * * Cap the start of the pipe with a ball * * History * July 4, 95 : [marcfo] * - Wrote it * \**************************************************************************/
void NORMAL_PIPE::DrawStartCap( int newDir ) { if( bTexture ) { align_plusz( newDir ); pNState->ballCap->Draw(); } else { // draw big ball in default orientation
pNState->bigBall->Draw(); align_plusz( newDir ); } }
/**************************************************************************\
* DrawEndCap(): * * - Draws a ball, used to cap end of a pipe * \**************************************************************************/
void NORMAL_PIPE::DrawEndCap( ) { glPushMatrix();
// Translate to current position
TranslateToCurrentPosition();
if( bTexture ) { glPushMatrix(); align_plusz( lastDir ); align_notch( lastDir, notchVec ); pNState->ballCap->Draw(); glPopMatrix(); } else pNState->bigBall->Draw();
glPopMatrix(); }
/**************************************************************************\
* ChooseElbow * * - 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 * \**************************************************************************/
// 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 GLint 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 };
GLint 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] == notchVec ) return i; } // we shouldn't arrive here
return -1; }
/**************************************************************************\
* DrawJoint * * Draw a joint between 2 pipes * * History * Apr. 28, 95 : [marcfo] * - Wrote it * \**************************************************************************/
void NORMAL_PIPE::DrawJoint( int newDir ) { int jointType; int iBend;
jointType = pNState->ChooseJointType(); #if PIPES_DEBUG
if( newDir == oppositeDir[lastDir] ) printf( "Warning: opposite dir chosen!\n" ); #endif
switch( jointType ) { case BALL_JOINT: if( bTexture ) { // use special texture-friendly ballJoints
align_plusz( newDir ); glPushMatrix();
align_plusy( lastDir, newDir );
// translate forward 1.0*r along +z to get set for drawing elbow
glTranslatef( 0.0f, 0.0f, radius ); // decide which elbow orientation to use
iBend = ChooseElbow( lastDir, newDir ); pNState->ballJoints[iBend]->Draw();
glPopMatrix(); } else { // draw big ball in default orientation
pNState->bigBall->Draw(); align_plusz( newDir ); } // move ahead 1.0*r to draw pipe
glTranslatef( 0.0f, 0.0f, radius ); break;
case ELBOW_JOINT: align_plusz( newDir );
// the align_plusy() here will mess up our notch calcs, so
// we push-pop
glPushMatrix();
align_plusy( lastDir, newDir );
// translate forward 1.0*r along +z to get set for drawing elbow
glTranslatef( 0.0f, 0.0f, radius ); // decide which elbow orientation to use
iBend = ChooseElbow( lastDir, newDir ); if( iBend == -1 ) { #if PIPES_DEBUG
printf( "ChooseElbow() screwed up\n" ); #endif
iBend = 0; // recover
} pNState->elbows[iBend]->Draw();
glPopMatrix();
glTranslatef( 0.0f, 0.0f, radius ); break;
default: // Horrors! It's the teapot!
DrawTeapot(); align_plusz( newDir ); // move ahead 1.0*r to draw pipe
glTranslatef( 0.0f, 0.0f, radius ); } // update the current notch vector
notchVec = notchTurn[lastDir][newDir][notchVec]; #if PIPES_DEBUG
if( notchVec == iXX ) printf( "notchTurn gave bad value\n" ); #endif
}
/**************************************************************************\
* Geometry functions \**************************************************************************/
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 };
/*-----------------------------------------------------------------------
| | | align_plusy( int lastDir, int newDir ) | | - Assuming +z axis is already aligned with newDir, align | | +y axis BACK along lastDir | | | -----------------------------------------------------------------------*/
static void align_plusy( int oldDir, int newDir ) { GLfloat rotz;
rotz = RotZ[oldDir][newDir]; glRotatef( rotz, 0.0f, 0.0f, 1.0f ); }
// given a dir, determine how much to rotate cylinder around z to match notches
// format is [newDir][notchVec]
static GLfloat 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 }; /*-----------------------------------------------------------------------
| | | align_notch( int newDir ) | | - 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 | | | -----------------------------------------------------------------------*/
static void align_notch( int newDir, int notch ) { GLfloat rotz; GLint curNotch;
// figure out where notch is presently after +z alignment
curNotch = defCylNotch[newDir]; // (don't need this now we have lut)
// look up rotation value in table
rotz = alignNotchRot[newDir][notch]; #if PIPES_DEBUG
if( rotz == fXX ) { printf( "align_notch(): unexpected value\n" ); return; } #endif
if( rotz != 0.0f ) glRotatef( rotz, 0.0f, 0.0f, 1.0f ); }
|