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

#include "Mix/Scene/ICamera.h"
#include "Mix/Scene/IMaterial.h"
#include "Mix/Scene/IParticleSystem.h"
#include "Mix/Scene/IParticleGenerator.h"
#include "Mix/Scene/IParticleProcessor.h"
#include "Mix/Private/Scene/Common/Octree.h"

#ifdef _DEBUG
	#include "Mix/Graphics/Utility/IPerspectiveRenderer.h"
	#include "Mix/Private/Scene/Common/Debug.h"
#endif //_DEBUG

namespace Mix{ namespace Scene{ namespace Common{

const wchar_t* ScatterParticle::FAILED_CREATE = L"スキャッターパーティクルの作成に失敗";
const wchar_t* ScatterParticle::FAILED_SET_MATERIAL = L"スキャッターパーティクルのマテリアルの設定に失敗";

////////////////////////////////////////////////////////////////////////////////////////////////////
// ScatterParticleUnit
////////////////////////////////////////////////////////////////////////////////////////////////////

ScatterParticleUnit::ScatterParticleUnit( void )
{
}

ScatterParticleUnit::~ScatterParticleUnit( void )
{
}

Boolean ScatterParticleUnit::InternalRefresh( const Mix::Matrix4x4& bbMat )
{
	if( faceNum == 0 )
	{
		return False;
	}

	if( bBillboard == True )
	{
		InternalParticle::FixedBillboardSubset( bbMat, subset.quads, subset.quadCount );
	}

	return True;
}

const Mix::Geometry::Sphere& ScatterParticleUnit::GetBounds( void ) const
{
	return subset.bounds;
}

Mix::Scene::Common::WIDGET_SPHERE_SUBSET* ScatterParticleUnit::GetSubsetPtr( void )
{
	return &subset;
}

Boolean ScatterParticleUnit::CanLocalLighting( void ) const
{
	return bLocalLighting;
}

Boolean ScatterParticleUnit::IsDraw( void ) const
{
	return bDraw;
}

Mix::Scene::WATER_CONTAINS_RESULT ScatterParticleUnit::GetDefaultWaterContainsResult( void ) const
{
	return defWCR;
}

#ifdef _DEBUG

UInt32 ScatterParticleUnit::Debug_GetVertexStride( void ) const
{
	return pDebOwner->Debug_GetVertexStride();
}

#endif //_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////
// ScatterParticle : UnitList
////////////////////////////////////////////////////////////////////////////////////////////////////

void ScatterParticle::UnitList_Init( UNIT_LIST& list )
{
	list.pTop = NULL;
	list.pBottom = NULL;
	list.count = 0;
}

void ScatterParticle::UnitList_Add( UNIT_LIST& list, ScatterParticleUnit* pUnit )
{
	MIX_ASSERT( pUnit != NULL );
	MIX_ASSERT( pUnit->pDebList == NULL );

	if( list.pTop == NULL )
	{
		pUnit->pPrev = NULL;
		pUnit->pNext = NULL;

		list.pTop = list.pBottom = pUnit;
	}
	else
	{
		pUnit->pPrev = list.pBottom;
		pUnit->pNext = NULL;

		list.pBottom->pNext = pUnit;
		list.pBottom = pUnit;
	}

	list.count++;

#ifdef _DEBUG
	pUnit->pDebList = &list;
#endif //_DEBUG
}

void ScatterParticle::UnitList_Remove( UNIT_LIST& list, ScatterParticleUnit* pUnit )
{
	MIX_ASSERT( list.count > 0 );
	MIX_ASSERT( pUnit != NULL );
	MIX_ASSERT( pUnit->pDebList == &list );

	if( ( list.pTop == pUnit ) && ( list.pBottom == pUnit ) )
	{
		list.pTop = list.pBottom = NULL;
	}
	else if( ( list.pTop == pUnit ) && ( list.pBottom != pUnit ) )
	{
		list.pTop = list.pTop->pNext;
		list.pTop->pPrev = NULL;
	}
	else if( ( list.pTop != pUnit ) && ( list.pBottom == pUnit ) )
	{
		list.pBottom = list.pBottom->pPrev;
		list.pBottom->pNext = NULL;
	}
	else
	{
		pUnit->pPrev->pNext = pUnit->pNext;
		pUnit->pNext->pPrev = pUnit->pPrev;
	}

	list.count--;

#ifdef _DEBUG
	pUnit->pPrev = NULL;
	pUnit->pNext = NULL;
	pUnit->pDebList = NULL;
#endif //_DEBUG
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// ScatterParticle
////////////////////////////////////////////////////////////////////////////////////////////////////

ScatterParticle* ScatterParticle::CreateInstance(	Mix::Scene::IMaterial* pMaterial,
													Mix::Scene::IParticleSystem* pSystem,
													UInt32 defUnitCapacity,
													UInt32 defQuadCapacity,
													UInt32 quadResizeStep,
													const wchar_t* pDebugName )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, ScatterParticle, pMaterial, pSystem, defUnitCapacity, defQuadCapacity, quadResizeStep, pDebugName );
}

ScatterParticle::ScatterParticle(	Mix::Scene::IMaterial* pMaterial,
									Mix::Scene::IParticleSystem* pSystem,
									UInt32 defUnitCapacity,
									UInt32 defQuadCapacity,
									UInt32 quadResizeStep,
									const wchar_t* pDebugName ) : InternalParticle( pDebugName ),
m_pOctree( NULL ),
m_pSystem( NULL ),
m_pGenerator( NULL ),
m_bLocalLighting( False ),
m_bDraw( True ),
m_TRPriority( 0 ),
m_DefWCResult( Mix::Scene::WCR_FRONT )
{
	MIX_ASSERT( pMaterial != NULL );
	MIX_ASSERT( pSystem != NULL );
	MIX_ASSERT( pDebugName != NULL );
	MIX_ASSERT( defUnitCapacity > 0 );
	MIX_ASSERT( defQuadCapacity > 0 );
	MIX_ASSERT( quadResizeStep > 0 );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// デバッグ
	////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
		m_DebugDrawAxisScaling = 1.0f;
#endif //_DEBUG

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// システム
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_ADD_REF( pSystem );
	m_pSystem = pSystem;

	m_bBillboard = ( MIX_TESTBIT( m_pSystem->GetConfig().baseFlags, IParticleSystem::BILLBOARD ) == IParticleSystem::BILLBOARD );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ジェネレーター
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pSystem->Internal_GetGenerator( &m_pGenerator );
	MIX_ASSERT( m_pGenerator != NULL );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ユニット
	////////////////////////////////////////////////////////////////////////////////////////////////////

	ScatterParticle::UnitList_Init( m_UnitList );
	ScatterParticle::UnitList_Init( m_UnitPool );

	for( UInt32 i = 0; i < defUnitCapacity; i++ )
	{
		ScatterParticleUnit* pUnit;

		pUnit = MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, ScatterParticleUnit );
		MIX_ASSERT( pUnit != NULL );

#ifdef _DEBUG
		pUnit->pProcessor = NULL;
		pUnit->pDebList = NULL;
		pUnit->pDebGenerator = m_pGenerator;
		pUnit->pDebOwner = this;
#endif //_DEBUG

		m_pSystem->Internal_CreateProcessor( &( pUnit->pProcessor ) );
		MIX_ASSERT( pUnit->pProcessor != NULL );

		pUnit->pOctObj = NULL;
		pUnit->bLocalLighting = False; // 下の SetMaterial で設定される
		pUnit->bDraw = True;
		pUnit->defWCR = Mix::Scene::WCR_UNKNOWN;

		ScatterParticle::UnitList_Add( m_UnitPool, pUnit );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クワッド
	////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG

	Mix::StringW tempStr;

	tempStr.Sprintf( L"%s/QuadPool", pDebugName );
	m_QuadPool.Initialize( defQuadCapacity, quadResizeStep, tempStr.GetConstPtr() );

#else //_DEBUG

	m_QuadPool.Initialize( defQuadCapacity, quadResizeStep );

#endif //_DEBUG

	m_QuadPool.Add( defQuadCapacity );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ステータス
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_State.unitCount = 0;
	m_State.unitCapacity = m_UnitPool.count;
	m_State.quadCount = 0;
	m_State.quadCapacity = 0;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアル
	////////////////////////////////////////////////////////////////////////////////////////////////////

	SetMaterial( pMaterial );
}

ScatterParticle::~ScatterParticle( void )
{
	MIX_ASSERT( m_pOctree == NULL );

	ScatterParticleUnit* pUnit;
	ScatterParticleUnit* pNextUnit;

	// クリアしてストックリストに移す
	Clear();

	// ストックリストでユニットを解放
	pUnit = m_UnitPool.pTop;
	while( pUnit != NULL )
	{
		pNextUnit = pUnit->pNext;

		MIX_ASSERT( pUnit->pOctObj == NULL ); //クリアで NULL になっているはず
		MIX_RELEASE( pUnit->pProcessor );
		MIX_LIB_DELETE_T( ScatterParticleUnit, pUnit );

		pUnit = pNextUnit;
	}

	MIX_RELEASE( m_pGenerator );
	MIX_RELEASE( m_pSystem );
}

ScatterParticleUnit* ScatterParticle::AddUnit( const Mix::Matrix4x4& worldMat )
{
	const IParticleSystem::CONFIG& sysCfg = m_pSystem->GetConfig();
	Mix::Vector3 worldPos = worldMat.GetTranslation();
	ScatterParticleUnit* pUnit;
	Mix::Scene::Common::WIDGET_SPHERE_SUBSET* pSubset;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ユニットの作成
	//  パーティクルプロセッサー
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_UnitPool.count > 0 )
	{
		//キャッシュから取得
		pUnit = m_UnitPool.pBottom;
		ScatterParticle::UnitList_Remove( m_UnitPool, pUnit );

		pSubset = &( pUnit->subset );
	}
	else
	{
		//新規に作成
		pUnit = MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, ScatterParticleUnit );

		MIX_ASSERT( pUnit != NULL );

#ifdef _DEBUG
		pUnit->pProcessor = NULL;
		pUnit->pDebList = NULL;
		pUnit->pDebGenerator = m_pGenerator;
		pUnit->pDebOwner = this;
#endif //_DEBUG

		m_pSystem->Internal_CreateProcessor( &( pUnit->pProcessor ) );
		MIX_ASSERT( pUnit->pProcessor != NULL );

		// 新規追加によるサブセットの初期化
		pSubset = &( pUnit->subset );
		pSubset->priority = m_TRPriority;
		pSubset->pMaterial = m_pMaterial;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ユニットの初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pSubset->bounds.center = worldPos;
	pSubset->bounds.radius = 0.0f;
	pSubset->quadCount = 0;
	pSubset->quads = NULL;

	pUnit->bBillboard = m_bBillboard;
	pUnit->worldMat = worldMat;
	pUnit->pOctObj = ( m_pOctree != NULL )? m_pOctree->AddScatterParticleUnit( pUnit ) : NULL;
	pUnit->bLocalLighting = CanLocalLighting();
	pUnit->bDraw = m_bDraw;
	pUnit->defWCR = m_DefWCResult;
	pUnit->faceNum = 0;
	pUnit->faces = NULL;
	pUnit->quadOffset = 0;

//  UnitList_Add で設定される
//	pUnit->pPrev = NULL;
//	pUnit->pNext = NULL;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// リストへ追加
	////////////////////////////////////////////////////////////////////////////////////////////////////

	ScatterParticle::UnitList_Add( m_UnitList, pUnit );

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

	return pUnit;
}

ScatterParticleUnit* ScatterParticle::RemoveUnit( ScatterParticleUnit* pUnit )
{
	MIX_ASSERT( pUnit != NULL );

	ScatterParticleUnit* pNextUnit = pUnit->pNext;

	if( pUnit->pOctObj != NULL )
	{
		pUnit->pOctObj->Destroy();
		pUnit->pOctObj = NULL;
	}

	ScatterParticle::UnitList_Remove( m_UnitList, pUnit );
	ScatterParticle::UnitList_Add( m_UnitPool, pUnit );

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

	return pNextUnit;
}

void ScatterParticle::FlashUnits( void )
{
	Boolean bCanLocalLighting = CanLocalLighting();
	ScatterParticleUnit* pUnit;

	pUnit = m_UnitList.pTop;
	while( pUnit != NULL )
	{
		pUnit->bLocalLighting = bCanLocalLighting;
		pUnit->bDraw = m_bDraw;
		pUnit->defWCR = m_DefWCResult;
		pUnit->subset.priority = m_TRPriority;
		pUnit->subset.pMaterial = m_pMaterial;

		pUnit = pUnit->pNext;
	}

	pUnit = m_UnitPool.pTop;
	while( pUnit != NULL )
	{
		pUnit->bLocalLighting = bCanLocalLighting;
		pUnit->bDraw = m_bDraw;
		pUnit->defWCR = m_DefWCResult;
		pUnit->subset.priority = m_TRPriority;
		pUnit->subset.pMaterial = m_pMaterial;

		pUnit = pUnit->pNext;
	}
}

void ScatterParticle::Attach( Mix::Scene::Common::Octree* pOctree )
{
	MIX_ASSERT( pOctree != NULL );
	MIX_ASSERT( m_pOctree == NULL );

	ScatterParticleUnit* pUnit = m_UnitList.pTop;

	m_pOctree = pOctree;

	while( pUnit != NULL )
	{
		MIX_ASSERT( pUnit->pOctObj == NULL );

		pUnit->pOctObj = m_pOctree->AddScatterParticleUnit( pUnit );

		pUnit = pUnit->pNext;
	}

	RendererObject::SetRendering( True );
}

void ScatterParticle::Detach( void )
{
	if( m_pOctree != NULL )
	{
		ScatterParticleUnit* pUnit = m_UnitList.pTop;

		while( pUnit != NULL )
		{
			MIX_ASSERT( pUnit->pOctObj != NULL );

			pUnit->pOctObj->Destroy();
			pUnit->pOctObj = NULL;

			pUnit = pUnit->pNext;
		}

		m_pOctree = NULL;
	}

	RendererObject::SetRendering( False );
}

#ifdef _DEBUG

UInt32 ScatterParticle::Debug_GetVertexStride( void ) const
{
	return m_DebVertexStride;
}

#endif //_DEBUG

void ScatterParticle::Clear( void )
{
	ScatterParticleUnit* pUnit = m_UnitList.pTop;

	while( pUnit != NULL )
	{
		pUnit = RemoveUnit( pUnit );
	}
}

void ScatterParticle::Emit( const Mix::Matrix4x4& worldMat )
{
	MIX_ASSERT( m_pSystem != NULL );
	MIX_ASSERT( m_pGenerator != NULL );

	UInt32 genNum = m_pSystem->Internal_GetGenerateCount();

	if( genNum > 0 )
	{
		ScatterParticleUnit* pUnit;

		pUnit = AddUnit( worldMat );
		pUnit->pProcessor->Internal_Add( worldMat, m_pGenerator, genNum );
	}
}

void ScatterParticle::Emit( const Mix::Matrix4x4& worldMat, UInt32 genNum )
{
	MIX_ASSERT( m_pGenerator != NULL );

	if( genNum > 0 )
	{
		ScatterParticleUnit* pUnit;

		pUnit = AddUnit( worldMat );
		pUnit->pProcessor->Internal_Add( worldMat, m_pGenerator, genNum );
	}
}

const Mix::Scene::IScatterParticle::STATE& ScatterParticle::GetState( void ) const
{
	return m_State;
}

void ScatterParticle::Update( Float32 dt )
{
	ScatterParticleUnit* pUnit = m_UnitList.pTop;
	UInt32 quadOffset = 0;
	UInt32 faceNum;
	Mix::Scene::IParticleProcessor* pProcessor;

	while( pUnit != NULL )
	{
		pProcessor = pUnit->pProcessor;

		pProcessor->Internal_Update( dt );
		faceNum = pProcessor->Internal_GetFaceNum();

		if( faceNum > 0 )
		{
			pUnit->faceNum = faceNum;
			pUnit->faces = pProcessor->Internal_GetFaces();
			pUnit->quadOffset = quadOffset;

			pUnit = pUnit->pNext;

			quadOffset += faceNum;
		}
		else
		{
			pUnit = RemoveUnit( pUnit );
		}
	}

	m_State.unitCount = m_UnitList.count;
	m_State.unitCapacity = m_UnitList.count + m_UnitPool.count;
}

void ScatterParticle::Refresh( void )
{
	ScatterParticleUnit* pUnit = m_UnitList.pTop;

	if( pUnit == NULL )
	{
		m_State.quadCount = 0;
		m_State.quadCapacity = m_QuadPool.GetCount();
		return;
	}

	const IParticleSystem::CONFIG& sysCfg = m_pSystem->GetConfig();

	ScatterParticleUnit* pBottomUnit = m_UnitList.pBottom;
	UInt32 quadNum = pBottomUnit->quadOffset + pBottomUnit->faceNum;
	UInt32 quadPoolCapacity = m_QuadPool.GetCount();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クワッド : プールのキャパシティチェック
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( quadPoolCapacity < quadNum )
	{
		InternalParticle::ExtendQuadsPool( quadNum - quadPoolCapacity );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クワッド : リストの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_bBillboard == True )
	{
		while( pUnit != NULL )
		{
			InternalParticle::RefreshBillboardSubset( pUnit->faces, pUnit->faceNum, pUnit->quadOffset, pUnit->subset );

			if( pUnit->pOctObj != NULL )
			{
				pUnit->pOctObj->Refresh();
			}

			pUnit = pUnit->pNext;
		}
	}
	else
	{
		while( pUnit != NULL )
		{
			InternalParticle::RefreshDefaultSubset(	pUnit->worldMat, pUnit->faces, pUnit->faceNum, pUnit->quadOffset, pUnit->subset );

			if( pUnit->pOctObj != NULL )
			{
				pUnit->pOctObj->Refresh();
			}

			pUnit = pUnit->pNext;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クワッド : ステータスの設定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_State.quadCount = quadNum;
	m_State.quadCapacity = m_QuadPool.GetCount();
}

void ScatterParticle::Refresh1( void )
{
	ScatterParticleUnit* pUnit = m_UnitList.pTop;

	if( pUnit == NULL )
	{
		m_State.quadCount = 0;
		m_State.quadCapacity = m_QuadPool.GetCount();
		return;
	}

	const IParticleSystem::CONFIG& sysCfg = m_pSystem->GetConfig();

	ScatterParticleUnit* pBottomUnit = m_UnitList.pBottom;
	UInt32 quadNum = pBottomUnit->quadOffset + pBottomUnit->faceNum;
	UInt32 quadPoolCapacity = m_QuadPool.GetCount();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クワッド : プールのキャパシティチェック
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( quadPoolCapacity < quadNum )
	{
		InternalParticle::ExtendQuadsPool( quadNum - quadPoolCapacity );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クワッド : リストの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_bBillboard == True )
	{
		while( pUnit != NULL )
		{
			InternalParticle::RefreshBillboardSubset( pUnit->faces, pUnit->faceNum, pUnit->quadOffset, pUnit->subset );

			pUnit = pUnit->pNext;
		}
	}
	else
	{
		while( pUnit != NULL )
		{
			InternalParticle::RefreshDefaultSubset(	pUnit->worldMat, pUnit->faces, pUnit->faceNum, pUnit->quadOffset, pUnit->subset );

			pUnit = pUnit->pNext;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クワッド : ステータスの設定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_State.quadCount = quadNum;
	m_State.quadCapacity = m_QuadPool.GetCount();
}

void ScatterParticle::Refresh2( void )
{
	ScatterParticleUnit* pUnit = m_UnitList.pTop;

	if( pUnit == NULL )
	{
		return;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ユニットを八分木に再配置
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_bBillboard == True )
	{
		while( pUnit != NULL )
		{
			if( pUnit->pOctObj != NULL )
			{
				pUnit->pOctObj->Refresh();
			}

			pUnit = pUnit->pNext;
		}
	}
	else
	{
		while( pUnit != NULL )
		{
			if( pUnit->pOctObj != NULL )
			{
				pUnit->pOctObj->Refresh();
			}

			pUnit = pUnit->pNext;
		}
	}
}

Float32 ScatterParticle::Debug_GetDrawAxisScaling( void ) const
{
#ifdef _DEBUG
	return m_DebugDrawAxisScaling;
#else //_DEBUG
	return 0.0f;
#endif //_DEBUG
}

void ScatterParticle::Debug_SetDrawAxisScaling( Float32 scaling )
{
#ifdef _DEBUG
	m_DebugDrawAxisScaling = max( 0.0f, scaling );
#endif //_DEBUG
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::IWidget
////////////////////////////////////////////////////////////////////////////////////////////////////

void ScatterParticle::GetMaterial( Mix::Scene::IMaterial** ppMaterial )
{
	InternalParticle::GetMaterial( ppMaterial );
}

Boolean ScatterParticle::SetMaterial( Mix::Scene::IMaterial* pMaterial )
{
	if( pMaterial == NULL )
	{
		return False;
	}

#ifdef _DEBUG
	if( InternalParticle::CheckMaterial( pMaterial, ScatterParticle::FAILED_SET_MATERIAL, m_DebugName.GetConstPtr() ) == False )
	{
		return False;
	}
#else //_DEBUG
	if( InternalParticle::CheckMaterial( pMaterial, ScatterParticle::FAILED_SET_MATERIAL, Mix::STR_UNKNOWN ) == False )
	{
		return False;
	}
#endif //_DEBUG

	if( InternalParticle::SetMaterial( pMaterial ) == False )
	{
		return False;
	}

	FlashUnits();

	return True;
}

Boolean ScatterParticle::CanLocalLighting( void ) const
{
	MIX_ASSERT( m_pMaterial != NULL );

	return ( ( m_pMaterial->IsLighting() == True ) && ( m_bLocalLighting == True ) );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::IEntity
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean ScatterParticle::IsDraw( void ) const
{
	return m_bDraw;
}

void ScatterParticle::SetDraw( Boolean state )
{
	if( m_bDraw != state )
	{
		m_bDraw = state;

		FlashUnits();
	}
}

Boolean ScatterParticle::IsLocalLighting( void ) const
{
	return m_bLocalLighting;
}

void ScatterParticle::SetLocalLighting( Boolean state )
{
	if( m_bLocalLighting != state )
	{
		m_bLocalLighting = state;

		FlashUnits();
	}
}

UInt32 ScatterParticle::GetTransparencyPriority( void ) const
{
	return m_TRPriority;
}

void ScatterParticle::SetTransparencyPriority( UInt32 priority )
{
	if( m_TRPriority != priority )
	{
		m_TRPriority = priority;

		FlashUnits();
	}
}

Mix::Scene::WATER_CONTAINS_RESULT ScatterParticle::GetDefaultWaterContainsResult( void ) const
{
	return m_DefWCResult;
}

void ScatterParticle::SetDefaultWaterContainsResult( Mix::Scene::WATER_CONTAINS_RESULT result )
{
	if( m_DefWCResult != result )
	{
		m_DefWCResult = result;

		FlashUnits();
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::IRendererObject
////////////////////////////////////////////////////////////////////////////////////////////////////

Mix::Scene::IRendererObject::TYPE ScatterParticle::GetType( void ) const
{
	return Mix::Scene::IRendererObject::SCATTER_PARTICLE;
}

Boolean ScatterParticle::IsRendering( void ) const
{
	return RendererObject::IsRendering();
}

#ifdef _DEBUG

void ScatterParticle::Debug_Draw( Mix::Graphics::Utility::IPerspectiveRenderer* pPerspectiveRenderer, UInt32 flags, ScatterParticleUnit* pUnit )
{
	MIX_ASSERT( pPerspectiveRenderer != NULL );
	MIX_ASSERT( pUnit != NULL );

	Mix::Matrix4x4 oldMat = pPerspectiveRenderer->GetMatrix();
	Mix::Vector4 oldColor = pPerspectiveRenderer->GetColor();

	if( MIX_TESTBIT( flags, Mix::Scene::DDF_PARTICLE_AXIS ) == Mix::Scene::DDF_PARTICLE_AXIS )
	{
		pPerspectiveRenderer->SetMatrix( pUnit->worldMat );
		pPerspectiveRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
		pPerspectiveRenderer->AddAxis( pUnit->pDebOwner->Debug_GetDrawAxisScaling() );
	}

	if( MIX_TESTBIT( flags, Mix::Scene::DDF_PARTICLE_BOUNDS ) == Mix::Scene::DDF_PARTICLE_BOUNDS )
	{
		pPerspectiveRenderer->SetMatrix( Mix::Matrix4x4::Identity() );
		pPerspectiveRenderer->SetColor( Mix::Scene::Common::Debug::GetDrawColor( Mix::Scene::DDC_BOUNDS ) );
		pPerspectiveRenderer->AddSphere( pUnit->subset.bounds );
	}

	if( MIX_TESTBIT( flags, Mix::Scene::DDF_PARTICLE_GENERATOR ) == Mix::Scene::DDF_PARTICLE_GENERATOR )
	{
		pPerspectiveRenderer->SetMatrix( Mix::Matrix4x4::Identity() );
		pPerspectiveRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
		pUnit->pDebGenerator->Debug_Draw( pUnit->worldMat, pPerspectiveRenderer );
	}

	if( MIX_TESTBIT( flags, Mix::Scene::DDF_PARTICLE_PROCESSOR ) == Mix::Scene::DDF_PARTICLE_PROCESSOR )
	{
		UInt32 quadNum = pUnit->subset.quadCount;

		pPerspectiveRenderer->SetMatrix( Mix::Matrix4x4::Identity() );

		if( quadNum > 0 )
		{
			Mix::Scene::Common::WIDGET_QUAD** ppQuad = &( pUnit->subset.quads[0] );
			Mix::Scene::Common::WIDGET_QUAD** ppQuadEnd = ppQuad + quadNum;
			Mix::Scene::Common::WIDGET_QUAD* pQuad;

			while( ppQuad != ppQuadEnd )
			{
				pQuad = ( *ppQuad );

				pPerspectiveRenderer->SetColor( pQuad->color );
				pPerspectiveRenderer->AddPolygon( pQuad->points, 4 );

				ppQuad++;
			}
		}

		pPerspectiveRenderer->SetColor( Mix::Vector4( 1.0f, 1.0f, 1.0f, 1.0f ) );
		pUnit->pProcessor->Debug_Draw( pUnit->worldMat, pPerspectiveRenderer );
	}

	pPerspectiveRenderer->SetColor( oldColor );
	pPerspectiveRenderer->SetMatrix( oldMat );
}

#endif //_DEBUG

}}}
