예제 #1
0
//////////////////////////////////////////////////////////////////////////
// flipTransform
void MdlNode::flipTransform( BcMat4d& Transform )
{
	Transform.transpose();
	Transform[0][2] = -Transform[0][2];
	Transform[1][2] = -Transform[1][2];
	Transform[2][0] = -Transform[2][0];
	Transform[2][1] = -Transform[2][1];
	Transform[2][3] = -Transform[2][3];
	Transform.transpose();
}
예제 #2
0
//////////////////////////////////////////////////////////////////////////
// bakeTransform
void MdlMesh::bakeTransform( const BcMat4d& Transform )
{
	BcMat4d NrmTransform = Transform;
	NrmTransform.translation( BcVec3d( 0.0f, 0.0f, 0.0f ) );
	for( BcU32 i = 0; i < aVertices_.size(); ++i )
	{
		aVertices_[ i ].Position_ = aVertices_[ i ].Position_ * Transform;
		aVertices_[ i ].Normal_ = aVertices_[ i ].Normal_ * NrmTransform;
		aVertices_[ i ].Normal_.normalise();
		aVertices_[ i ].Tangent_ = aVertices_[ i ].Tangent_ * NrmTransform;
		aVertices_[ i ].Tangent_.normalise();
	}
}
예제 #3
0
////////////////////////////////////////////////////////////////////////////////
// render
//virtual
void GaMainGameState::render()
{
	// NEILO HACK: REMOVE.
	OsClient* pClient = OsCore::pImpl()->getClient( 0 );
	RsViewport Viewport( 0, 0, pClient->getWidth(), pClient->getHeight() );
	
	// Render background.
	Projection_.perspProjectionHorizontal( BcPIDIV4, (BcReal)pClient->getWidth() / (BcReal)pClient->getHeight(), 1.0f, 1024.0f );
	WorldView_.lookAt( BcVec3d( 0.0f, 350.0f, 270.0f ), BcVec3d( 0.0f, 0.0f, 0.0f ), BcVec3d( 0.0f, 0.0f, 1.0f ) );

	if( SsCore::pImpl() != NULL )
	{
		SsCore::pImpl()->setListener( BcVec3d( 0.0f, 350.0f, 270.0f ), BcVec3d( 0.0f, -4.0f, -2.0f ).normal(), BcVec3d( 0.0f, 0.0f, 1.0f  ) );
	}

	setMaterialComponentParams( BackgroundMaterialComponent_, BcMat4d() );
	Canvas_->setMaterialComponent( BackgroundMaterialComponent_ );
	Canvas_->drawSpriteCentered3D( BcVec3d( 0.0f, 0.0f, 0.0f ), WorldHalfSize_ * 4.0f, 0, RsColour::WHITE, 0 );

	// Render entities.
	for( BcU32 Idx = 0; Idx < Entities_.size(); ++Idx )
	{
		GaGameComponent* pEntity = Entities_[ Idx ];
		pEntity->render( Canvas_ );
	}

	// Draw foreground.
	BcMat4d Ortho;
	Ortho.orthoProjection( -WorldHalfSize_.x(), WorldHalfSize_.x(), -WorldHalfSize_.y(), WorldHalfSize_.y(), -1.0f, 0.0f );

	Canvas_->pushMatrix( Ortho );
	Canvas_->setMaterialComponent( ForegroundMaterialComponent_ );
	Canvas_->drawSpriteCentered( BcVec2d( 0.0f, 0.0f ), BcVec2d( WorldHalfSize_.x() * 2.2f, WorldHalfSize_.y() * -2.0f ), 0, RsColour::WHITE, 20 );

	BcReal Width = BcMax( 0.0f, FoodHealth_ - 0.5f ) * 2.0f;

	RsColour Colour;
	Colour.lerp( RsColour::RED, RsColour::GREEN, Width );

	Canvas_->setMaterialComponent( BarMaterialComponent_ );
	Canvas_->drawSpriteCentered( 
		BcVec2d( 0.0f, WorldHalfSize_.y() - ( WorldHalfSize_.y() * 0.05f ) ), 
		BcVec2d( WorldHalfSize_.x() * 1.5f * Width, WorldHalfSize_.y() * 0.05f ), 
		0, Colour, 20 );

	Canvas_->popMatrix();

	// Base render.
	GaBaseGameState::render();
}
예제 #4
0
//////////////////////////////////////////////////////////////////////////
// makeAbsoluteTransform
void MdlNode::makeAbsoluteTransform( const BcMat4d& ParentAbsolute )
{
	// Parent another node to this tree.
	MdlNode* pNextNode = pChild_;

	//
	BcMat4d InverseParent = ParentAbsolute;
	InverseParent.inverse();

	AbsoluteTransform_ = ParentAbsolute * RelativeTransform_;

	// For all the nodes parented to the same as us.
	while( pNextNode != NULL )
	{
		pNextNode->makeAbsoluteTransform( AbsoluteTransform_ );
		pNextNode = pNextNode->pNext_;
	}
}
//virtual
void ScnParticleSystemComponent::render( RsFrame* pFrame, RsRenderSort Sort )
{
	// Grab vertex buffer and flip for next frame to use.
	TVertexBuffer& VertexBuffer = VertexBuffers_[ CurrentVertexBuffer_ ];
	//CurrentVertexBuffer_ = 1 - CurrentVertexBuffer_;

	// Lock vertex buffer.
	VertexBuffer.pVertexBuffer_->lock();

	// Iterate over alive particles, and setup vertex buffer.
	BcU32 NoofParticlesToRender = 0;
	ScnParticleVertex* pVertex = VertexBuffer.pVertexArray_;
	for( BcU32 Idx = 0; Idx < NoofParticles_; ++Idx )
	{
		ScnParticle& Particle = pParticleBuffer_[ Idx ];

		if( Particle.Alive_ )
		{
			// Half size.
			const BcVec2d HalfSize = Particle.Scale_ * 0.5f;

			// Crappy rotation implementation :P
			const BcReal Radians = Particle.CurrentTime_ * Particle.RotationMultiplier_;
			BcVec2d CornerA = BcVec2d( -1.0f, -1.0f ) * HalfSize;
			BcVec2d CornerB = BcVec2d(  1.0f, -1.0f ) * HalfSize;
			BcVec2d CornerC = BcVec2d(  1.0f,  1.0f ) * HalfSize;
			BcVec2d CornerD = BcVec2d( -1.0f,  1.0f ) * HalfSize;
			if( Radians != NULL )
			{
				BcMat4d Rotation;
				Rotation.rotation( BcVec3d( 0.0f, 0.0f, Radians ) );
				CornerA = CornerA * Rotation;
				CornerB = CornerB * Rotation;
				CornerC = CornerC * Rotation;
				CornerD = CornerD * Rotation;
			}

			const BcU32 Colour = Particle.Colour_.asABGR();

			// Grab vertices.
			ScnParticleVertex& VertexA = *pVertex++;
			ScnParticleVertex& VertexB = *pVertex++;
			ScnParticleVertex& VertexC = *pVertex++;

			ScnParticleVertex& VertexD = *pVertex++;
			ScnParticleVertex& VertexE = *pVertex++;
			ScnParticleVertex& VertexF = *pVertex++;
			
			// 
			VertexA.X_ = Particle.Position_.x();
			VertexA.Y_ = Particle.Position_.y();
			VertexA.Z_ = Particle.Position_.z();
			VertexA.NX_ = CornerA.x();
			VertexA.NY_ = CornerA.y();
			VertexA.NZ_ = 0.0f;
			VertexA.U_ = Particle.UVBounds_.x();
			VertexA.V_ = Particle.UVBounds_.y();
			VertexA.RGBA_ = Colour;

			// 
			VertexB.X_ = Particle.Position_.x();
			VertexB.Y_ = Particle.Position_.y();
			VertexB.Z_ = Particle.Position_.z();
			VertexB.NX_ = CornerB.x();
			VertexB.NY_ = CornerB.y();
			VertexB.NZ_ = 0.0f;
			VertexB.U_ = Particle.UVBounds_.z();
			VertexB.V_ = Particle.UVBounds_.y();
			VertexB.RGBA_ = Colour;

			// 
			VertexC.X_ = Particle.Position_.x();
			VertexC.Y_ = Particle.Position_.y();
			VertexC.Z_ = Particle.Position_.z();
			VertexC.NX_ = CornerC.x();
			VertexC.NY_ = CornerC.y();
			VertexC.NZ_ = 0.0f;
			VertexC.U_ = Particle.UVBounds_.z();
			VertexC.V_ = Particle.UVBounds_.w();
			VertexC.RGBA_ = Colour;

			// 
			VertexD.X_ = Particle.Position_.x();
			VertexD.Y_ = Particle.Position_.y();
			VertexD.Z_ = Particle.Position_.z();
			VertexD.NX_ = CornerC.x();
			VertexD.NY_ = CornerC.y();
			VertexD.NZ_ = 0.0f;
			VertexD.U_ = Particle.UVBounds_.z();
			VertexD.V_ = Particle.UVBounds_.w();
			VertexD.RGBA_ = Colour;

			// 
			VertexE.X_ = Particle.Position_.x();
			VertexE.Y_ = Particle.Position_.y();
			VertexE.Z_ = Particle.Position_.z();
			VertexE.NX_ = CornerD.x();
			VertexE.NY_ = CornerD.y();
			VertexE.NZ_ = 0.0f;
			VertexE.U_ = Particle.UVBounds_.x();
			VertexE.V_ = Particle.UVBounds_.w();
			VertexE.RGBA_ = Colour;

			// 
			VertexF.X_ = Particle.Position_.x();
			VertexF.Y_ = Particle.Position_.y();
			VertexF.Z_ = Particle.Position_.z();
			VertexF.NX_ = CornerA.x();
			VertexF.NY_ = CornerA.y();
			VertexF.NZ_ = 0.0f;
			VertexF.U_ = Particle.UVBounds_.x();
			VertexF.V_ = Particle.UVBounds_.y();
			VertexF.RGBA_ = Colour;

			//
			++NoofParticlesToRender;
		}
	}

	// Update and unlock vertex buffer.	VertexBuffer.pVertexBuffer_->setNoofUpdateVertices( NoofParticlesToRender * 6 );
	VertexBuffer.pVertexBuffer_->unlock();

	// Bind material.
	MaterialComponent_->setParameter( WorldTransformParam_, BcMat4d() );
	MaterialComponent_->bind( pFrame, Sort );

	// Setup render node.
	ScnParticleSystemComponentRenderNode* pRenderNode = pFrame->newObject< ScnParticleSystemComponentRenderNode >();
	pRenderNode->pPrimitive_ = VertexBuffer.pPrimitive_;
	pRenderNode->NoofIndices_ = NoofParticlesToRender * 6;

	// Add to frame.
	pRenderNode->Sort_ = Sort;
	pFrame->addRenderNode( pRenderNode );
}
예제 #6
0
//////////////////////////////////////////////////////////////////////////
// GaGameComponent
//virtual
void GaGameComponent::update( BcReal Tick )
{
	BcU32 Param = FontMaterial_->findParameter( "aAlphaTestStep" );
	FontMaterial_->setParameter( Param, BcVec2d( 0.4f, 0.5f ) );

	if( GameState_ == GS_PLAYING )
	{
		pSimulator_->tick( Tick );

		if( pSimulator_->getTimeOut() > 5.0f )
		{
			GameState_ = GS_TIMEOUT;
		}

		if( pSimulator_->getUnitCount( TeamID_ ) == 0 ||
			pSimulator_->getUnitCount( 1 - TeamID_ ) == 0 )
		{
			GameState_ = GS_OVER;
		}


		if( !Networked_ )
		{
			AITickTime_ -= Tick;

			if( AITickTime_ < 0.0f )
			{
				pSimulator_->runAI( 1 - TeamID_ );
				AITickTime_ = AITickMaxTime_;
			}
		}
	}
	
	//if( TeamID_ == 0 )
	{
		if( CanvasComponent_.isValid() )
		{
			OsClient* pClient = OsCore::pImpl()->getClient( 0 );
			BcReal HW = static_cast< BcReal >( pClient->getWidth() ) / 2.0f;
			BcReal HH = static_cast< BcReal >( pClient->getHeight() ) / 2.0f;
			BcReal AspectRatio = HW / HH;

			BcMat4d Ortho;
			Ortho.orthoProjection( -HW, HW, HH, -HH, -1.0f, 1.0f );

			// Clear canvas and push projection matrix.
			CanvasComponent_->clear();   

			CanvasComponent_->pushMatrix( Ortho );

			CanvasComponent_->setMaterialComponent( BackgroundMaterial_ );
			CanvasComponent_->drawSpriteCentered( BcVec2d( 0.0f, 0.0f ), BcVec2d( 1280.0f, 720.0f ), 0, RsColour( 1.0f, 1.0f, 1.0f, 1.0f ), 0 );

			CanvasComponent_->setMaterialComponent( SpriteSheetMaterials_[ 0 ] );
			pSimulator_->render( CanvasComponent_, 0 );
			CanvasComponent_->setMaterialComponent( SpriteSheetMaterials_[ 1 ] );
			pSimulator_->render( CanvasComponent_, 1 );

			// Find unit over mouse.
			GaGameUnitIDList SelectionList;
			if( MouseDown_ )
			{
				if( BoxSelection_ )
				{
					pSimulator_->findUnits( SelectionList, StartGameCursorPosition_, EndGameCursorPosition_, BcErrorCode, BcErrorCode );
				}
			}
			else
			{
				pSimulator_->findUnits( SelectionList, GameCursorPosition_, 0.8f, BcErrorCode, BcErrorCode );
				while( SelectionList.size() > 1 )
				{
					SelectionList.pop_back();
				}
			}

			for( BcU32 Idx = 0; Idx < UnitSelection_.size(); ++Idx )
			{
				SelectionList.push_back( UnitSelection_[ Idx ] );
			}

			CanvasComponent_->setMaterialComponent( HUDMaterial_ );
			pSimulator_->renderHUD( CanvasComponent_, SelectionList, TeamID_ );
		}

		switch( GameState_ )
		{
		case GS_PLAYING:
			{
				// Draw cursor.
				CanvasComponent_->setMaterialComponent( HUDMaterial_ );
				CanvasComponent_->drawSpriteCentered( BcVec2d( CursorPosition_.x(), CursorPosition_.y() ), BcVec2d( 64.0f, 64.0f ), 1, AttackMove_ ? RsColour::RED : RsColour::WHITE, 10 );

				// Draw selection box.
				if( MouseDown_ && BoxSelection_ ) 
				{
					BcVec2d Min = BcVec2d( StartGameCursorPosition_.x(), StartGameCursorPosition_.y() ) * 32.0f;
					BcVec2d Max = BcVec2d( GameCursorPosition_.x(), GameCursorPosition_.y() ) * 32.0f;
					CanvasComponent_->drawSprite( Min, Max - Min, 0, RsColour::GREEN * RsColour( 1.0f, 1.0f, 1.0f, 0.1f ), 11 );
				}

				std::string Text0 = TeamID_ == 0 ? "YOU ARE RED!" : "YOU ARE BLUE!";
				BcVec2d TextSize0 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text0, RsColour::WHITE, BcTrue );
				Font_->draw( CanvasComponent_, ( -TextSize0 / 2.0f ) + BcVec2d( 0.0f, -350.0f ), Text0, TeamID_ == 0 ? RsColour::RED : RsColour::BLUE, BcFalse );

			}
			break;

		case GS_TIMEOUT:
			{
				std::string Text0 = "Connection timed out :(";
				std::string Text1 = "Press ESC to Quit.";
				BcVec2d TextSize0 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text0, RsColour::WHITE, BcTrue );
				Font_->draw( CanvasComponent_, ( -TextSize0 / 2.0f ) + BcVec2d( 0.0f, -64.0f ), Text0, RsColour::WHITE, BcFalse );
				BcVec2d TextSize1 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text1, RsColour::WHITE, BcTrue );
				Font_->draw( CanvasComponent_, ( -TextSize1 / 2.0f ) + BcVec2d( 0.0f, 64.0f ), Text1, RsColour::WHITE, BcFalse );
			}
			break;

		case GS_OVER:
			{
				if( pSimulator_->getUnitCount( TeamID_ ) > 0 )
				{
					std::string Text0 = "You Won! :D";
					std::string Text1 = "Press ESC to Quit.";
					BcVec2d TextSize0 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text0, RsColour::WHITE, BcTrue );
					Font_->draw( CanvasComponent_, ( -TextSize0 / 2.0f ) + BcVec2d( 0.0f, -64.0f ), Text0, RsColour::WHITE, BcFalse );
					BcVec2d TextSize1 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text1, RsColour::WHITE, BcTrue );
					Font_->draw( CanvasComponent_, ( -TextSize1 / 2.0f ) + BcVec2d( 0.0f, 64.0f ), Text1, RsColour::WHITE, BcFalse );
				}
				else
				{
					std::string Text0 = "You Lost! :<";
					std::string Text1 = "Press ESC to Quit.";
					BcVec2d TextSize0 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text0, RsColour::WHITE, BcTrue );
					Font_->draw( CanvasComponent_, ( -TextSize0 / 2.0f ) + BcVec2d( 0.0f, -64.0f ), Text0, RsColour::WHITE, BcFalse );
					BcVec2d TextSize1 = Font_->draw( CanvasComponent_, BcVec2d( 0.0f, 0.0f ), Text1, RsColour::WHITE, BcTrue );
					Font_->draw( CanvasComponent_, ( -TextSize1 / 2.0f ) + BcVec2d( 0.0f, 64.0f ), Text1, RsColour::WHITE, BcFalse );
				}
			}
			break;
		}
	}


}
예제 #7
0
//////////////////////////////////////////////////////////////////////////
// load
MdlNode* MD5MeshLoader::load( const BcChar* FileName, const BcChar* NodeName )
{
	BcFile File;
	BcBool Ret;

	ParseMode_ = PM_MAIN;

	BcU32 iJoint = 0;
	BcU32 iMesh = 0;
	BcU32 iVert = 0;
	BcU32 iInd = 0;
	BcU32 iWeight = 0;

	if( File.open( FileName ) == BcFalse )
	{
		return NULL;
	}

	BcChar Buffer[1024];
	BcChar Command[1024];
	BcChar* pBuffer;

	// Begin the parsage.
	while( !File.eof() )
	{
		// Parse a line	without	the	spaces at the start	or tabs.
		{
			pBuffer	= &Buffer[0];

			BcChar TheChar = 0;
			BcBool bAtSentence = BcFalse;
			while( TheChar != 10 &&	!File.eof()	)
			{
				File.read( &TheChar, 1 );

				if ( TheChar != '\t' )
				{
					bAtSentence	= BcTrue;
				}

				if ( TheChar != 10 &&
				     TheChar != 13 &&
				     bAtSentence )
				{
					*pBuffer = TheChar;
					++pBuffer;
					Ret	= ( pBuffer < ( Buffer + 1024 ) );
					BcAssert( Ret );
					if( !Ret )
					{
						return NULL;
					}
				}
			}

			// Terminate it.
			*pBuffer = 0;
			++pBuffer;
		}

		sscanf( Buffer, "%s", Command );

		if ( BcStrLength( Buffer ) == 0 )
		{
			Command[ 0 ] = 0;
		}

		switch( ParseMode_ )
		{
		case PM_MAIN:
			{
				if( BcStrCompare( "numJoints", Command ) )
				{
					sscanf( Buffer, "numJoints %u", &nJoints_ );
					
					pJoints_ = new MD5_Joint[ nJoints_ ]; 
				}
				else if( BcStrCompare( "numMeshes", Command ) )
				{
					sscanf( Buffer, "numMeshes %u", &nMeshes_ );
					
					pMeshes_ = new MD5_Mesh[ nMeshes_ ]; 
				}
				else if( BcStrCompare( "joints", Command ) )
				{
					ParseMode_ = PM_JOINTS;
				}
				else if( BcStrCompare( "mesh", Command ) )
				{
					ParseMode_ = PM_MESH;

					iVert = 0;
					iInd = 0;
					iWeight = 0;
				}
			}
			break;

		case PM_JOINTS:
			{
				if( BcStrCompare( "}", Command ) )
				{
					ParseMode_ = PM_MAIN;
				}
				else
				{
					// Parse a joint off.
					BcAssert( iJoint < nJoints_ );
					MD5_Joint* pJoint = &pJoints_[ iJoint ];
					sscanf( Buffer, "%s %i ( %f %f %f ) ( %f %f %f )", pJoint->Name_, &pJoint->ParentID_, &pJoint->TX_, &pJoint->TY_, &pJoint->TZ_, &pJoint->QX_, &pJoint->QY_, &pJoint->QZ_ );
					++iJoint;
				}
			}
			break;

		case PM_MESH:
			{
				if( BcStrCompare( "}", Command ) )
				{
					++iMesh;
					ParseMode_ = PM_MAIN;
				}
				else
				{
					BcAssert( iMesh < nMeshes_ );
					MD5_Mesh* pMesh = &pMeshes_[ iMesh ];

					if ( BcStrCompare( "shader", Command ) )
					{
						sscanf( Buffer, "shader \"%s", pMesh->Shader_ );
						BcU32 i = BcStrLength( pMesh->Shader_ ) - 1;
						pMesh->Shader_[ i ] = '\0';
					}
					else if ( BcStrCompare( "numverts", Command ) )
					{
						sscanf( Buffer, "numverts %u", &pMesh->nVerts_ );
						pMesh->pVerts_ = new MD5_Vert[ pMesh->nVerts_ ];
					}
					else if ( BcStrCompare( "vert", Command ) )
					{
						// Parse a vert off
						BcAssert( iVert < pMesh->nVerts_ );
						MD5_Vert* pVert = &pMesh->pVerts_[ iVert ];
						sscanf( Buffer, "vert %i ( %f %f ) %i %i", &pVert->Index_, &pVert->U_, &pVert->V_, &pVert->WeightIndex_, &pVert->nWeights_ );
						++iVert;
					}
					else if ( BcStrCompare( "numtris", Command ) )
					{
						sscanf( Buffer, "numtris %u", &pMesh->nIndices_ );
						pMesh->nIndices_ *= 3;
						pMesh->pIndices_ = new BcU32[ pMesh->nIndices_ ];
					}
					else if ( BcStrCompare( "tri", Command ) )
					{
						// Parse a vert off
						BcAssert( iInd < pMesh->nIndices_ );
						BcU32 Index;
						BcU32* pIndex = &pMesh->pIndices_[ iInd ];
						sscanf( Buffer, "tri %i %i %i %i", &Index, &pIndex[0], &pIndex[1], &pIndex[2] );
						iInd += 3;
					}
					else if ( BcStrCompare( "numweights", Command ) )
					{
						sscanf( Buffer, "numweights %u", &pMesh->nWeights_ );
						pMesh->pWeights_ = new MD5_Weight[ pMesh->nWeights_ ];
					}
					else if ( BcStrCompare( "weight", Command ) )
					{
						// Parse a vert off
						BcAssert( iWeight < pMesh->nWeights_ );
						MD5_Weight* pWeight = &pMesh->pWeights_[ iWeight ];
						sscanf( Buffer, "weight %i %i %f ( %f %f %f )", &pWeight->Index_, &pWeight->JointID_, &pWeight->Weight_, &pWeight->X_, &pWeight->Y_, &pWeight->Z_ );
						++iWeight;
					}
				}
			}
			break;
		}
	}

	// Now that we are loaded we can build the node graph.
	MdlNode* pRootNode = new MdlNode();

	pRootNode->name( NodeName );

	for( BcU32 i = 0; i < nMeshes_; ++i )
	{
		buildBindPose( pRootNode, i );
	}

	// Parent joints up.
	//if( nJoints_ > 1 )
	{
		for( BcU32 i = 0; i < nJoints_; ++i )
		{
			MD5_Joint* pJoint = &pJoints_[ i ];
			MdlNode* pNode = new MdlNode();

			pNode->name( pJoint->Name_ );
			pNode->type( eNT_JOINT );

			// Build the transform and inverse bind pose.
			BcQuat JointRot( pJoint->QX_, pJoint->QY_, pJoint->QZ_, 0.0f );
			JointRot.calcFromXYZ();
			BcMat4d JointRotation;
			BcMat4d JointTranslate;
			BcMat4d JointTransform;
			BcMat4d InverseBindpose;
			JointRot.asMatrix4d( JointRotation );
			JointTranslate.identity();
			JointTranslate.row3( BcVec4d( pJoint->TX_, pJoint->TY_, pJoint->TZ_, 1.0f ) );

			JointTransform = JointRotation * JointTranslate;
			InverseBindpose = JointTransform;
			InverseBindpose.inverse();

			pNode->absoluteTransform( JointTransform );
			pNode->inverseBindpose( InverseBindpose );

			if( pJoint->ParentID_ != BcErrorCode )
			{
				pRootNode->parentNode( pNode, pJoints_[ pJoint->ParentID_ ].Name_ );
			}
			else
			{
				// Parent to root.
				pRootNode->parentNode( pNode, pRootNode->name() );
			}
		}
	}

	// Cleanup
	nJoints_ = 0;
	delete [] pJoints_;
	pJoints_ = NULL;

	for( BcU32 i = 0; i < nMeshes_; ++i )
	{
		delete [] pMeshes_[ i ].pIndices_;
		delete [] pMeshes_[ i ].pVerts_;
		delete [] pMeshes_[ i ].pWeights_;
	}

	nMeshes_ = 0;
	delete [] pMeshes_;
	pMeshes_ = NULL;

	//
	BcMat4d RootTransform;
	RootTransform.identity();
	pRootNode->makeRelativeTransform( RootTransform );

	return pRootNode;
}