#include "Mix/Private/Scene/Common/OctreeView.h"
#include "Mix/Private/Scene/Common/Octree.h"

namespace Mix{ namespace Scene{ namespace Common{

const UInt32 OctreeView::V_OBJECTS_DEF_SIZE = 256;
const UInt32 OctreeView::V_OBJECTS_RESIZE_STEP = 32;

OctreeView::OctreeView( Mix::Scene::Common::Octree* pOwner, const Mix::Scene::Common::OCTREE_VIEW_DATA& data, const wchar_t* pDebugName ) :
m_pOwner( NULL )
{
	MIX_ASSERT( pOwner != NULL );
	MIX_ASSERT( data.colBit != 0 );
	MIX_ASSERT( data.sdwBit != 0 );
	MIX_ASSERT( data.mask != 0 );
	MIX_ASSERT( data.invMask != 0 );
	MIX_ASSERT( pDebugName != NULL );

	Mix::String tempStr;

	m_pOwner = pOwner;
	m_Data = data;

	m_NxtClearMask = m_Data.invMask;

	tempStr.Sprintf( L"%s/ValidLeavingParticleObjects", pDebugName );
	m_ValidLeavingParticleObjects.Initialize( OctreeView::V_OBJECTS_DEF_SIZE, OctreeView::V_OBJECTS_RESIZE_STEP, tempStr.GetConstPtr() );

	tempStr.Sprintf( L"%s/ValidActorModelObjects", pDebugName );
	m_ValidActorModelObjects.Initialize( OctreeView::V_OBJECTS_DEF_SIZE, OctreeView::V_OBJECTS_RESIZE_STEP, tempStr.GetConstPtr() );
}

OctreeView::~OctreeView( void )
{
	MIX_ASSERT( m_pOwner == NULL );
}

void OctreeView::Valid( Mix::Scene::Common::OCTREE_VIEW_TYPE type )
{
	MIX_ASSERT( ( type == Mix::Scene::Common::OCTREE_VIEW_COLOR ) || ( type == Mix::Scene::Common::OCTREE_VIEW_SHADOW ) );

	switch( type )
	{
	case Mix::Scene::Common::OCTREE_VIEW_COLOR:
		MIX_SETBIT( m_NxtClearMask, m_Data.colBit );
		break;
	case Mix::Scene::Common::OCTREE_VIEW_SHADOW:
		MIX_SETBIT( m_NxtClearMask, m_Data.sdwBit );
		break;
	}
}

void OctreeView::DestroyObject( Mix::Scene::Common::LeavingParticleObject* pObj )
{
	MIX_ASSERT( pObj != NULL );

	m_ValidLeavingParticleObjects.Remove( pObj );
}

void OctreeView::DestroyObject( Mix::Scene::Common::ActorModelObject* pObj )
{
	MIX_ASSERT( pObj != NULL );

	m_ValidActorModelObjects.Remove( pObj );
}

UInt32 OctreeView::GetID( void ) const
{
	return m_Data.id;
}

void OctreeView::Switch( void )
{
	MIX_ASSERT( m_pOwner != NULL );

	m_pOwner->SwitchView( this );
}

void OctreeView::Finish( void )
{
	UInt32 pcObjCount = m_ValidLeavingParticleObjects.GetCount();
	UInt32 amObjCount = m_ValidActorModelObjects.GetCount();
	UInt32 validCount;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 無効なオブジェクトを切り捨てるため SC→S→C でオブジェクトをソート
	//  ↓
	// ステートを適用
	//  ↓
	// 無効なものを切り捨てる
	//
	// S=Shadow
	// C=Color
	////////////////////////////////////////////////////////////////////////////////////////////////////

	//パーティクル
	if( pcObjCount > 0 )
	{
		OctreeView::SortValidObjects( m_ValidLeavingParticleObjects.GetBeginPtr(), 0, pcObjCount - 1, m_Data.mask );
		validCount = OctreeView::ApplyStateObjects( m_ValidLeavingParticleObjects, m_Data.mask, m_Data.invMask, m_NxtClearMask );
		m_ValidLeavingParticleObjects.Reduction( validCount );
	}

	//アクターモデル
	if( amObjCount > 0 )
	{
		OctreeView::SortValidObjects( m_ValidActorModelObjects.GetBeginPtr(), 0, amObjCount - 1, m_Data.mask );
		validCount = OctreeView::ApplyStateObjects( m_ValidActorModelObjects, m_Data.mask, m_Data.invMask, m_NxtClearMask );
		m_ValidActorModelObjects.Reduction( validCount );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クリア
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_NxtClearMask = m_Data.invMask;
}

void OctreeView::Destroy( void )
{
	MIX_ASSERT( m_pOwner != NULL );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 現在有効になっているオブジェクトを無効にする
	////////////////////////////////////////////////////////////////////////////////////////////////////

	/*
		パーティクル
	*/

	OctreeView::InvalidateObjects( m_ValidLeavingParticleObjects, m_Data.invMask );

	/*
		アクターモデル
	*/

	OctreeView::InvalidateObjects( m_ValidActorModelObjects, m_Data.invMask );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 自身を破棄
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pOwner->DestroyView( this );
	m_pOwner = NULL;

	MIX_LIB_DELETE_THIS_T( OctreeView, this );
}

#ifdef _DEBUG

Boolean OctreeView::Debug_HasValidObjects( void ) const
{
	return ( ( m_ValidLeavingParticleObjects.GetCount() > 0 ) || ( m_ValidActorModelObjects.GetCount() > 0 ) );
}

#endif //_DEBUG

}}}
