示例#1
0
//////////////////////////////////////////////////////////////////////////
// findLongestDirection
MaVec3d GaEnemyComponent::findLongestDirection()
{
	// Ray cast in the 4 directions to determine path.
	BcF32 LongestDistance = 0.0f;
	MaVec3d LongestDirection( 0.0f, 0.0f, 0.0f );
	MaVec3d Directions[] =
	{
		MaVec3d(  1.0f,  0.0f,  0.0f ),
		MaVec3d( -1.0f,  0.0f,  0.0f ),
		MaVec3d(  0.0f,  1.0f,  0.0f ),
		MaVec3d(  0.0f, -1.0f,  0.0f ),
	};

	MaVec3d Position = getParentEntity()->getWorldPosition();

	BcBSPPointInfo BSPPointInfo;
	for( BcU32 Idx = 0; Idx < 4; ++Idx )
	{
		if( BSP_->lineIntersection( Position, Position + Directions[ Idx ] * 256.0f, &BSPPointInfo ) )
		{
			if( BSPPointInfo.Distance_ > LongestDistance )
			{
				LongestDistance = BSPPointInfo.Distance_;
				LongestDirection = Directions[ Idx ];
			}
		}
	}
	
	BcPrintf( "GaEnemyComponent: Got direction [%.1f, %.1f, %.f1]\n", LongestDirection.x(), LongestDirection.y(), LongestDirection.z() );

	return LongestDirection;
}
	virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)
	{
		ScnDebugRenderComponent::pImpl()->drawLine(
			MaVec3d( from.x(), from.y(), from.z() ),
			MaVec3d( to.x(), to.y(), to.z() ),
			RsColour( color.x(), color.y(), color.z(), 1.0f ) );
	}
//////////////////////////////////////////////////////////////////////////
// drawEllipsoid
void ScnDebugRenderComponent::drawEllipsoid( const MaVec3d& Position, const MaVec3d& Size, const RsColour& Colour, BcU32 Layer )
{
	// Draw outer circles for all axis.
	BcU32 LOD = 16;
	BcF32 Angle = 0.0f;
	BcF32 AngleInc = ( BcPI * 2.0f ) / BcF32( LOD );

	// Draw axis lines.
	for( BcU32 i = 0; i < LOD; ++i )
	{
		MaVec2d PosA( BcCos( Angle ), -BcSin( Angle ) );
		MaVec2d PosB( BcCos( Angle + AngleInc ), -BcSin( Angle + AngleInc ) );

		MaVec3d XAxisA = MaVec3d( 0.0f,                 PosA.x() * Size.y(), PosA.y() * Size.z() );
		MaVec3d YAxisA = MaVec3d( PosA.x() * Size.x(), 0.0f,                 PosA.y() * Size.z() );
		MaVec3d ZAxisA = MaVec3d( PosA.x() * Size.x(), PosA.y() * Size.y(), 0.0f                 );
		MaVec3d XAxisB = MaVec3d( 0.0f,                 PosB.x() * Size.y(), PosB.y() * Size.z() );
		MaVec3d YAxisB = MaVec3d( PosB.x() * Size.x(), 0.0f,                 PosB.y() * Size.z() );
		MaVec3d ZAxisB = MaVec3d( PosB.x() * Size.x(), PosB.y() * Size.y(), 0.0f                 );

		drawLine( XAxisA + Position, XAxisB + Position, Colour, 0 );
		drawLine( YAxisA + Position, YAxisB + Position, Colour, 0 );
		drawLine( ZAxisA + Position, ZAxisB + Position, Colour, 0 );

		Angle += AngleInc;
	}

	// Draw a cross down centre.
	MaVec3d XAxis = MaVec3d( Size.x(), 0.0f, 0.0f );
	MaVec3d YAxis = MaVec3d( 0.0f, Size.y(), 0.0f );
	MaVec3d ZAxis = MaVec3d( 0.0f, 0.0f, Size.z() );
	drawLine( Position - XAxis, Position + XAxis, Colour, Layer );
	drawLine( Position - YAxis, Position + YAxis, Colour, Layer );
	drawLine( Position - ZAxis, Position + ZAxis, Colour, Layer );
}
示例#4
0
//////////////////////////////////////////////////////////////////////////
// setMaterialParameters
void ScnLightComponent::setMaterialParameters( BcU32 LightIndex, ScnMaterialComponent* MaterialComponent )
{
	const MaVec4d& Position( getParentEntity()->getWorldMatrix().row3() );
	const MaVec4d& Direction( getParentEntity()->getWorldMatrix().row2() );
	MaterialComponent->setLightParameters( LightIndex,
	                                       MaVec3d( Position.x(), Position.y(), Position.z() ),
	                                       MaVec3d( Direction.x(), Direction.y(), Direction.z() ),
	                                       AmbientColour_,
										   DiffuseColour_,
	                                       AttnC_,
	                                       AttnL_,
	                                       AttnQ_ );
}
示例#5
0
//////////////////////////////////////////////////////////////////////////b
// initialise
void GaRobotComponent::initialise( const Json::Value& Object )
{
	Team_ = Object[ "team" ].asUInt();

	TargetDistance_ = 1.0f;
	TargetPosition_ = MaVec3d( 0.0f, 0.0f, 0.0f );
	MaxVelocity_ = 4.0f;

	Health_ = 100.0f;
	Energy_ = 0.0f;
	EnergyChargeRate_ = 5.0f;

	WeaponACoolDown_ = 0.1f;
	WeaponACost_ = 10.0f;
	WeaponATimer_ = 0.0f;
	WeaponBCoolDown_ = 4.0f;
	WeaponBCost_ = 50.0f;
	WeaponBTimer_ = 0.0f;
	MoveTimer_ = 0.0f;
	
	CurrentState_ = 0;
	CurrentOp_ = 0;
	NextOp_ = 0;
	CurrentOpTimer_ = 0.0f;
	CurrentOpTime_ = 0.1f;

	MoveAngle_ = 0.0f;
}
示例#6
0
//////////////////////////////////////////////////////////////////////////
// initialise
//virtual
void ScnSoundEmitterComponent::initialise( const Json::Value& Object )
{
	Super::initialise();

	Position_ = MaVec3d( 0.0f, 0.0f, 0.0f );
	Gain_ = 1.0f;
	Pitch_ = 1.0f;	
}
//////////////////////////////////////////////////////////////////////////
// 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();
}
示例#8
0
//////////////////////////////////////////////////////////////////////////
// bakeTransform
void MdlMesh::bakeTransform( const MaMat4d& Transform )
{
	MaMat4d NrmTransform = Transform;
	NrmTransform.translation( MaVec3d( 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();
	}
}
示例#9
0
//////////////////////////////////////////////////////////////////////////
// addPrimitive
void ScnCanvasComponent::addPrimitive( 
		RsTopologyType Type, 
		ScnCanvasComponentVertex* pVertices, 
		BcU32 NoofVertices, 
		BcU32 Layer, 
		BcBool UseMatrixStack )
{
	BcAssertMsg( MaterialComponent_.isValid(), "ScnCanvasComponent: Material component has not been set!" );

	// Check if the vertices are owned by us, if not copy in.
	if( pVertices < pVertices_ || pVertices_ >= pVerticesEnd_ )
	{
		ScnCanvasComponentVertex* pNewVertices = allocVertices( NoofVertices );
		if( pNewVertices != NULL )
		{
			BcMemCopy( pNewVertices, pVertices, sizeof( ScnCanvasComponentVertex ) * NoofVertices );
			pVertices = pNewVertices;
		}
	}
	
	// Matrix stack.
	if( UseMatrixStack == BcTrue && IsIdentity_ == BcFalse )
	{
		MaMat4d Matrix = getMatrix();

		for( BcU32 Idx = 0; Idx < NoofVertices; ++Idx )
		{
			ScnCanvasComponentVertex* pVertex = &pVertices[ Idx ];
			MaVec3d Vertex = MaVec3d( pVertex->X_, pVertex->Y_, pVertex->Z_ ) * Matrix;
			pVertex->X_ = Vertex.x();
			pVertex->Y_ = Vertex.y();
			pVertex->Z_ = Vertex.z();
		}
	}
	
	// TODO: If there was a previous primitive which we can marge into, attempt to.
	BcU32 VertexIndex = convertVertexPointerToIndex( pVertices );
	ScnCanvasComponentPrimitiveSection PrimitiveSection = 
	{
		Type,
		VertexIndex,
		NoofVertices,
		Layer,
		MaterialComponent_,
		nullptr
	};
	
	PrimitiveSectionList_.push_back( PrimitiveSection );
	LastPrimitiveSection_ = (BcU32)PrimitiveSectionList_.size() - 1;
}
//////////////////////////////////////////////////////////////////////////
// lineCast
BcBool ScnPhysicsWorldComponent::lineCast( const MaVec3d& A, const MaVec3d& B, MaVec3d& Intersection, MaVec3d& Normal )
{
	btCollisionWorld::ClosestRayResultCallback HitResult( 
		btVector3( A.x(), A.y(), A.z() ),
		btVector3( B.x(), B.y(), B.z() ) );
	DynamicsWorld_->rayTest( 
		btVector3( A.x(), A.y(), A.z() ),
		btVector3( B.x(), B.y(), B.z() ),
		HitResult );

	if( HitResult.hasHit() )
	{
		Intersection = MaVec3d( 
			HitResult.m_hitPointWorld.x(),
			HitResult.m_hitPointWorld.y(),
			HitResult.m_hitPointWorld.z() );
		Normal = MaVec3d( 
			HitResult.m_hitNormalWorld.x(),
			HitResult.m_hitNormalWorld.y(),
			HitResult.m_hitNormalWorld.z() );
		return BcTrue;
	}
	return BcFalse;
}
示例#11
0
//////////////////////////////////////////////////////////////////////////
// fireWeaponB
void GaRobotComponent::fireWeaponB( BcF32 Radius )
{
	if( WeaponBTimer_ < 0.0f && Energy_ > WeaponBCost_ )
	{
		auto Robots = getRobots( 1 - Team_ );
		if( Robots.size() > 0 )
		{
			Energy_ -= WeaponBCost_;
			WeaponBTimer_ = WeaponBCoolDown_;
			MoveTimer_ = WeaponBCoolDown_ * 0.1f;

			// Spawn entity.
			ScnEntitySpawnParams EntityParams = 
			{
				"default", BcName( "WeaponEntity", 1 ), BcName( "WeaponEntity", 1 ),
				getParentEntity()->getLocalMatrix(),
				getParentEntity()->getParentEntity()
			};

			auto Entity = ScnCore::pImpl()->spawnEntity( EntityParams );
			BcAssert( Entity != nullptr );
			auto WeaponComponent = Entity->getComponentByType< GaWeaponComponent >();
			WeaponComponent->TargetPosition_ = Robots[ 0 ]->getParentEntity()->getLocalPosition();
			// Randomise target position slightly.
			WeaponComponent->TargetPosition_ += MaVec3d( 
				BcRandom::Global.randRealRange( -1.0f, 1.0f ),
				0.0f,
				BcRandom::Global.randRealRange( -1.0f, 1.0f ) ).normal() * Radius;

			playSound( "weaponb" );
		}
	}
	else
	{
		playSound( "fail" );
	}
}
示例#12
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 );
}
示例#13
0
//////////////////////////////////////////////////////////////////////////
// drawSpriteCentered
void ScnCanvasComponent::drawSpriteCenteredUp3D( const MaVec3d& Position, const MaVec2d& Size, BcU32 TextureIdx, const RsColour& Colour, BcU32 Layer )
{
	MaVec3d NewPosition = Position - MaVec3d( Size.x() * 0.5f, 0.0f, Size.y() * 0.5f );
	drawSpriteUp3D( NewPosition, Size, TextureIdx, Colour, Layer );
}
示例#14
0
				{
					NearestWeapon = Weapon;
				}
			}
			MaVec3d AvoidPosition = NearestWeapon->TargetPosition_;
#else
			MaVec3d AvoidPosition;
			for( auto* Weapon : Weapons )
			{
				auto WeaponPosition = Weapon->getParentEntity()->getLocalPosition();
				AvoidPosition += WeaponPosition;;
			}
			AvoidPosition /= BcF32( Weapons.size() );
#endif
			auto Direction = ( LocalPosition - AvoidPosition );
			auto Perp = MaVec3d( Direction.z(), 0.0f, -Direction.x() );
			// Move nearest point away.
			ThisRobot->TargetPosition_ = LocalPosition + 
				Perp.normal() * Distance;
			return BcErrorCode;
		}
	},

	/**
	 * Attack weapon a.
	 * Radius to spray.
	 */
	{
		"op_attack_a",
		[]( GaRobotComponent* ThisRobot, BcU32 Radius )->BcU32
		{
示例#15
0
//////////////////////////////////////////////////////////////////////////
// drawGrid
void ScnDebugRenderComponent::drawGrid( const MaVec3d& Position, const MaVec3d& Size, BcF32 StepSize, BcF32 SubDivideMultiple, BcU32 Layer )
{
	BcU32 NoofAxis = ( Size.x() > 0 ? 1 : 0  ) + ( Size.y() > 0 ? 1 : 0  ) + ( Size.z() > 0 ? 1 : 0 );
	BcAssertMsg( NoofAxis == 2, "Only supports 2 axis in the grid!" );
	
	// Determine which axis to draw along.
	MaVec3d XAxis;
	MaVec3d YAxis;
	BcF32 XSize = 0.0f;
	BcF32 YSize = 0.0f;

	if( Size.x() > 0.0f )
	{
		XAxis = MaVec3d( Size.x(), 0.0f, 0.0f );
		XSize = Size.x();
		if( Size.y() > 0.0f )
		{
			YAxis = MaVec3d( 0.0f, Size.y(), 0.0f );
			YSize = Size.y();
		}
		else
		{
			YAxis = MaVec3d( 0.0f, 0.0f, Size.z() );
			YSize = Size.z();
		}
	}
	else
	{
		XAxis = MaVec3d( 0.0f, Size.y(), 0.0f );
		YAxis = MaVec3d( 0.0f, 0.0f, Size.z() );
		XSize = Size.y();
		YSize = Size.z();
	}

	// Normalise.
	XAxis.normalise();
	YAxis.normalise();

	while( StepSize < XSize && StepSize < YSize )
	{
		// Draw grid.
		for( BcF32 X = 0.0f; X <= XSize; X += StepSize )
		{
			MaVec3d A1( Position + ( XAxis * X ) + ( YAxis *  YSize ) );
			MaVec3d B1( Position + ( XAxis * X ) + ( YAxis * -YSize ) );
			MaVec3d A2( Position + ( XAxis * -X ) + ( YAxis *  YSize ) );
			MaVec3d B2( Position + ( XAxis * -X ) + ( YAxis * -YSize ) );
			drawLine( A1, B1, RsColour( 1.0f, 1.0f, 1.0f, 0.05f ), Layer );
			drawLine( A2, B2, RsColour( 1.0f, 1.0f, 1.0f, 0.05f ), Layer );
		}

		for( BcF32 Y = 0.0f; Y <= YSize; Y += StepSize )
		{
			MaVec3d A1( Position + ( XAxis *  YSize ) + ( YAxis * Y ) );
			MaVec3d B1( Position + ( XAxis * -YSize ) + ( YAxis * Y ) );
			MaVec3d A2( Position + ( XAxis *  YSize ) + ( YAxis * -Y ) );
			MaVec3d B2( Position + ( XAxis * -YSize ) + ( YAxis * -Y ) );
			drawLine( A1, B1, RsColour( 1.0f, 1.0f, 1.0f, 0.05f ), Layer );
			drawLine( A2, B2, RsColour( 1.0f, 1.0f, 1.0f, 0.05f ), Layer );
		}

		StepSize *= SubDivideMultiple;
	}
}
示例#16
0
//////////////////////////////////////////////////////////////////////////
// drawLine
void ScnCanvasComponent::drawLine( const MaVec2d& PointA, const MaVec2d& PointB, const RsColour& Colour, BcU32 Layer )
{
	ScnCanvasComponentVertex* pVertices = allocVertices( 2 );
	ScnCanvasComponentVertex* pFirstVertex = pVertices;
	
	// Only draw if we can allocate vertices.
	if( pVertices != NULL )
	{
		// Now copy in data.
		BcU32 ABGR = Colour.asABGR();
		
		pVertices->X_ = PointA.x();
		pVertices->Y_ = PointA.y();
		pVertices->Z_ = 0.0f;
		pVertices->W_ = 1.0f;
		pVertices->ABGR_ = ABGR;
		++pVertices;
		pVertices->X_ = PointB.x();
		pVertices->Y_ = PointB.y();
		pVertices->Z_ = 0.0f;
		pVertices->W_ = 1.0f;
		pVertices->ABGR_ = ABGR;

		// Quickly check last primitive.
		BcBool AddNewPrimitive = BcTrue;
		if( LastPrimitiveSection_ != BcErrorCode )
		{
			ScnCanvasComponentPrimitiveSection& PrimitiveSection = PrimitiveSectionList_[ LastPrimitiveSection_ ];

			// If the last primitive was the same type as ours we can append to it.
			// NOTE: Need more checks here later.
			if( PrimitiveSection.Type_ == RsTopologyType::LINE_LIST &&
				PrimitiveSection.Layer_ == Layer &&
				PrimitiveSection.MaterialComponent_ == MaterialComponent_ )
			{
				PrimitiveSection.NoofVertices_ += 2;

				// Matrix stack.
				// TODO: Factor into a seperate function.
				if( IsIdentity_ == BcFalse )
				{
					MaMat4d Matrix = getMatrix();

					for( BcU32 Idx = 0; Idx < 2; ++Idx )
					{
						ScnCanvasComponentVertex* pVertex = &pFirstVertex[ Idx ];
						MaVec3d Vertex = MaVec3d( pVertex->X_, pVertex->Y_, pVertex->Z_ ) * Matrix;
						pVertex->X_ = Vertex.x();
						pVertex->Y_ = Vertex.y();
						pVertex->Z_ = Vertex.z();
						pVertices->W_ = 1.0f;
					}
				}
				
				AddNewPrimitive = BcFalse;
			}
		}
		
		// Add primitive.
		if( AddNewPrimitive == BcTrue )
		{
			addPrimitive( RsTopologyType::LINE_LIST, pFirstVertex, 2, Layer, BcTrue );
		}
	}
}
示例#17
0
//////////////////////////////////////////////////////////////////////////
// drawSprite
void ScnCanvasComponent::drawSprite( const MaVec2d& Position, const MaVec2d& Size, BcU32 TextureIdx, const RsColour& Colour, BcU32 Layer )
{
	ScnCanvasComponentVertex* pVertices = allocVertices( 6 );
	ScnCanvasComponentVertex* pFirstVertex = pVertices;
	
	const MaVec2d CornerA = Position;
	const MaVec2d CornerB = Position + Size;

	const ScnRect Rect = DiffuseTexture_.isValid() ? DiffuseTexture_->getRect( TextureIdx ) : ScnRect();
	
	// Only draw if we can allocate vertices.
	if( pVertices != NULL )
	{
		// Now copy in data.
		BcU32 ABGR = Colour.asABGR();
		
		pVertices->X_ = CornerA.x();
		pVertices->Y_ = CornerA.y();
		pVertices->Z_ = 0.0f;
		pVertices->W_ = 1.0f;
		pVertices->U_ = Rect.X_;
		pVertices->V_ = Rect.Y_;
		pVertices->ABGR_ = ABGR;
		++pVertices;
		
		pVertices->X_ = CornerB.x();
		pVertices->Y_ = CornerA.y();
		pVertices->Z_ = 0.0f;
		pVertices->W_ = 1.0f;
		pVertices->U_ = Rect.X_ + Rect.W_;
		pVertices->V_ = Rect.Y_;
		pVertices->ABGR_ = ABGR;
		++pVertices;
		
		pVertices->X_ = CornerA.x();
		pVertices->Y_ = CornerB.y();
		pVertices->Z_ = 0.0f;
		pVertices->W_ = 1.0f;
		pVertices->U_ = Rect.X_;
		pVertices->V_ = Rect.Y_ + Rect.H_;
		pVertices->ABGR_ = ABGR;
		++pVertices;
		
		pVertices->X_ = CornerA.x();
		pVertices->Y_ = CornerB.y();
		pVertices->Z_ = 0.0f;
		pVertices->W_ = 1.0f;
		pVertices->U_ = Rect.X_;
		pVertices->V_ = Rect.Y_ + Rect.H_;
		pVertices->ABGR_ = ABGR;
		++pVertices;

		pVertices->X_ = CornerB.x();
		pVertices->Y_ = CornerA.y();
		pVertices->Z_ = 0.0f;
		pVertices->W_ = 1.0f;
		pVertices->U_ = Rect.X_ + Rect.W_;
		pVertices->V_ = Rect.Y_;
		pVertices->ABGR_ = ABGR;
		++pVertices;

		pVertices->X_ = CornerB.x();
		pVertices->Y_ = CornerB.y();
		pVertices->Z_ = 0.0f;
		pVertices->W_ = 1.0f;
		pVertices->U_ = Rect.X_ + Rect.W_;
		pVertices->V_ = Rect.Y_ + Rect.H_;
		pVertices->ABGR_ = ABGR;
		
		// Quickly check last primitive.
		BcBool AddNewPrimitive = BcTrue;
		if( LastPrimitiveSection_ != BcErrorCode )
		{
			ScnCanvasComponentPrimitiveSection& PrimitiveSection = PrimitiveSectionList_[ LastPrimitiveSection_ ];

			// If the last primitive was the same type as ours we can append to it.
			// NOTE: Need more checks here later.
			if( PrimitiveSection.Type_ == RsTopologyType::TRIANGLE_LIST &&
				PrimitiveSection.Layer_ == Layer &&
				PrimitiveSection.MaterialComponent_ == MaterialComponent_ )
			{
				PrimitiveSection.NoofVertices_ += 6;

				// Matrix stack.
				// TODO: Factor into a seperate function.
				if( IsIdentity_ == BcFalse )
				{
					MaMat4d Matrix = getMatrix();

					for( BcU32 Idx = 0; Idx < 6; ++Idx )
					{
						ScnCanvasComponentVertex* pVertex = &pFirstVertex[ Idx ];
						MaVec3d Vertex = MaVec3d( pVertex->X_, pVertex->Y_, pVertex->Z_ ) * Matrix;
						pVertex->X_ = Vertex.x();
						pVertex->Y_ = Vertex.y();
						pVertex->Z_ = Vertex.z();
						pVertex->W_ = 1.0f;
					}
				}
				
				AddNewPrimitive = BcFalse;
			}
		}
		
		// Add primitive.
		if( AddNewPrimitive == BcTrue )
		{
			addPrimitive( RsTopologyType::TRIANGLE_LIST, pFirstVertex, 6, Layer, BcTrue );
		}
	}
}
示例#18
0
//////////////////////////////////////////////////////////////////////////
// import
BcBool ScnAnimationImport::import( const Json::Value& )
{
#if PSY_IMPORT_PIPELINE
	if( Source_.empty() )
	{
		PSY_LOG( "ERROR: Missing 'source' field.\n" );
		return BcFalse;
	}

	CsResourceImporter::addDependency( Source_.c_str() );

	auto PropertyStore = aiCreatePropertyStore();

	aiLogStream AssimpLogger =
	{
		AssimpLogStream, (char*)this
	};
	aiAttachLogStream( &AssimpLogger );

	Scene_ = aiImportFileExWithProperties( 
		Source_.c_str(), 
		0,
		nullptr, 
		PropertyStore );

	aiReleasePropertyStore( PropertyStore );

	if( Scene_ != nullptr )
	{
		PSY_LOG( "Found %u animations:\n", Scene_->mNumAnimations );
		for( int Idx = 0; Idx < (int)Scene_->mNumAnimations; ++Idx )
		{
			PSY_LOG( " - %s\n", Scene_->mAnimations[ Idx ]->mName.C_Str() );
		}

		// Build animated nodes list. Need this to calculate relative transforms later.
		recursiveParseAnimatedNodes( Scene_->mRootNode, BcErrorCode );

		// Pack down animation into useful internal format.
		BcAssert( Scene_->mNumAnimations == 1 );
		for( BcU32 AnimationIdx = 0; AnimationIdx < 1; ++AnimationIdx )
		{
			auto* Animation = Scene_->mAnimations[ AnimationIdx ];

			BcF32 Rate = 1.0f;
			BcU32 Duration = static_cast< BcU32 >( Animation->mDuration / Rate );

			// Setup data streams.
			ScnAnimationHeader Header;
			Header.NoofNodes_ = Animation->mNumChannels;
			Header.NoofPoses_ = Duration;
			Header.Flags_ = scnAF_DEFAULT;
			Header.Packing_ = scnAP_R16S16T16; // TODO: Make this configurable when we factor out into another class.
			HeaderStream_ << Header;

			// Animation node file data.
			ScnAnimationNodeFileData NodeFileData;
			for( BcU32 NodeIdx = 0; NodeIdx < Animation->mNumChannels; ++NodeIdx )
			{
				auto* Channel = Animation->mChannels[ NodeIdx ];
				NodeFileData.Name_ = CsResourceImporter::addString( Channel->mNodeName.C_Str() );
				NodeStream_ << NodeFileData;
			}

			// Calculate output pose.
			for( BcF32 Time = 0.0f; Time <= Animation->mDuration; Time += Rate )
			{
				ScnAnimationPoseFileData Pose;
				Pose.Time_ = Time / FrameRate_;
				Pose.KeyDataOffset_ = static_cast< BcU32 >( KeyStream_.dataSize() );

				// Iterate over all node channels to generate keys.
				for( BcU32 ChannelIdx = 0; ChannelIdx < Animation->mNumChannels; ++ChannelIdx )
				{
					auto* Channel = Animation->mChannels[ ChannelIdx ];
					auto& AnimatedNode = findAnimatedNode( Channel->mNodeName.C_Str() );

					aiVector3D OutPositionKey;
					aiVector3D OutScaleKey;
					aiQuaternion OutRotationKey;

					// Extract position.
					GetKeyNodeAnim( 
						Channel->mPositionKeys, 
						Channel->mNumPositionKeys, 
						Time, 
						BcTrue, 
						OutPositionKey );
	
					// Extract scale.
					GetKeyNodeAnim( 
						Channel->mScalingKeys, 
						Channel->mNumScalingKeys, 
						Time, 
						BcTrue, 
						OutScaleKey );

					// Extract rotation.
					GetKeyNodeAnim( 
						Channel->mRotationKeys, 
						Channel->mNumRotationKeys, 
						Time, 
						BcTrue, 
						OutRotationKey );

					// Combine key into transform.
					ScnAnimationTransform Transform;
					Transform.R_ = MaQuat( OutRotationKey.x, OutRotationKey.y, OutRotationKey.z, OutRotationKey.w );
					Transform.S_ = MaVec3d( OutScaleKey.x, OutScaleKey.y, OutScaleKey.z );
					Transform.T_ = MaVec3d( OutPositionKey.x, OutPositionKey.y, OutPositionKey.z );
				
					// Store as local matrix.
					Transform.toMatrix( AnimatedNode.LocalTransform_ );
				}

				// Calculate local node matrices relative to their parents.
				for( auto& AnimatedNode : AnimatedNodes_ )
				{
					if( AnimatedNode.ParentIdx_ != BcErrorCode )
					{
						auto& ParentAnimatedNode( AnimatedNodes_[ AnimatedNode.ParentIdx_ ] );
						MaMat4d ParentLocal = ParentAnimatedNode.LocalTransform_;
						AnimatedNode.WorldTransform_ = ParentLocal * AnimatedNode.LocalTransform_;
					}
					else
					{
						AnimatedNode.WorldTransform_ = AnimatedNode.LocalTransform_;
					}
				}

				// Write out pose keys.
				ScnAnimationTransformKey_R16S16T16 OutKey;
				for( BcU32 ChannelIdx = 0; ChannelIdx < Animation->mNumChannels; ++ChannelIdx )
				{
					auto* Channel = Animation->mChannels[ ChannelIdx ];
					const auto& AnimatedNode = findAnimatedNode( Channel->mNodeName.C_Str() );

					// Extract individual transform elements.
					ScnAnimationTransform Transform;
					Transform.fromMatrix( AnimatedNode.LocalTransform_ );

					// Pack into output key.
					OutKey.pack( 
						Transform.R_,
						Transform.S_,
						Transform.T_ );

					KeyStream_ << OutKey;
				}
			
				// Final size + CRC.
				Pose.KeyDataSize_ = static_cast< BcU32 >( KeyStream_.dataSize() - Pose.KeyDataOffset_ );
				Pose.CRC_ = BcHash::GenerateCRC32( 0, KeyStream_.pData() + Pose.KeyDataOffset_, Pose.KeyDataSize_ );

				// Write out pose.
				PoseStream_ << Pose;
			}
		
			// Write out chunks.
			CsResourceImporter::addChunk( BcHash( "header" ), HeaderStream_.pData(), HeaderStream_.dataSize(), 16, csPCF_IN_PLACE );
			CsResourceImporter::addChunk( BcHash( "nodes" ), NodeStream_.pData(), NodeStream_.dataSize() );
			CsResourceImporter::addChunk( BcHash( "poses" ), PoseStream_.pData(), PoseStream_.dataSize() );
			CsResourceImporter::addChunk( BcHash( "keys" ), KeyStream_.pData(), KeyStream_.dataSize() );
		}

		aiReleaseImport( Scene_ );
		Scene_ = nullptr;

		//
		return BcTrue;
	}
#endif // PSY_IMPORT_PIPELINE
	return BcFalse;	
}
示例#19
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;
	}
}
示例#20
0
MaVec3d MaAABB::corner( BcU32 i ) const
{
	return MaVec3d( ( i & 1 ) ? Min_.x() : Max_.x(),
	                ( i & 2 ) ? Min_.y() : Max_.y(),
	                ( i & 4 ) ? Min_.z() : Max_.z() );
}
示例#21
0
//////////////////////////////////////////////////////////////////////////
// rayIntersect
BcBool MaAABB::lineIntersect( const MaVec3d& Start, const MaVec3d& End, MaVec3d* pIntersectionPoint, MaVec3d* pIntersectionNormal ) const
{
	// Planes. Screw it.
	// Totally inoptimal.
	MaPlane Planes[6];
	MaVec3d Intersects[6];
	BcF32 Distance;
	for( BcU32 i = 0; i < 6; ++i )
	{
		Planes[i] = facePlane( i );
		if( !Planes[i].lineIntersection( Start, End, Distance, Intersects[i] ) )
		{
			Intersects[i] = MaVec3d( 1e24f, 1e24f, 1e24f );
		}
	}

	// Reject classified and find nearest.
	BcF32 Nearest = 1e24f;
	BcU32 iNearest = BcErrorCode;

	for( BcU32 i = 0; i < 6; ++i )
	{
		// For every point...
		// ...check against planes.
		BcBool Valid = BcTrue;
		for( BcU32 j = 0; j < 6; ++j )
		{
			if( Planes[j].classify( Intersects[i] ) == MaPlane::bcPC_FRONT )
			{
				Valid = BcFalse;
				break;
			}
		}

		// If its valid, check distance.
		if( Valid )
		{
			BcF32 Distance = ( Start - Intersects[i] ).magnitudeSquared();

			if( Distance < Nearest )
			{
				Nearest = Distance;
				iNearest = i;
			}
		}
	}

	//
	if( iNearest != BcErrorCode )
	{
		if( pIntersectionPoint != NULL )
		{
			*pIntersectionPoint = Intersects[ iNearest ];
		}

		if( pIntersectionNormal != NULL )
		{
			*pIntersectionNormal = Planes[ iNearest ].normal();
		}

		return BcTrue;
	}
	return BcFalse;
}
示例#22
0
//////////////////////////////////////////////////////////////////////////
// update
//virtual
void GaEnemyComponent::update( BcF32 Tick )
{
	// Find move vector.
	BcF32 MoveSpeed = 2.0f;
	MaVec3d MoveVector;

	PulseTimer_ += Tick;

	// Set direction and handle if we need to change direction.
	MaVec3d Position = getParentEntity()->getWorldPosition();
	MoveVector = Direction_;

	BcBSPPointInfo BSPPointInfo;
	if( BSP_->lineIntersection( Position, Position + Direction_ * 256.0f, &BSPPointInfo ) )
	{
		if( BSPPointInfo.Distance_ < 1.0f )
		{
			// New direction.
			Direction_ = Direction_.reflect( BSPPointInfo.Plane_.normal() );

			// Belt & braces: it will become denormalised over time.
			Direction_.normalise();
			
			// Clamp position (this is to prevent wandering, if angles aren't sitting on an integer, expect weirdness).
			Position = MaVec3d( BcRound( Position.x() ), BcRound( Position.y() ), BcRound( Position.z() ) );

		}
	}

	BcF32 PulseTime = 2.0f;

	if( BSP_->canSeePlayer( Position ) )
	{
		BcPrintf( "I CAN SEE UUU\n" );
		PulseTime = 0.5f;
		IsTargetting_ = BcTrue;
		TargetTimer_ -= Tick;
	}
	else
	{
		IsTargetting_ = BcFalse;
		TargetTimer_ = 3.0f;
	}

	// Pulse.
	if( PulseTimer_ > PulseTime )
	{
		Pressure_->setSample( Position, 0.5f );
		PulseTimer_ = 0.0f;
	}

	// Shoot player.
	if( IsTargetting_ && TargetTimer_ < 0.0f )
	{
		BSP_->killPlayer();
	}
	
	// Set the move.
	if( !IsTargetting_ )
	{
		MaVec3d AppliedMoveVector = MoveVector;
		AppliedMoveVector.z( 0.0f );
		AppliedMoveVector = AppliedMoveVector.normal() * MoveSpeed;
		Pawn_->setMove( AppliedMoveVector );
	}
	else
	{
		Pawn_->setMove( MaVec3d( 0.0f, 0.0f, 0.0f ) );
	}
}
//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 );
	}
}
//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 );
	}
}