Terrain.cpp

#include "Terrain.h"

TerrainBlock* TerrainBlock::mCenterBlock = NULL;

TerrainBlock::TerrainBlock(const NxString& name, const NxOgre::Pose& pose, Shape* shape, 
			Scene* scene, const NodeRenderableParams& visualParams, const ActorParams& params) 
			: Actor(name, scene, shape, pose, params)
{
	mLowPolyMesh = NULL;
	mHighPolyMesh = NULL;
	mNorthBlock = NULL;
	mEastBlock = NULL;
	mSouthBlock = NULL;
	mWestBlock = NULL;
	mTypeHash = 004;
	mStringType = "TerrainBlock";
	mScene = scene;

	// Create the NodeRenderable based on the Params. The outcome is
	// based on the Renderer used (specified in the Scene).
	mRenderable = mOwner->getSceneRenderer()->createNodeRenderable(visualParams);
	mNodeRenderable = static_cast(mRenderable);
	mVoidPointer->RenderPtr = this;
	setRenderMode(RM_Interpolate);

	// You can use the NodeRenderable functions to mirror most or if
	// not all of the actual RenderSystem's NodeRenderable functions
	// but in some instances you can't. But you can cast it into another,
	// if you have to.
	if (mNodeRenderable->getHashType() == NxOgreClass_OgreNodeRenderable)
		mOgreNodeRenderable = static_cast(mNodeRenderable);

	mOwner->getSceneRenderer()->registerSource(this);

	this->setActive( false );
	mOgreNodeRenderable->removeEntity( this->getName() );
}

TerrainBlock::TerrainBlock(const VisualIdentifier& vi, const NxOgre::Pose& pose, Shape* shape, 
				Scene* scene, const ActorParams& params) 
				: Actor(vi.getIdentifier(), scene, shape, pose, params)
{
	mLowPolyMesh = NULL;
	mHighPolyMesh = NULL;
	mNorthBlock = NULL;
	mEastBlock = NULL;
	mSouthBlock = NULL;
	mWestBlock = NULL;
	mTypeHash = 004;
	mStringType = "TerrainBlock";
	mScene = scene;

	NodeRenderableParams renderParams;
	renderParams.setToDefault();
	renderParams.mGraphicsModel = vi.getVisualIdentifier();
	renderParams.mGraphicsModelScale = NxVec3(1, 1, 1);
	renderParams.mIdentifier = vi.getIdentifier();
	renderParams.mIdentifierUsage = renderParams.IU_Use;
	renderParams.mMode = RenderableSource::RM_Interpolate;

	mRenderable = mOwner->getSceneRenderer()->createNodeRenderable( renderParams );
	mNodeRenderable = static_cast(mRenderable);
	mVoidPointer->RenderPtr = this;

	setRenderMode(RM_Absolute);

	if (mNodeRenderable->getHashType() == NxOgreClass_OgreNodeRenderable)
		mOgreNodeRenderable = static_cast(mNodeRenderable);

	mOwner->getSceneRenderer()->registerSource(this);
	this->setActive( false );
	mOgreNodeRenderable->removeEntity( this->getName() );
}

TerrainBlock::~TerrainBlock()
{
	mOgreNodeRenderable->getNode()->removeAndDestroyAllChildren();
	if( mLowPolyMesh )
	{
		delete mLowPolyMesh;
		mLowPolyMesh = 0;
	}
	if( mHighPolyMesh )
	{
		delete mHighPolyMesh;
		mHighPolyMesh = 0;
	}
	mOwner->getSceneRenderer()->unregisterSource(this);
	if (mRenderable) 
	{
		delete mRenderable;
		mRenderable = 0;
	}

	//destroyed in GameActorFactory via SharedList
	mNorthBlock = 0;
	mSouthBlock = 0;
	mEastBlock = 0;
	mWestBlock = 0;
	mCenterBlock = 0;
	
	//destroyed in main app
	mSceneMgr = 0;
	mScene = 0;
}

void TerrainBlock::initialize( String north, String east, String south, String west )
{
	mNorthBlockName = north;
	mEastBlockName = east;
	mSouthBlockName = south;
	mWestBlockName = west;
}

void TerrainBlock::connectTheBlocks()
{
	if( mNorthBlockName != "" )
	{
		mNorthBlock = (TerrainBlock*)mScene->getActor( mNorthBlockName );
		if( mNorthBlock == NULL )
		{
			LogManager::getSingleton().logMessage( "[Error]TerrainBlock '" + getName() 
					+ "' tried to connect north to invalid actor name:  " + mNorthBlockName );
		}
	}
	if( mEastBlockName != "" )
	{
		mEastBlock = (TerrainBlock*)mScene->getActor( mEastBlockName );
		if( mEastBlock == NULL )
		{
			LogManager::getSingleton().logMessage( "[Error]TerrainBlock '" + getName() 
					+ "' tried to connect east to invalid actor name:  " + mEastBlockName );
		}
	}
	if( mSouthBlockName != "" )
	{
		mSouthBlock = (TerrainBlock*)mScene->getActor( mSouthBlockName );
		if( mSouthBlock == NULL )
		{
			LogManager::getSingleton().logMessage( "[Error]TerrainBlock '" + getName() 
					+ "' tried to connect south to invalid actor name:  " + mSouthBlockName );
		}
	}
	if( mWestBlockName != "" )
	{
		mWestBlock = (TerrainBlock*)mScene->getActor( mWestBlockName );
		if( mWestBlock == NULL )
		{
			LogManager::getSingleton().logMessage( "[Error]TerrainBlock '" + getName() 
					+ "' tried to connect west to invalid actor name:  " + mWestBlockName );
		}
	}	
}

NxOgre::Pose TerrainBlock::getSourcePose(const NxOgre::TimeStep&) const
{
	return getGlobalPose();
}

NxShortHashIdentifier TerrainBlock::getType() 
{
	return mTypeHash;
}

NxString TerrainBlock::getStringType() 
{
	return mStringType;
}

void TerrainBlock::setType( NxShortHashIdentifier newHash ) 
{
	mTypeHash = newHash;
}

void TerrainBlock::setStringType( NxString newStringType ) 
{
	mStringType = newStringType;
}

void TerrainBlock::setLowPolyMesh( Entity* newLowPolyMesh )
{
	if( newLowPolyMesh != NULL )
	{
		if( mLowPolyMesh != NULL )
		{
			mOgreNodeRenderable->destroyEntity(  mLowPolyMesh );
		}
		mLowPolyMesh = newLowPolyMesh;

		if( !mHighPolyMesh->isAttached() )
		{
			mOgreNodeRenderable->addEntity( mLowPolyMesh );
		}
	}
}

void TerrainBlock::setHighPolyMesh( Entity* newHighPolyMesh )
{
	if( newHighPolyMesh != NULL )
	{
		if( mHighPolyMesh != NULL )
		{
			mOgreNodeRenderable->destroyEntity( mHighPolyMesh );
		}
		mHighPolyMesh = newHighPolyMesh;

		if(( mLowPolyMesh != NULL && !mLowPolyMesh->isAttached()) || mLowPolyMesh == NULL )
		{
			mOgreNodeRenderable->addEntity( mHighPolyMesh );
		}
	}
}

void TerrainBlock::setActive( bool isActive )
{
	mIsActive = isActive;
	//Low poly meshes are optional for each block
	if( !mIsActive )
	{
		if( mLowPolyMesh != NULL && !mLowPolyMesh->isAttached() )
		{
			this->mOgreNodeRenderable->addEntity( mLowPolyMesh );
			this->mOgreNodeRenderable->removeEntity( mHighPolyMesh );
		}
	}
	else
	{
		if( mLowPolyMesh != NULL && !mLowPolyMesh->isAttached() )
		{
			this->mOgreNodeRenderable->addEntity( mHighPolyMesh );
			this->mOgreNodeRenderable->removeEntity( mLowPolyMesh );
		}
	}
	
}

bool TerrainBlock::isCenter()
{
	bool isCenter = false;
	if( this == mCenterBlock )
	{
		isCenter = true;
	}
	return isCenter;
}

bool TerrainBlock::getActive()
{
	return mIsActive;
}

void TerrainBlock::disableDirection( TerrainBlock* block, OrdinalDirections direction )
{
	//Warning: this function is recursive.  Be careful if you mess with the anchor.
	if( block != NULL )
	{
		block->setActive( false );
		switch( direction )
		{
		case DIR_NORTH:
			if( block->mNorthBlock != NULL && block->mNorthBlock->getActive() )
			{
				disableDirection( block->mNorthBlock, DIR_NORTH );
				block->mNorthBlock->setActive( false );
			}
			if( block->mEastBlock != NULL && block->mEastBlock->getActive() )
			{
				disableDirection( block->mEastBlock, DIR_NORTH );
				block->mEastBlock->setActive( false );
			}
			if( block->mWestBlock != NULL && block->mWestBlock->getActive() )
			{
				disableDirection( block->mWestBlock, DIR_NORTH );
				block->mWestBlock->setActive( false );
			}
			break;	
		case DIR_EAST:
			if( block->mEastBlock != NULL && block->mEastBlock->getActive() )
			{
				disableDirection( block->mEastBlock, DIR_EAST );
				block->mEastBlock->setActive( false );
			}
			if( block->mNorthBlock != NULL && block->mNorthBlock->getActive() )
			{
				disableDirection( block->mNorthBlock, DIR_EAST );
				block->mNorthBlock->setActive( false );
			}
			if( block->mSouthBlock != NULL && block->mSouthBlock->getActive() )
			{
				disableDirection( block->mSouthBlock, DIR_EAST );
				block->mSouthBlock->setActive( false );
			}
			break;
		case DIR_SOUTH:
			if( block->mSouthBlock != NULL && block->mSouthBlock->getActive() )
			{
				disableDirection( block->mSouthBlock, DIR_SOUTH );
				block->mSouthBlock->setActive( false );
			}
			if( block->mEastBlock != NULL && block->mEastBlock->getActive() )
			{
				disableDirection( block->mEastBlock, DIR_SOUTH );
				block->mEastBlock->setActive( false );
			}
			if( block->mWestBlock != NULL && block->mWestBlock->getActive() )
			{
				disableDirection( block->mWestBlock, DIR_SOUTH );
				block->mWestBlock->setActive( false );
			}
			break;
		case DIR_WEST:
			if( block->mWestBlock != NULL && block->mWestBlock->getActive() )
			{
				disableDirection( block->mWestBlock, DIR_WEST );
				block->mWestBlock->setActive( false );
			}
			if( block->mNorthBlock != NULL && block->mNorthBlock->getActive() )
			{
				disableDirection( block->mNorthBlock, DIR_WEST );
				block->mNorthBlock->setActive( false );
			}
			if( block->mSouthBlock != NULL && block->mSouthBlock->getActive() )
			{
				disableDirection( block->mSouthBlock, DIR_WEST );
				block->mSouthBlock->setActive( false );
			}
			break;
		}
	}
}

void TerrainBlock::centerOnThisBlock()
{
	if( mCenterBlock != NULL )
	{
		int direction = -1;
		if( mCenterBlock->mNorthBlock == this )
		{
			direction = DIR_NORTH;
		}
		else if( mCenterBlock->mEastBlock == this )
		{
			direction = DIR_EAST;
		}
		else if( mCenterBlock->mSouthBlock == this )
		{
			direction = DIR_SOUTH;
		}
		else if( mCenterBlock->mWestBlock == this )
		{
			direction = DIR_WEST;
		}

		if( direction >= 0 )
		{
			LogManager::getSingleton().logMessage( "**TerrainBlock re-centering on:  " 
						+ this->getName() );

			switch( direction )
			{
			case DIR_NORTH:
				if( mCenterBlock->mSouthBlock != NULL )
				{
					disableDirection( mCenterBlock->mSouthBlock, DIR_SOUTH );
					if( mCenterBlock->mEastBlock !=NULL 
								&& mCenterBlock->mEastBlock->mSouthBlock != NULL )
					{
						disableDirection( mCenterBlock->mEastBlock->mSouthBlock, DIR_SOUTH );
					}
					if( mCenterBlock->mWestBlock !=NULL 
								&& mCenterBlock->mWestBlock->mSouthBlock != NULL )
					{
						disableDirection( mCenterBlock->mWestBlock->mSouthBlock, DIR_SOUTH );
					}
				}
				if( this->mNorthBlock != NULL )
				{
					this->mNorthBlock->setActive( true );
					if( this->mNorthBlock->mEastBlock != NULL )
					{
						this->mNorthBlock->mEastBlock->setActive( true );
					}
					if( this->mNorthBlock->mWestBlock != NULL )
					{
						this->mNorthBlock->mWestBlock->setActive( true );
					}
				}
				else
				{
					if( this->mEastBlock != NULL && this->mEastBlock->mNorthBlock != NULL )
					{
						this->mEastBlock->mNorthBlock->setActive( true );
					}
					if( this->mWestBlock != NULL && this->mWestBlock->mNorthBlock != NULL )
					{
						this->mWestBlock->mNorthBlock->setActive( true );
					}
				}
				break;
			case DIR_EAST:
				if( mCenterBlock->mWestBlock != NULL )
				{
					disableDirection( mCenterBlock->mWestBlock, DIR_WEST );
					if( mCenterBlock->mNorthBlock !=NULL 
								&& mCenterBlock->mNorthBlock->mWestBlock != NULL )
					{
						disableDirection( mCenterBlock->mNorthBlock->mWestBlock, DIR_WEST );
					}
					if( mCenterBlock->mSouthBlock !=NULL 
								&& mCenterBlock->mSouthBlock->mWestBlock != NULL )
					{
						disableDirection( mCenterBlock->mSouthBlock->mWestBlock, DIR_WEST );
					}
				}
				if( this->mEastBlock != NULL )
				{
					this->mEastBlock->setActive( true );
					if( this->mEastBlock->mNorthBlock != NULL )
					{
						this->mEastBlock->mNorthBlock->setActive( true );
					}
					if( this->mEastBlock->mSouthBlock != NULL )
					{
						this->mEastBlock->mSouthBlock->setActive( true );
					}
				}
				else
				{
					if( this->mNorthBlock != NULL && this->mNorthBlock->mEastBlock != NULL )
					{
						this->mNorthBlock->mEastBlock->setActive( true );
					}
					if( this->mSouthBlock != NULL && this->mSouthBlock->mEastBlock != NULL )
					{
						this->mSouthBlock->mEastBlock->setActive( true );
					}
				}
				break;
			case DIR_SOUTH:
				if( mCenterBlock->mSouthBlock != NULL )
				{
					disableDirection( mCenterBlock->mNorthBlock, DIR_NORTH );
					if( mCenterBlock->mEastBlock !=NULL 
								&& mCenterBlock->mEastBlock->mNorthBlock != NULL )
					{
						disableDirection( mCenterBlock->mEastBlock->mNorthBlock, DIR_NORTH );
					}
					if( mCenterBlock->mWestBlock !=NULL 
								&& mCenterBlock->mWestBlock->mNorthBlock != NULL )
					{
						disableDirection( mCenterBlock->mWestBlock->mNorthBlock, DIR_NORTH );
					}
				}
				if( this->mSouthBlock != NULL )
				{
					this->mSouthBlock->setActive( true );
					if( this->mSouthBlock->mEastBlock != NULL )
					{
						this->mSouthBlock->mEastBlock->setActive( true );
					}
					if( this->mSouthBlock->mWestBlock != NULL )
					{
						this->mSouthBlock->mWestBlock->setActive( true );
					}
				}
				else
				{
					if( this->mEastBlock != NULL && this->mEastBlock->mSouthBlock != NULL )
					{
						this->mEastBlock->mSouthBlock->setActive( true );
					}
					if( this->mWestBlock != NULL && this->mWestBlock->mSouthBlock != NULL )
					{
						this->mWestBlock->mSouthBlock->setActive( true );
					}
				}
				break;
			case DIR_WEST:
				if( mCenterBlock->mWestBlock != NULL )
				{
					disableDirection( mCenterBlock->mEastBlock, DIR_EAST );
					if( mCenterBlock->mNorthBlock !=NULL 
								&& mCenterBlock->mNorthBlock->mEastBlock != NULL )
					{
						disableDirection( mCenterBlock->mNorthBlock->mEastBlock, DIR_EAST );
					}
					if( mCenterBlock->mSouthBlock !=NULL 
								&& mCenterBlock->mSouthBlock->mEastBlock != NULL )
					{
						disableDirection( mCenterBlock->mSouthBlock->mEastBlock, DIR_EAST );
					}
				}
				if( this->mWestBlock != NULL )
				{
					this->mWestBlock->setActive( true );
					if( this->mWestBlock->mNorthBlock != NULL )
					{
						this->mWestBlock->mNorthBlock->setActive( true );
					}
					if( this->mWestBlock->mSouthBlock != NULL )
					{
						this->mWestBlock->mSouthBlock->setActive( true );
					}
				}
				else
				{
					if( this->mNorthBlock != NULL && this->mNorthBlock->mWestBlock != NULL )
					{
						this->mNorthBlock->mWestBlock->setActive( true );
					}
					if( this->mSouthBlock != NULL && this->mSouthBlock->mWestBlock != NULL )
					{
						this->mSouthBlock->mWestBlock->setActive( true );
					}
				}
				break;
			}

			mCenterBlock = this;
			LogManager::getSingleton().logMessage( "**TerrainBlock re-centered on:  " 
						+ mCenterBlock->getName() );
		}
		else
		{
			//This might happen if the player is somehow thrown across a level, or jumps to a 
			//	block diagonal (jumping to adjacent blocks shouldn't trigger this)
			//
			//As long as at least one of the old blocks are still touching the new set they should 
			//	be cleaned by the directional deactivation function which is recursive.
			LogManager::getSingleton().logMessage( "**TerrainBlock center lost - used to be:  " 
						+ mCenterBlock->getName() + " -- currently creating new center at: " 
						+ this->getName() );
			createNewCenter();
		}
	}
	else
	{
		LogManager::getSingleton().logMessage( 
					"Center doesn't exist == Activating blocks surrounding player as new center" );
		createNewCenter();
	}
}

void TerrainBlock::createNewCenter()
{
	mCenterBlock = this;
	this->setActive( true );
	if( this->mNorthBlock != NULL )
	{
		this->mNorthBlock->setActive( true );
		if( this->mNorthBlock->mEastBlock != NULL )
		{
			this->mNorthBlock->mEastBlock->setActive( true );
		}
		if( this->mNorthBlock->mWestBlock != NULL )
		{
			this->mNorthBlock->mWestBlock->setActive( true );
		}
	}
	else
	{
		if( this->mEastBlock != NULL && this->mEastBlock->mNorthBlock != NULL )
		{
			this->mEastBlock->mNorthBlock->setActive( true );
		}
		if( this->mWestBlock != NULL && this->mWestBlock->mNorthBlock != NULL )
		{
			this->mWestBlock->mNorthBlock->setActive( true );
		}
	}
	if( this->mEastBlock != NULL )
	{
		this->mEastBlock->setActive( true );
		if( this->mEastBlock->mNorthBlock != NULL )
		{
			this->mEastBlock->mNorthBlock->setActive( true );
		}
		if( this->mEastBlock->mSouthBlock != NULL )
		{
			this->mEastBlock->mSouthBlock->setActive( true );
		}
	}
	else
	{
		if( this->mNorthBlock != NULL && this->mNorthBlock->mEastBlock != NULL )
		{
			this->mNorthBlock->mEastBlock->setActive( true );
		}
		if( this->mSouthBlock != NULL && this->mSouthBlock->mEastBlock != NULL )
		{
			this->mSouthBlock->mEastBlock->setActive( true );
		}
	}
	if( this->mSouthBlock != NULL )
	{
		this->mSouthBlock->setActive( true );
		if( this->mSouthBlock->mEastBlock != NULL )
		{
			this->mSouthBlock->mEastBlock->setActive( true );
		}
		if( this->mSouthBlock->mWestBlock != NULL )
		{
			this->mSouthBlock->mWestBlock->setActive( true );
		}
	}
	else
	{
		if( this->mEastBlock != NULL && this->mEastBlock->mSouthBlock != NULL )
		{
			this->mEastBlock->mSouthBlock->setActive( true );
		}
		if( this->mWestBlock != NULL && this->mWestBlock->mSouthBlock != NULL )
		{
			this->mWestBlock->mSouthBlock->setActive( true );
		}
	}
	if( this->mWestBlock != NULL )
	{
		this->mWestBlock->setActive( true );
		if( this->mWestBlock->mNorthBlock != NULL )
		{
			this->mWestBlock->mNorthBlock->setActive( true );
		}
		if( this->mWestBlock->mSouthBlock != NULL )
		{
			this->mWestBlock->mSouthBlock->setActive( true );
		}
	}
	else
	{
		if( this->mNorthBlock != NULL && this->mNorthBlock->mWestBlock != NULL )
		{
			this->mNorthBlock->mWestBlock->setActive( true );
		}
		if( this->mSouthBlock != NULL && this->mSouthBlock->mWestBlock != NULL )
		{
			this->mSouthBlock->mWestBlock->setActive( true );
		}
	}
}