//////////////////////////////////////////////////////////////////////////
// update
//virtual
void GaSpeechBubbleComponent::update( BcF32 Tick )
{
	Super::update( Tick );

	if ( !FontComponent_.isValid() )
	{
		Canvas_ = ParentEntity_->getComponentAnyParentByType< ScnCanvasComponent >();
		FontComponent_ = ParentEntity_->getComponentAnyParentByType< ScnFontComponent >();
	}
	if ( !SpeechBubble_.isValid() )
	{
		SpeechBubble_ = ParentEntity_->getComponentByType<ScnSpriteComponent>( BcName( "SpeechBubbleComponent", 0 ) );
	}
	if ( SpeechBubble_.isValid() )
	{
		SpeechBubble_->setColour( RsColour( 1, 1, 1, Visible_ ? 0.8 : 0 ) );
	}
	if ( !TargetEntity_.isValid() )
	{
		// We aren't even gonna bother
		return;
	}

	MaMat4d TextScaleMatrix;
	//TextScaleMatrix.scale( MaVec4d( 0.04f, 0.04f, 1.0f, 1.0f ) );
	TextScaleMatrix.scale( MaVec4d( 1.00f, -1.00f, 1.0f, 1.0f ) );

	FontComponent_->setAlphaTestStepping( MaVec2d( 0.4f, 0.45f ) );


	if (Visible_)
	{
		TimeBeenVisible_ += Tick;
		if ( TimeBeenVisible_ > VisibleTime_ )
			Visible_ = false;
		//MaMat4d Matrix = getParentEntity()->getWorldMatrix();
		//Matrix = Canvas_->popMatrix();
		Canvas_->pushMatrix( TextScaleMatrix );
	
		MaVec2d Size;
		MaVec3d worldPos = TargetEntity_->getWorldPosition();
		MaVec2d Position( 0 , 0 );
		MaVec2d localPos  = SpeechBubble_->getPosition();
		localPos  = MaVec2d(TargetEntity_->getWorldPosition().x(), -TargetEntity_->getWorldPosition().y() ) + FontOffset_;
		SpeechBubble_->setPosition( MaVec2d( TargetEntity_->getWorldPosition().x(), TargetEntity_->getWorldPosition().y() )  + SpriteOffset_ );
		for( BcU32 Idx = 0; Idx < Text_.size(); ++Idx )
		{
			const auto& Option( Text_[ Idx ] );
			const auto Colour = RsColour::BLACK;
			Size = FontComponent_->drawCentered( Canvas_, localPos + Position, Text_[ Idx ] , Colour, 280 );
			Position += MaVec2d( 0.0f, Size.y() );
		}



		Canvas_->popMatrix();
	}
	//Canvas_->pushMatrix( Matrix );
	//Canvas_->setMatrix( Matrix );
}
예제 #2
0
//////////////////////////////////////////////////////////////////////////
// getScreenPosition
MaVec2d ScnViewComponent::getScreenPosition( const MaVec3d& WorldPosition ) const
{
	MaVec4d ScreenSpace = MaVec4d( WorldPosition, 1.0f ) * ViewUniformBlock_.ClipTransform_;
	MaVec2d ScreenPosition = MaVec2d( ScreenSpace.x() / ScreenSpace.w(), -ScreenSpace.y() / ScreenSpace.w() );

	BcF32 HalfW = BcF32( Viewport_.width() ) * 0.5f;
	BcF32 HalfH = BcF32( Viewport_.height() ) * 0.5f;
	return MaVec2d( ( ScreenPosition.x() * HalfW ), ( ScreenPosition.y() * HalfH ) );
}
예제 #3
0
//////////////////////////////////////////////////////////////////////////
// setMouseLock
void OsClientWindows::setMouseLock( BcBool Enabled )
{
	// Hide cursor too.
	CURSORINFO CursorInfo;
	CursorInfo.cbSize = sizeof(CursorInfo);
	GetCursorInfo( &CursorInfo );

	if( Enabled )
	{
		if( MouseLocked_ == BcFalse )
		{
			POINT MousePosition;
			POINT WindowPosition;
			RECT Rect;

			// Get window rect in screen space.
			::GetWindowRect( hWnd_, &Rect );
		
			// Screen space cood of the client area.
			WindowPosition.x = 0;
			WindowPosition.y = 0;
			::ClientToScreen( hWnd_, &WindowPosition );
		
			// Get the cursor position
			::GetCursorPos( &MousePosition );

			const BcS32 WX = ( Rect.right - Rect.left );
			const BcS32 WY = ( Rect.bottom - Rect.top );

			// Reset delta.
			MouseDelta_ = MaVec2d( 0.0f, 0.0f );
			MousePrevDelta_ = MaVec2d( 0.0f, 0.0f );

			// Position in center of screen.
			::SetCursorPos( Rect.left + ( WX / 2 ), Rect.top + ( WY / 2 ) );

			if ( CursorInfo.flags == CURSOR_SHOWING )
			{
				while ( ShowCursor( FALSE ) >= 0 )
				{
				}
			}
		}
	}
	else
	{
		if ( CursorInfo.flags != CURSOR_SHOWING )
		{
			while ( ShowCursor( TRUE ) < 0 )
			{
			}
		}
	}

	MouseLocked_ = Enabled;
}
예제 #4
0
//////////////////////////////////////////////////////////////////////////
// setupTopology
void GaStructureComponent::setupTopology()
{
	// Setup physics.
	std::vector< GaPhysicsPointMass > PointMasses;
	std::vector< GaPhysicsConstraint > Constraints;
	PointMasses.reserve( 4 );
	Constraints.reserve( 6 );

	// TODO: Calculate this *properly* instead of drunkenly guessing?
	const BcF32 Size = 64.0f;
	const BcF32 PointMass = 1.0f;
	MaVec2d Offsets[3] = 
	{
		MaVec2d( 0.0f, -1.0f ) * Size * 0.5f,
		MaVec2d( -0.9f, 0.5f ) * Size * 0.5f,
		MaVec2d( 0.9f, 0.5f ) * Size * 0.5f,
	};
	/*
	if( StructureType_ == GaStructureType::BASE )
	{
		Offsets[0] = MaVec2d( 0.0f, -1.0f ) * Size * 0.5f;
		Offsets[1] = MaVec2d( -0.9f, 1.5f ) * Size * 0.5f;
		Offsets[2] = MaVec2d( 0.9f, 1.5f ) * Size * 0.5f;
	}
	*/

	MaVec2d Position = getParentEntity()->getWorldPosition().xy();

	// Central point + external constraints.
	PointMasses.emplace_back( GaPhysicsPointMass( Position, 0.05f, 1.0f / PointMass ) );
	Constraints.emplace_back( GaPhysicsConstraint( 0, 1, -1.0f, 0.1f ) );
	Constraints.emplace_back( GaPhysicsConstraint( 0, 2, -1.0f, 0.1f ) );
	Constraints.emplace_back( GaPhysicsConstraint( 0, 3, -1.0f, 0.1f ) );

	// Outer edges.
	for( size_t Idx = 0; Idx < 3; ++Idx )
	{
		const MaVec2d Offset( Offsets[ Idx ] );
		PointMasses.emplace_back( GaPhysicsPointMass( Position + Offset, 0.01f, 1.0f / PointMass ) );
		Constraints.emplace_back( GaPhysicsConstraint( 1 + Idx, 1 + ( ( Idx + 1 ) % 3 ), -1.0f, 1.0f ) );
	}

	WeightedPoints_.push_back( 1 );
	BouyantPoints_.push_back( 2 );
	BouyantPoints_.push_back( 3 );

	Physics_ = getParentEntity()->getComponentByType< GaPhysicsComponent >();
	BcAssert( Physics_ );
	Physics_->setup( std::move( PointMasses ), std::move( Constraints ) );

	// Grab absolute position.
	AbsolutePosition_ = getParentEntity()->getWorldPosition().xy();

	PSY_LOG( "GaStructureComponent::setupTopology: %f, %f", AbsolutePosition_.x(), AbsolutePosition_.y() );
}
//////////////////////////////////////////////////////////////////////////
// initialise
void GaSpeechBubbleComponent::initialise()
{
	VisibleTime_ = 5.0f;
	TimeBeenVisible_ = 0.0f;
	RequiredSize_ = 0.0f;
	Visible_ = true;
	/*Text_.push_back(" ");
	Text_.push_back("I must escape");
	Text_.push_back("escape this");
	Text_.push_back("cage!");/**/

	FontOffset_ = MaVec2d( -165.0f, -210.0f );
	SpriteOffset_ = MaVec2d( -340.0f, 350.0f );
}
예제 #6
0
//////////////////////////////////////////////////////////////////////////
// drawLineBox
void ScnCanvasComponent::drawLineBox( const MaVec2d& CornerA, const MaVec2d& CornerB, const RsColour& Colour, BcU32 Layer )
{
	// SLOW.
	drawLine( MaVec2d( CornerA.x(), CornerA.y() ), MaVec2d( CornerB.x(), CornerA.y() ), Colour, Layer );
	drawLine( MaVec2d( CornerB.x(), CornerA.y() ), MaVec2d( CornerB.x(), CornerB.y() ), Colour, Layer );
	drawLine( MaVec2d( CornerB.x(), CornerB.y() ), MaVec2d( CornerA.x(), CornerB.y() ), Colour, Layer );
	drawLine( MaVec2d( CornerA.x(), CornerB.y() ), MaVec2d( CornerA.x(), CornerA.y() ), Colour, Layer );
}
//////////////////////////////////////////////////////////////////////////
// allocParticle
BcBool ScnParticleSystemComponent::allocParticle( ScnParticle*& pParticle )
{
	// We can't be allocating whilst we're updating.
	BcAssert( UpdateFence_.count() == 0 );

	// TODO: Perhaps a free list of indices? Reordering of dead particles?
	//       Either way I want the update to be cache friendly.
	for( BcU32 Idx = 0; Idx < NoofParticles_; ++Idx )
	{
		BcU32 RealIdx = ( Idx + PotentialFreeParticle_ ) % NoofParticles_; // Slow. If we use powers of 2, we can &.
		ScnParticle* pPotentiallyFreeParticle = &pParticleBuffer_[ RealIdx ];

		if( pPotentiallyFreeParticle->Alive_ == BcFalse )
		{
			pParticle = pPotentiallyFreeParticle;

			// Prevent it being rendered for the first frame.
			pParticle->Scale_ = MaVec2d( 0.0f, 0.0 );
			pParticle->Colour_ = RsColour( 0.0f, 0.0f, 0.0f, 0.0f );

			++PotentialFreeParticle_;
			return BcTrue;
		}
	}
	
	return BcFalse;
}
예제 #8
0
//////////////////////////////////////////////////////////////////////////
// update
//virtual
void GaIntroComponent::update( BcF32 Tick )
{
	OsClient* Client = OsCore::pImpl()->getClient( 0 );
	BcF32 HalfWidth = static_cast< BcF32 >( Client->getWidth() / 2 );
	BcF32 HalfHeight = static_cast< BcF32 >( Client->getHeight() / 2 );

	{
		std::string Title = "Mined the 'roids!\nA game by NeiloGD for Ludum Dare 32!";
		std::string Message = 
			
			"The aim of the game is to eliminate your competitor, Blue Corp., from the 'roid mining business."
			"Unfortunately, we can't simply attack them. It must look like an accident, or the law will be on to us.\n\n"
			"Click on the Red Inc. mothership, and it will show you its commands:\n"
			" - LMB to build a miner (Costs $50).\n"
			" - RMB to repair any damage (Costs $50).\n\n"
			"Click on a miner, then point at a 'roid to see its commands:\n"
			" - LMB to mine a 'roid.\n"
			" - RMB to 'accidentally' crash.\n\n"
			"Click on a miner, then point at a mothership to see its commands:\n"
			" - RMB to take mined asteroid bits back.\n\n";
		
		ScnFontDrawParams DrawParams = ScnFontDrawParams()
			.setSize( 50.0f )
			.setMargin( 32.0f )
			.setWrappingEnabled( BcTrue )
			.setTextColour( RsColour::WHITE )
			.setAlignment( ScnFontAlignment::HCENTRE | ScnFontAlignment::TOP );

		auto Size = Font_->drawText( Canvas_, DrawParams, MaVec2d( -HalfWidth, -HalfHeight ), MaVec2d( HalfWidth * 2.0f, 0.0f ), Title );

		DrawParams.setSize( 25.0f );
		DrawParams.setAlignment( ScnFontAlignment::LEFT | ScnFontAlignment::TOP );
		Font_->drawText( Canvas_, DrawParams, MaVec2d( -HalfWidth, -HalfHeight + Size.y() + DrawParams.getMargin() ), MaVec2d( HalfWidth * 2.0f, 0.0f ), Message );

		if( Timer_ > 5.0f )
		{
			DrawParams.setSize( 50.0f );
			DrawParams.setAlignment( ScnFontAlignment::HCENTRE | ScnFontAlignment::BOTTOM );
			DrawParams.setTextColour( RsColour::GREEN );
			Font_->drawText( Canvas_, DrawParams, MaVec2d( -HalfWidth, -HalfHeight ), MaVec2d( HalfWidth * 2.0f, HalfHeight * 2.0f ), "Press any key to start!" );
		}
	}

	Timer_ += Tick;

	Super::update( Tick );
}
예제 #9
0
//////////////////////////////////////////////////////////////////////////
// getWorldPosition
void ScnViewComponent::getWorldPosition( const MaVec2d& ScreenPosition, MaVec3d& Near, MaVec3d& Far ) const
{
	// TODO: Take normalised screen coordinates.
	MaVec2d Screen = ScreenPosition - MaVec2d( static_cast<BcF32>( Viewport_.x() ), static_cast<BcF32>( Viewport_.y() ) );
	const MaVec2d RealScreen( ( Screen.x() / Viewport_.width() ) * 2.0f - 1.0f, ( Screen.y() / Viewport_.height() ) * 2.0f - 1.0f );

	Near.set( RealScreen.x(), -RealScreen.y(), 0.0f );
	Far.set( RealScreen.x(), -RealScreen.y(), 1.0f );

	Near = Near * ViewUniformBlock_.InverseProjectionTransform_;
	Far = Far * ViewUniformBlock_.InverseProjectionTransform_;

	if( ViewUniformBlock_.ProjectionTransform_[3][3] == 0.0f )
	{
		Near *= Viewport_.zNear();
		Far *= Viewport_.zFar();
	}

	Near = Near * ViewUniformBlock_.InverseViewTransform_;
	Far = Far * ViewUniformBlock_.InverseViewTransform_;
}
//////////////////////////////////////////////////////////////////////////
// initialise
void GaSpeechBubbleComponent::initialise( const Json::Value& Object )
{
	GaSpeechBubbleComponent::initialise();

	if ( Object[ "requiredSize" ].type() != Json::nullValue )
		RequiredSize_ = BcF32( Object[ "requiredsize" ].asDouble() );

	if ( Object[ "visibletime" ].type() != Json::nullValue )
		VisibleTime_ = BcF32( Object[ "visibletime" ].asDouble() );

	if ( Object[ "visible" ].type() != Json::nullValue )
		Visible_ = ( Object[ "visible" ].asBool() );
	if ( Object[ "spriteoffset" ].type() != Json::nullValue )
		SpriteOffset_ = MaVec2d( Object[ "spriteoffset" ].asCString() );

	if ( Object[ "text" ].type() != Json::nullValue )
	{
		std::string text = Object[ "text" ].asString();
		setText(text);
		
	}
}
예제 #11
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 );
}
예제 #12
0
//////////////////////////////////////////////////////////////////////////
// Ctor
OsClientHTML5::OsClientHTML5()
{
	// Setup keycode map.
	KeyCodeMap_[ SDLK_CANCEL ] = OsEventInputKeyboard::KEYCODE_CANCEL;
	KeyCodeMap_[ SDLK_TAB ] = OsEventInputKeyboard::KEYCODE_TAB;
	KeyCodeMap_[ SDLK_CLEAR ] = OsEventInputKeyboard::KEYCODE_CLEAR;
	KeyCodeMap_[ SDLK_RETURN ] = OsEventInputKeyboard::KEYCODE_RETURN;
	KeyCodeMap_[ SDLK_MENU ] = OsEventInputKeyboard::KEYCODE_ALT;
	KeyCodeMap_[ SDLK_PAUSE ] = OsEventInputKeyboard::KEYCODE_PAUSE;
	KeyCodeMap_[ SDLK_ESCAPE ] = OsEventInputKeyboard::KEYCODE_ESCAPE;
	KeyCodeMap_[ SDLK_SPACE ] = OsEventInputKeyboard::KEYCODE_SPACE;
	KeyCodeMap_[ SDLK_PRIOR ] = OsEventInputKeyboard::KEYCODE_PGUP;
	KeyCodeMap_[ SDLK_END ] = OsEventInputKeyboard::KEYCODE_END;
	KeyCodeMap_[ SDLK_HOME ] = OsEventInputKeyboard::KEYCODE_HOME;
	KeyCodeMap_[ SDLK_LEFT ] = OsEventInputKeyboard::KEYCODE_LEFT;
	KeyCodeMap_[ SDLK_UP ] = OsEventInputKeyboard::KEYCODE_UP;
	KeyCodeMap_[ SDLK_RIGHT ] = OsEventInputKeyboard::KEYCODE_RIGHT;
	KeyCodeMap_[ SDLK_DOWN ] = OsEventInputKeyboard::KEYCODE_DOWN;
	KeyCodeMap_[ SDLK_SELECT ] = OsEventInputKeyboard::KEYCODE_SELECT;
	KeyCodeMap_[ SDLK_EXECUTE ] = OsEventInputKeyboard::KEYCODE_EXECUTE;
	KeyCodeMap_[ SDLK_INSERT ] = OsEventInputKeyboard::KEYCODE_INSERT;
	KeyCodeMap_[ SDLK_DELETE ] = OsEventInputKeyboard::KEYCODE_DELETE;
	KeyCodeMap_[ SDLK_HELP ] = OsEventInputKeyboard::KEYCODE_HELP;
	KeyCodeMap_[ SDLK_KP_0 ] = OsEventInputKeyboard::KEYCODE_NUMPAD0;
	KeyCodeMap_[ SDLK_KP_1 ] = OsEventInputKeyboard::KEYCODE_NUMPAD1;
	KeyCodeMap_[ SDLK_KP_2 ] = OsEventInputKeyboard::KEYCODE_NUMPAD2;
	KeyCodeMap_[ SDLK_KP_3 ] = OsEventInputKeyboard::KEYCODE_NUMPAD3;
	KeyCodeMap_[ SDLK_KP_4 ] = OsEventInputKeyboard::KEYCODE_NUMPAD4;
	KeyCodeMap_[ SDLK_KP_5 ] = OsEventInputKeyboard::KEYCODE_NUMPAD5;
	KeyCodeMap_[ SDLK_KP_6 ] = OsEventInputKeyboard::KEYCODE_NUMPAD6;
	KeyCodeMap_[ SDLK_KP_7 ] = OsEventInputKeyboard::KEYCODE_NUMPAD7;
	KeyCodeMap_[ SDLK_KP_8 ] = OsEventInputKeyboard::KEYCODE_NUMPAD8;
	KeyCodeMap_[ SDLK_KP_9 ] = OsEventInputKeyboard::KEYCODE_NUMPAD9;
	KeyCodeMap_[ SDLK_SEPARATOR ] = OsEventInputKeyboard::KEYCODE_SEPARATOR;
	KeyCodeMap_[ SDLK_KP_MINUS ] = OsEventInputKeyboard::KEYCODE_SUBTRACT;
	KeyCodeMap_[ SDLK_KP_PERIOD ] = OsEventInputKeyboard::KEYCODE_DECIMAL;
	KeyCodeMap_[ SDLK_KP_DIVIDE ] = OsEventInputKeyboard::KEYCODE_DIVIDE;
	KeyCodeMap_[ SDLK_F1 ] = OsEventInputKeyboard::KEYCODE_F1;
	KeyCodeMap_[ SDLK_F2 ] = OsEventInputKeyboard::KEYCODE_F2;
	KeyCodeMap_[ SDLK_F3 ] = OsEventInputKeyboard::KEYCODE_F3;
	KeyCodeMap_[ SDLK_F4 ] = OsEventInputKeyboard::KEYCODE_F4;
	KeyCodeMap_[ SDLK_F5 ] = OsEventInputKeyboard::KEYCODE_F5;
	KeyCodeMap_[ SDLK_F6 ] = OsEventInputKeyboard::KEYCODE_F6;
	KeyCodeMap_[ SDLK_F7 ] = OsEventInputKeyboard::KEYCODE_F7;
	KeyCodeMap_[ SDLK_F8 ] = OsEventInputKeyboard::KEYCODE_F8;
	KeyCodeMap_[ SDLK_F9 ] = OsEventInputKeyboard::KEYCODE_F9;
	KeyCodeMap_[ SDLK_F10 ] = OsEventInputKeyboard::KEYCODE_F10;
	KeyCodeMap_[ SDLK_F11 ] = OsEventInputKeyboard::KEYCODE_F11;
	KeyCodeMap_[ SDLK_F12 ] = OsEventInputKeyboard::KEYCODE_F12;
	KeyCodeMap_[ SDLK_F13 ] = OsEventInputKeyboard::KEYCODE_F13;
	KeyCodeMap_[ SDLK_F14 ] = OsEventInputKeyboard::KEYCODE_F14;
	KeyCodeMap_[ SDLK_F15 ] = OsEventInputKeyboard::KEYCODE_F15;
	KeyCodeMap_[ SDLK_F16 ] = OsEventInputKeyboard::KEYCODE_F16;
	KeyCodeMap_[ SDLK_F17 ] = OsEventInputKeyboard::KEYCODE_F17;
	KeyCodeMap_[ SDLK_F18 ] = OsEventInputKeyboard::KEYCODE_F18;
	KeyCodeMap_[ SDLK_F19 ] = OsEventInputKeyboard::KEYCODE_F19;
	KeyCodeMap_[ SDLK_F20 ] = OsEventInputKeyboard::KEYCODE_F20;
	KeyCodeMap_[ SDLK_F21 ] = OsEventInputKeyboard::KEYCODE_F21;
	KeyCodeMap_[ SDLK_F22 ] = OsEventInputKeyboard::KEYCODE_F22;
	KeyCodeMap_[ SDLK_F23 ] = OsEventInputKeyboard::KEYCODE_F23;
	KeyCodeMap_[ SDLK_F24 ] = OsEventInputKeyboard::KEYCODE_F24;

	PrevMouseX_ = 0;
	PrevMouseY_ = 0;
	MouseLocked_ = BcFalse;
	Width_ = 0;
	Height_ = 0;

	MousePrevDelta_ = MaVec2d( 0.0f, 0.0f );
	MouseDelta_ = MaVec2d( 0.0f, 0.0f );
	MousePos_ = MaVec2d( 0.0f, 0.0f );
}
예제 #13
0
//////////////////////////////////////////////////////////////////////////
// Ctor
OsClientWindows::OsClientWindows()
{
	// Setup keycode map.
	KeyCodeMap_[ VK_LBUTTON ] = OsEventInputKeyboard::KEYCODE_LBUTTON;
	KeyCodeMap_[ VK_RBUTTON ] = OsEventInputKeyboard::KEYCODE_RBUTTON;
	KeyCodeMap_[ VK_CANCEL ] = OsEventInputKeyboard::KEYCODE_CANCEL;
	KeyCodeMap_[ VK_MBUTTON ] = OsEventInputKeyboard::KEYCODE_MBUTTON;
	KeyCodeMap_[ VK_BACK ] = OsEventInputKeyboard::KEYCODE_BACKSPACE;
	KeyCodeMap_[ VK_TAB ] = OsEventInputKeyboard::KEYCODE_TAB;
	KeyCodeMap_[ VK_CLEAR ] = OsEventInputKeyboard::KEYCODE_CLEAR;
	KeyCodeMap_[ VK_RETURN ] = OsEventInputKeyboard::KEYCODE_RETURN;
	KeyCodeMap_[ VK_SHIFT ] = OsEventInputKeyboard::KEYCODE_SHIFT;
	KeyCodeMap_[ VK_CONTROL ] = OsEventInputKeyboard::KEYCODE_CONTROL;
	KeyCodeMap_[ VK_MENU ] = OsEventInputKeyboard::KEYCODE_ALT;
	KeyCodeMap_[ VK_PAUSE ] = OsEventInputKeyboard::KEYCODE_PAUSE;
	KeyCodeMap_[ VK_CAPITAL ] = OsEventInputKeyboard::KEYCODE_CAPSLOCK;
	KeyCodeMap_[ VK_ESCAPE ] = OsEventInputKeyboard::KEYCODE_ESCAPE;
	KeyCodeMap_[ VK_SPACE ] = OsEventInputKeyboard::KEYCODE_SPACE;
	KeyCodeMap_[ VK_PRIOR ] = OsEventInputKeyboard::KEYCODE_PGUP;
	KeyCodeMap_[ VK_NEXT ] = OsEventInputKeyboard::KEYCODE_PGDN;
	KeyCodeMap_[ VK_END ] = OsEventInputKeyboard::KEYCODE_END;
	KeyCodeMap_[ VK_HOME ] = OsEventInputKeyboard::KEYCODE_HOME;
	KeyCodeMap_[ VK_LEFT ] = OsEventInputKeyboard::KEYCODE_LEFT;
	KeyCodeMap_[ VK_UP ] = OsEventInputKeyboard::KEYCODE_UP;
	KeyCodeMap_[ VK_RIGHT ] = OsEventInputKeyboard::KEYCODE_RIGHT;
	KeyCodeMap_[ VK_DOWN ] = OsEventInputKeyboard::KEYCODE_DOWN;
	KeyCodeMap_[ VK_SELECT ] = OsEventInputKeyboard::KEYCODE_SELECT;
	KeyCodeMap_[ VK_PRINT ] = OsEventInputKeyboard::KEYCODE_PRINT;
	KeyCodeMap_[ VK_EXECUTE ] = OsEventInputKeyboard::KEYCODE_EXECUTE;
	KeyCodeMap_[ VK_SNAPSHOT ] = OsEventInputKeyboard::KEYCODE_PRINT_SCREEN;
	KeyCodeMap_[ VK_INSERT ] = OsEventInputKeyboard::KEYCODE_INSERT;
	KeyCodeMap_[ VK_DELETE ] = OsEventInputKeyboard::KEYCODE_DELETE;
	KeyCodeMap_[ VK_HELP ] = OsEventInputKeyboard::KEYCODE_HELP;
	KeyCodeMap_[ VK_NUMPAD0 ] = OsEventInputKeyboard::KEYCODE_NUMPAD0;
	KeyCodeMap_[ VK_NUMPAD1 ] = OsEventInputKeyboard::KEYCODE_NUMPAD1;
	KeyCodeMap_[ VK_NUMPAD2 ] = OsEventInputKeyboard::KEYCODE_NUMPAD2;
	KeyCodeMap_[ VK_NUMPAD3 ] = OsEventInputKeyboard::KEYCODE_NUMPAD3;
	KeyCodeMap_[ VK_NUMPAD4 ] = OsEventInputKeyboard::KEYCODE_NUMPAD4;
	KeyCodeMap_[ VK_NUMPAD5 ] = OsEventInputKeyboard::KEYCODE_NUMPAD5;
	KeyCodeMap_[ VK_NUMPAD6 ] = OsEventInputKeyboard::KEYCODE_NUMPAD6;
	KeyCodeMap_[ VK_NUMPAD7 ] = OsEventInputKeyboard::KEYCODE_NUMPAD7;
	KeyCodeMap_[ VK_NUMPAD8 ] = OsEventInputKeyboard::KEYCODE_NUMPAD8;
	KeyCodeMap_[ VK_NUMPAD9 ] = OsEventInputKeyboard::KEYCODE_NUMPAD9;
	KeyCodeMap_[ VK_SEPARATOR ] = OsEventInputKeyboard::KEYCODE_SEPARATOR;
	KeyCodeMap_[ VK_SUBTRACT ] = OsEventInputKeyboard::KEYCODE_SUBTRACT;
	KeyCodeMap_[ VK_DECIMAL ] = OsEventInputKeyboard::KEYCODE_DECIMAL;
	KeyCodeMap_[ VK_DIVIDE ] = OsEventInputKeyboard::KEYCODE_DIVIDE;
	KeyCodeMap_[ VK_F1 ] = OsEventInputKeyboard::KEYCODE_F1;
	KeyCodeMap_[ VK_F2 ] = OsEventInputKeyboard::KEYCODE_F2;
	KeyCodeMap_[ VK_F3 ] = OsEventInputKeyboard::KEYCODE_F3;
	KeyCodeMap_[ VK_F4 ] = OsEventInputKeyboard::KEYCODE_F4;
	KeyCodeMap_[ VK_F5 ] = OsEventInputKeyboard::KEYCODE_F5;
	KeyCodeMap_[ VK_F6 ] = OsEventInputKeyboard::KEYCODE_F6;
	KeyCodeMap_[ VK_F7 ] = OsEventInputKeyboard::KEYCODE_F7;
	KeyCodeMap_[ VK_F8 ] = OsEventInputKeyboard::KEYCODE_F8;
	KeyCodeMap_[ VK_F9 ] = OsEventInputKeyboard::KEYCODE_F9;
	KeyCodeMap_[ VK_F10 ] = OsEventInputKeyboard::KEYCODE_F10;
	KeyCodeMap_[ VK_F11 ] = OsEventInputKeyboard::KEYCODE_F11;
	KeyCodeMap_[ VK_F12 ] = OsEventInputKeyboard::KEYCODE_F12;
	KeyCodeMap_[ VK_F13 ] = OsEventInputKeyboard::KEYCODE_F13;
	KeyCodeMap_[ VK_F14 ] = OsEventInputKeyboard::KEYCODE_F14;
	KeyCodeMap_[ VK_F15 ] = OsEventInputKeyboard::KEYCODE_F15;
	KeyCodeMap_[ VK_F16 ] = OsEventInputKeyboard::KEYCODE_F16;
	KeyCodeMap_[ VK_F17 ] = OsEventInputKeyboard::KEYCODE_F17;
	KeyCodeMap_[ VK_F18 ] = OsEventInputKeyboard::KEYCODE_F18;
	KeyCodeMap_[ VK_F19 ] = OsEventInputKeyboard::KEYCODE_F19;
	KeyCodeMap_[ VK_F20 ] = OsEventInputKeyboard::KEYCODE_F20;
	KeyCodeMap_[ VK_F21 ] = OsEventInputKeyboard::KEYCODE_F21;
	KeyCodeMap_[ VK_F22 ] = OsEventInputKeyboard::KEYCODE_F22;
	KeyCodeMap_[ VK_F23 ] = OsEventInputKeyboard::KEYCODE_F23;
	KeyCodeMap_[ VK_F24 ] = OsEventInputKeyboard::KEYCODE_F24;
	KeyCodeMap_[ VK_NUMLOCK ] = OsEventInputKeyboard::KEYCODE_NUMLOCK;
	KeyCodeMap_[ VK_SCROLL ] = OsEventInputKeyboard::KEYCODE_SCROLL;
	KeyCodeMap_[ VK_LSHIFT ] = OsEventInputKeyboard::KEYCODE_LSHIFT;
	KeyCodeMap_[ VK_RSHIFT ] = OsEventInputKeyboard::KEYCODE_RSHIFT;
	KeyCodeMap_[ VK_LCONTROL ] = OsEventInputKeyboard::KEYCODE_LCONTROL;
	KeyCodeMap_[ VK_RCONTROL ] = OsEventInputKeyboard::KEYCODE_RCONTROL;
	KeyCodeMap_[ VK_LMENU ] = OsEventInputKeyboard::KEYCODE_LMENU;
	KeyCodeMap_[ VK_RMENU ] = OsEventInputKeyboard::KEYCODE_RMENU;
	KeyCodeMap_[ VK_PLAY ] = OsEventInputKeyboard::KEYCODE_PLAY;
	KeyCodeMap_[ VK_ZOOM ] = OsEventInputKeyboard::KEYCODE_ZOOM;

	PrevMouseX_ = 0;
	PrevMouseY_ = 0;
	MouseLocked_ = BcFalse;

	MousePrevDelta_ = MaVec2d( 0.0f, 0.0f );
	MouseDelta_ = MaVec2d( 0.0f, 0.0f );
	MousePos_ = MaVec2d( 0.0f, 0.0f );
}
예제 #14
0
//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 );
	}
}
예제 #15
0
//////////////////////////////////////////////////////////////////////////
// update
void GaStructureComponent::update( BcF32 Tick )
{
	// Get water.
	auto Water = getParentEntity()->getComponentAnyParentByType< GaWaterComponent >();

	// If we have point masses, calculate position.
	const size_t NoofPointMasses = Physics_->getNoofPointMasses();
	if( Physics_->getNoofPointMasses() > 0 )
	{
		// Points with weight.
		const BcF32 Gravity = 500.0f;
		for( auto WeightedPoint : WeightedPoints_ )
		{
			Physics_->setPointMassAcceleration( WeightedPoint, MaVec2d( 0.0f, Gravity ) );
		}

		// Points with bouyancy.
		for( auto BouyantPoint : BouyantPoints_ )
		{
			const auto& PointMass = Physics_->getPointMass( BouyantPoint );
			auto WaterPosition = Water->getWaterSurfacePosition( PointMass.CurrPosition_ );
			BcF32 Diff = PointMass.CurrPosition_.y() - WaterPosition.y();

			if( Diff > 1.0f )
			{
				Physics_->setPointMassAcceleration( BouyantPoint, MaVec2d( 0.0f, -Gravity ) );
			}
			else
			{
				Physics_->setPointMassAcceleration( BouyantPoint, MaVec2d( 0.0f, Gravity ) );
			}
		}

		// Position.
		MaVec2d Centre( Physics_->getPointMassPosition( 0 ) );
		getParentEntity()->setLocalPosition( MaVec3d( Centre, 0.0f ) );

		// Rotation.
		MaVec2d Direction = Centre - Physics_->getPointMassPosition( 1 ); 
		BcF32 Angle = std::atan2f( Direction.x(), Direction.y() );
		Sprite_->setRotation( Angle );

		if( Timer_ <= CalculatedFireRate_ )
		{
			Timer_ += Tick;
		}
	}
	
	switch( StructureType_ )
	{
	case GaStructureType::BASE:
		break;
	case GaStructureType::TURRET:
		if( Timer_ >= CalculatedFireRate_ )
		{
			// Find a tentacle.
			GaTentacleComponent* NearestTentacle = Game_->getNearestTentacle( getParentEntity()->getWorldPosition().xy(), BcFalse );
			if( NearestTentacle == nullptr )
			{
				NearestTentacle = Game_->getNearestTentacle( getParentEntity()->getWorldPosition().xy(), BcTrue );
			}
				
			// Spawn a projectile.
			if( NearestTentacle && TemplateProjectile_ )
			{
				auto Entity = ScnCore::pImpl()->spawnEntity( ScnEntitySpawnParams( 
					BcName::INVALID, TemplateProjectile_,
					getParentEntity()->getWorldMatrix(),
					Game_->getParentEntity() ) );
				auto Projectile = Entity->getComponentByType< GaProjectileComponent >();
				Projectile->setLevel( Level_ );
				Projectile->setTarget( NearestTentacle->getParentEntity() );
				Game_->launchProjectile( Projectile );

				// Time to spawn!
				Timer_ -= CalculatedFireRate_;
			}
		}
		break;

	case GaStructureType::RESOURCE:
		break;

	case GaStructureType::POTATO:
		break;

	case GaStructureType::MINE:
		break;
	}
}
예제 #16
0
//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_;

	// Calculate lock size.
	BcU32 NoofParticlesToRender = 0;
	for( BcU32 Idx = 0; Idx < NoofParticles_; ++Idx )
	{
		ScnParticle& Particle = pParticleBuffer_[ Idx ];

		if( Particle.Alive_ )
		{
			++NoofParticlesToRender;
		}
	}

	// Lock vertex buffer.
	if( NoofParticlesToRender > 0 )
	{
		UploadFence_.increment();
		RsCore::pImpl()->updateBuffer( 
			VertexBuffer.pVertexBuffer_,
			0,
			NoofParticlesToRender * sizeof( ScnParticleVertex ) * 6,
			RsResourceUpdateFlags::ASYNC,
			[ this, NoofParticlesToRender ]
			( RsBuffer* Buffer, const RsBufferLock& Lock )
			{
				BcU32 NoofParticlesRendered = 0;
				ScnParticleVertex* pVertex = reinterpret_cast< ScnParticleVertex* >( Lock.Buffer_ );
				for( BcU32 Idx = 0; Idx < NoofParticles_; ++Idx )
				{
					ScnParticle& Particle = pParticleBuffer_[ Idx ];

					if( Particle.Alive_ )
					{
						++NoofParticlesRendered;

						// Half size.
						const MaVec2d HalfSize = Particle.Scale_ * 0.5f;
						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 != 0.0f )
						{
							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.W_ = 1.0f;
						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.W_ = 1.0f;
						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.W_ = 1.0f;
						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.W_ = 1.0f;
						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.W_ = 1.0f;
						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.W_ = 1.0f;
						VertexF.NX_ = CornerA.x();
						VertexF.NY_ = CornerA.y();
						VertexF.NZ_ = 0.0f;
						VertexF.U_ = UVBounds.x();
						VertexF.V_ = UVBounds.y();
						VertexF.RGBA_ = Colour;
					}
				}

				BcAssert( NoofParticlesRendered == NoofParticlesToRender );
				UploadFence_.decrement();
			} );
	}

	// Update uniform buffer.
	if( IsLocalSpace_ )
	{
		VertexBuffer.ObjectUniforms_.WorldTransform_ = getParentEntity()->getWorldMatrix();
	}
	else
	{
		VertexBuffer.ObjectUniforms_.WorldTransform_ = MaMat4d();
	}

	// Upload uniforms.
	RsCore::pImpl()->updateBuffer( 
		VertexBuffer.UniformBuffer_,
		0, sizeof( VertexBuffer.ObjectUniforms_ ),
		RsResourceUpdateFlags::ASYNC,
		[ this, VertexBuffer ]( RsBuffer* Buffer, const RsBufferLock& Lock )
		{
			BcMemCopy( Lock.Buffer_, &VertexBuffer.ObjectUniforms_, sizeof( VertexBuffer.ObjectUniforms_ ) );
		} );

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

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

		// Bind material component.
		MaterialComponent_->bind( pFrame, Sort );

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

		// Add to frame.
		pRenderNode->Sort_ = Sort;
		pFrame->addRenderNode( pRenderNode );
	}
}