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

#include "Mix/Private/Scene/Common/Octree.h"
#include "Mix/Private/Scene/Common/OctreeNode.h"
#include "Mix/Private/Scene/Common/PointLight.h"
#include "Mix/Private/Scene/Common/SpotLight.h"
#include "Mix/Private/Scene/Common/WaterPool.h"
#include "Mix/Private/Scene/Common/Planter.h"
#include "Mix/Private/Scene/Common/LeavingParticle.h"
#include "Mix/Private/Scene/Common/ScatterParticle.h"
#include "Mix/Private/Scene/Common/ActorModel.h"

namespace Mix{ namespace Scene{ namespace Common{

/*
	ポイントライトオブジェクト
*/

PointLightObject::PointLightObject(	Mix::Scene::Common::OctreeNode* pNode,
									Mix::Scene::Common::PointLight* pPointLight ) :
m_pPointLight( NULL )
{
	MIX_ASSERT( pPointLight != NULL );
	m_pPointLight = pPointLight;

	pNode->AttachObject( this );
}

PointLightObject::~PointLightObject( void )
{
	MIX_ASSERT( m_pNode == NULL );
	MIX_ASSERT( m_pPointLight == NULL );
}

Boolean PointLightObject::IsEnabled( void ) const
{
	return m_pPointLight->IsEnabled();
}

const Mix::Geometry::Sphere& PointLightObject::GetBounds( void ) const
{
	return m_pPointLight->GetBounds();
}

Mix::Scene::Common::LOCAL_LIGHT* PointLightObject::Generate( Mix::Scene::Common::LOCAL_LIGHT* pOutput )
{
	MIX_ASSERT( m_pPointLight != NULL );
	MIX_ASSERT( pOutput != NULL );

	const Mix::Scene::Common::PointLight::PARAM& param = m_pPointLight->GetParam();

	pOutput->type = Mix::Scene::IRendererObject::POINT_LIGHT;
	pOutput->pos = param.pos;
	pOutput->atten = param.atten;
	pOutput->color = param.color;
	pOutput->outerRadius = param.outerRadius;
	pOutput->invDiffRadius = param.invDiffRadius;

	pOutput->bounds = m_pPointLight->GetBounds();
//	pOutput->z = 0.0f;
//	pOutput->backZ = 0.0f;
//	pOutput->offsetZ = 0.0f;

	return pOutput;
}

void PointLightObject::Refresh( void )
{
	MIX_ASSERT( m_pNode != NULL );
	m_pNode->RefreshObject( this );
}

void PointLightObject::Destroy( void )
{
	MIX_ASSERT( m_pNode != NULL );
	MIX_ASSERT( m_pPointLight != NULL );

	m_pNode->DestroyObject( this );
	m_pNode = NULL;

	m_pPointLight = NULL;

	MIX_LIB_DELETE_THIS_T( PointLightObject, this );
}

#ifdef _DEBUG

UInt32 PointLightObject::Debug_GetType( void ) const
{
	return Mix::Scene::IRendererObject::POINT_LIGHT;
}

void* PointLightObject::Debug_GetInternalPtr( void ) const
{
	return m_pPointLight;
}

#endif //_DEBUG

/*
	スポットライトオブジェクト
*/

SpotLightObject::SpotLightObject(	Mix::Scene::Common::OctreeNode* pNode,
									Mix::Scene::Common::SpotLight* pSpotLight ) :
m_pSpotLight( NULL )
{
	MIX_ASSERT( pSpotLight != NULL );
	m_pSpotLight = pSpotLight;

	MIX_ASSERT( pNode != NULL );
	pNode->AttachObject( this );
}

SpotLightObject::~SpotLightObject( void )
{
	MIX_ASSERT( m_pNode == NULL );
	MIX_ASSERT( m_pSpotLight == NULL );
}

Boolean SpotLightObject::IsEnabled( void ) const
{
	return m_pSpotLight->IsEnabled();
}

const Mix::Geometry::Sphere& SpotLightObject::GetBounds( void ) const
{
	return m_pSpotLight->GetBounds();
}

Mix::Scene::Common::LOCAL_LIGHT* SpotLightObject::Generate( Mix::Scene::Common::LOCAL_LIGHT* pOutput )
{
	MIX_ASSERT( m_pSpotLight != NULL );
	MIX_ASSERT( pOutput != NULL );

	const Mix::Scene::Common::SpotLight::PARAM& param = m_pSpotLight->GetParam();

	pOutput->type = Mix::Scene::IRendererObject::SPOT_LIGHT;
	pOutput->pos = param.pos;
	pOutput->atten = param.atten;
	pOutput->color = param.color;
	pOutput->dir = param.dir;
	pOutput->range = param.range;
	pOutput->innerCos = param.innerCos;
	pOutput->outerCos = param.outerCos;
	pOutput->exp = param.exp;

	pOutput->bounds = m_pSpotLight->GetBounds();
//	pOutput->z = 0.0f;
//	pOutput->backZ = 0.0f;
//	pOutput->offsetZ = 0.0f;

	return pOutput;
}

void SpotLightObject::Refresh( void )
{
	MIX_ASSERT( m_pNode != NULL );
	m_pNode->RefreshObject( this );
}

void SpotLightObject::Destroy( void )
{
	MIX_ASSERT( m_pNode != NULL );

	m_pNode->DestroyObject( this );
	m_pNode = NULL;

	m_pSpotLight = NULL;

	MIX_LIB_DELETE_THIS_T( SpotLightObject, this );
}

#ifdef _DEBUG

UInt32 SpotLightObject::Debug_GetType( void ) const
{
	return Mix::Scene::IRendererObject::SPOT_LIGHT;
}

void* SpotLightObject::Debug_GetInternalPtr( void ) const
{
	return m_pSpotLight;
}

#endif //_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////
// ウィジェット
////////////////////////////////////////////////////////////////////////////////////////////////////

/*
	リービングパーティクルオブジェクト
*/

LeavingParticleObject::LeavingParticleObject(	const UInt32* pViewBits,
												Mix::Scene::Common::OctreeNode* pNode,
												Mix::Scene::Common::LeavingParticle* pContent ) : ManagedViewObject( pViewBits ),
m_pContent( NULL )
{
	MIX_ASSERT( pNode != NULL );
	MIX_ASSERT( pContent != NULL );

	m_pContent = pContent;

	//アタッチすることによって m_pNode に pNode が設定される
	pNode->AttachObject( this );
}

LeavingParticleObject::~LeavingParticleObject( void )
{
	MIX_ASSERT( m_pNode == NULL );
	MIX_ASSERT( m_pContent == NULL );
}

const Mix::Geometry::AABB& LeavingParticleObject::GetBounds( void ) const
{
	MIX_ASSERT( m_pContent != NULL );
	return m_pContent->GetBounds();
}

Mix::Scene::Common::LeavingParticle* LeavingParticleObject::GetContentPtr( void ) const
{
	MIX_ASSERT( m_pContent != NULL );
	return m_pContent;
}

void LeavingParticleObject::Invalid( Mix::Scene::Common::OCTREE_VIEW_TYPE viewType )
{
	MIX_ASSERT( m_pViewBits != NULL );
	MIX_ASSERT( m_pViewBits[viewType] != 0 );

	MIX_RESETBIT( m_NxtState, m_pViewBits[viewType] );
}

void LeavingParticleObject::Refresh( void )
{
	MIX_ASSERT( m_pNode != NULL );

	m_pNode->RefreshObject( this );
}

void LeavingParticleObject::Destroy( void )
{
	MIX_ASSERT( m_pNode != NULL );

	m_pNode->DestroyObject( this );
	m_pNode = NULL;

	m_pContent = NULL;

	MIX_LIB_DELETE_THIS_T( LeavingParticleObject, this );
}

#ifdef _DEBUG

UInt32 LeavingParticleObject::Debug_GetType( void ) const
{
	return Mix::Scene::IRendererObject::LEAVING_PARTICLE;
}

void* LeavingParticleObject::Debug_GetInternalPtr( void ) const
{
	return m_pContent;
}

#endif //_DEBUG

/*
	スキャッターパーティクルユニットオブジェクト
*/

ScatterParticleUnitObject::ScatterParticleUnitObject( void ) :
m_pContent( NULL )
{
}

ScatterParticleUnitObject::~ScatterParticleUnitObject( void )
{
	MIX_ASSERT( m_pNode == NULL );
	MIX_ASSERT( m_pContent == NULL );
}

void ScatterParticleUnitObject::Initialize( Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::ScatterParticleUnit* pContent )
{
	MIX_ASSERT( pNode != NULL );
	MIX_ASSERT( pContent != NULL );
	MIX_ASSERT( m_pNode == NULL );
	MIX_ASSERT( m_pContent == NULL );

	m_pContent = pContent;

	//アタッチすることによって m_pNode に pNode が設定される
	pNode->AttachObject( this );
}

const Mix::Geometry::Sphere& ScatterParticleUnitObject::GetBounds( void ) const
{
	MIX_ASSERT( m_pContent != NULL );
	return m_pContent->GetBounds();
}

Mix::Scene::Common::ScatterParticleUnit* ScatterParticleUnitObject::GetContentPtr( void ) const
{
	MIX_ASSERT( m_pContent != NULL );
	return m_pContent;
}

void ScatterParticleUnitObject::Refresh( void )
{
	MIX_ASSERT( m_pNode != NULL );

	m_pNode->RefreshObject( this );
}

void ScatterParticleUnitObject::Destroy( void )
{
	MIX_ASSERT( m_pNode != NULL );

	m_pNode->DestroyObject( this );
	m_pNode = NULL;

	m_pContent = NULL;

	// スキャッターパーティクルはキャッシュされるので解放しない
//	MIX_LIB_DELETE_THIS( this );
}

#ifdef _DEBUG

UInt32 ScatterParticleUnitObject::Debug_GetType( void ) const
{
	return Mix::Scene::IRendererObject::SCATTER_PARTICLE;
}

void* ScatterParticleUnitObject::Debug_GetInternalPtr( void ) const
{
	return m_pContent;
}

#endif //_DEBUG

/*
	プランターオブジェクト
*/

PlanterObject::PlanterObject( Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::Planter* pContent ) :
m_pContent( NULL ),
m_pBounds( NULL )
{
	MIX_ASSERT( pContent != NULL );

	m_pContent = pContent;
	m_pBounds = &( pContent->GetBounds() );

	//アタッチすることによって m_pNode に pNode が設定される
	pNode->AttachObject( this );
}

PlanterObject::~PlanterObject( void )
{
	MIX_ASSERT( m_pNode == NULL );
	MIX_ASSERT( m_pContent == NULL );
}

Boolean PlanterObject::IsEnabled( void ) const
{
	if( m_pContent->GetUnitCount() == 0 )
	{
		// ユニットが存在しない
		return False;
	}

	return m_pContent->IsDraw();
}

const Mix::Geometry::AABB& PlanterObject::GetBounds( void ) const
{
	return *m_pBounds;
}

Mix::Scene::Common::Planter* PlanterObject::GetContentPtr( void ) const
{
	return m_pContent;
}

void PlanterObject::Refresh( void )
{
	MIX_ASSERT( m_pNode != NULL );
	m_pNode->RefreshObject( this );
}

void PlanterObject::Destroy( void )
{
	MIX_ASSERT( m_pNode != NULL );

	m_pNode->DestroyObject( this );
	m_pNode = NULL;

	m_pContent = NULL;

	MIX_LIB_DELETE_THIS_T( PlanterObject, this );
}

#ifdef _DEBUG

UInt32 PlanterObject::Debug_GetType( void ) const
{
	return Mix::Scene::IRendererObject::PLANTER;
}

void* PlanterObject::Debug_GetInternalPtr( void ) const
{
	return m_pContent;
}

#endif //_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////
// モデル
////////////////////////////////////////////////////////////////////////////////////////////////////

/*
	アクターモデルオブジェクト
*/

ActorModelObject::ActorModelObject(	const UInt32* pViewBits,
									Mix::Scene::Common::OctreeNode* pNode,
									Mix::Scene::Common::ActorModel* pContent ) : ManagedViewObject( pViewBits ),
m_pContent( NULL )
{
	MIX_ASSERT( pNode != NULL );
	MIX_ASSERT( pContent != NULL );

	m_pContent = pContent;

	//アタッチすることによって m_pNode に pNode が設定される
	pNode->AttachObject( this );
}

ActorModelObject::~ActorModelObject( void )
{
	MIX_ASSERT( m_pNode == NULL );
	MIX_ASSERT( m_pContent == NULL );
}

const Mix::Geometry::Sphere& ActorModelObject::GetBounds( void ) const
{
	MIX_ASSERT( m_pContent != NULL );
	return m_pContent->GetBounds();
}

Mix::Scene::Common::ActorModel* ActorModelObject::GetContentPtr( void ) const
{
	MIX_ASSERT( m_pContent != NULL );
	return m_pContent;
}

void ActorModelObject::Invalid( Mix::Scene::Common::OCTREE_VIEW_TYPE viewType )
{
	MIX_ASSERT( m_pViewBits != NULL );
	MIX_ASSERT( m_pViewBits[viewType] != 0 );

	MIX_RESETBIT( m_NxtState, m_pViewBits[viewType] );
}

void ActorModelObject::Refresh( void )
{
	MIX_ASSERT( m_pNode != NULL );
	m_pNode->RefreshObject( this );
}

void ActorModelObject::Destroy( void )
{
	MIX_ASSERT( m_pNode != NULL );

	m_pNode->DestroyObject( this );
	m_pNode = NULL;

	m_pContent = NULL;

	MIX_LIB_DELETE_THIS_T( ActorModelObject, this );
}

#ifdef _DEBUG

UInt32 ActorModelObject::Debug_GetType( void ) const
{
	return Mix::Scene::IRendererObject::ACTOR_MODEL;
}

void* ActorModelObject::Debug_GetInternalPtr( void ) const
{
	return m_pContent;
}

#endif //_DEBUG

////////////////////////////////////////////////////////////////////////////////////////////////////
// その他
////////////////////////////////////////////////////////////////////////////////////////////////////

/*
	ウォータープールオブジェクト
*/

WaterPoolObject::WaterPoolObject( Mix::Scene::Common::OctreeNode* pNode, Mix::Scene::Common::WaterPool* pContent ) :
m_pContent( NULL ),
m_pBounds( NULL )
{
	MIX_ASSERT( pContent != NULL );

	m_pContent = pContent;
	m_pContentContext = m_pContent->GetContextPtr();
	m_pBounds = &( pContent->GetBounds() );

	//アタッチすることによって m_pNode に pNode が設定される
	pNode->AttachObject( this );
}

WaterPoolObject::~WaterPoolObject( void )
{
	MIX_ASSERT( m_pNode == NULL );
	MIX_ASSERT( m_pContent == NULL );
}

const Mix::Geometry::AABB& WaterPoolObject::GetBounds( void ) const
{
	return *m_pBounds;
}

Mix::Scene::Common::WaterPool* WaterPoolObject::GetContentPtr( void ) const
{
	return m_pContent;
}

Mix::Scene::IWaterPoolContext* WaterPoolObject::GetContentContextPtr( void ) const
{
	return m_pContentContext;
}

void WaterPoolObject::Refresh( void )
{
	MIX_ASSERT( m_pNode != NULL );
	m_pNode->RefreshObject( this );
}

void WaterPoolObject::Destroy( void )
{
	MIX_ASSERT( m_pNode != NULL );

	m_pNode->DestroyObject( this );
	m_pNode = NULL;

	m_pContent = NULL;
	m_pContentContext = NULL;

	MIX_LIB_DELETE_THIS_T( WaterPoolObject, this );
}

#ifdef _DEBUG

UInt32 WaterPoolObject::Debug_GetType( void ) const
{
	return Mix::Scene::IRendererObject::WATER_POOL;
}

void* WaterPoolObject::Debug_GetInternalPtr( void ) const
{
	return m_pContent;
}

#endif //_DEBUG

}}}
