#include "Mix/Tool/CLR/Core/Graphics/Manager.h"
#include "Mix/Tool/Win32/Core/Graphics/Manager.h"

namespace Mix{ namespace Tool{ namespace Graphics{

////////////////////////////////////////////////////////////////////////////////////////////////////
// Manager::MaterialEffectPackageProperty
////////////////////////////////////////////////////////////////////////////////////////////////////

Manager::EffectPackageProperty::EffectPackageProperty( Mix::Tool::Win32::Graphics::Manager* _implManager ) :
implManager( _implManager )
{
}

Manager::EffectPackageProperty::~EffectPackageProperty( void )
{
	implManager = nullptr;
}

Mix::Tool::Graphics::ShaderModels Manager::EffectPackageProperty::Models::get( void )
{
	unsigned int flags = implManager->MEP_GetShaderModels();
	Mix::Tool::Graphics::ShaderModels ret = Mix::Tool::Graphics::ShaderModels::Init;

	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_MODEL_3 ) == Mix::Tool::Win32::Graphics::SHADER_MODEL_3 ) { ret = ret | Mix::Tool::Graphics::ShaderModels::DirectX9_3_0; }
	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_MODEL_4 ) == Mix::Tool::Win32::Graphics::SHADER_MODEL_4 ) { ret = ret | Mix::Tool::Graphics::ShaderModels::DirectX10_4_0; }
	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_MODEL_5 ) == Mix::Tool::Win32::Graphics::SHADER_MODEL_5 ) { ret = ret | Mix::Tool::Graphics::ShaderModels::DirectX11_5_0; }

	return ret;
}

Mix::Tool::Graphics::ShaderProcessFlags Manager::EffectPackageProperty::ProcessFlags::get( void )
{
	unsigned int flags = implManager->MEP_GetProcessFlags();
	Mix::Tool::Graphics::ShaderProcessFlags ret = Mix::Tool::Graphics::ShaderProcessFlags::Init;

	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_FOG )          == Mix::Tool::Win32::Graphics::SHADER_PROCESS_FOG )          { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::Fog; }
	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_SHADOW )       == Mix::Tool::Win32::Graphics::SHADER_PROCESS_SHADOW )       { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::Shadow; }
	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_REFRACT )      == Mix::Tool::Win32::Graphics::SHADER_PROCESS_REFRACT )      { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::Refract; }
//	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_SOFTPARTICLE ) == Mix::Tool::Win32::Graphics::SHADER_PROCESS_SOFTPARTICLE ) { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::SoftParticle; }
//	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_BLOOM )        == Mix::Tool::Win32::Graphics::SHADER_PROCESS_BLOOM )        { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::Bloom; }
//	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_DOF )          == Mix::Tool::Win32::Graphics::SHADER_PROCESS_DOF )          { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::DepthOfField; }
	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_ATMOSPHERE )   == Mix::Tool::Win32::Graphics::SHADER_PROCESS_ATMOSPHERE )   { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::Atmosphere; }
//	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_LUMINANCE )    == Mix::Tool::Win32::Graphics::SHADER_PROCESS_LUMINANCE )    { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::Luminance; }
	if( MIX_TEST_BIT( flags, Mix::Tool::Win32::Graphics::SHADER_PROCESS_SSAO )         == Mix::Tool::Win32::Graphics::SHADER_PROCESS_SSAO )         { ret = ret | Mix::Tool::Graphics::ShaderProcessFlags::SSAO; }

	return ret;
}

void Manager::EffectPackageProperty::Load(	Mix::Tool::Graphics::ShaderModels models,
											Mix::Tool::Graphics::ShaderProcessFlags procFlags,
											System::String^ directoryName,
											System::String^ name )
{
	unsigned int ssmFlags = 0;
	unsigned int deFlags = 0;
	pin_ptr<const wchar_t> wpDirectoryName = PtrToStringChars( directoryName );
	pin_ptr<const wchar_t> wpName = PtrToStringChars( name );

	if( MIX_TEST_BIT( models, Mix::Tool::Graphics::ShaderModels::DirectX9_3_0 )  == Mix::Tool::Graphics::ShaderModels::DirectX9_3_0 )  { ssmFlags |= Mix::Tool::Win32::Graphics::SHADER_MODEL_3; }
	if( MIX_TEST_BIT( models, Mix::Tool::Graphics::ShaderModels::DirectX10_4_0 ) == Mix::Tool::Graphics::ShaderModels::DirectX10_4_0 ) { ssmFlags |= Mix::Tool::Win32::Graphics::SHADER_MODEL_4; }
	if( MIX_TEST_BIT( models, Mix::Tool::Graphics::ShaderModels::DirectX11_5_0 ) == Mix::Tool::Graphics::ShaderModels::DirectX11_5_0 ) { ssmFlags |= Mix::Tool::Win32::Graphics::SHADER_MODEL_5; }

	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::Fog )           == Mix::Tool::Graphics::ShaderProcessFlags::Fog )          { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_FOG; }
	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::Shadow )        == Mix::Tool::Graphics::ShaderProcessFlags::Shadow )       { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_SHADOW; }
	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::Refract )       == Mix::Tool::Graphics::ShaderProcessFlags::Refract )      { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_REFRACT; }
//	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::SoftParticle )  == Mix::Tool::Graphics::ShaderProcessFlags::SoftParticle ) { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_SOFTPARTICLE; }
//	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::Bloom )         == Mix::Tool::Graphics::ShaderProcessFlags::Bloom )        { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_BLOOM; }
//	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::DepthOfField )  == Mix::Tool::Graphics::ShaderProcessFlags::DepthOfField ) { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_DOF; }
	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::Atmosphere )    == Mix::Tool::Graphics::ShaderProcessFlags::Atmosphere )   { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_ATMOSPHERE; }
//	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::Luminance )     == Mix::Tool::Graphics::ShaderProcessFlags::Luminance )    { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_LUMINANCE; }
	if( MIX_TEST_BIT( procFlags, Mix::Tool::Graphics::ShaderProcessFlags::SSAO )          == Mix::Tool::Graphics::ShaderProcessFlags::SSAO )         { deFlags |= Mix::Tool::Win32::Graphics::SHADER_PROCESS_SSAO; }

	implManager->MEP_Load( ssmFlags, deFlags, wpDirectoryName, wpName );
}

void Manager::EffectPackageProperty::Save( void )
{
	implManager->MEP_Save();
}

void Manager::EffectPackageProperty::Compile( void )
{
	implManager->MEP_Compile();
}

void Manager::EffectPackageProperty::Compile( System::Collections::Generic::List<System::String^>^ subDirList )
{
	std::vector<std::wstring> list;

	for each( System::String^ dirPath in subDirList )
	{
		pin_ptr<const wchar_t> wDirPath = PtrToStringChars( dirPath );
		list.push_back( wDirPath );
	}

	implManager->MEP_Compile( list );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Manager::PerspectiveProperty
////////////////////////////////////////////////////////////////////////////////////////////////////

Manager::PerspectiveProperty::PerspectiveProperty( Mix::Tool::Win32::Graphics::Manager* _implManager ) :
implManager( _implManager )
{
}

Manager::PerspectiveProperty::~PerspectiveProperty( void )
{
	implManager = nullptr;
}

float Manager::PerspectiveProperty::FovY::get( void )
{
	return implManager->GetPerspectiveFovY();
}

void Manager::PerspectiveProperty::FovY::set( float value )
{
	implManager->SetPerspectiveFovY( value );
	implManager->UpdateProjectionMatrix();
}

float Manager::PerspectiveProperty::NearZ::get( void )
{
	return implManager->GetPerspectiveNearZ();
}

void Manager::PerspectiveProperty::NearZ::set( float value )
{
	implManager->SetPerspectiveNearZ( value );
	implManager->UpdateProjectionMatrix();
}

float Manager::PerspectiveProperty::FarZ::get( void )
{
	return implManager->GetPerspectiveFarZ();
}

void Manager::PerspectiveProperty::FarZ::set( float value )
{
	implManager->SetPerspectiveFarZ( value );
	implManager->UpdateProjectionMatrix();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Manager::MouseSensitivityProperty
////////////////////////////////////////////////////////////////////////////////////////////////////

Manager::MouseSensitivityProperty::MouseSensitivityProperty( Mix::Tool::Win32::Graphics::Manager* _implManager ) :
implManager( _implManager )
{
}

Manager::MouseSensitivityProperty::~MouseSensitivityProperty( void )
{
	implManager = nullptr;
}

float Manager::MouseSensitivityProperty::Scaling::get( void )
{
	return implManager->GetMouseScalingSensitivity();
}

void Manager::MouseSensitivityProperty::Scaling::set( float value )
{
	implManager->SetMouseScalingSensitivity( value );
}

float Manager::MouseSensitivityProperty::Rotation::get( void )
{
	return implManager->GetMouseRotationSensitivity();
}

void Manager::MouseSensitivityProperty::Rotation::set( float value )
{
	implManager->SetMouseRotationSensitivity( value );
}

float Manager::MouseSensitivityProperty::Translation::get( void )
{
	return implManager->GetMouseTranslationSensitivity();
}

void Manager::MouseSensitivityProperty::Translation::set( float value )
{
	implManager->SetMouseTranslationSensitivity( value );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Manager
////////////////////////////////////////////////////////////////////////////////////////////////////

Manager::Manager( void ) :
impl( new Mix::Tool::Win32::Graphics::Manager() ),
m_EffectPackage( gcnew Manager::EffectPackageProperty( impl ) ),
m_Perspective( gcnew Manager::PerspectiveProperty( impl ) ),
m_MouseSensitivity( gcnew Manager::MouseSensitivityProperty( impl ) )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( impl->Initialize() == false )
	{
		throw gcnew System::Exception( "Mix.Tool.Graphics.Manager の初期化に失敗しました" );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// サポートしているシェーダーモデルを決定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	{
		bool bFirst = false;
		unsigned int support = impl->GetSupportShaderModels();

		if( ( support & Mix::Tool::Win32::Graphics::SHADER_MODEL_3 ) == Mix::Tool::Win32::Graphics::SHADER_MODEL_3 )
		{
			m_SupportShaderModels = ( bFirst == true )? Mix::Tool::Graphics::ShaderModels::DirectX9_3_0 : m_SupportShaderModels | Mix::Tool::Graphics::ShaderModels::DirectX9_3_0;
			bFirst = false;
		}

		if( ( support & Mix::Tool::Win32::Graphics::SHADER_MODEL_4 ) == Mix::Tool::Win32::Graphics::SHADER_MODEL_4 )
		{
			m_SupportShaderModels = ( bFirst == true )? Mix::Tool::Graphics::ShaderModels::DirectX10_4_0 : m_SupportShaderModels | Mix::Tool::Graphics::ShaderModels::DirectX10_4_0;
			bFirst = false;
		}

		if( ( support & Mix::Tool::Win32::Graphics::SHADER_MODEL_5 ) == Mix::Tool::Win32::Graphics::SHADER_MODEL_5 )
		{
			m_SupportShaderModels = ( bFirst == true )? Mix::Tool::Graphics::ShaderModels::DirectX11_5_0 : m_SupportShaderModels | Mix::Tool::Graphics::ShaderModels::DirectX11_5_0;
			bFirst = false;
		}
	}
}

Manager::~Manager( void )
{
	if( m_EffectPackage != nullptr )
	{
		delete m_EffectPackage;
	}

	if( m_Perspective != nullptr )
	{
		delete m_Perspective;
	}

	if( m_MouseSensitivity != nullptr )
	{
		delete m_MouseSensitivity;
	}

	if( impl != NULL )
	{
		delete impl;
		impl = NULL;
	}
}

System::String^ Manager::RootDirectoryPath::get( void )
{
	return gcnew System::String( impl->GetRootDirectoryPath() );
}

void Manager::RootDirectoryPath::set( System::String^ value )
{
	pin_ptr<const wchar_t> wptr = PtrToStringChars( value );

	impl->SetRootDirectoryPath( wptr );
}

Mix::Tool::Graphics::ShaderModels Manager::SupportShaderModels::get( void )
{
	return m_SupportShaderModels;
}

Manager::EffectPackageProperty^ Manager::EffectPackage::get( void )
{
	return m_EffectPackage;
}

Manager::PerspectiveProperty^ Manager::Perspective::get( void )
{
	return m_Perspective;
}

Manager::MouseSensitivityProperty^ Manager::MouseSensitivity::get( void )
{
	return m_MouseSensitivity;
}

void Manager::Update( int baseFps, float fps, float mag )
{
	impl->Update( baseFps, fps, mag );
}

void Manager::Refresh( void )
{
	impl->Refresh();
}

void Manager::Draw( void )
{
	impl->Draw();
}

}}}
