#include "Mix/Private/Scene/Standard/DX9/DefaultMaterial.h"
#include "Mix/Graphics/IDevice.h"

namespace Mix{ namespace Scene{ namespace Standard{ namespace DX9{

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::Standard::DX9::DefaultMaterial
////////////////////////////////////////////////////////////////////////////////////////////////////

DefaultMaterial* DefaultMaterial::CreateInstance(	Mix::Graphics::IDevice* pDevice,
													Mix::Scene::Common::EffectPackage* pEffectPackage,
													Mix::IO::IReader* pReader,
													Boolean bWithMagicNumber,
													const wchar_t* pNameLabel,
													const wchar_t* pName )
{
	Mix::Scene::Standard::DX9::DefaultMaterial* pMaterial;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// インターフェースの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pMaterial = MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, Mix::Scene::Standard::DX9::DefaultMaterial );
	if( pMaterial == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : %s[%s]", DefaultMaterial::FAILED_CREATE, Mix::STR_OUTOFMEMORY, pNameLabel, pName );
		return NULL;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// インターフェースの初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( Mix::Scene::Standard::Common::DefaultMaterial::Initialize(	pDevice,
																	pEffectPackage,
																	pReader,
																	bWithMagicNumber,
																	pNameLabel,
																	pName,
																	pMaterial ) == False )
	{
		MIX_RELEASE( pMaterial );
		return NULL;
	}

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

	return pMaterial;
}

DefaultMaterial::~DefaultMaterial( void )
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::IDefaultMaterial
////////////////////////////////////////////////////////////////////////////////////////////////////

const Mix::Vector4& DefaultMaterial::GetAmbientColor( void ) const
{
	return m_PSR[DefaultMaterial::PSR_AMBIENT_COLOR];
}

void DefaultMaterial::SetAmbientColor( const Mix::Vector4& color )
{
	m_PSR[DefaultMaterial::PSR_AMBIENT_COLOR] = color;
}

const Mix::Vector4& DefaultMaterial::GetDiffuseColor( void ) const
{
	return m_PSR[DefaultMaterial::PSR_DIFFUSE_COLOR];
}

void DefaultMaterial::SetDiffuseColor( const Mix::Vector4& color )
{
	m_PSR[DefaultMaterial::PSR_DIFFUSE_COLOR] = color;
}

Float32 DefaultMaterial::GetDiffuseFresnelIntensity( void ) const
{
	return m_PSR[DefaultMaterial::PSR_DIFFUSE_PARAM].data[DefaultMaterial::PSR_DIFFUSE_PI_FI];
}

void DefaultMaterial::SetDiffuseFresnelIntensity( Float32 intensity )
{
	m_PSR[DefaultMaterial::PSR_DIFFUSE_PARAM].data[DefaultMaterial::PSR_DIFFUSE_PI_FI] = intensity;
}

Float32 DefaultMaterial::GetDiffuseRLHardness( void ) const
{
	return m_PSR[DefaultMaterial::PSR_DIFFUSE_PARAM].data[DefaultMaterial::PSR_DIFFUSE_PI_RL_H];
}

void DefaultMaterial::SetDiffuseRLHardness( Float32 hardness )
{
	m_PSR[DefaultMaterial::PSR_DIFFUSE_PARAM].data[DefaultMaterial::PSR_DIFFUSE_PI_RL_H] = hardness;
}

Float32 DefaultMaterial::GetDiffuseRLScale( void ) const
{
	return m_PSR[DefaultMaterial::PSR_DIFFUSE_PARAM].data[DefaultMaterial::PSR_DIFFUSE_PI_RL_S];
}

void DefaultMaterial::SetDiffuseRLScale( Float32 scale )
{
	m_PSR[DefaultMaterial::PSR_DIFFUSE_PARAM].data[DefaultMaterial::PSR_DIFFUSE_PI_RL_S] = scale;
}

const Mix::Vector4& DefaultMaterial::GetSpecularColor( void ) const
{
	return m_PSR[DefaultMaterial::PSR_SPECULAR_COLOR];
}

void DefaultMaterial::SetSpecularColor( const Mix::Vector4& color )
{
	m_PSR[DefaultMaterial::PSR_SPECULAR_COLOR] = color;
}

Float32 DefaultMaterial::GetSpecularHardness( void ) const
{
	return m_PSR[DefaultMaterial::PSR_SPECULAR_PARAM0].data[DefaultMaterial::PSR_SPECULAR_PI0_H];
}

void DefaultMaterial::SetSpecularHardness( Float32 hardness )
{
	m_PSR[DefaultMaterial::PSR_SPECULAR_PARAM0].data[DefaultMaterial::PSR_SPECULAR_PI0_H] = hardness;
}

Float32 DefaultMaterial::GetSpecularScale( void ) const
{
	return m_PSR[DefaultMaterial::PSR_SPECULAR_PARAM0].data[DefaultMaterial::PSR_SPECULAR_PI0_S];
}

void DefaultMaterial::SetSpecularScale( Float32 scale )
{
	m_PSR[DefaultMaterial::PSR_SPECULAR_PARAM0].data[DefaultMaterial::PSR_SPECULAR_PI0_S] = scale;
}

Float32 DefaultMaterial::GetSpecularCTFresnel( void ) const
{
	return m_PSR[DefaultMaterial::PSR_SPECULAR_PARAM1].data[DefaultMaterial::PSR_SPECULAR_PI1_CT_F];
}

void DefaultMaterial::SetSpecularCTFresnel( Float32 fresnel )
{
	m_PSR[DefaultMaterial::PSR_SPECULAR_PARAM1].data[DefaultMaterial::PSR_SPECULAR_PI1_CT_F] = fresnel;
}

Float32 DefaultMaterial::GetSpecularCTRoughness( void ) const
{
	return m_SpecularCTRoughness;
}

void DefaultMaterial::SetSpecularCTRoughness( Float32 roughness )
{
	m_SpecularCTRoughness = roughness;
	m_PSR[DefaultMaterial::PSR_SPECULAR_PARAM1].data[DefaultMaterial::PSR_SPECULAR_PI1_CT_RI] = MIX_FLOAT_RECIPROCAL( m_SpecularCTRoughness );
	m_PSR[DefaultMaterial::PSR_SPECULAR_PARAM1].data[DefaultMaterial::PSR_SPECULAR_PI1_CT_R2] = m_SpecularCTRoughness * m_SpecularCTRoughness;
}

Float32 DefaultMaterial::GetReflectScale( void ) const
{
	return m_PSR[DefaultMaterial::PSR_REFLECT_PARAM].data[DefaultMaterial::PSR_REFLECT_PI_S];
}

void DefaultMaterial::SetReflectScale( Float32 scale )
{
	m_PSR[DefaultMaterial::PSR_REFLECT_PARAM].data[DefaultMaterial::PSR_REFLECT_PI_S] = scale;
}

Float32 DefaultMaterial::GetReflectIntensity( void ) const
{
	return m_PSR[DefaultMaterial::PSR_REFLECT_PARAM].data[DefaultMaterial::PSR_REFLECT_PI_I];
}

void DefaultMaterial::SetReflectIntensity( Float32 intensity )
{
	m_PSR[DefaultMaterial::PSR_REFLECT_PARAM].data[DefaultMaterial::PSR_REFLECT_PI_I] = intensity;
}

Float32 DefaultMaterial::GetReflectBias( void ) const
{
	return m_PSR[DefaultMaterial::PSR_REFLECT_PARAM].data[DefaultMaterial::PSR_REFLECT_PI_B];
}

void DefaultMaterial::SetReflectBias( Float32 bias )
{
	m_PSR[DefaultMaterial::PSR_REFLECT_PARAM].data[DefaultMaterial::PSR_REFLECT_PI_B] = bias;
}

Float32 DefaultMaterial::GetReflectExprosure( void ) const
{
	return m_PSR[DefaultMaterial::PSR_REFLECT_PARAM].data[DefaultMaterial::PSR_REFLECT_PI_E];
}

void DefaultMaterial::SetReflectExprosure( Float32 exprosure )
{
	m_PSR[DefaultMaterial::PSR_REFLECT_PARAM].data[DefaultMaterial::PSR_REFLECT_PI_E] = exprosure;
}

const Mix::Vector4& DefaultMaterial::GetEmissiveColor( void ) const
{
	return m_PSR[DefaultMaterial::PSR_EMISSIVE_COLOR];
}

void DefaultMaterial::SetEmissiveColor( const Mix::Vector4& color )
{
	m_PSR[DefaultMaterial::PSR_EMISSIVE_COLOR] = color;
}

Float32 DefaultMaterial::GetEmissiveScale( void ) const
{
	return m_PSR[DefaultMaterial::PSR_EMISSIVE_PARAM].data[DefaultMaterial::PSR_EMISSIVE_PI_S];
}

void DefaultMaterial::SetEmissiveScale( Float32 scale )
{
	m_PSR[DefaultMaterial::PSR_EMISSIVE_PARAM].data[DefaultMaterial::PSR_EMISSIVE_PI_S] = scale;
}

Float32 DefaultMaterial::GetBumpHeightScale( void ) const
{
	return m_PSR[DefaultMaterial::PSR_BUMP_PARAM0].data[DefaultMaterial::PSR_BUMP_PI0_HS];
}

void DefaultMaterial::SetBumpHeightScale( Float32 scale )
{
	m_PSR[DefaultMaterial::PSR_BUMP_PARAM0].data[DefaultMaterial::PSR_BUMP_PI0_HS] = scale;
}

Int32 DefaultMaterial::GetBumpSampleCount( void ) const
{
	return static_cast<Int32>( m_PSR[DefaultMaterial::PSR_BUMP_PARAM0].data[DefaultMaterial::PSR_BUMP_PI0_SC] );
}

void DefaultMaterial::SetBumpSampleCount( Int32 sampleCount )
{
	m_PSR[DefaultMaterial::PSR_BUMP_PARAM0].data[DefaultMaterial::PSR_BUMP_PI0_SC] = static_cast<Float32>( sampleCount );
}

Float32 DefaultMaterial::GetBumpReflectFactor( void ) const
{
	return m_PSR[DefaultMaterial::PSR_BUMP_PARAM0].data[DefaultMaterial::PSR_BUMP_PI0_RL_F];
}

void DefaultMaterial::SetBumpReflectFactor( Float32 factor )
{
	m_PSR[DefaultMaterial::PSR_BUMP_PARAM0].data[DefaultMaterial::PSR_BUMP_PI0_RL_F] = factor;
}

Float32 DefaultMaterial::GetWaveUVOffset( void ) const
{
	return m_PSR[DefaultMaterial::PSR_BUMP_PARAM0].data[DefaultMaterial::PSR_BUMP_PI0_WAVE_O];
}

void DefaultMaterial::SetWaveUVOffset( Float32 uvOffset )
{
	m_PSR[DefaultMaterial::PSR_BUMP_PARAM0].data[DefaultMaterial::PSR_BUMP_PI0_WAVE_O] = uvOffset;
}

Float32 DefaultMaterial::GetWaveGap( void ) const
{
	return m_PSR[DefaultMaterial::PSR_BUMP_PARAM1].data[DefaultMaterial::PSR_BUMP_PI1_WAVE_G];
}

void DefaultMaterial::SetWaveGap( Float32 gap )
{
	m_PSR[DefaultMaterial::PSR_BUMP_PARAM1].data[DefaultMaterial::PSR_BUMP_PI1_WAVE_G] = gap;
}

Float32 DefaultMaterial::GetWaveRefractiveIndex( void ) const
{
	return m_PSR[DefaultMaterial::PSR_BUMP_PARAM1].data[DefaultMaterial::PSR_BUMP_PI1_RR_I];
}

void DefaultMaterial::SetWaveRefractiveIndex( Float32 index )
{
	m_PSR[DefaultMaterial::PSR_BUMP_PARAM1].data[DefaultMaterial::PSR_BUMP_PI1_RR_I] = index;
}

Float32 DefaultMaterial::GetSoftParticleThickness( void ) const
{
	return m_PSR[DefaultMaterial::PSR_PARTICLE_PARAM].data[DefaultMaterial::PSR_PARTICLE_PI_T];
}

void DefaultMaterial::SetSoftParticleThickness( Float32 tickness )
{
	m_PSR[DefaultMaterial::PSR_PARTICLE_PARAM].data[DefaultMaterial::PSR_PARTICLE_PI_T] = tickness;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Mix::Scene::IMaterial
////////////////////////////////////////////////////////////////////////////////////////////////////

void DefaultMaterial::Update( Float32 dt )
{
	Float32* waveData = m_PSR[DefaultMaterial::PSR_BUMP_PARAM1].data;
	Mix::Vector2 waveUV = UpdateWave( dt );

	waveData[DefaultMaterial::PSR_BUMP_PI1_WAVE_U] = waveUV.u;
	waveData[DefaultMaterial::PSR_BUMP_PI1_WAVE_V] = waveUV.v;
}

void DefaultMaterial::RenderShadow( Mix::Graphics::IDevice* pDevice, Mix::Scene::IMaterial::TRANSFORM_TYPE trType )
{
	pDevice->SetBlendState( Mix::Graphics::BLEND_COPY );
	pDevice->SetDepthState( True, ( m_bTransparency == False ) );
	pDevice->SetRasterizerState( Mix::Graphics::FILL_SOLID, ( m_CullType == Mix::Graphics::CULL_NONE )? Mix::Graphics::CULL_NONE : Mix::Graphics::CULL_BACK, False );

	pDevice->SetTexture( DefaultMaterial::TS_DIFFUSE, m_TextureFilter, m_TextureAddress, m_pDiffuseTexture );

	pDevice->SetPixelShaderConstantF( DefaultMaterial::PSR_HEAD + DefaultMaterial::PSR_DIFFUSE_COLOR, &m_PSR[DefaultMaterial::PSR_DIFFUSE_COLOR], 1 );

	pDevice->SetVertexLayout( m_pVertexLayout[trType] );
	pDevice->SetVertexShader( m_pVertexShader[trType][DefaultMaterial::RE_SHADOW] );
	pDevice->SetPixelShader( m_pPixelShader[DefaultMaterial::RE_SHADOW] );
}

void DefaultMaterial::RenderColor( Mix::Graphics::IDevice* pDevice, Mix::Scene::IMaterial::TRANSFORM_TYPE trType )
{
	Mix::Graphics::BLEND_DESC blendDesc = pDevice->GetBlendState();
	Mix::Graphics::RASTERIZER_DESC rasterizerDesc = pDevice->GetRasterizerState();
	Mix::Graphics::DEPTH_DESC depthDesc = pDevice->GetDepthState();

	blendDesc.type = m_BlendType;
	rasterizerDesc.cullMode = m_CullType;
	depthDesc.bWrite = m_bZWrite;

	pDevice->SetBlendState( blendDesc );
	pDevice->SetRasterizerState( rasterizerDesc );
	pDevice->SetDepthState( depthDesc );

	pDevice->SetTexture( DefaultMaterial::TS_DIFFUSE, m_TextureFilter, m_TextureAddress, m_pDiffuseTexture );
	pDevice->SetTexture( DefaultMaterial::TS_SPECULAR, m_TextureFilter, m_TextureAddress, m_pSpecularTexture );
	pDevice->SetTexture( DefaultMaterial::TS_EMISSIVE, m_TextureFilter, m_TextureAddress, m_pEmissiveTexture );
	pDevice->SetTexture( DefaultMaterial::TS_BUMP, Mix::Graphics::TEXTURE_FILTER_POINT, m_TextureAddress, m_pBumpTexture );

	pDevice->SetPixelShaderConstantF( DefaultMaterial::PSR_HEAD, m_PSR, DefaultMaterial::PSR_NUM );

	pDevice->SetVertexLayout( m_pVertexLayout[trType] );
	pDevice->SetVertexShader( m_pVertexShader[trType][DefaultMaterial::RE_COLOR] );
	pDevice->SetPixelShader( m_pPixelShader[DefaultMaterial::RE_COLOR] );
}

Boolean DefaultMaterial::Clone( Mix::Scene::IMaterial** ppMaterial )
{
	MIX_ASSERT( ppMaterial != NULL );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ : 開始
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_LOG_INFO_SECT_START( L"デフォルトマテリアルの複製 : Name[%s] Type[Standard( Default )]", m_Name.GetConstPtr() );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 作成 〜 初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	Mix::Scene::Standard::DX9::DefaultMaterial* pMaterial = MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, Mix::Scene::Standard::DX9::DefaultMaterial );
	if( pMaterial == NULL )
	{
		MIX_LOG_ERROR( Mix::STR_OUTOFMEMORY );
		MIX_LOG_INFO_SECT_END();
		return False;
	}

	if( Mix::Scene::Standard::Common::DefaultMaterial::InternalClone( pMaterial ) == False )
	{
		MIX_LOG_INFO_SECT_END();
		return False;
	}

	( *ppMaterial ) = pMaterial;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ : 終了
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_LOG_INFO_SECT_END();

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

	return True;
}

}}}}
