/******************************Module*Header*******************************\ * Module Name: npipe.cxx * * Normal pipes code * * Copyright (c) 1995 Microsoft Corporation * \**************************************************************************/ #include #include #include #include #include #include #include #include #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 ); }