// == LICENSE INFORMATION ==
/*
 * First author tiritomato 2013.
 * This program is distributed under the GNU General Public License(GPL).
 * support blog (Japanese only) http://d.hatena.ne.jp/tiri_tomato/
 */
// == LICENSE INFORMATION ==

/*!
@brief 先行インクルード用ベースヘッダ
@details UVTexIntegra全体で、全てのヘッダが最初にインクルードすべき基底ヘッダーファイルです。
また、このヘッダを*.c/*.cppファイルが直接インクルードする事は通常ありません。
このヘッダをベースにして宣言を追記したヘッダを作成し、その追記ヘッダを定義ソースにインクルードしてコンパイルします。
*/
#pragma once

#using "mscorlib.dll"
#using "windowsbase.dll"

#include "MQCLI.hpp"
#include "msclr/marshal.h"
#include "msclr/marshal_windows.h"
#include "msclr/marshal_cppstd.h"

#include <bitset>
#include <gcroot.h>

#define MAKER_NAME					"tiritomato"
#define PLUGIN_NAME					"UV and Texture Integration Tool"
#define PLUGIN_STRING				"UVTexIntegra"
#define PLUGIN_SETTING_KEY			"UVTI_ParamsKey"
#define PILOT_SWITCH_STRING_CLEAR	"UV統合情報をクリア"
#define PILOT_SWITCH_STRING_CREATE	"UV統合情報を作成"
#define CUSTOMBAKE_CONFIG_FILENAME	"CustomBake.dat"

namespace UVTexIntegra {

	//! @addtogroup UVTexIntegra名前空間
	//! @{

	//! @brief カンバスの表示モードを定義します。
	public enum class CanvasMode {
		Normal,
		VertexColorPreview
	};
	
	//! @brief DLLパス解析失敗イベントを拡張して、独自のDLL配置パスを探査してDLLアセンブリをロードするクラス
	public ref class CustomAssemblyResolver {
	public:
		static CustomAssemblyResolver^ Singleton() { if ( m_instance == nullptr ) m_instance = gcnew CustomAssemblyResolver(); return m_instance; }
	private:
		static CustomAssemblyResolver^ m_instance = nullptr;
		initonly System::String^ DllLoadDirectory;
		CustomAssemblyResolver();
		System::Reflection::Assembly^ CustomAssemblyResolve(System::Object^ sender, System::ResolveEventArgs^ args);
	};

	//! @brief 表示名を返すプロパティを公開するインターフェース。
	public interface class IDisplayName {
		property System::String^ DisplayName { System::String^ get(); }
	};

	//! @brief double型によるUV座標構造体
	struct UVCoordinate {
		double u, v;
		UVCoordinate() { u = v = 0.0; }
		UVCoordinate( const double u_, const double v_ ) { u = u_; v = v_; }
		UVCoordinate( const MQCoordinate& src ) { u = src.u; v = src.v; }
		UVCoordinate operator - () { return UVCoordinate(-u, -v); }
		void Add( const double src ) { u += src; v += src; }
		void Add( const double u_, const double v_ ) { u += u_; v += v_; }
		void Add( const UVCoordinate& src ) { u += src.u; v += src.v; }
		void CopyTo( MQCoordinate &dest ) { dest.u = (float)u; dest.v = (float)v; }
		double Magnitude() const { const double sqmag = SqrMagnitude(); if ( 0.0 < sqmag ) return std::sqrt( sqmag ); return 0.0; }
		void Magnitude( const double setMagnitude ) { const double mag = Magnitude(); if ( 0.0 < mag ) Mul( setMagnitude / mag ); }
		void Mul( const double src ) { u *= src; v *= src; }
		void Mul( const double u_, const double v_ ) { u *= u_; v *= v_; }
		void Mul( const UVCoordinate& src ) { u *= src.u; v *= src.v; }
		void Normalize() { const double mag = Magnitude(); if ( 0.0 < mag ) Mul( 1.0 / mag ); }
		void Rotate(const double angle_degree, const UVCoordinate& o) {
			const double cos = System::Math::Cos(angle_degree);
			const double sin = System::Math::Sin(angle_degree);
			const UVCoordinate dist( u - o.u, v - o.v );
			u = dist.u * cos - dist.v * sin + o.u;
			v = dist.u * sin - dist.v * cos + o.v;
		}
		void Rotate(const double angle_degree) { Rotate( angle_degree, UVCoordinate() ); }
		double SqrMagnitude() const { return u*u+v*v; }
	};

	// @}
}

#include "MQCLIExtention.hpp"

namespace UVTexIntegra {

	//! @addtogroup UVTexIntegra名前空間
	//! @{

	//! @brief プラグイン全体の設定情報を定義します。
	//! @details この設定は、メタセコの開始終了で呼び出されるプラグインの開始終了契機で入出力されます。
	//! XMLSerializerで入出力されます。
	[System::Serializable]
	public ref class Config {
	public:
		int Width;
		int Height;
		int SplitterW;
		int CanvasRestoreW;
		int GridResolution;
		int TexSetFormW, TexSetFormH;
		UVTexIntegra::CanvasMode CanvasMode;
		System::Int32 BakeTexBaseColor;
		int BakeTexImgW, BakeTexImgH;
		float BakeTexBorder;
		int BuildResultFormW, BuildResultFormH;
		System::String^ ScriptLoadDir;
		int BitFlags32;

		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayTransparent {
			bool get() { return std::bitset<32>(BitFlags32)[0]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[0] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayGrid {
			bool get() { return std::bitset<32>(BitFlags32)[1]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[1] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayFill {
			bool get() { return std::bitset<32>(BitFlags32)[2]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[2] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayBorder {
			bool get() { return std::bitset<32>(BitFlags32)[3]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[3] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayPoly {
			bool get() { return std::bitset<32>(BitFlags32)[4]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[4] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayObjcetTransMenu {
			bool get() { return std::bitset<32>(BitFlags32)[5]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[5] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayCmbTexMenu {
			bool get() { return std::bitset<32>(BitFlags32)[6]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[6] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayBakeTexMenu {
			bool get() { return std::bitset<32>(BitFlags32)[7]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[7] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplaySelectedObjectMenu {
			bool get() { return std::bitset<32>(BitFlags32)[8]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[8] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		property bool IsDisplayMaterialEditMenu {
			bool get() { return std::bitset<32>(BitFlags32)[9]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[9] = value; BitFlags32 = int(bits.to_ulong()); }
		}

		Config^ Clone() { return static_cast<Config^>(MemberwiseClone()); }
		
		Config() {
			Width = -1;
			Height = -1;
			SplitterW = -1;
			CanvasRestoreW = -1;
			BitFlags32 = 0;
			IsDisplayTransparent = true;
			IsDisplayGrid = true;
			IsDisplayFill = true;
			IsDisplayBorder = true;
			IsDisplayPoly = false;
			IsDisplayObjcetTransMenu = true;
			IsDisplayCmbTexMenu = true;
			IsDisplayBakeTexMenu = true;
			IsDisplaySelectedObjectMenu = true;
			IsDisplayMaterialEditMenu = true;
			TexSetFormW = 0;
			TexSetFormH = 0;
			CanvasMode = CanvasMode::Normal;
			BakeTexBaseColor = 0xFFFFFFFF;
			BakeTexImgW = BakeTexImgH = 1024;
			BakeTexBorder = 0.0f;
			ScriptLoadDir = nullptr;
		}
	};

	//! @brief メタセコイアオブジェクトごとの編集データを格納します。
	//! @details なお、このクラスをリードオンリーなインターフェース類を提供するのか、クローニングによるオリジナル保護を実施するのかは検討中となっています。
	public ref class EditData : System::ICloneable {
	public:
		//! @brief EditDataコレクションをラッピングして、全ての要素で値が共通するプロパティについてはその値を、一つでも異なるデータを含めば無効な値を返すインターフェースを提供するクラスです。
		//! @details 列挙そのものはリードオンリーですが、要素は読み書き可能なEditDataインスタンスを扱います。
		ref class SelectedCollection : System::Collections::IEnumerable, System::Collections::Generic::IEnumerable<EditData^> {
		public:
			property bool^ IsTransExecute {
				bool^ get() {
					if ( (m_src==nullptr) || (m_src->Count<=0) ) return nullptr;
					const bool ret = m_src[0]->IsTransExecute;
					for each ( EditData^ data in m_src ) if ( ret != data->IsTransExecute ) return nullptr;
					return ret;
				}
				void set( bool^ value ){ if ((m_src!=nullptr)&&(value!=nullptr)) for each ( EditData^ data in m_src ) data->IsTransExecute = *value; }
			}
			property UINT ToMaterialID {
				UINT get() {
					if ( (m_src==nullptr) || (m_src->Count<=0) ) return -1;
					const UINT ret = m_src[0]->ToMaterialID;
					for each ( EditData^ data in m_src ) if ( ret != data->ToMaterialID ) return -1;
					return ret;
				}
				void set( UINT value ){ if ( m_src != nullptr ) for each ( EditData^ data in m_src ) data->ToMaterialID = value; }
			}
			property System::String^ ToMaterialName {
				System::String^ get() {
					if ( (m_src==nullptr) || (m_src->Count<=0) ) return nullptr;
					System::String^ ret = m_src[0]->ToMaterialName;
					for each ( EditData^ data in m_src ) if ( System::String::Compare(ret,data->ToMaterialName) != 0 ) return nullptr;
					return ret;
				}
				void set( System::String^ value ){ if ( m_src != nullptr ) for each ( EditData^ data in m_src ) data->ToMaterialName = value; }
			}
			property float MoveU {
				float get() {
					if ( (m_src==nullptr) || (m_src->Count<=0) ) return float::NaN;
					const float ret = m_src[0]->MoveU;
					for each ( EditData^ data in m_src ) if ( ret != data->MoveU ) return float::NaN;
					return ret;
				}
				void set( float value ){ if ( m_src != nullptr ) for each ( EditData^ data in m_src ) data->MoveU = value; }
			}
			property float MoveV {
				float get() {
					if ( (m_src==nullptr) || (m_src->Count<=0) ) return float::NaN;
					const float ret = m_src[0]->MoveV;
					for each ( EditData^ data in m_src ) if ( ret != data->MoveV ) return float::NaN;
					return ret;
				}
				void set( float value ){ if ( m_src != nullptr ) for each ( EditData^ data in m_src ) data->MoveV = value; }
			}
			property float ScaleU {
				float get() {
					if ( (m_src==nullptr) || (m_src->Count<=0) ) return float::NaN;
					const float ret = m_src[0]->ScaleU;
					for each ( EditData^ data in m_src ) if ( ret != data->ScaleU ) return float::NaN;
					return ret;
				}
				void set( float value ){ if ( m_src != nullptr ) for each ( EditData^ data in m_src ) data->ScaleU = value; }
			}
			property float ScaleV {
				float get() {
					if ( (m_src==nullptr) || (m_src->Count<=0) ) return float::NaN;
					const float ret = m_src[0]->ScaleV;
					for each ( EditData^ data in m_src ) if ( ret != data->ScaleV ) return float::NaN;
					return ret;
				}
				void set( float value ){ if ( m_src != nullptr ) for each ( EditData^ data in m_src ) data->ScaleV = value; }
			}
			property float Padding {
				float get() {
					if ( (m_src==nullptr) || (m_src->Count<=0) ) return float::NaN;
					const float ret = m_src[0]->Padding;
					for each ( EditData^ data in m_src ) if ( ret != data->Padding ) return float::NaN;
					return ret;
				}
				void set( float value ){ if ( m_src != nullptr ) for each ( EditData^ data in m_src ) data->Padding = value; }
			}
			property EditData^ default[int] {
				EditData^ get(int index) { if ( (m_src!=nullptr) && (0<=index) && (index<m_src->Count) ) return m_src[index]; return nullptr; }
			};
			virtual property int Count { int get(){ if (m_src!=nullptr) return m_src->Count; return 0; } }
			SelectedCollection( System::Collections::ObjectModel::ReadOnlyCollection<EditData^>^ src ) : m_src(src) {}
			virtual System::Collections::IEnumerator^ GetEnumerator() = System::Collections::IEnumerable::GetEnumerator
			{
				if ( m_src != nullptr ) return m_src->GetEnumerator(); return nullptr;
			}
			virtual System::Collections::Generic::IEnumerator<EditData^>^ GetGenericEnumerator() = System::Collections::Generic::IEnumerable<EditData^>::GetEnumerator
			{
				if ( m_src != nullptr ) return m_src->GetEnumerator(); return nullptr;
			}
		private:
			System::Collections::ObjectModel::ReadOnlyCollection<EditData^>^ m_src;
		};
		UINT UniqueID;
		System::String^ MaterialName;
		bool IsTransExecute;
		UINT ToMaterialID;
		System::String^ ToMaterialName;
		float ScaleU, ScaleV;
		float MoveU, MoveV;
		float Padding;
		property bool IsTransExecutableStatus {
			bool get(){
				return ((float::IsNaN(ScaleU)||float::IsNaN(ScaleV)||float::IsNaN(MoveU)||float::IsNaN(MoveV)||float::IsInfinity(ScaleU)||float::IsInfinity(ScaleV)||float::IsInfinity(MoveU)||float::IsInfinity(MoveV))==false) &&
						IsTransExecute&&(ScaleU!=0.0f)&&(ScaleV!=0.0f);
			}
		}
		//! @brief デフォルトコンストラクタ
		EditData() { Clear(-1,nullptr); }
		//! @brief コンストラクタ
		EditData( const UINT uid_, System::String^ name ) { Clear(uid_,name); }
		//! @brief シャローコピーによるクローンを作成します。今のところString以外値型なのでシャロー実装です。
		EditData^ Clone() { return static_cast<EditData^>(MemberwiseClone()); }
		//! @brief ICloneable::Cloneの実装(シャローコピーによるクローン／今のところString以外値型なのでシャロー実装です)
		virtual System::Object^ InterfaceClone() = System::ICloneable::Clone { return MemberwiseClone(); }
		//! @brief リセット処理です。UniqueID以外のメンバがクリアされます。
		void Reset() {
			IsTransExecute = false;
			MaterialName = nullptr;
			ToMaterialID = -1;
			ToMaterialName = nullptr;
			ScaleU = 0.0f;
			ScaleV = 0.0f;
			MoveU = 0.0f;
			MoveV = 0.0f;
			Padding = 0.0f;
		}
	private:
		void Clear(const UINT uid_, System::String^ name ) {
			Reset();
			UniqueID = uid_;
			MaterialName = name;
			IsTransExecute = true;
		}
	};

	//! @brief DocumentFormatクラスをリードオンリーで公開するためのインターフェース。
	//! @details ただし完全なリードオンリーではなく、EditDataインスタンスは書き込み可能なので注意してください。
	public interface class IDocumentFormat {
		property System::Int32 AlphaClearColor { System::Int32 get(); }
		property System::Int32 BumpClearColor { System::Int32 get();  }
		property System::Int32 TextureClearColor { System::Int32 get(); }
		property System::Collections::ObjectModel::ReadOnlyCollection<EditData^>^ EditDataItems {
			System::Collections::ObjectModel::ReadOnlyCollection<EditData^>^ get();
		}
		property bool IsCloneTrans { bool get(); }
		property bool IsRecursiveTrans { bool get(); }
		property bool IsIntegrateTexture { bool get(); }
		property bool IsClrTextureOnIntegrate { bool get(); }
		property bool IsIntegrateAlpha { bool get(); }
		property bool IsClrAlphaOnIntegrate { bool get(); }
		property bool IsIntegrateBump { bool get(); }
		property bool IsClrBumpOnIntegrate { bool get(); }
		property /*!*/::MQDocument MQDocument { ::MQDocument get(); }
		//! @brief ユニークIDを指定してEditDataアイテムを検索します。見つからない場合はnullが返ります。
		EditData^ ItemFromID( const UINT UniqueID );
		//! @brief マテリアル名を指定してEditDataアイテムを検索します。見つからない場合はnullが返ります。
		EditData^ ItemFromName( System::String^ matName );
		//! @brief インデックスを指定してEditDataアイテムを検索します。見つからない場合はnullが返ります。
		EditData^ ItemFromIndex( const int index );
		//! @brief ユニークIDを指定して、EditDataアイテムのインデックスを検索します。見つからない場合は無効な負のインデックスが返ります。
		int ItemIndexFromID( const UINT UniqueID );
		//! @brief 保有するEditData配列の中で、なおかつMQDocumentで現在マテリアル選択されているEditDataのコレクションを返します。
		//! @details MQDocumentがNULLの時は空の配列が返ります。先頭のカレントマテリアル以外のマテリアルの順序は不定です。
		EditData::SelectedCollection^ ItemsOnSelected();
		//! @brief 保有するEditData配列の中で、なおかつMQDocumentで現在マテリアル選択されているEditDataのコレクションを返します。
		//! @details MQDocumentがNULLの時は空の配列が返ります。先頭のカレントマテリアル以外のマテリアルの順序は不定です。
		//! @param [in] index -1などItemFromIndex()に渡してEditDataが取得不能なインデックスを指定すると何も起こりませんが、ItemFromIndex()に渡してEditDataが取得可能なインデックスを指定すると、カレントマテリアルよりも先にそのEditDataが挿入されます。
		//! このとき、そのEditDataマテリアルが現在選択されているかどうかは判定されません。以後は通常通りカレントマテリアルが並んでからその他複数選択中のマテリアルが続きます。
		EditData::SelectedCollection^ ItemsOnSelected(const int index);
	};

	//! @brief メタセコイアのドキュメントごとのプラグイン編集データをXMLシリアライズするフォーマットクラスです。
	public ref class DocumentFormat : IDocumentFormat, System::ICloneable {
	public:
		//! @brief boolで設定／取得する「Is〜」プロパティの実態を一つの変数に集約する（XML処理簡潔化のため）。
		int BitFlags32;
		//! @brief 内部のEditData配列を取得／設定します。
		//! @details なおこのプロパティを介してはnullの取得／設定は出来ません。nullは代わりに空の配列が返却／代入されます。
		property System::Collections::Generic::List<EditData^>^ EditDataItems {
			System::Collections::Generic::List<EditData^>^ get() {
				if ( m_editDataItems == nullptr ) m_editDataItems = gcnew System::Collections::Generic::List<EditData^>();
				return m_editDataItems;
			}
			void set(System::Collections::Generic::List<EditData^>^ value) {
				if (value == nullptr) value = gcnew System::Collections::Generic::List<EditData^>();
				m_editDataItems = value;
			}
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property System::Collections::ObjectModel::ReadOnlyCollection<EditData^>^ ReadonlyEditDataItems {
			System::Collections::ObjectModel::ReadOnlyCollection<EditData^>^ get() = IDocumentFormat::EditDataItems::get {
				if (m_editDataItems != nullptr) m_editDataItems->AsReadOnly();
				return System::Array::AsReadOnly(gcnew array<EditData^>{});
			}
		}
		virtual property System::Int32 AlphaClearColor {
			System::Int32 get() { return m_alphaClearColor; }
			void set(System::Int32 value) { m_alphaClearColor = value; }
		}
		virtual property System::Int32 BumpClearColor {
			System::Int32 get() { return m_bumpClearColor; }
			void set(System::Int32 value) { m_bumpClearColor = value; }
		}
		virtual property System::Int32 TextureClearColor {
			System::Int32 get() { return m_textureClearColor; }
			void set(System::Int32 value) { m_textureClearColor = value; }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property bool IsCloneTrans {
			bool get() { return std::bitset<32>(BitFlags32)[0]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[0] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property bool IsRecursiveTrans {
			bool get() { return std::bitset<32>(BitFlags32)[1]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[1] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property bool IsIntegrateTexture {
			bool get() { return std::bitset<32>(BitFlags32)[2]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[2] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property bool IsClrTextureOnIntegrate {
			bool get() { return std::bitset<32>(BitFlags32)[3]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[3] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property bool IsIntegrateAlpha {
			bool get() { return std::bitset<32>(BitFlags32)[4]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[4] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property bool IsClrAlphaOnIntegrate {
			bool get() { return std::bitset<32>(BitFlags32)[5]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[5] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property bool IsIntegrateBump {
			bool get() { return std::bitset<32>(BitFlags32)[6]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[6] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property bool IsClrBumpOnIntegrate {
			bool get() { return std::bitset<32>(BitFlags32)[7]; }
			void set(bool value) { std::bitset<32> bits(BitFlags32); bits[7] = value; BitFlags32 = int(bits.to_ulong()); }
		}
		[System::Xml::Serialization::XmlIgnoreAttribute]
		virtual property /*!*/::MQDocument MQDocument {
			::MQDocument get() { return m_doc; }
			void set( ::MQDocument value ) { m_doc = value; }
		}
		
		//! @brief デフォルトコンストラクタ
		DocumentFormat();
		//! @brief コピーコンストラクタ（ディープコピーを行います）
		DocumentFormat( DocumentFormat^ src );
		//! @brief コピーコンストラクタを呼び出してディープコピークローンを生成します。
		//! @details クローンオブジェクトをIDocumentFormatとして開示すると、データの書き換えに対してより安全なコーディングが出来ます。
		DocumentFormat^ Clone() { return gcnew DocumentFormat(this); }
		//! @brief ディープコピークローンをICloneableインターフェースに提供します。
		virtual System::Object^ InterfaceClone() = System::ICloneable::Clone { return Clone(); }
		//! @brief ユニークIDを指定してEditDataアイテムを検索します。見つからない場合はnullが返ります。
		virtual EditData^ ItemFromID( const UINT UniqueID );
		//! @brief マテリアル名を指定してEditDataアイテムを検索します。見つからない場合はnullが返ります。
		virtual EditData^ ItemFromName( System::String^ matName );
		//! @brief インデックスを指定してEditDataアイテムを検索します。見つからない場合はnullが返ります。
		virtual EditData^ ItemFromIndex( const int index );
		//! @brief ユニークIDを指定して、EditDataアイテムのインデックスを検索します。見つからない場合は無効な負のインデックスが返ります。
		virtual int ItemIndexFromID( const UINT UniqueID );
		//! @brief 保有するEditData配列の中で、なおかつMQDocumentで現在マテリアル選択されているEditDataのコレクションを返します。
		//! @details MQDocumentがNULLの時は空の配列が返ります。先頭のカレントマテリアル以外のマテリアルの順序は不定です。
		virtual EditData::SelectedCollection^ ItemsOnSelected() { return ItemsOnSelected(-1); }
		//! @brief 保有するEditData配列の中で、なおかつMQDocumentで現在マテリアル選択されているEditDataのコレクションを返します。
		//! @details MQDocumentがNULLの時は空の配列が返ります。先頭のカレントマテリアル以外のマテリアルの順序は不定です。
		//! @param [in] index -1などItemFromIndex()に渡してEditDataが取得不能なインデックスを指定すると何も起こりませんが、ItemFromIndex()に渡してEditDataが取得可能なインデックスを指定すると、カレントマテリアルよりも先にそのEditDataが挿入されます。
		//! このとき、そのEditDataマテリアルが現在選択されているかどうかは判定されません。以後は通常通りカレントマテリアルが並んでからその他複数選択中のマテリアルが続きます。
		virtual EditData::SelectedCollection^ ItemsOnSelected(const int index);
	private:
		System::Int32 m_textureClearColor;
		System::Int32 m_alphaClearColor;
		System::Int32 m_bumpClearColor;
		::MQDocument m_doc;
		System::Collections::Generic::List<EditData^>^ m_editDataItems;
	};

	inline System::String^ GetCustomBakeConfigPath()
	{
		System::Reflection::Assembly^ assembly = System::Reflection::Assembly::GetExecutingAssembly();
		System::IO::FileInfo^ fileInfo = gcnew System::IO::FileInfo(assembly->Location);
		return fileInfo->Directory + "\\" + System::IO::Path::GetFileNameWithoutExtension(fileInfo->Name) + "\\" + CUSTOMBAKE_CONFIG_FILENAME;
	}

	//! @}
}

#include "UVTexIntegra.IConfig.hpp"