#pragma once

#include "Mix/Scene/IDefaultMaterial.h"

namespace Mix{ namespace Scene{ namespace Common{
	class EffectPackage;
}}}

namespace Mix{ namespace Scene{ namespace Standard{ namespace Common{

	class DefaultMaterial : public Mix::Scene::IDefaultMaterial
	{
	public:
		//レンダータイプ列挙定数
		enum RENDER_TYPE
		{
			RE_SHADOW	= 0,	//シャドウ
			RE_MASK		= 1,	//マスク
			RE_COLOR	= 2,	//カラー

			RE_MAX		= 3,	//最大数
		};

	protected:
		//テクスチャステージ列挙定数
		enum TS
		{
			TS_DIFFUSE	= 0,	//ディフューズ
			TS_SPECULAR = 1,	//スペキュラー
			TS_EMISSIVE = 2,	//エミッシブ
			TS_BUMP		= 3,	//バンプ
		};

	protected:
		enum MTL_VALUE
		{
			//マジックナンバー
			MTL_MAGIC_NUMBER = 0x5F4C544D,

			//バージョン
			MTL_VERSION_1_0_0_0 = 0x01000000,
			MTL_VERSION_1_1_0_0 = 0x01010000,
			MTL_VERSION_OLD = MTL_VERSION_1_0_0_0,
			MTL_VERSION_CUR = MTL_VERSION_1_1_0_0,
		};

		enum MTL_TYPE
		{
			MTL_DEFAULT = 0,
		};

		enum MTL_COMPILE_FLAG
		{
			MCF_NORMAL					= 0x00000001,
			MCF_TANGENT_SPACE			= 0x00000002,
			MCF_TEXTURE					= 0x00000004,

			MCF_SIMPLE_VERTEX			= 0x00000008,
			MCF_BLEND_VERTEX			= 0x00000010,

			MCF_LIGHTING				= 0x00000020,
			MCF_BOTH_LIGHTING			= 0x00000040,
			MCF_SHADOW_RECEIVE			= 0x00000080,

			MCF_REFRACT_CLIP			= 0x00000100,

			MCF_DIFFUSE_HALF_LAMBERT	= 0x00000200,
			MCF_DIFFUSE_MAPPING			= 0x00000400,
			MCF_DIFFUSE_FRESNEL			= 0x00000800,
			MCF_DIFFUSE_RIM_LIGHTING	= 0x00001000,

			MCF_SPECULAR_PHONG			= 0x00002000,
			MCF_SPECULAR_BLINN_PHONG	= 0x00004000,
			MCF_SPECULAR_COOK_TORRANCE	= 0x00008000,
			MCF_SPECULAR_MAPPING		= 0x00010000,

			MCF_REFLECT_MAPPING			= 0x00020000,
			MCF_REFLECT_FRESNEL			= 0x00040000,

			MCF_EMISSIVE_MAPPING		= 0x00080000,

			MCF_BUMP_MAPPING			= 0x00100000,
			MCF_PARALLAX				= 0x00200000,
			MCF_WATER					= 0x00400000,
			MCF_REFRACT_MAPPING			= 0x00800000,

			MCF_SOFTPARTICLE			= 0x01000000,

			MCF_WAVE_INVERT				= 0x02000000,

			MCF_ATMOSPHERE				= 0x10000000,
			MCF_FOG						= 0x20000000,
			MCF_SHADOW					= 0x40000000,
			MCF_SSAO					= 0x80000000,
		};

		enum MTL_FLAG
		{
			MTL_BACKCULLING         = 0x00000001, //背面カリングを行う
			MTL_TRANSPARENCY        = 0x00000002, //半透明として処理する
			MTL_ZWRITE				= 0x00000004, //深度を書き込む
			MTL_BOTH_LIGHTING       = 0x00000008, //両面ライティングを行う
			MTL_DIFFUSE_FRESNEL     = 0x00000010, //ディフューズ : フレネル効果
			MTL_DIFFUSE_RIMLIGHTING = 0x00000020, //ディフューズ : リムライティング
			MTL_SOFTPARTICLE        = 0x00000040, //ソフトパーティクル
			MTL_SHADOW_RECEIVE      = 0x00000080, //シャドウ : 自身に影を落とす
			MTL_SHADOW_CAST         = 0x00000100, //シャドウ : 他者に影を落とす
			MTL_DIFFUSE_TEXTURE     = 0x00000200, //ディフューズテクスチャを所持している
			MTL_SPECULAR_TEXTURE    = 0x00000400, //スペキュラーテクスチャを所持している
			MTL_EMISSIVE_TEXTURE    = 0x00000800, //エミッシブテクスチャを所持している
			MTL_BUMP_TEXTURE        = 0x00001000, //バンプテクスチャを所持している
			MTL_TEXTURE_MASK		= 0x00001E00, //テクスチャマスク
		};

		struct MTL_FILE_HEADER
		{
			UInt32 magicNumber;
			UInt32 version;
		};

		struct MTL_INFO_HEADER_1_1_0_0
		{
			wchar_t name[32];

			UInt32 vertexShaderID[IDefaultMaterial::TR_MAX];
			UInt32 pixelShaderID;

			UInt32 type;
		};

		struct MTL_DATA_HEADER_1_1_0_0
		{
			UInt32 shaderType;
			UInt32 blendMode;
			UInt32 texFilterType;
			UInt32 texAddressType;
			UInt32 flags;
			UInt32 transparencyMethod;

			Float32 ambientColor[4];

			UInt32 diffuseType;
			Float32 diffuseColor[4];
			Float32 diffuseFresnelRatio;
			Float32 diffuseRLHardness;
			Float32 diffuseRLScale;

			UInt32 specularType;
			Float32 specularColor[4];
			Float32 specularHardness;
			Float32 specularScale;
			Float32 specularCTFresnel;
			Float32 specularCTRoughness;

			UInt32 reflectType;
			Float32 reflectScale;
			Float32 reflectIntensity;
			Float32 reflectBias;
			Float32 reflectExprosure;

			Float32 emissiveColor[4];
			Float32 emissiveScale;

			UInt32 bumpType;
			Float32 bumpHeightScale;
			Int32 bumpSampleCount;
			Float32 bumpReflectRatio;

			UInt32 waveType;
			UInt32 waveDir;
			Float32 waveVelocity;
			Float32 waveUVOffset;
			Float32 waveGap; // 1.1.0.0

			Float32 refractRatio;

			Float32 particleThickness;
		};

	protected:
		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 共通
		////////////////////////////////////////////////////////////////////////////////////////////////////

		Mix::StringW m_Name;

		Mix::Scene::IDefaultMaterial::SHADER_TYPE m_ShaderType;

		Mix::Graphics::BLEND_TYPE m_BlendType;
		Mix::Graphics::CULL_TYPE m_CullType;
		Boolean m_bZWrite;

		Mix::Graphics::TEXTURE_FILTER_TYPE m_TextureFilter;
		Mix::Graphics::TEXTURE_ADDRESS_TYPE m_TextureAddress;

		Boolean m_bBothFacesLighting;

		Boolean m_bTransparency;
		Mix::Scene::IMaterial::TRANSPARENCY_METHOD m_TransparencyMethod;

		Boolean m_bReceiveShadow;
		Boolean m_bCastShadow;

		Mix::Scene::IDefaultMaterial::DIFFUSE_TYPE m_DiffuseType;
		Boolean m_bDiffuseFresnel;
		Boolean m_bDiffuseRL;

		Mix::Scene::IDefaultMaterial::SPECULAR_TYPE m_SpecularType;

		Mix::Scene::IDefaultMaterial::REFLECT_TYPE m_ReflectType;

		Mix::Scene::IDefaultMaterial::BUMP_TYPE m_BumpType;

		Boolean m_bWave;
		Mix::Scene::IDefaultMaterial::WAVE_TYPE m_WaveType;
		Mix::Scene::IDefaultMaterial::WAVE_DIR m_WaveDir;
		Boolean m_bWaveInvert;
		Float32 m_WaveVelocity;
		Float32 m_WavePos;

		Boolean m_bRefract;

		Boolean m_bSoftParticle;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// シェーダー
		////////////////////////////////////////////////////////////////////////////////////////////////////

		Mix::Graphics::IVertexLayout* m_pVertexLayout[IDefaultMaterial::TR_MAX];
		Mix::Graphics::IVertexShader* m_pVertexShader[IDefaultMaterial::TR_MAX][DefaultMaterial::RE_MAX];
		Mix::Graphics::IPixelShader* m_pPixelShader[DefaultMaterial::RE_MAX];

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// テクスチャ
		////////////////////////////////////////////////////////////////////////////////////////////////////

		Mix::Graphics::ITexture* m_pDiffuseTexture;
		Mix::Graphics::ITexture* m_pSpecularTexture;
		Mix::Graphics::ITexture* m_pEmissiveTexture;
		Mix::Graphics::ITexture* m_pBumpTexture;

	protected:
		DefaultMaterial( void );
		virtual ~DefaultMaterial( void );

		static Boolean Initialize(	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::Common::DefaultMaterial* pMaterial );

		Boolean InternalClone( Mix::Scene::Standard::Common::DefaultMaterial* pMaterial );

		Mix::Vector2 UpdateWave( Float32 dt );

	private:
		static Mix::Graphics::ITexture* CreateTexture( const wchar_t* pName, Mix::Graphics::IDevice* pDevice, Mix::IO::IReader* pReader, Mix::STL::Vector<Mix::Memory::SECTION_SCENE, UInt8>& tempBuff );

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

		virtual const wchar_t* GetName( void ) const;

		virtual Mix::Scene::IDefaultMaterial::SHADER_TYPE GetShaderType( void ) const;

		virtual Mix::Graphics::BLEND_TYPE GetBlendType( void ) const;
		virtual void SetBlendType( Mix::Graphics::BLEND_TYPE type );

		virtual Mix::Graphics::CULL_TYPE GetCullingType( void ) const;
		virtual void SetCullingType( Mix::Graphics::CULL_TYPE type );

		virtual Boolean IsZWrite( void ) const;
		virtual void SetZWrite( Boolean state );

		virtual Mix::Graphics::TEXTURE_FILTER_TYPE GetTextureFilterType( void ) const;
		virtual void SetTextureFilterType( Mix::Graphics::TEXTURE_FILTER_TYPE filter );

		virtual Mix::Graphics::TEXTURE_ADDRESS_TYPE GetTextureAddressType( void ) const;
		virtual void SetTextureAddressType( Mix::Graphics::TEXTURE_ADDRESS_TYPE address );

		virtual Boolean IsBothFacesLighting( void ) const;

		virtual Boolean IsReceiveShadow( void ) const;
		virtual Boolean IsCastShadow( void ) const;

		virtual Mix::Scene::IDefaultMaterial::DIFFUSE_TYPE GetDiffuseType( void ) const;
		virtual Boolean GetDiffuseTexture( Mix::Graphics::ITexture** ppTexture );
		virtual Boolean SetDiffuseTexture( Mix::Graphics::ITexture* pTexture );
		virtual Boolean IsDiffuseFresnel( void ) const;
		virtual Boolean IsDiffuseRL( void ) const;

		virtual Mix::Scene::IDefaultMaterial::SPECULAR_TYPE GetSpecularType( void ) const;
		virtual Boolean GetSpecularTexture( Mix::Graphics::ITexture** ppTexture );
		virtual Boolean SetSpecularTexture( Mix::Graphics::ITexture* pTexture );

		virtual Mix::Scene::IDefaultMaterial::REFLECT_TYPE GetReflectType( void ) const;

		virtual Boolean GetEmissiveTexture( Mix::Graphics::ITexture** ppTexture );
		virtual Boolean SetEmissiveTexture( Mix::Graphics::ITexture* pTexture );

		virtual Boolean IsBump( void ) const;
		virtual Mix::Scene::IDefaultMaterial::BUMP_TYPE GetBumpType( void ) const;
		virtual Boolean GetBumpTexture( Mix::Graphics::ITexture** ppTexture );
		virtual Boolean SetBumpTexture( Mix::Graphics::ITexture* pTexture );

		virtual Boolean IsWave( void ) const;
		virtual Mix::Scene::IDefaultMaterial::WAVE_TYPE GetWaveType( void ) const;
		virtual Mix::Scene::IDefaultMaterial::WAVE_DIR GetWaveDir( void ) const;
		virtual Boolean IsWaveInvert( void ) const;
		virtual void SetWaveDir( Mix::Scene::IDefaultMaterial::WAVE_DIR dir );
		virtual Float32 GetWaveVelocity( void ) const;
		virtual void SetWaveVelocity( Float32 vel );

		virtual Boolean IsSoftParticle( void ) const;

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

		virtual Mix::Scene::IMaterial::TYPE GetType( void ) const;

		virtual Boolean IsTransformable( Mix::Scene::IMaterial::TRANSFORM_TYPE type ) const;

		virtual UInt32 GetVertexStride( Mix::Scene::IMaterial::TRANSFORM_TYPE type ) const;
		virtual UInt32 GetVertexInputSigunature( Mix::Scene::IMaterial::TRANSFORM_TYPE type ) const;

		virtual Boolean NeedsUpdate( void ) const;

		virtual Boolean IsShadowing( void ) const;
		virtual Boolean IsLighting( void ) const;
		virtual Boolean IsRefractive( void ) const;
		virtual Boolean IsTransparency( void ) const;
		virtual Mix::Scene::IMaterial::TRANSPARENCY_METHOD GetTransparencyMethod( void ) const;

		virtual void RenderMask( Mix::Graphics::IDevice* pDevice, Mix::Scene::IMaterial::TRANSFORM_TYPE trType );

	public:
		static const wchar_t* FAILED_CREATE;

	private:
		static const wchar_t* FAILED_CLONE;
		static const Mix::Vector2 WAVE_VEC_TABLE[4];
	};

}}}}
