#include "Mix/Private/Scene/Common/DefaultParticleSystem.h"

namespace Mix{ namespace Scene{ namespace Common{

const wchar_t* DefaultParticleSystem::FAILED_CREATE = L"デフォルトパーティクルシステムの作成に失敗";

////////////////////////////////////////////////////////////////////////////////////////////////////
// DefaultParticleSystem::InternalGenerator
////////////////////////////////////////////////////////////////////////////////////////////////////

DefaultParticleSystem::InternalGenerator* DefaultParticleSystem::InternalGenerator::CreateInstance( Mix::Scene::IDefaultParticleSystem::PLANE_TYPE planeType )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, DefaultParticleSystem::InternalGenerator, planeType );
}

DefaultParticleSystem::InternalGenerator::InternalGenerator( Mix::Scene::IDefaultParticleSystem::PLANE_TYPE planeType ) :
m_PlaneType( planeType ),
m_MinAngularImpulse( -4.0f, -4.0f, -4.0f ),
m_MaxAngularImpulse( +4.0f, +4.0f, +4.0f ),
m_DiffAngularImpulse( m_MaxAngularImpulse - m_MinAngularImpulse ),
m_MinAngularAcc( 0.0f, 0.0f, 0.0f ),
m_MaxAngularAcc( 0.0f, 0.0f, 0.0f ),
m_DiffAngularAcc( m_MaxAngularAcc - m_MinAngularAcc )
{
	switch( m_PlaneType )
	{
	case IDefaultParticleSystem::P_XY:
		m_Normal.Set( 0.0f, 0.0f, 1.0f );
		m_Tangent.Set( 0.0f, 1.0f, 0.0f );
		m_Binormal.Set( 1.0f, 0.0f, 0.0f );
		break;
	case IDefaultParticleSystem::P_XZ:
		m_Normal.Set( 0.0f, 1.0f, 0.0f );
		m_Tangent.Set( 0.0f, 0.0f, 1.0f );
		m_Binormal.Set( 1.0f, 0.0f, 0.0f );
		break;
	case IDefaultParticleSystem::P_YZ:
		m_Normal.Set( 1.0f, 0.0f, 0.0f );
		m_Tangent.Set( 0.0f, 1.0f, 0.0f );
		m_Binormal.Set( 0.0f, 0.0f, 1.0f );
		break;
	}
}

DefaultParticleSystem::InternalGenerator::~InternalGenerator( void )
{
}

const Mix::Vector3& DefaultParticleSystem::InternalGenerator::GetMinAngularImpulse( void ) const
{
	return m_MinAngularImpulse;
}

const Mix::Vector3& DefaultParticleSystem::InternalGenerator::GetMaxAngularImpulse( void ) const
{
	return m_MaxAngularImpulse;
}

void DefaultParticleSystem::InternalGenerator::SetAngularImpulse( const Mix::Vector3& minImpulse, const Mix::Vector3& maxImpulse )
{
	m_MinAngularImpulse = minImpulse;
	m_MaxAngularImpulse = Mix::Vector3::Max( m_MinAngularImpulse, maxImpulse );
	m_DiffAngularImpulse = m_MaxAngularImpulse - m_MinAngularImpulse;
}

const Mix::Vector3& DefaultParticleSystem::InternalGenerator::GetMinAngularAcceleration( void ) const
{
	return m_MinAngularAcc;
}

const Mix::Vector3& DefaultParticleSystem::InternalGenerator::GetMaxAngularAcceleration( void ) const
{
	return m_MaxAngularAcc;
}

void DefaultParticleSystem::InternalGenerator::SetAngularAcceleration( const Mix::Vector3& minAcc, const Mix::Vector3& maxAcc )
{
	m_MinAngularAcc = minAcc;
	m_MaxAngularAcc = Mix::Vector3::Max( m_MinAngularAcc, maxAcc );
	m_DiffAngularAcc = m_MaxAngularAcc - m_MinAngularAcc;
}

Mix::Scene::IDefaultParticleSystem::PLANE_TYPE DefaultParticleSystem::InternalGenerator::GetPlaneType( void ) const
{
	return m_PlaneType;
}

void DefaultParticleSystem::InternalGenerator::Internal_GetData( UInt32 dataSize, void* pData )
{
	MIX_ASSERT( dataSize = sizeof( DefaultParticleSystem::DATA ) );
	MIX_ASSERT( pData != NULL );

	DefaultParticleSystem::DATA* pDst = reinterpret_cast<DefaultParticleSystem::DATA*>( pData );

	Float32 mass;
	Mix::Vector2 middleSize;
	Mix::Matrix4x4 invInertia;
	Mix::Vector3 angularImpulse;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// データの取得１ : 共通
	////////////////////////////////////////////////////////////////////////////////////////////////////

	SimpleParticleGenerator::GetData(	mass,
										pDst->pos,
										pDst->life,
										pDst->invLifeMax,
										pDst->constLinearAcceleration,
										pDst->constLinearVelocity,
										pDst->linearAcceleration,
										pDst->linearVelocity,
										pDst->linearVelocityDamping,
										pDst->angularVelocityDamping,
										pDst->initalSize,
										middleSize,
										pDst->lastSize,
										pDst->initalColor,
										pDst->middleColor,
										pDst->lastColor,
										pDst->colorCtrlPoints,
										pDst->tex[0],
										pDst->tex[1] );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// データの取得２ : 慣性テンソルの取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	switch( m_PlaneType )
	{
	case IDefaultParticleSystem::P_XY:
		SimpleParticleGenerator::GetData( mass, middleSize.x, middleSize.y, 1.0f, invInertia );
		break;
	case IDefaultParticleSystem::P_XZ:
		SimpleParticleGenerator::GetData( mass, middleSize.x, 1.0f, middleSize.y, invInertia );
		break;
	case IDefaultParticleSystem::P_YZ:
		SimpleParticleGenerator::GetData( mass, 1.0f, middleSize.y, middleSize.x, invInertia );
		break;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// データの取得３ : 回転関係
	////////////////////////////////////////////////////////////////////////////////////////////////////

	angularImpulse = m_MinAngularImpulse + m_DiffAngularImpulse * Mix::Vector3::Rand();

	pDst->planeType = m_PlaneType;
	pDst->rot = Mix::Quaternion::Identity();
	pDst->normal = m_Normal;
	pDst->tangent = m_Tangent;
	pDst->binormal = m_Binormal;
	pDst->angularAcceleration = m_MinAngularAcc + m_DiffAngularAcc * Mix::Vector3::Rand();
	pDst->angularVelocity = invInertia.TransformSR( angularImpulse );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// DefaultParticleSystem::InternalProcessor
////////////////////////////////////////////////////////////////////////////////////////////////////

DefaultParticleSystem::InternalProcessor* DefaultParticleSystem::InternalProcessor::CreateInstance( const wchar_t* pDebugName )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, DefaultParticleSystem::InternalProcessor, pDebugName );
}

DefaultParticleSystem::InternalProcessor::InternalProcessor( const wchar_t* pDebugName ) :
m_FaceNum( 0 )
{
#ifdef _DEBUG

	Mix::StringW tempStr;

	tempStr.Sprintf( L"%s/DataList", MIX_SAFE_NAME( pDebugName ) );
	m_DataList.Initialize( DefaultParticleSystem::LIST_DEF_SIZE, DefaultParticleSystem::LIST_RESIZE_STEP, tempStr.GetConstPtr() );

	tempStr.Sprintf( L"%s/FacePool", MIX_SAFE_NAME( pDebugName ) );
	m_FacePool.Initialize( DefaultParticleSystem::LIST_DEF_SIZE, DefaultParticleSystem::LIST_RESIZE_STEP, tempStr.GetConstPtr() );

#else //_DEBUG

	m_DataList.Initialize( DefaultParticleSystem::LIST_DEF_SIZE, DefaultParticleSystem::LIST_RESIZE_STEP );
	m_FacePool.Initialize( DefaultParticleSystem::LIST_DEF_SIZE, DefaultParticleSystem::LIST_RESIZE_STEP );

#endif //_DEBUG
}

DefaultParticleSystem::InternalProcessor::~InternalProcessor( void )
{
}

UInt32 DefaultParticleSystem::InternalProcessor::Internal_GetCount( void ) const
{
	return ( m_DataList.GetCount() > 0 );
}

void DefaultParticleSystem::InternalProcessor::Internal_Clear( void )
{
	m_DataList.Clear();
	m_FacePool.Clear();
	m_FaceNum = 0;
}

UInt32 DefaultParticleSystem::InternalProcessor::Internal_Add( Mix::Scene::IParticleGenerator* pGenerator, UInt32 genCount )
{
	MIX_ASSERT( genCount > 0 );

	UInt32 dataSize = sizeof( DefaultParticleSystem::DATA );
	DefaultParticleSystem::DATA* pData = m_DataList.Add( genCount );
	
	UInt32 i;
	UInt32 dataNum;
	UInt32 faceCapacity;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// データを取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( i = 0; i < genCount; i++ )
	{
		pGenerator->Internal_GetData( dataSize, pData );
		pData++;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// フェイスプールを必要に応じて拡張
	////////////////////////////////////////////////////////////////////////////////////////////////////

	dataNum = m_DataList.GetCount();
	faceCapacity = m_FacePool.GetCount();

	if( faceCapacity < dataNum )
	{
		m_FacePool.Add( dataNum - faceCapacity );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return genCount;
}

UInt32 DefaultParticleSystem::InternalProcessor::Internal_Add( const Mix::Matrix4x4& worldMat, Mix::Scene::IParticleGenerator* pGenerator, UInt32 genCount )
{
	MIX_ASSERT( genCount > 0 );

	UInt32 dataSize = sizeof( DefaultParticleSystem::DATA );
	DefaultParticleSystem::DATA* pData = m_DataList.Add( genCount );
	
	UInt32 i;
	UInt32 dataNum;
	UInt32 faceCapacity;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// データを取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( i = 0; i < genCount; i++ )
	{
		pGenerator->Internal_GetData( dataSize, pData );

		pData->pos = worldMat * pData->pos;
		pData->normal = worldMat.TransformSR( pData->normal );
		pData->tangent = worldMat.TransformSR( pData->tangent );
		pData->binormal = worldMat.TransformSR( pData->binormal );
		pData->linearAcceleration = worldMat.TransformSR( pData->linearAcceleration );
		pData->linearVelocity = worldMat.TransformSR( pData->linearVelocity );

		pData++;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// フェイスプールを必要に応じて拡張
	////////////////////////////////////////////////////////////////////////////////////////////////////

	dataNum = m_DataList.GetCount();
	faceCapacity = m_FacePool.GetCount();

	if( faceCapacity < dataNum )
	{
		m_FacePool.Add( dataNum - faceCapacity );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return genCount;
}

Boolean DefaultParticleSystem::InternalProcessor::Internal_Update( Float32 dt )
{
	UInt32 dataNum;

	UInt32 dataIndex;
	DefaultParticleSystem::DATA* dats;
	DefaultParticleSystem::DATA* pData;

	Mix::Scene::IParticleProcessor::FACE* faces;
	Mix::Scene::IParticleProcessor::FACE* pFace;

	Mix::Vector3 axis;
	Float32 angle;

	const Float32* colCtrlPoints;
	Mix::Vector3* localPoints;
	const Mix::Vector2* texTL;
	const Mix::Vector2* texBR;
	Mix::Vector2* texCoords;

	Float32 lifeRatio;
	Mix::Vector2 size;
	Mix::Matrix4x4 rotMat;

	Float32 a;
	Float32 b;
	Float32 a2;
	Float32 b2;
	Float32 t;

	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_FaceNum = 0;

	dataNum = m_DataList.GetCount();
	if( dataNum == 0 )
	{
		return False;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////

	dats = m_DataList.GetBeginPtr();
	dataIndex = 0;

	faces = m_FacePool.GetBeginPtr();

	while( dataIndex < dataNum )
	{
		pData = &( dats[dataIndex] );

		pData->life -= dt;

		if( pData->life >= 0.0f )
		{
			pFace = &( faces[m_FaceNum] );

			lifeRatio = MIX_FLOAT_SATURATE( 1.0f - pData->life * pData->invLifeMax );

			// データ : 回転

			pData->angularVelocity += pData->angularAcceleration * dt;
			pData->angularVelocity -= pData->angularVelocity * pData->angularVelocityDamping;

			axis = pData->angularVelocity * dt;
			angle = axis.Normalize();

			pData->rot.RotationAxis( axis, angle );
			pData->rot.Normalize();

			// データ : 移動

			pData->linearVelocity += pData->constLinearVelocity * dt;
			pData->linearVelocity += pData->constLinearAcceleration * dt;
			pData->linearVelocity -= pData->linearVelocity * pData->linearVelocityDamping;

			pData->pos += pData->linearVelocity * dt;

			// フェイス : 回転

			rotMat.SetRotation( pData->rot );

			// フェイス : 位置

			pFace->pos = pData->pos;

			// フェイス : ライティング

			pFace->normal = rotMat * pData->normal;
			pFace->tangent = rotMat * pData->tangent;
			pFace->binormal = rotMat * pData->binormal;

			// フェイス : カラー

			colCtrlPoints = pData->colorCtrlPoints;

			a = 1.0f - lifeRatio;
			b = lifeRatio;
			a2 = a * a;
			b2 = b * b;

			t = a2 * a * colCtrlPoints[0] +
				3.0f * a2 * b * colCtrlPoints[1] +
				3.0f * a * b2 * colCtrlPoints[2] +
				b2 * b * colCtrlPoints[3];

			if( t < 0.5f )
			{
				t = MIX_FLOAT_SATURATE( t * 2.0f );
				pFace->color = Mix::Vector4::Lerp( pData->initalColor, pData->middleColor, t );
			}
			else
			{
				t = MIX_FLOAT_SATURATE( ( t - 0.5f ) * 2.0f );
				pFace->color = Mix::Vector4::Lerp( pData->middleColor, pData->lastColor, t );
			}

			// フェイス : ローカルポイント

			localPoints = pFace->localPoints;
			size = Mix::Vector2::Lerp( pData->initalSize, pData->lastSize, lifeRatio );

			switch( pData->planeType )
			{
			case IDefaultParticleSystem::P_XY:
				localPoints[0].Set( -size.x, +size.y, 0.0f );
				localPoints[1].Set( +size.x, +size.y, 0.0f );
				localPoints[2].Set( +size.x, -size.y, 0.0f );
				localPoints[3].Set( -size.x, -size.y, 0.0f );
				break;
			case IDefaultParticleSystem::P_XZ:
				localPoints[0].Set( -size.x, 0.0f, +size.y );
				localPoints[1].Set( +size.x, 0.0f, +size.y );
				localPoints[2].Set( +size.x, 0.0f, -size.y );
				localPoints[3].Set( -size.x, 0.0f, -size.y );
				break;
			case IDefaultParticleSystem::P_YZ:
				localPoints[0].Set( 0.0f, +size.y, -size.x );
				localPoints[1].Set( 0.0f, +size.y, +size.x );
				localPoints[2].Set( 0.0f, -size.y, +size.x );
				localPoints[3].Set( 0.0f, -size.y, -size.x );
				break;
			}

			localPoints[0] = rotMat * localPoints[0];
			localPoints[1] = rotMat * localPoints[1];
			localPoints[2] = rotMat * localPoints[2];
			localPoints[3] = rotMat * localPoints[3];

			// フェイス : テクスチャ座標

			texCoords = pFace->texCoords;

			texTL = &( pData->tex[0] );
			texBR = &( pData->tex[1] );

			texCoords[0].Set( texTL->x, texTL->y );
			texCoords[1].Set( texBR->x, texTL->y );
			texCoords[2].Set( texBR->x, texBR->y );
			texCoords[3].Set( texTL->x, texBR->y );

			m_FaceNum++;
			dataIndex++;
		}
		else
		{
			m_DataList.FastRemoveByIndex( dataIndex ); // 最後の要素と入れ替えて削除するので dataIndex はインクリメントしない
			dataNum = m_DataList.GetCount(); // データ数を取得しなおす
		}
	}

	return True;
}

Boolean DefaultParticleSystem::InternalProcessor::Internal_Duplicate( Mix::Scene::IParticleProcessor** ppProcessor, const wchar_t* pDebugName )
{
	DefaultParticleSystem::InternalProcessor* pProcessor = DefaultParticleSystem::InternalProcessor::CreateInstance( MIX_SAFE_NAME( pDebugName ) );
	if( pProcessor == NULL )
	{
		return False;
	}

	UInt32 dataNum = m_DataList.GetCount();
	UInt32 faceCapacity = m_FacePool.GetCount();

	if( dataNum > 0 )
	{
		pProcessor->m_DataList.Add( m_DataList.GetConstBeginPtr(), dataNum );
	}

	if( faceCapacity > 0 )
	{
		pProcessor->m_FacePool.Add( faceCapacity );
	}

	( *ppProcessor ) = pProcessor;

	return True;
}

UInt32 DefaultParticleSystem::InternalProcessor::Internal_GetFaceNum( void ) const
{
	return m_FaceNum;
}

const Mix::Scene::IParticleProcessor::FACE* DefaultParticleSystem::InternalProcessor::Internal_GetFaces( void ) const
{
	return m_FacePool.GetBeginPtr();
}

#ifdef _DEBUG

void DefaultParticleSystem::InternalProcessor::Debug_Draw( const Mix::Matrix4x4& worldMat, Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer )
{
}

#endif //_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////
// DefaultParticleSystem
////////////////////////////////////////////////////////////////////////////////////////////////////

DefaultParticleSystem* DefaultParticleSystem::CreateInstance( Boolean bSimWorldSpace, const wchar_t* pDebugName )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, DefaultParticleSystem, bSimWorldSpace, pDebugName );
}

DefaultParticleSystem::DefaultParticleSystem( Boolean bSimWorldSpace, const wchar_t* pDebugName ) :
m_pGenerator( NULL ),
m_MinEmitInterval( 0.1f ),
m_MaxEmitInterval( 0.2f ),
m_DiffEmitInterval( m_MaxEmitInterval - m_MinEmitInterval ),
m_MinEmitCount( 2 ),
m_MaxEmitCount( 4 ),
m_DiffEmitCount( m_MaxEmitCount - m_MinEmitCount )
{
	m_Config.baseFlags = ( bSimWorldSpace == True )? IParticleSystem::SIMULATION_WORLD_SPACE : 0;
	m_Config.behaviorFlags = IParticleSystem::INVISIBLE_SLEEP | IParticleSystem::FAR_SKIP_FRAMES;
	m_Config.farMinDist = 30.0f;
	m_Config.farMaxDist = 50.0f;
	m_Config.maxSkipFrames = 4;

#ifdef _DEBUG
	m_DebugName = MIX_SAFE_NAME( pDebugName );
#endif //_DEBUG
}

DefaultParticleSystem::~DefaultParticleSystem( void )
{
	MIX_RELEASE( m_pGenerator );
}

Boolean DefaultParticleSystem::Initialize( Mix::Scene::IDefaultParticleSystem::PLANE_TYPE planeType )
{
	MIX_ASSERT( m_pGenerator == NULL );

#ifdef _DEBUG
	const wchar_t* pDebugName = m_DebugName.GetConstPtr();
#else //_DEBUG
	const wchar_t* pDebugName = Mix::STR_UNKNOWN;
#endif //_DEBUG

	m_pGenerator = DefaultParticleSystem::InternalGenerator::CreateInstance( planeType );
	if( m_pGenerator == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : Name[%s]", DefaultParticleSystem::FAILED_CREATE, Mix::STR_OUTOFMEMORY, pDebugName );
		return False;
	}

	return True;
}

const Mix::Vector3& DefaultParticleSystem::GetMinAngularImpulse( void ) const
{
	return m_pGenerator->GetMinAngularImpulse();
}

const Mix::Vector3& DefaultParticleSystem::GetMaxAngularImpulse( void ) const
{
	return m_pGenerator->GetMaxAngularImpulse();
}

void DefaultParticleSystem::SetAngularImpulse( const Mix::Vector3& minImpulse, const Mix::Vector3& maxImpulse )
{
	m_pGenerator->SetAngularImpulse( minImpulse, maxImpulse );
}

const Mix::Vector3& DefaultParticleSystem::GetMinAngularAcceleration( void ) const
{
	return m_pGenerator->GetMinAngularAcceleration();
}

const Mix::Vector3& DefaultParticleSystem::GetMaxAngularAcceleration( void ) const
{
	return m_pGenerator->GetMaxAngularAcceleration();
}

void DefaultParticleSystem::SetAngularAcceleration( const Mix::Vector3& minAcc, const Mix::Vector3& maxAcc )
{
	m_pGenerator->SetAngularAcceleration( minAcc, maxAcc );
}

Mix::Scene::IDefaultParticleSystem::PLANE_TYPE DefaultParticleSystem::GetPlaneType( void ) const
{
	return m_pGenerator->GetPlaneType();
}

Boolean DefaultParticleSystem::IsBillboard( void ) const
{
	return ( MIX_TESTBIT( m_Config.baseFlags, IParticleSystem::BILLBOARD ) == IParticleSystem::BILLBOARD );
}

Boolean DefaultParticleSystem::IsSimulationWorldSpace( void ) const
{
	return ( MIX_TESTBIT( m_Config.baseFlags, IParticleSystem::SIMULATION_WORLD_SPACE ) == IParticleSystem::SIMULATION_WORLD_SPACE );
}

Boolean DefaultParticleSystem::IsInvisibleSleep( void ) const
{
	return ( MIX_TESTBIT( m_Config.behaviorFlags, IParticleSystem::INVISIBLE_SLEEP ) == IParticleSystem::INVISIBLE_SLEEP );
}

void DefaultParticleSystem::SetInvisibleSleep( Boolean state )
{
	if( state == True )
	{
		MIX_SETBIT( m_Config.behaviorFlags, IParticleSystem::INVISIBLE_SLEEP );
	}
	else
	{
		MIX_RESETBIT( m_Config.behaviorFlags, IParticleSystem::INVISIBLE_SLEEP );
	}
}

Float32 DefaultParticleSystem::GetMinFarDist( void ) const
{
	return m_Config.farMinDist;
}

Float32 DefaultParticleSystem::GetMaxFarDist( void ) const
{
	return m_Config.farMaxDist;
}

void DefaultParticleSystem::SetFarDist( Float32 minDist, Float32 maxDist )
{
	m_Config.farMinDist = max( 0.0f, minDist );
	m_Config.farMaxDist = max( m_Config.farMinDist, maxDist );
}

Boolean DefaultParticleSystem::IsFarSkipFrames( void ) const
{
	return ( MIX_TESTBIT( m_Config.behaviorFlags, IParticleSystem::FAR_SKIP_FRAMES ) == IParticleSystem::FAR_SKIP_FRAMES );
}

void DefaultParticleSystem::SetFarSkipFrames( Boolean state )
{
	if( state == True )
	{
		MIX_SETBIT( m_Config.behaviorFlags, IParticleSystem::FAR_SKIP_FRAMES );
	}
	else
	{
		MIX_RESETBIT( m_Config.behaviorFlags, IParticleSystem::FAR_SKIP_FRAMES );
	}
}

UInt32 DefaultParticleSystem::GetMaxFarSkipFrames( void ) const
{
	return m_Config.maxSkipFrames;
}

void DefaultParticleSystem::SetMaxFarSkipFrames( UInt32 value )
{
	m_Config.maxSkipFrames = value;
}

Float32 DefaultParticleSystem::GetMinEmitInterval( void ) const
{
	return m_MinEmitInterval;
}

Float32 DefaultParticleSystem::GetMaxEmitInterval( void ) const
{
	return m_MinEmitInterval;
}

void DefaultParticleSystem::SetEmitInterval( Float32 minEI, Float32 maxEI )
{
	m_MinEmitInterval = max( 0.0f, minEI );
	m_MaxEmitInterval = max( m_MinEmitInterval, maxEI );
	m_DiffEmitInterval = m_MaxEmitInterval - m_MinEmitInterval;
}

UInt32 DefaultParticleSystem::GetMinEmitCount( void ) const
{
	return m_MinEmitCount;
}

UInt32 DefaultParticleSystem::GetMaxEmitCount( void ) const
{
	return m_MaxEmitCount;
}

void DefaultParticleSystem::SetEmitCount( UInt32 minEC, UInt32 maxEC )
{
	m_MinEmitCount = max( 0, minEC );
	m_MaxEmitCount = max( m_MinEmitCount, maxEC );
	m_DiffEmitCount = m_MaxEmitCount - m_MinEmitCount;
}

const Mix::Vector3& DefaultParticleSystem::GetEmitRadius( void ) const
{
	return m_pGenerator->GetEmitRadius();
}

void DefaultParticleSystem::SetEmitRadius( const Mix::Vector3& radius )
{
	m_pGenerator->SetEmitRadius( radius );
}

Float32 DefaultParticleSystem::GetEmitOffset( void ) const
{
	return m_pGenerator->GetEmitOffset();
}

void DefaultParticleSystem::SetEmitOffset( Float32 offset )
{
	m_pGenerator->SetEmitOffset( offset );
}

Float32 DefaultParticleSystem::GetMinLife( void ) const
{
	return m_pGenerator->GetMinLife();
}

Float32 DefaultParticleSystem::GetMaxLife( void ) const
{
	return m_pGenerator->GetMaxLife();
}

void DefaultParticleSystem::SetLife( Float32 minLife, Float32 maxLife )
{
	m_pGenerator->SetLife( minLife, maxLife );
}

Float32 DefaultParticleSystem::GetMinMass( void ) const
{
	return m_pGenerator->GetMinMass();
}

Float32 DefaultParticleSystem::GetMaxMass( void ) const
{
	return m_pGenerator->GetMaxMass();
}

void DefaultParticleSystem::SetMass( Float32 minMass, Float32 maxMass )
{
	m_pGenerator->SetMass( minMass, maxMass );
}

const Mix::Vector3& DefaultParticleSystem::GetGravity( void ) const
{
	return m_pGenerator->GetGravity();
}

void DefaultParticleSystem::SetGravity( const Mix::Vector3& gravity )
{
	m_pGenerator->SetGravity( gravity );
}

const Mix::Vector3& DefaultParticleSystem::GetConstantLinearVelocity( void ) const
{
	return m_pGenerator->GetConstantLinearVelocity();
}

void DefaultParticleSystem::SetConstantLinearVelocity( const Mix::Vector3& vel )
{
	m_pGenerator->SetConstantLinearVelocity( vel );
}

const Mix::Vector3& DefaultParticleSystem::GetMinLinearImpulse( void ) const
{
	return m_pGenerator->GetMinLinearImpulse();
}

const Mix::Vector3& DefaultParticleSystem::GetMaxLinearImpulse( void ) const
{
	return m_pGenerator->GetMaxLinearImpulse();
}

void DefaultParticleSystem::SetLinearImpulse( const Mix::Vector3& minImpulse, const Mix::Vector3& maxImpulse )
{
	m_pGenerator->SetLinearImpulse( minImpulse, maxImpulse );
}

const Mix::Vector3& DefaultParticleSystem::GetMinLinearAcceleration( void ) const
{
	return m_pGenerator->GetMinLinearAcceleration();
}

const Mix::Vector3& DefaultParticleSystem::GetMaxLinearAcceleration( void ) const
{
	return m_pGenerator->GetMaxLinearAcceleration();
}

void DefaultParticleSystem::SetLinearAcceleration( const Mix::Vector3& minAcc, const Mix::Vector3& maxAcc )
{
	m_pGenerator->SetLinearAcceleration( minAcc, maxAcc );
}

Float32 DefaultParticleSystem::GetMinLinearVelocityDamping( void ) const
{
	return m_pGenerator->GetMinLinearVelocityDamping();
}

Float32 DefaultParticleSystem::GetMaxLinearVelocityDamping( void ) const
{
	return m_pGenerator->GetMaxLinearVelocityDamping();
}

void DefaultParticleSystem::SetLinearVelocityDamping( Float32 minDamping, Float32 maxDamping )
{
	m_pGenerator->SetLinearVelocityDamping( minDamping, maxDamping );
}

Float32 DefaultParticleSystem::GetMinAngularVelocityDamping( void ) const
{
	return m_pGenerator->GetMinAngularVelocityDamping();
}

Float32 DefaultParticleSystem::GetMaxAngularVelocityDamping( void ) const
{
	return m_pGenerator->GetMaxAngularVelocityDamping();
}

void DefaultParticleSystem::SetAngularVelocityDamping( Float32 minDamping, Float32 maxDamping )
{
	m_pGenerator->SetAngularVelocityDamping( minDamping, maxDamping );
}

const Mix::Vector2& DefaultParticleSystem::GetInitalSize( void ) const
{
	return m_pGenerator->GetInitalSize();
}

const Mix::Vector2& DefaultParticleSystem::GetLastSize( void ) const
{
	return m_pGenerator->GetLastSize();
}

Float32 DefaultParticleSystem::GetMinSizeRand( void ) const
{
	return m_pGenerator->GetMinSizeRand();
}

Float32 DefaultParticleSystem::GetMaxSizeRand( void ) const
{
	return m_pGenerator->GetMaxSizeRand();
}

void DefaultParticleSystem::SetSize( const Mix::Vector2& initalSize, const Mix::Vector2& lastSize, Float32 minSizeScale, Float32 maxSizeScale )
{
	m_pGenerator->SetSize( initalSize, lastSize, minSizeScale, maxSizeScale );
}

const Mix::Vector4& DefaultParticleSystem::GetInitalColor( void ) const
{
	return m_pGenerator->GetInitalColor();
}

const Mix::Vector4& DefaultParticleSystem::GetMiddleColor( void ) const
{
	return m_pGenerator->GetMiddleColor();
}

const Mix::Vector4& DefaultParticleSystem::GetLastColor( void ) const
{
	return m_pGenerator->GetLastColor();
}

void DefaultParticleSystem::SetColor( const Mix::Vector4& initalColor, const Mix::Vector4& middleColor, const Mix::Vector4& lastColor )
{
	m_pGenerator->SetColor( initalColor, middleColor, lastColor );
}

Float32 DefaultParticleSystem::GetColorControlPoint1( void ) const
{
	return m_pGenerator->GetColorControlPoint1();
}

Float32 DefaultParticleSystem::GetColorControlPoint2( void ) const
{
	return m_pGenerator->GetColorControlPoint2();
}

void DefaultParticleSystem::SetColorControlPoints( Float32 p1, Float32 p2 )
{
	m_pGenerator->SetColorControlPoints( p1, p2 );
}

const Mix::Vector2& DefaultParticleSystem::GetTexTL( void ) const
{
	return m_pGenerator->GetTexTL();
}

const Mix::Vector2& DefaultParticleSystem::GetTexBR( void ) const
{
	return m_pGenerator->GetTexBR();
}

void DefaultParticleSystem::SetTexCoords( const Mix::Vector2& tl, const Mix::Vector2& br )
{
	m_pGenerator->SetTexCoords( tl, br );
}

const Mix::Scene::IParticleSystem::CONFIG& DefaultParticleSystem::GetConfig( void ) const
{
	return m_Config;
}

void DefaultParticleSystem::Internal_GetGenerator( Mix::Scene::IParticleGenerator** ppGenerator )
{
	MIX_ASSERT( ppGenerator != NULL );

	MIX_ADD_REF( m_pGenerator );
	( *ppGenerator ) = m_pGenerator;
}

Boolean DefaultParticleSystem::Internal_CreateProcessor( Mix::Scene::IParticleProcessor** ppProcessor )
{
	MIX_ASSERT( ppProcessor != NULL );

#ifdef _DEBUG
	const wchar_t* pDebugName = m_DebugName.GetConstPtr();
#else //_DEBUG
	const wchar_t* pDebugName = NULL;
#endif //_DEBUG

	DefaultParticleSystem::InternalProcessor* pInternalProcessor = DefaultParticleSystem::InternalProcessor::CreateInstance( pDebugName );
	if( pInternalProcessor == NULL )
	{
		return False;
	}

	( *ppProcessor ) = pInternalProcessor;

	return True;
}

Float32 DefaultParticleSystem::Internal_GetGenerateInterval( void ) const
{
	return m_MinEmitInterval + m_DiffEmitInterval * Mix::RandF();
}

UInt32 DefaultParticleSystem::Internal_GetGenerateCount( void ) const
{
	return m_MinEmitCount + ( Mix::Rand() % m_DiffEmitCount );
}

}}}

