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

namespace Mix{ namespace Scene{ namespace Common{

////////////////////////////////////////////////////////////////////////////////////////////////////
// DefaultWaterPoolContext
////////////////////////////////////////////////////////////////////////////////////////////////////

DefaultWaterPoolContext* DefaultWaterPoolContext::CreateInstance( const Mix::Vector3& halfExtents )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, DefaultWaterPoolContext, halfExtents );
}

DefaultWaterPoolContext::DefaultWaterPoolContext( const Mix::Vector3& halfExtents ) :
m_HalfExtents( halfExtents )
{
}

DefaultWaterPoolContext::~DefaultWaterPoolContext( void )
{
}

void DefaultWaterPoolContext::Update( const Mix::Matrix4x4& worldMat )
{
	Mix::Vector3 worldPos = worldMat.GetTranslation();

	m_Bounds.min = worldPos - m_HalfExtents;
	m_Bounds.max = worldPos + m_HalfExtents;

	m_Bounds.ComputePoints();
}

const Mix::Geometry::AABB& DefaultWaterPoolContext::GetBounds( void ) const
{
	return m_Bounds;
}

Float32 DefaultWaterPoolContext::Contains( const Mix::Vector3& pos ) const
{
	return pos.y - m_Bounds.max.y;
}

Mix::Scene::WATER_CONTAINS_RESULT DefaultWaterPoolContext::Contains( const Mix::Geometry::AABB& bounds ) const
{
	if( m_Bounds.max.y < bounds.min.y )
	{
		return Mix::Scene::WCR_FRONT;
	}
	else if( m_Bounds.max.y >= bounds.max.y )
	{
		return Mix::Scene::WCR_BACK;
	}

	return Mix::Scene::WCR_OVERLAP;
}

Mix::Scene::WATER_CONTAINS_RESULT DefaultWaterPoolContext::Contains( const Mix::Geometry::Sphere& bounds ) const
{
	Float32 y = bounds.center.y;
	Float32 radius = bounds.radius;
	Float32 minY = y - radius;
	Float32 maxY = y + radius;

	if( m_Bounds.max.y < minY )
	{
		return Mix::Scene::WCR_FRONT;
	}
	else if( m_Bounds.max.y >= maxY )
	{
		return Mix::Scene::WCR_BACK;
	}

	return Mix::Scene::WCR_OVERLAP;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// WaterPool
////////////////////////////////////////////////////////////////////////////////////////////////////

const wchar_t* WaterPool::FAILED_CREATE = L"ウォータープールの作成に失敗";

WaterPool* WaterPool::CreateInstance( Mix::Scene::IWaterPoolContext* pContext )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, WaterPool, pContext );
}

WaterPool::WaterPool( Mix::Scene::IWaterPoolContext* pContext ) :
m_pContext( NULL ),
m_pOctObj( NULL ),
m_bRefraction( False )
{
	MIX_ASSERT( pContext != NULL );

	MIX_ADD_REF( pContext );
	m_pContext = pContext;

	m_VisualParam.color = Mix::Vector4( 0.1f, 0.7f, 1.0f, 0.4f );
	m_VisualParam.density = 80.0f;
	m_VisualParam.intensity = 1.0f;
	m_VisualParam.depth = 500.0f;
}

WaterPool::~WaterPool( void )
{
	MIX_ASSERT( m_pOctObj == NULL );

	MIX_RELEASE( m_pContext );
}

void WaterPool::Attach( Mix::Scene::Common::WaterPoolObject* pOctObj )
{
	MIX_ASSERT( pOctObj != NULL );
	MIX_ASSERT( m_pOctObj == NULL );

	m_pOctObj = pOctObj;

	RendererObject::SetRendering( True );
}

void WaterPool::Detach( void )
{
	if( m_pOctObj != NULL )
	{
		m_pOctObj->Destroy();
		m_pOctObj = NULL;
	}

	RendererObject::SetRendering( False );
}

Mix::Scene::IWaterPoolContext* WaterPool::GetContextPtr( void ) const
{
	return m_pContext;
}

Boolean WaterPool::IsRefraction( void ) const
{
	return m_bRefraction;
}

void WaterPool::SetRefraction( Boolean state )
{
	m_bRefraction = state;
}

const Mix::Scene::IWaterPool::VISUAL_PARAM& WaterPool::GetVisualParam( void ) const
{
	return m_VisualParam;
}

void WaterPool::SetVisualParam( const Mix::Scene::IWaterPool::VISUAL_PARAM& param )
{
	m_VisualParam.color = param.color.ToSaturate();
	m_VisualParam.density = max( 0.0f, param.density );
	m_VisualParam.intensity = max( 1.0f, param.intensity );
	m_VisualParam.depth = max( 0.0f, param.depth );
}

const Mix::Matrix4x4& WaterPool::GetWorldMatrix( void ) const
{
	return m_WorldMat;
}

void WaterPool::SetWorldMatrix( const Mix::Matrix4x4& worldMat )
{
	m_WorldMat = worldMat;
}

void WaterPool::Update( void ) const
{
	MIX_ASSERT( m_pContext != NULL );
	m_pContext->Update( m_WorldMat );
}

const Mix::Geometry::AABB& WaterPool::GetBounds( void ) const
{
	return m_pContext->GetBounds();
}

void WaterPool::Refresh( void ) const
{
	if( m_pOctObj != NULL )
	{
		m_pOctObj->Refresh();
	}
}

Boolean WaterPool::IsIllegal( void ) const
{
	if( m_pOctObj == NULL )
	{
		return False;
	}

	return m_pOctObj->IsIllegal();
}

Mix::Scene::IRendererObject::TYPE WaterPool::GetType( void ) const
{
	return Mix::Scene::IRendererObject::WATER_POOL;
}

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

}}}
