#pragma once

#include <string>

#include "Mix/Tool/Win32/Core/Object.h"
#include "Mix/Tool/Win32/Core/File/InputStream.h"
#include "Mix/Tool/Win32/Core/File/OutputStream.h"

namespace Mix{ namespace Tool{ namespace Win32{ namespace Graphics{

	class Manager;
	class Texture;
	class FileTexture;
	class MaterialShader;
	class VertexLayout;
	class VertexShader;
	class PixelShader;
	class DrawObject;
	class MaterialSlot;

	//マテリアルクラス
	//※使用する前に必ず Update を呼び出すこと
	class Material : public Mix::Tool::Win32::Object
	{
	public:
		static const wchar_t* FILE_EXT;

		//MTLタイプ
		enum MTL_TYPE
		{
			MTL_DEFAULT = 0, //デフォルト
		};

		//MTLの値
		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,

			//フラグ( デフォルト )
			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, //テクスチャマスク

			//テクスチャフィルターB
			MTL_TEXF_POINT			= 0,
			MTL_TEXF_LINEAR			= 1,
			MTL_TEXF_ANISOTROPIC	= 2,
			MTL_TEXF_MAX			= 3,

			//テクスチャアドレス
			MTL_TEXA_WRAP			= 0,
			MTL_TEXA_CLAMP			= 1,
			MTL_TEXA_MAX			= 2,
		};

		//MTLファイルヘッダ( 1.1.0.0 )
		struct MTL_FILE_HEADER
		{
			unsigned int magicNumber;
			unsigned int version;
		};

		//MTLインフォヘッダ( 1.1.0.0 から実装 ) : 一応ナンバリング
		struct MTL_INFO_HEADER_1_1_0_0
		{
			wchar_t name[Mix::Tool::Win32::Graphics::MAX_NAME_SIZE];

			unsigned int vertexShaderID[Mix::Tool::Win32::Graphics::VERTEX_TYPE_MAX];
			unsigned int pixelShaderID;

			unsigned int type;
		};

		//MTLデータヘッダ( 1.1.0.0 ) : デフォルトマテリアル
		struct MTL_DATA_HEADER_1_1_0_0
		{
			unsigned int shaderType;
			unsigned int blendMode;
			unsigned int texFilterType;
			unsigned int texAddressType;
			unsigned int flags;
			unsigned int transparencyMethod;

			D3DXVECTOR4 ambientColor;

			unsigned int diffuseType;
			D3DXVECTOR4 diffuseColor;
			float diffuseFresnelRatio;
			float diffuseRLHardness;
			float diffuseRLScale;

			unsigned int specularType;
			D3DXVECTOR4 specularColor;
			float specularHardness;
			float specularScale;
			float specularCTFresnel;
			float specularCTRoughness;

			unsigned int reflectType;
			float reflectScale;
			float reflectIntensity;
			float reflectBias;
			float reflectExprosure;

			D3DXVECTOR4 emissiveColor;
			float emissiveScale;

			unsigned int bumpType;
			float bumpHeightScale;
			int bumpSample;
			float bumpReflectRatio;

			unsigned int waveType;
			unsigned int waveDir;
			float waveVelocity;
			float waveUVOffset;
			float waveGap; // 1.1.0.0

			float refractRatio;

			float particleThickness;
		};

	private:
		Mix::Tool::Win32::Graphics::MaterialSlot* m_pSlot;

		bool m_bAutoUpdate;
		Mix::Tool::Win32::Graphics::MaterialShader* m_pShader;

		bool m_bDefault;
		bool m_bActive;

	private:
		std::wstring m_DefaultName;
		std::wstring m_Name;

		std::wstring m_SaveFilePath;

		Mix::Tool::Win32::Graphics::SHADER_TYPE m_ShaderType;

		D3DXVECTOR4 m_AmbientColor;
		bool m_bBothLighting;

		Mix::Tool::Win32::Graphics::BLEND_MODE m_BlendMode;

		bool m_bTransparency;
		Mix::Tool::Win32::Graphics::TRANSPARENCY_METHOD m_TransparencyMethod;
		bool m_bZWrite;
		bool m_bSoftEdge;
		float m_SoftEdgeThickness;

		bool m_bBackculling;

		Mix::Tool::Win32::Graphics::DIFFUSE_TYPE m_DiffuseType;
		D3DXVECTOR4 m_DiffuseColor;
		std::wstring m_DiffuseTextureFileName;
		Mix::Tool::Win32::Graphics::FileTexture* m_pDiffuseTexture;
		bool m_bDiffuseFresnel;
		float m_DiffuseFresnelRatio;
		bool m_bDiffuseRL;
		float m_DiffuseRLHardness;
		float m_DiffuseRLScale;

		Mix::Tool::Win32::Graphics::SPECULAR_TYPE m_SpecularType;
		D3DXVECTOR4 m_SpecularColor;
		float m_SpecularHardness;
		float m_SpecularScale;
		float m_SpecularCTFresnel;
		float m_SpecularCTRoughness;
		std::wstring m_SpecularTextureFileName;
		Mix::Tool::Win32::Graphics::FileTexture* m_pSpecularTexture;

		Mix::Tool::Win32::Graphics::REFLECT_TYPE m_ReflectType;
		float m_ReflectIntensity;
		float m_ReflectScale;
		float m_ReflectBias;
		float m_ReflectExprosure;
		float m_ReflectBumpRatio;

		D3DXVECTOR4 m_EmissiveColor;
		float m_EmissiveScale;
		std::wstring m_EmissiveTextureFileName;
		Mix::Tool::Win32::Graphics::FileTexture* m_pEmissiveTexture;

		std::wstring m_BumpTextureFileName;
		Mix::Tool::Win32::Graphics::FileTexture* m_pBumpTexture;
		Mix::Tool::Win32::Graphics::BUMP_TYPE m_BumpType;
		float m_BumpHeightScale;
		int m_BumpSample;

		Mix::Tool::Win32::Graphics::WAVE_TYPE m_WaveType;
		Mix::Tool::Win32::Graphics::WAVE_DIR m_WaveDir;
		D3DXVECTOR2 m_WaveDirVec;
		float m_WaveVelocity;
		float m_WaveUVOffset;
		float m_WaveGap;
		bool m_bWaveInvert;
		float m_WaveRefractRatio;
		float m_WavePos;
		D3DXVECTOR2 m_WaveUV;

		D3DTEXTUREFILTERTYPE m_TextureFilterType;
		D3DTEXTUREADDRESS m_TextureAddressType;

		bool m_bShadowReceive;
		bool m_bShadowCast;

	private:
//		static Mix::Tool::Win32::Graphics::FileTexture* LoadTexture( const wchar_t* pFileName, const wchar_t* pTypeName, Mix::Tool::Win32::Graphics::Manager* pMgr, Mix::Tool::Win32::File::InputStream& input );
		static bool SaveTexture( Mix::Tool::Win32::Graphics::FileTexture* pTexture, Mix::Tool::Win32::File::OutputStream& output );

	private:
		void OnActivate( bool bActive );
		void OnUpdate( int baseFrameRate, float mag );
		void OnUpdateShader( unsigned int flags );

		void AutoUpdate( void );

		void SetDefaultName( const wchar_t* pName );
//		bool Load( const wchar_t* pFilePath );
		bool Save( void );
		bool Write( const wchar_t* pFilePath, Mix::Tool::Win32::File::OutputStream& output );

	public:
		Material( Mix::Tool::Win32::Graphics::MaterialSlot* pSlot, bool bDefault );
		~Material( void );

		Mix::Tool::Win32::Graphics::VertexLayout* GetVertexLayout( Mix::Tool::Win32::Graphics::VERTEX_TYPE vertexType ) const;
		Mix::Tool::Win32::Graphics::VertexShader* GetVertexShader( Mix::Tool::Win32::Graphics::VERTEX_TYPE vertexType, Mix::Tool::Win32::Graphics::MAPPING_TYPE mappingType ) const;
		Mix::Tool::Win32::Graphics::PixelShader* GetPixelShader( Mix::Tool::Win32::Graphics::MAPPING_TYPE mappingType ) const;
		Mix::Tool::Win32::Graphics::VertexShader* GetSelectVertexShader( Mix::Tool::Win32::Graphics::VERTEX_TYPE vertexType ) const;
		Mix::Tool::Win32::Graphics::PixelShader* GetSelectPixelShader( void ) const;

		void Destroy( void );

	public:
		const wchar_t* GetDefaultName( void ) const;

		const wchar_t* GetName( void ) const;
		void SetName( const wchar_t* pName );

		Mix::Tool::Win32::Graphics::SHADER_TYPE GetShaderType( void ) const;
		void SetShaderType( Mix::Tool::Win32::Graphics::SHADER_TYPE type );

		const D3DXVECTOR4& GetAmbientColor( void ) const;
		void SetAmbientColor( const D3DXVECTOR4& color );
		bool GetBothLighting( void ) const;
		void SetBothLighting( bool state );

		Mix::Tool::Win32::Graphics::BLEND_MODE GetBlendMode( void ) const;
		void SetBlendMode( Mix::Tool::Win32::Graphics::BLEND_MODE blendMode );

		bool GetTransparency( void ) const;
		void SetTransparency( bool state );
		Mix::Tool::Win32::Graphics::TRANSPARENCY_METHOD GetTransparencyMethod( void ) const;
		void SetTransparencyMethod( Mix::Tool::Win32::Graphics::TRANSPARENCY_METHOD draw );
		bool GetZWrite( void ) const; //Z値の書き込み( 半透明なものしか機能しません )
		void SetZWrite( bool state );
		bool GetSoftEdge( void ) const;
		void SetSoftEdge( bool state );
		float GetSoftEdgeThickness( void ) const;
		void SetSoftEdgeThickness( float thickness );
		D3DXVECTOR4 GetTransparencyParam( void );

		bool GetBackculling( void ) const;
		void SetBackculling( bool state );

		D3DTEXTUREFILTERTYPE GetTextureFilterType( void ) const;
		void SetTextureFilterType( D3DTEXTUREFILTERTYPE type );
		D3DTEXTUREADDRESS GetTextureAddressType( void ) const;
		void SetTextureAddressType( D3DTEXTUREADDRESS type );

		bool GetShadowReceive( void ) const;
		void SetShadowReceive( bool state );
		bool GetShadowCast( void ) const;
		void SetShadowCast( bool state );

		Mix::Tool::Win32::Graphics::DIFFUSE_TYPE GetDiffuseType( void ) const;
		void SetDiffuseType( Mix::Tool::Win32::Graphics::DIFFUSE_TYPE type );
		const D3DXVECTOR4& GetDiffuseColor( void ) const;
		void SetDiffuseColor( const D3DXVECTOR4& color );
		bool GetDiffuseFresnel( void ) const;
		void SetDiffuseFresnel( bool state );
		float GetDiffuseFresnelRatio( void ) const;
		void SetDiffuseFresnelRatio( float ratio );
		bool GetDiffuseRL( void ) const;
		void SetDiffuseRL( bool state );
		float GetDiffuseRLHardness( void ) const;
		void SetDiffuseRLHardness( float hardness );
		void SetDiffuseRLScale( float scale );
		float GetDiffuseRLScale( void ) const;
		const wchar_t* GetDiffuseTextureFileName( void ) const;
		void SetDiffuseTextureFileName( const wchar_t* pFileName );
		Mix::Tool::Win32::Graphics::Texture* GetDiffuseTexture( void );
		bool LoadDiffuseTexture( void );
		bool LoadDiffuseTexture( const wchar_t* pFileName );
		D3DXVECTOR4 GetDiffuseParam( void );

		Mix::Tool::Win32::Graphics::SPECULAR_TYPE GetSpecularType( void ) const;
		void SetSpecularType( Mix::Tool::Win32::Graphics::SPECULAR_TYPE type );
		const D3DXVECTOR4& GetSpecularColor( void ) const;
		void SetSpecularColor( const D3DXVECTOR4& color );
		float GetSpecularHardness( void ) const;
		void SetSpecularHardness( float hardness );
		float GetSpecularScale( void ) const;
		void SetSpecularScale( float scale );
		float GetSpecularCTFresnel( void ) const;
		void SetSpecularCTFresnel( float fresnel );
		float GetSpecularCTRoughness( void ) const;
		void SetSpecularCTRoughness( float roughness );
		const wchar_t* GetSpecularTextureFileName( void ) const;
		void SetSpecularTextureFileName( void );
		void SetSpecularTextureFileName( const wchar_t* pFileName );
		Mix::Tool::Win32::Graphics::Texture* GetSpecularTexture( void );
		bool LoadSpecularTexture( void );
		bool LoadSpecularTexture( const wchar_t* pFileName );
		D3DXVECTOR4 GetSpecularParam0( void );
		D3DXVECTOR4 GetSpecularParam1( void );

		Mix::Tool::Win32::Graphics::REFLECT_TYPE GetReflectType( void ) const;
		void SetReflectType( Mix::Tool::Win32::Graphics::REFLECT_TYPE type );
		float GetReflectScale( void ) const;
		void SetReflectScale( float scale );
		float GetReflectIntensity( void ) const;
		void SetReflectIntensity( float intensity );
		float GetReflectBias( void ) const;
		void SetReflectBias( float bias );
		float GetReflectExprosure( void ) const;
		void SetReflectExprosure( float exprosure );
		float GetReflectBumpRatio( void ) const;
		void SetReflectBumpRatio( float ratio );
		D3DXVECTOR4 GetReflectParam( void );

		const D3DXVECTOR4& GetEmissiveColor( void ) const;
		void SetEmissiveColor( const D3DXVECTOR4& color );
		float GetEmissiveScale( void ) const;
		void SetEmissiveScale( float scale );
		void SetEmissiveTextureFileName( void );
		void SetEmissiveTextureFileName( const wchar_t* pFileName );
		const wchar_t* GetEmissiveTextureFileName( void ) const;
		bool LoadEmissiveTexture( void );
		bool LoadEmissiveTexture( const wchar_t* pFileName );
		Mix::Tool::Win32::Graphics::Texture* GetEmissiveTexture( void );
		D3DXVECTOR4 GetEmissiveParam( void );

		void SetBumpTextureFileName( void );
		void SetBumpTextureFileName( const wchar_t* pFileName );
		const wchar_t* GetBumpTextureFileName( void ) const;
		bool LoadBumpTexture( void );
		bool LoadBumpTexture( const wchar_t* pFileName );
		Mix::Tool::Win32::Graphics::Texture* GetBumpTexture( void );
		void SetBumpType( Mix::Tool::Win32::Graphics::BUMP_TYPE type );
		Mix::Tool::Win32::Graphics::BUMP_TYPE GetBumpType( void ) const;
		void SetBumpHeightScale( float scale );
		float GetBumpHeightScale( void ) const;
		void SetBumpSample( int sample );
		int GetBumpSample( void ) const;
		Mix::Tool::Win32::Graphics::WAVE_TYPE GetBumpWaveType( void ) const;
		void SetBumpWaveType( Mix::Tool::Win32::Graphics::WAVE_TYPE type );
		Mix::Tool::Win32::Graphics::WAVE_DIR GetBumpWaveDir( void ) const;
		void SetBumpWaveDir( Mix::Tool::Win32::Graphics::WAVE_DIR dir );
		float GetBumpWaveVelocity( void ) const;
		void SetBumpWaveVelocity( float vel );
		float GetBumpWaveUVOffset( void ) const;
		void SetBumpWaveUVOffset( float offset );
		float GetBumpWaveGap( void ) const;
		void SetBumpWaveGap( float gap );
		bool GetBumpWaveInvert( void ) const;
		void SetBumpWaveInvert( bool state );
		float GetBumpRefractRatio( void ) const;
		void SetBumpRefractRatio( float ratio );

		D3DXVECTOR4 GetBumpParam0( void );
		D3DXVECTOR4 GetBumpParam1( void );

		bool GetAutoUpdate( void ) const;
		void SetAutoUpdate( bool state );

		void Update( bool bNotifyDrawObject = true );

		bool GetDefault( void ) const;

		void SetActive( void );
		bool GetActive( void ) const;

		const wchar_t* GetSaveFilePath( void ) const;
		void SetSaveFilePath( const wchar_t* pFilePath );

	public:
		virtual Mix::Tool::Win32::Object::TYPE GetType( void ) const;

	private:
		static const Mix::Tool::Win32::Graphics::SHADER_TYPE DEF_SHADER_TYPE;

		static const D3DXVECTOR4 DEF_AMBIENT_COLOR;
		static const bool DEF_BOTH_LIGHTING;

		static const Mix::Tool::Win32::Graphics::BLEND_MODE DEF_BLEND_MODE;

		static const bool DEF_TRANSPARENCY;
		static const Mix::Tool::Win32::Graphics::TRANSPARENCY_METHOD DEF_TRANSPARENCY_DRAW;
		static const bool DEF_ZWRITE;
		static const bool DEF_SOFTEDGE;
		static const float DEF_SOFTEDGE_THICKNESS;

		static const bool DEF_BACKCULLING;

		static const D3DTEXTUREFILTERTYPE DEF_TEXFILTER_TYPE;
		static const D3DTEXTUREADDRESS DEF_TEXADDRES_TYPE;

		static const bool DEF_SHADOW_RECEIVE;
		static const bool DEF_SHADOW_CAST;

		static const Mix::Tool::Win32::Graphics::DIFFUSE_TYPE DEF_DIFFUSE_TYPE;
		static const D3DXVECTOR4 DEF_DIFFUSE_COLOR;
		static const bool DEF_DIFFUSE_FRESNEL;
		static const float DEF_DIFFUSE_FRESNEL_RATIO;
		static const bool DEF_DIFFUSE_RL;
		static const float DEF_DIFFUSE_RL_HARDNESS;
		static const float DEF_DIFFUSE_RL_SCALE;

		static const Mix::Tool::Win32::Graphics::SPECULAR_TYPE DEF_SPECULAR_TYPE;
		static const D3DXVECTOR4 DEF_SPECULAR_COLOR;
		static const float DEF_SPECULAR_HARDNESS;
		static const float DEF_SPECULAR_SCALE;
		static const float DEF_SPECULAR_CT_FRESNEL;
		static const float DEF_SPECULAR_CT_ROUGHNESS;

		static const Mix::Tool::Win32::Graphics::REFLECT_TYPE DEF_REFLECT_TYPE;
		static const float DEF_REFLECT_INTENSITY;
		static const float DEF_REFLECT_SCALE;
		static const float DEF_REFLECT_BIAS;
		static const float DEF_REFLECT_EXPROSURE;
		static const float DEF_REFLECT_BUMP_RATIO;

		static const D3DXVECTOR4 DEF_EMISSIVE_COLOR;
		static const float DEF_EMISSIVE_SCALE;

		static const Mix::Tool::Win32::Graphics::BUMP_TYPE DEF_BUMP_TYPE;
		static const float DEF_PARALLAX_HEIGHT_SCALE;
		static const int DEF_PARALLAX_SAMPLE;

		static const Mix::Tool::Win32::Graphics::WAVE_TYPE DEF_WAVE_TYPE;
		static const Mix::Tool::Win32::Graphics::WAVE_DIR DEF_WAVE_DIR;
		static const D3DXVECTOR2 DEF_WAVE_DIR_VEC;
		static const float DEF_WAVE_VELOCITY;
		static const float DEF_WAVE_UV_OFFSET;
		static const float DEF_WAVE_GAP;
		static const float DEF_WAVE_REFRACT_RATIO;

		//D3Dテクスチャフィルターテーブル
		static const D3DTEXTUREFILTERTYPE D3D_TEXF_TABLE[Material::MTL_TEXF_MAX];
		//D3Dテクスチャアドレステーブル
		static const D3DTEXTUREADDRESS D3D_TEXA_TABLE[Material::MTL_TEXA_MAX];

		friend class Manager;
		friend class MaterialSlot;
	};

}}}}
