Esempio n. 1
0
BcBool MaAABB::boxIntersect( const MaAABB& AABB, MaAABB* pIntersectionBox ) const
{
	// Check for no overlap.
	if( ( Min_.x() > AABB.Max_.x() ) ||
		( Max_.x() < AABB.Min_.x() ) ||
		( Min_.y() > AABB.Max_.y() ) ||
		( Max_.y() < AABB.Min_.y() ) ||
		( Min_.z() > AABB.Max_.z() ) ||
		( Max_.z() < AABB.Min_.z() ) )
	{
		return BcFalse;
	}

	// Overlap, compute AABB of intersection.
	if( pIntersectionBox != NULL )
	{
		pIntersectionBox->Min_.x( BcMax( Min_.x(), AABB.Min_.x() ) );
		pIntersectionBox->Max_.x( BcMin( Max_.x(), AABB.Max_.x() ) );
		pIntersectionBox->Min_.y( BcMax( Min_.y(), AABB.Min_.y() ) );
		pIntersectionBox->Max_.y( BcMin( Max_.y(), AABB.Max_.y() ) );
		pIntersectionBox->Min_.z( BcMax( Min_.z(), AABB.Min_.z() ) );
		pIntersectionBox->Max_.z( BcMin( Max_.z(), AABB.Max_.z() ) );
	}

	return BcTrue;
}
Esempio n. 2
0
void MaAABB::expandBy( const MaAABB& AABB )
{
	Min_.x( BcMin( Min_.x(), AABB.Min_.x() ) );
	Min_.y( BcMin( Min_.y(), AABB.Min_.y() ) );
	Min_.z( BcMin( Min_.z(), AABB.Min_.z() ) );

	Max_.x( BcMax( Max_.x(), AABB.Max_.x() ) );
	Max_.y( BcMax( Max_.y(), AABB.Max_.y() ) );
	Max_.z( BcMax( Max_.z(), AABB.Max_.z() ) );
}
Esempio n. 3
0
void MaAABB::expandBy( const MaVec3d& Point )
{
	Min_.x( BcMin( Min_.x(), Point.x() ) );
	Min_.y( BcMin( Min_.y(), Point.y() ) );
	Min_.z( BcMin( Min_.z(), Point.z() ) );

	Max_.x( BcMax( Max_.x(), Point.x() ) );
	Max_.y( BcMax( Max_.y(), Point.y() ) );
	Max_.z( BcMax( Max_.z(), Point.z() ) );
}
Esempio n. 4
0
//////////////////////////////////////////////////////////////////////////
// Ctor
SysKernel::SysKernel( BcReal TickRate ):
	JobQueue_( BcMax( BcGetHardwareThreadCount(), BcU32( 1 ) ) ),
	TickRate_( TickRate )
{
	ShuttingDown_ = BcFalse;
	SleepAccumulator_ = 0.0f;
	FrameTime_ = 0.0f;

	// Set user mask to the workers we have.
	SysKernel::USER_WORKER_MASK = ( ( 1 << JobQueue_.workerCount() ) - 1 );
}
Esempio n. 5
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();
}
Esempio n. 6
0
//////////////////////////////////////////////////////////////////////////
// execute
//virtual
void SysKernel::execute()
{
	// Set main thread.
	extern void BcSetGameThread();
	BcSetGameThread();

	// Run until there are no more systems to run.
	do
	{
		// Mark main timer.
		MainTimer_.mark();
		
		// Tick systems.
		tick();
		
		// Sleep if we have a fixed rate specified, otherwise just yield.
		if( TickRate_ > 0.0f )
		{
			BcReal TimeSpent = MainTimer_.time();
			SleepAccumulator_ += BcMax( ( TickRate_ ) - TimeSpent, 0.0f );
		
			if( SleepAccumulator_ > 0.0f )
			{
				BcReal SleepTime = SleepAccumulator_;
				SleepAccumulator_ -= SleepTime;
				BcSleep( BcMin( SleepTime, TickRate_ ) );
			}
		}
		else
		{
			BcYield();
		}

		// Store frame time.
		FrameTime_ = BcMin( MainTimer_.time(), TickRate_ * 4.0f );

		BcAssert( FrameTime_ >= 0.0f );
	}
	while( SystemList_.size() > 0 );
}
//////////////////////////////////////////////////////////////////////////
// updateParticles
void ScnParticleSystemComponent::updateParticles( BcF32 Tick )
{
	// Wait for upload to have completed.
	UploadFence_.wait();

	// TODO: Iterate over every "affector" at a time, rather than by particle.
	// - See "updateParticle".

	MaAABB FullAABB( MaVec3d( 0.0f, 0.0f, 0.0f ), MaVec3d( 0.0f, 0.0f, 0.0f ) );

	// Not optimal, but clear code is clear. (For now...)
	for( BcU32 Idx = 0; Idx < NoofParticles_; ++Idx )
	{
		ScnParticle& Particle = pParticleBuffer_[ Idx ];

		if( Particle.Alive_ )
		{
			// Update particle.
			updateParticle( Particle, Tick );

			// Expand AABB by particle's max bounds.
			const BcF32 MaxHalfSize = BcMax( Particle.Scale_.x(), Particle.Scale_.y() ) * 0.5f;
			FullAABB.expandBy( Particle.Position_ - MaVec3d( MaxHalfSize, MaxHalfSize, MaxHalfSize ) );
			FullAABB.expandBy( Particle.Position_ + MaVec3d( MaxHalfSize, MaxHalfSize, MaxHalfSize ) );
		}
	}

	// Transform AABB.
	if( IsLocalSpace_ )
	{
		const MaMat4d& WorldTransform = getParentEntity()->getWorldMatrix();
		AABB_ = FullAABB.transform( WorldTransform );
	}
	else
	{
		AABB_ = FullAABB;
	}

	UpdateFence_.decrement();
}
Esempio n. 8
0
//////////////////////////////////////////////////////////////////////////
// update
//virtual
void GaRobotComponent::update( BcF32 Tick )
{
	if( Health_ <= 0.0f )
	{
		return;
	}

	CurrentOpTimer_ -= Tick;
	if( CurrentOpTimer_ < 0.0f )
	{
		CurrentOpTimer_ += CurrentOpTime_;

		// Handle robot program.
		BcBool ExecutedCode = BcFalse;
		if( Program_.size() > 0 )
		{
			CurrentOp_ = NextOp_;
			const auto& Op = Program_[ CurrentOp_ ];
			if( Op.State_ == CurrentState_ )
			{
				auto Condition = ProgramFunctionMap_[ Op.Condition_ ];
				if( Condition != nullptr )
				{
					if( Condition( this, Op.ConditionVar_ ) )
					{
						auto Operation = ProgramFunctionMap_[ Op.Operation_ ];
						if( Operation == nullptr )
						{
							BcPrintf( "No operation \"%s\"\n", Op.Operation_.c_str() );
						}
						else
						{
							auto RetVal = Operation( this, Op.OperationVar_ );
							if( RetVal != BcErrorCode )
							{
								CurrentState_ = RetVal;
							}
						}
					}
				}
				ExecutedCode = BcTrue;
			}

			// Advance to next valid op.
			if( ExecutedCode )
			{
				for( BcU32 Idx = 0; Idx < Program_.size(); ++Idx )
				{
					NextOp_ = ( NextOp_ + 1 ) % Program_.size();
					if( Program_[ NextOp_ ].State_ == CurrentState_ )
					{
						break;
					}
				}
			}

			// Did we fail to run code? If so, reset to op 0 and the state of op 0.
			if( ExecutedCode == BcFalse )
			{
				NextOp_ = 0;
				CurrentState_ = Program_[ NextOp_ ].State_;
			}
		}
	}

	// Grab entity + position.
	auto Entity = getParentEntity();
	auto LocalPosition = Entity->getLocalPosition();

	// Move if we need to move towards our target position.
	if( ( TargetPosition_ - LocalPosition ).magnitudeSquared() > ( TargetDistance_ * TargetDistance_ ) )
	{
		if( MoveTimer_ <= 0.0f )
		{
			Velocity_ +=  ( TargetPosition_ - LocalPosition ).normal() * MaxVelocity_;
		}
	}
	else
	{
		BcF32 SlowDownTick = BcClamp( Tick * 50.0f, 0.0f, 1.0f );
		Velocity_ -= ( Velocity_ * SlowDownTick );
	}

	// TODO LATER: Do rotation.
	if( Velocity_.magnitudeSquared() > 0.1f )
	{
		auto Angle = std::atan2( Velocity_.z(), Velocity_.x() ) + BcPIDIV2;

		MaMat4d RotMat;
		RotMat.rotation( MaVec3d( 0.0f, Angle, 0.0f ) );
		Base_->setLocalMatrix( RotMat );
	}

	// TODO LATER: Do rotation.
	auto Robots = getRobots( 1 - Team_ );
	if( Robots.size() > 0 )
	{
		auto Robot = Robots[ 0 ];
		auto RobotPosition = Robot->getParentEntity()->getLocalPosition();
		auto VectorTo = RobotPosition - LocalPosition;

		// Push out of away.
		if( VectorTo.magnitude() < 3.0f )
		{
			BcF32 Factor = ( 3.0f - VectorTo.magnitude() ) / 3.0f;
			BcF32 InvFactor = 1.0f - Factor;

			Velocity_ = ( -( VectorTo.normal() * MaxVelocity_ ) * Factor * 3.0f ) + ( Velocity_ * InvFactor );
		}

		// Face turret.
		auto Angle = std::atan2( VectorTo.z(), VectorTo.x() ) + BcPIDIV2;

		MaMat4d RotMat;
		RotMat.rotation( MaVec3d( 0.0f, Angle, 0.0f ) );
		Turret_->setLocalMatrix( RotMat );
	}

	LocalPosition += Velocity_ * Tick;

	// Slow down velocity.
	BcF32 SlowDownTick = BcClamp( Tick * 10.0f, 0.0f, 1.0f );
	Velocity_ -= ( Velocity_ * SlowDownTick );

	if( Velocity_.magnitude() > MaxVelocity_ )
	{
		Velocity_ = Velocity_.normal() * MaxVelocity_;
	}

	// Set local position.
	Entity->setLocalPosition( LocalPosition );

	// Handle health + energy.
	Health_ = BcClamp( Health_, 0.0f, 100.0f );
	Energy_ = BcClamp( Energy_ + ( EnergyChargeRate_ * Tick ), 0.0f, 100.0f );

	// Weapon timers.
	WeaponATimer_ = BcMax( WeaponATimer_ - Tick, -1.0f );
	WeaponBTimer_ = BcMax( WeaponBTimer_ - Tick, -1.0f );

	MoveTimer_ = BcMax( MoveTimer_ - Tick, -1.0f );

	// Health/energy bars.
	OsClient* Client = OsCore::pImpl()->getClient( 0 );
	BcF32 Width = BcF32( Client->getWidth() ) * 0.5f;
	BcF32 Height = BcF32( Client->getHeight() ) * 0.5f;
	MaMat4d Projection;
	Projection.orthoProjection( -Width, Width, Height, -Height, -1.0f, 1.0f );
	Canvas_->pushMatrix( Projection );

	Canvas_->setMaterialComponent( Material_ );

	auto ScreenPos = View_->getScreenPosition( getParentEntity()->getWorldPosition() );
	ScreenPos -= MaVec2d( 0.0f, Height / 8.0f );
	auto TLPos = ScreenPos - MaVec2d( Width / 16.0f, Height / 64.0f );
	auto BRPos = ScreenPos + MaVec2d( Width / 16.0f, Height / 64.0f );

	// Draw background.
	Canvas_->drawBox( TLPos, BRPos, RsColour::BLACK, 0 );

	// Draw inner bars.
	TLPos += MaVec2d( 1.0f, 1.0f );
	BRPos -= MaVec2d( 1.0f, 1.0f );

	auto HealthTL = MaVec2d(
		TLPos.x(),
		TLPos.y() );	
	auto HealthBR = MaVec2d( 
		TLPos.x() + ( BRPos.x() - TLPos.x() ) * ( Health_ / 100.0f ),
		( TLPos.y() + BRPos.y() ) * 0.5f );

	auto EnergyTL = MaVec2d(
		TLPos.x(),
		( TLPos.y() + BRPos.y() ) * 0.5f );
	auto EnergyBR = MaVec2d( 
		TLPos.x() + ( BRPos.x() - TLPos.x() ) * ( Energy_ / 100.0f ),
		BRPos.y() );

	Canvas_->drawBox( HealthTL, HealthBR, RsColour::GREEN, 0 );
	Canvas_->drawBox( EnergyTL, EnergyBR, RsColour::BLUE, 0 );

	Canvas_->popMatrix( );

	ScnDebugRenderComponent::pImpl()->drawLine(
		LocalPosition,
		TargetPosition_,
		RsColour::WHITE,
		0 );

	Super::update( Tick );
}
Esempio n. 9
0
//////////////////////////////////////////////////////////////////////////
// tickBehaviour
void GaGameUnit::tickBehaviour( BcFixed Delta )
{
#if PSY_DEBUG
	static BcU32 BreakID = BcErrorCode;
	if( ID_ == BreakID )
	{
		BcBreakpoint;
	}
#endif

	switch( Behaviour_ )
	{
	case BEHAVIOUR_IDLE:
		{
			CurrState_.Velocity_ = BcFixedVec2d( 0.0f, 0.0f );
			BcU32 NearestUnit = pSimulator_->findNearestUnit( CurrState_.Position_, ID_, 1 << ( 1 - TeamID_ ) );
			if( NearestUnit != BcErrorCode )
			{
				doAttack( NearestUnit );
			}
		}
		break;

	case BEHAVIOUR_GUARD:
		{
			CurrState_.Velocity_ = BcFixedVec2d( 0.0f, 0.0f );
			BcU32 NearestUnit = pSimulator_->findNearestUnit( CurrState_.Position_, ID_, 1 << ( 1 - TeamID_ ) );
			if( NearestUnit != BcErrorCode )
			{
				doAttack( NearestUnit );
			}
		}
		break;

	case BEHAVIOUR_MOVE:
		{
			BcU32 NearestUnit = pSimulator_->findNearestUnit( CurrState_.Position_, ID_, 1 << ( 1 - TeamID_ ) );
			if( IsAttackMove_ && inRangeForAttack( NearestUnit ) == RANGE_IN )
			{
				CurrState_.Velocity_ = BcFixedVec2d( 0.0f, 0.0f );

				doAttack( NearestUnit );
			}
			else
			{
				// Reset attack timer.
				AttackTimer_ = BcMax( AttackTimer_,  BcFixed( Desc_.CoolDownMultiplier_ ) / Desc_.RateOfAttack_ );
				
				// Make longer whe moving.
				AttackTimer_ = BcMin( BcFixed( 1.0f ) / Desc_.RateOfAttack_, AttackTimer_ + ( BcFixed( 1.0f ) / Desc_.RateOfAttack_ ) * ( Delta * 0.05f ) );

				// Calculate velocity vector.
				CurrState_.Velocity_ = BcFixedVec2d( MoveTargetPosition_ - CurrState_.Position_ ).normal() * Desc_.MoveSpeed_;
				BcFixed MoveDistance = Desc_.MoveSpeed_ * Delta;
				if( ( CurrState_.Position_ - MoveTargetPosition_ ).magnitudeSquared() < ( MoveDistance * MoveDistance ) )
				{
					CurrState_.Position_ = MoveTargetPosition_;
					setBehaviourIdle();
				}
			}
		}
		break;

	case BEHAVIOUR_ATTACK:
		{
			TRange Range = inRangeForAttack( TargetUnitID_ );
			if( Range == RANGE_IN )
			{
				doAttack( TargetUnitID_ );
			}
			else
			{
				// Reset attack timer.
				AttackTimer_ = BcMax( AttackTimer_,  BcFixed( Desc_.CoolDownMultiplier_ ) / ( Desc_.RateOfAttack_ ) );

				// Make longer whe moving.
				AttackTimer_ = BcMin( BcFixed( 1.0f ) / Desc_.RateOfAttack_, AttackTimer_ + ( BcFixed( 1.0f ) / Desc_.RateOfAttack_ ) * ( Delta * 0.05f ) );

				// Get unit position.
				GaGameUnit* pUnit = pSimulator_->getUnit( TargetUnitID_ );
				if( pUnit != NULL )
				{
					BcFixedVec2d Direction = ( getPosition() - pUnit->getPosition() ).normal() * ( ( Desc_.MinRange_ + Desc_.Range_ ) * 0.5f );
					MoveTargetPosition_ = pUnit->getPosition() + Direction;
				}
				else
				{
					// Attack move to previous target.
					IsAttackMove_ = BcTrue;
					Behaviour_ = BEHAVIOUR_MOVE;
				}

				// Calculate velocity vector.
				CurrState_.Velocity_ = BcFixedVec2d( MoveTargetPosition_ - CurrState_.Position_ ).normal() * Desc_.MoveSpeed_;

				// If we moved further away, then stop and set target.
				BcFixed CurrMagnitudeSquared = ( CurrState_.Position_ - MoveTargetPosition_ ).magnitudeSquared();
				BcFixed PrevMagnitudeSquared = ( PrevState_.Position_ - MoveTargetPosition_ ).magnitudeSquared();
				if( CurrMagnitudeSquared > PrevMagnitudeSquared )
				{
					setBehaviourIdle();
				}
			}
		}
		break;

	case BEHAVIOUR_DAMAGE:
		{
			// Calculate velocity vector.
			CurrState_.Velocity_ = BcFixedVec2d( MoveTargetPosition_ - CurrState_.Position_ ).normal() * Desc_.MoveSpeed_;
			BcFixed MoveDistance = Desc_.MoveSpeed_ * Delta;
			if( ( CurrState_.Position_ - MoveTargetPosition_ ).magnitudeSquared() < ( MoveDistance * MoveDistance ) )
			{
				CurrState_.Position_ = MoveTargetPosition_;

				// Cause damage.
				pSimulator_->applyDamage( MoveTargetPosition_, Desc_.Range_, Desc_.Health_ );

				// Debug point!
				pSimulator_->addDebugPoint( getPosition(), Desc_.Range_, RsColour::YELLOW );

				if( Desc_.pHitSound_ != NULL )
				{
					GaTopState::pImpl()->playSound( Desc_.pHitSound_, MoveTargetPosition_ );
				}

				// Set as dead.
				setBehaviourDead();
			}
		}
		break;
	}

	// Attack timer.
	if( AttackTimer_ > 0.0f )
	{
		AttackTimer_ -= Delta;
	}
	else if( AttackTimer_ < 0.0f )
	{
		AttackTimer_ = 0.0f;
	}

	// Death.
	if( Health_ <= 0.0f )
	{
		Health_ = 0.0f;
		Behaviour_ = BEHAVIOUR_DEAD;
	}
}
//virtual
void ScnParticleSystemComponent::render( class ScnViewComponent* pViewComponent, RsFrame* pFrame, RsRenderSort Sort )
{
	// Wait for update fence.
	UpdateFence_.wait();

	// 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 MaVec2d HalfSize = Particle.Scale_ * 0.5f;
			const BcF32 MaxHalfSize = BcMax( HalfSize.x(), HalfSize.y() );
			BcAssert( Particle.TextureIndex_ < UVBounds_.size() );
			const MaVec4d& UVBounds( UVBounds_[ Particle.TextureIndex_ ] );

			// Crappy rotation implementation :P
			const BcF32 Radians = Particle.Rotation_;
			MaVec2d CornerA = MaVec2d( -1.0f, -1.0f ) * HalfSize;
			MaVec2d CornerB = MaVec2d(  1.0f, -1.0f ) * HalfSize;
			MaVec2d CornerC = MaVec2d(  1.0f,  1.0f ) * HalfSize;
			MaVec2d CornerD = MaVec2d( -1.0f,  1.0f ) * HalfSize;
			if( Radians != NULL )
			{
				MaMat4d Rotation;
				Rotation.rotation( MaVec3d( 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_ = UVBounds.x();
			VertexA.V_ = 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_ = UVBounds.z();
			VertexB.V_ = 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_ = UVBounds.z();
			VertexC.V_ = 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_ = UVBounds.z();
			VertexD.V_ = 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_ = UVBounds.x();
			VertexE.V_ = 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_ = UVBounds.x();
			VertexF.V_ = UVBounds.y();
			VertexF.RGBA_ = Colour;
			
			//
			++NoofParticlesToRender;
		}
	}

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

	// Draw particles last.
	if( NoofParticlesToRender > 0 )
	{
		Sort.Layer_ = 15;

		// Bind material.
		if( IsLocalSpace_ )
		{
			const MaMat4d& WorldTransform = getParentEntity()->getWorldMatrix();
			MaterialComponent_->setParameter( WorldTransformParam_, WorldTransform );
		}
		else
		{
			MaterialComponent_->setParameter( WorldTransformParam_, MaMat4d() );
		}

		// Set material parameters for view.
		pViewComponent->setMaterialParameters( MaterialComponent_ );

		// Bind material component.
		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 );
	}
}