/*
First author tiritomato 2013.

mqsdx is distributed under the GNU Lesser General Public License 3.0(LGPLv3).

support blog (Japanese only)
http://d.hatena.ne.jp/tiri_tomato/
*/

#ifndef __MQSDKPlugIn0x_11_h__
#define __MQSDKPlugIn0x_11_h__

#define _USE_MATH_DEFINES
#include <math.h>
#include <stdint.h>
#include <string.h>

#include <algorithm>
#include <cmath>
#include <functional>
#include <iomanip>
#include <regex>
#include <sstream>
#include <utility>
#include <vector>

#define NOMINMAX
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <MQSetting.h>
#include <MQBasePlugin.h>
#include <MQPlugin.h>
#include <MQ3DLib.h>

#include "impl/MQ0x_11.hpp"

// Plugin Version Checker
#ifdef MQPLUGIN_VERSION
	#if MQPLUGIN_VERSION < 0x0300
	"MQx" need newer than mqsdk300
	#endif
#else
	"MQx" need newer than mqsdk300
#endif

namespace MQ0x {
	
/*!	@addtogroup MQ0xの一覧
	@{
*/

	/*!
@brief 組込型配列からハッシュコードを生成するクラス

@tparam T_OUT ハッシュコードの戻り値型を指定
@tparam default_seed ハッシュコードのデフォルトの初期値を指定。省略時は整数の17を使用します。

@code
	// 文字列のハッシュコードを取得する
	DWORD hashOfString = CollectionHashCode<DWORD>("ソース配列（文字列）");
	
	// short配列のハッシュコードを取得する
	const short array[] = { 0, 1, 2, 3 };
	unsigned int hashOfString = CollectionHashCode<unsigned int>(array, sizeof(array)/sizeof(array[0]));
@endcode

配列の各要素に対して次のような計算を繰り返してハッシュコードを生成します。四則演算に対応した組込型で、とくに浮動小数点ではない整数系の処理に向きます。
@code
	T_OUT hashCode = seed;

	(配列要素総当りループ) {
		hashCode = hashCode * ((sizeof(T_IN)*8)-1) ^ 配列要素;
	}
	return hashCode;
@endcode
	*/
	template <typename T_OUT, const size_t default_seed = 17> struct CollectionHashCode {
	public:
		///@brief T_OUTにキャストされたデフォルトの初期値
		static const T_OUT defaultSeed = (T_OUT)default_seed;
		///@brief デフォルトコンストラクタ
		CollectionHashCode( const T_OUT seed = defaultSeed ) : m_val( seed ) {}
		/*!
		@brief 配列の先頭ポインタと個数を指定してハッシュコードを生成
		@tparam T_IN ソース配列の型を指定
		@note pSrcがNULLまたは配列数が0である場合、与えられた初期値がそのままハッシュコードとして記録されます。
		*/
		template <typename T_IN> CollectionHashCode( const T_IN *pSrc, const size_t ct, const T_OUT seed = defaultSeed ) : m_val(seed) {
			if ( pSrc != NULL ) for ( size_t i = 0; i < ct; i++ ) m_val = (m_val * (T_OUT)(sizeof(T_IN) * 8 - 1)) ^ pSrc[i];
		}
		/*!
		@brief 文字列を指定してハッシュコードを生成
		@note pSrcがNULLまたは長さが0の空の文字列である場合、与えられた初期値がそのままハッシュコードとして記録されます。
		*/
		CollectionHashCode( const char *pSrc, const T_OUT seed = defaultSeed ) : m_val(FromTrailCodeCollection(pSrc,'\0',seed)) {}
		/*!
		@brief ワイド文字列を指定してハッシュコードを生成
		@note pSrcがNULLまたは長さが0の空の文字列である場合、与えられた初期値がそのままハッシュコードとして記録されます。
		*/
		CollectionHashCode( const wchar_t *pSrc, const T_OUT seed = defaultSeed ) : m_val(FromTrailCodeCollection(pSrc,L'\0',seed)) {}
		/*!
		@brief 配列の先頭ポインタと配列の終端値を指定してハッシュコードを生成
		@tparam T_IN ソース配列の型を指定
		@note pSrcがNULLまたは、最初のデータで終端する空の配列である場合、与えられた初期値がそのままハッシュコードとして記録されます。
		*/
		template <typename T_IN> static CollectionHashCode FromTrailCodeCollection( const T_IN *pSrc, const T_IN trailCode, const T_OUT seed = defaultSeed ) {
			CollectionHashCode ret(seed);
			if ( pSrc != NULL ) while ( (*pSrc) != trailCode ) ret.m_val = (ret.m_val * (T_OUT)(sizeof(T_IN) * 8 - 1)) ^ (*(pSrc++));
			return ret;
		}
		///@brief 暗黙のキャストを介して戻り値を取得
		operator T_OUT() { return m_val; }
	private:
		T_OUT m_val;
	};
	
	//! @brief HSV色構造体 @details 色相(H)・彩度(S)・明度(V)を使って色情報を保持します。またRGB(MQColor)との変換メソッドを備えます。
	//! @tparam T	値(h,s,v)に使う型を指定します。float/double/long doubleを指定してください。
	template <typename T> struct HSV {
		typedef T value_type;	///< @brief テンプレートでTに指定された型をtypedefします。Tには値(h,s,v)に使う型を指定します。Tにはfloat/double/long doubleを指定してください。
		T h;					///< @brief 色相 色相環の[0°,360°]を[0.0,1.0]として記録します。
		T s;					///< @brief 彩度を[0.0,1.0]として記録します。
		T v;					///< @brief 明度を[0.0,1.0]として記録します。
		HSV() : h(T(0)), s(T(0)), v(T(0)) {} ///< @brief デフォルトコンストラクタ
		HSV(T h_, T s_, T v_) : h(h_), s(s_), v(v_) {} ///< @brief コンストラクタ
		HSV( const HSV& src ) : h(src.h), s(src.s), v(src.v) {} ///< @brief コピーコンストラクタ
		/// @brief RGB（MQColor）からHSVに変換します。
		HSV( const MQColor& rgb ) : h(T(0)), s(T(0)), v(T(0))  {
			const T min = T(std::min(std::min(rgb.r,rgb.g),rgb.b));
			const T max = T(std::max(std::max(rgb.r,rgb.g),rgb.b));
			const T delta = max - min;
			v = max;
			if(delta!=T(0)) {
				s = delta / max;
				if ( rgb.r == max ) h = (rgb.g-rgb.b) / delta;
				else if (rgb.g == max) h = T(2) + (rgb.b-rgb.r) / delta;
				else h = T(4) + (rgb.r-rgb.g) / delta;
				h /= T(6);
				if ( h < T(0) ) h += T(1);
			}
		}
		/*! @brief グレースケールカラーか判定します。
		@param threshold グレースケール（＝彩度が限りなくゼロに等しい）と判定する時の閾値を指定します。この関数の戻り値は (threshold < s) です。
		@return グレースケールの時true。それ以外false。*/
		bool isGrayScale( T threshold ) const { return threshold < s; }
		/// @brief グレースケールカラーか判定します。
		/// @return グレースケールの時true。それ以外false。この関数の戻り値は isGrayScale(std::numeric_limits<value_type>::epsilon()) と等しくなります。
		bool isGrayScale() const { return isGrayScale(std::numeric_limits<T>::epsilon()); }
		//! @brief 色情報を正規化します。
		//! @details h,s,vをそれぞれ[0.0,1.0]に正規化します。hは回転角度として循環するよう正規化されますが、s,vはクランプ計算で飽和するように正規化されます。
		void normalize() {
			h -= std::floor(h);
			s = clamp01(s);
			v = clamp01(v);
		}
		/*!	@brief HSVからRGBへ変換します。 @details 彩度がゼロである場合、特例的に色相情報も切り捨てて明度だけを反映したグレースケールカラーが返ります。*/
		MQColor toMQColor() const {
			const HSV normal = toNormalized(); // to [0,1]
			if ( normal.isGrayScale() ) return MQColor( normal.v );
			const T H = normal.h * T(6);
			const int Hi = static_cast<int>(H);
			const T fr = H - T(Hi);
			const T m = normal.v * (T(1)-normal.s);
			const T n = normal.v * (T(1)-normal.s*fr);
			const T p = normal.v * (T(1)-normal.s*(T(1)-fr));
			switch(Hi) {
				case 0:		return MQColor( float(normal.v), float(p), float(m) );
				case 1:		return MQColor( float(n), float(normal.v), float(m) );
				case 2:		return MQColor( float(m), float(normal.v), float(p) );
				case 3:		return MQColor( float(m), float(n), float(normal.v) );
				case 4:		return MQColor( float(p), float(m), float(normal.v) );
				default:	return MQColor( float(normal.v), float(m), float(n) );
			}
		}
		/*! @brief 正規化したHSV色構造体を返します。 @details normalize() 同様に正規化した構造体を返します（自分自身の情報は正規化しません）。*/
		HSV toNormalized() const { return HSV( h - std::floor(h), Clamp01(s), Clamp01(v) ); }
	};

	/*!
	@brief MQSetting代行クラス
	@code
		PluginBase<MQCommandPlugin> some_plugin;
		{
			SettingProxy setting = some_plugin.Setting(); // Setting取得
			setting.Load( ... );
			setting.Save( ... );
			setting.Close(); // 省略可能（デストラクタ経由でもClose()は実行されます）
		}
	@endcode
	SettingProxyのコピーは禁止されています(notcopyable)
	*/
	struct SettingProxy {
	public:
		//!@brief SettingProxyクラスの生成ハンドル型
		struct Handle {
			///@cond
			friend struct SettingProxy;
			template <typename T_MQPLUGIN> friend class PluginBase;
			///@endcond
			static Handle Empty() { return Handle(NULL); }
		public:
			Handle( MQBasePlugin* plugin ) { this->plugin = plugin; }
			MQBasePlugin* plugin;
		};
		SettingProxy( Handle handle );
		~SettingProxy() { Close(); }
		void Close();
		bool Load(const char *name, bool& value, bool default_value=false);
		bool Load(const char *name, int& value, int default_value=0);
		bool Load(const char *name, unsigned int& value, unsigned int default_value=0);
		bool Load(const char *name, float& value, float default_value=0.0f);
		bool Load(const char *name, std::string& value, std::string default_value="");
		bool Save(const char *name, const bool& value);
		bool Save(const char *name, const int& value);
		bool Save(const char *name, const unsigned int& value);
		bool Save(const char *name, const float& value);
		bool Save(const char *name, const char* value);
		bool Save(const char *name, const std::string& value);
	private:
		SettingProxy(const SettingProxy&);				// kill copy
		SettingProxy& operator=(const SettingProxy&);	// kill copy
		MQBasePlugin* m_plugin;
		MQSetting* m_setting;
	};

/*!
@brief MQBasePluginを継承したクラスに、基本的な拡張を行うテンプレートラッパークラス
@tparam T_MQPLUGIN MQBasePluginを継承する型

@par

このクラスはコンストラクタで製造者名、プラグイン名、表示名を指定する事で以下の実装を自動化します。
- GetPlugInID()
- GetPlugInName()
- EnumString()
- MQSetting::Open()およびClose()

@par

@code
PluginBase<MQCommandPlugin> plugin("tiritomato", "SamplePlugin Copyright(C) 2013, tiritomato.", "SamplePlugin");
{
	SettingProxy setting = plugin.Setting();
	setting.Load(...);
	setting.Save(...);
	setting.Close(); // このClose()はSettingProxyのデストラクタに任せる事も出来ます。
}
@endcode

@par

ID決定の自動化には文字列のハッシュコードが採用されています。
- 製造者ID＝製造者名（productName）のハッシュコード
- プラグインID＝プラグイン名（GetPlugInName()で取得できる文字列）のハッシュコード
	
@par

ハッシュコード算出は典型的に「ハッシュコード = ハッシュコード * (入力型(文字列の場合char型)サイズのビット数-1) ^ 配列要素」という計算を、
配列要素の個数だけ繰り返すロジックが採用されています。このテンプレートクラスで最終的にラップするのか、このテンプレートクラスをベースクラスにして継承して拡張するのかは自由です。
	*/
	template <typename T_MQPLUGIN> class PluginBase : public T_MQPLUGIN {
	public:
		PluginBase( const char* productName, const char* pluginFullName, const char* pluginString ) :
			m_productName( productName ),
			m_pluginFullName( pluginFullName ),
			m_pluginString( pluginString ),
			m_idProduct( CollectionHashCode<DWORD>(productName) ),
			m_idPlugin( CollectionHashCode<DWORD>(pluginFullName) )
		{
		}

		PluginBase( const char* productName, const char* pluginFullName, const char* pluginString,
			const DWORD idProduct, const DWORD idPlugin	) :
			m_productName( productName ),
			m_pluginFullName( pluginFullName ),
			m_pluginString( pluginString ),
			m_idProduct( idProduct ),
			m_idPlugin( idPlugin )
		{
		}

		//! プラグインIDを返す。
		virtual void GetPlugInID(DWORD *Product, DWORD *ID) {
			*Product = m_idProduct;
			*ID = m_idPlugin;
		}
		//! プラグイン名を返す。
		virtual const char *GetPlugInName() { return m_pluginFullName.c_str(); }
		//! ボタンやメニューに表示される文字列を返す。
		virtual const char *EnumString() { return m_pluginString.c_str(); }
		//! 製造者名を返す（独自に追加）
		const char* GetProductName() { return m_productName.c_str(); }
		//! 継承された時に使う明示的キャスト
		MQBasePlugin* BasePlugin() { return this; }
		//! SettingProxy(MQSettingの代替)をオープンするハンドルを取得
		SettingProxy::Handle Setting() { return SettingProxy::Handle(BasePlugin()); }
		/// @brief プロダクトIDを取得する
		DWORD ProductID() { return m_idProduct; }
		/// @brief プラグインIDを取得する
		DWORD PluginID() { return m_idPlugin; }
	protected:
		const std::string m_productName;
		const std::string m_pluginFullName;
		const std::string m_pluginString;
		const DWORD m_idProduct;
		const DWORD m_idPlugin;
	};

	namespace Math {
		///@addtogroup MQ0x-Math名前空間
		///@{

		///@brief ceiling関数 @note 浮動小数点以外の整数値型にも対応するceilです。整数の時はsrcの値をそのまま返します。11仕様を満たす std::ceil() が無い環境で利用してください。
		template <typename T> inline T Ceil( T src ) { return src; }
		/// @cond
		template <> inline float Ceil( float src ) { return std::ceil(src); }
		template <> inline double Ceil( double src ) { return std::ceil(src); }
		template <> inline long double Ceil( long double src ) { return std::ceil(src); }
		/// @endcond

		//! @brief クランプ計算 @details srcがmin〜maxの外にある場合、srcを両端で飽和させてmin以上max以下におさめます。
		template <typename T> inline T Clamp( T src, T min, T max ) {
			return std::min( std::max(min,max), std::max( std::min(min,max), src) );
		}
		
		//! @brief 0〜1クランプ計算 @details srcが0〜1の外にある場合、srcを両端で飽和させて0以上1以下におさめます。
		template <typename T> inline T Clamp01( T src ) { return std::min(T(1),std::max(T(0),src)); }
		
		//! @brief floor関数 @note 浮動小数点以外の整数値型にも対応するfloorです。整数の時はsrcの値をそのまま返します。11仕様を満たす std::floor() が無い環境で利用してください。
		template <typename T> inline T Floor( T src ) { return src; }
		/// @cond
		template <> inline float Floor( float src ) { return std::floor(src); }
		template <> inline double Floor( double src ) { return std::floor(src); }
		template <> inline long double Floor( long double src ) { return std::floor(src); }
		/// @endcond

		/*! @brief 線形補間 (Linear interpolation)
		@return tが0の時はfrom、tが1の時はtoを返し、tが0.5の時はfromとtoの平均値を返します。tはclamp処理によって0〜1に丸められます。*/
		template <typename T> inline T Lerp(T from, T to, T t) { return from + (to - from) * clamp01(t); }
		
		//! @brief 現在の値から目標の値まで指定量移動します。 @details fromからtoへ向かってmovだけ移動します。movが大きくてもtoを追い越す事はなくtoで止まります。
		template <typename T> inline T MoveTo( T from, T to, T mov ) {
			mov = std::abs(mov);
			if ( std::abs(from - to) < mov ) return to;
			return from += ( from < to ? mov : -mov );
		}
		
		//! @brief PI @return PIを返します。
		template <typename T> inline T Pi() { return (T)M_PI; }
		/// @cond
		template <> long double Pi();
		/// @endcond

		/*! @brief 度数からラジアン角（弧度）に変換
		@code
		float d = 180.0f;                // as degree
		float rd = d * Deg2Rad<float>(); // to radian
		@endcode*/
		template <typename T> inline T Deg2Rad() { return Pi<T>() / (T)180; }
		//! @brief 度数からラジアン角（弧度）に変換 @code float rad = Deg2Rad<float>(180.0f); // convert 180.0 degree into radian @endcode
		template <typename T> inline T Deg2Rad(T degree) { return Deg2Rad<T>() * degree; }

		/*! @brief ラジアン角（弧度）から度数に変換
		@code
		float rd = 2.0f * Pi<float>();   // as radian
		float d = rd * Rad2Deg<float>(); // to degree
		@endcode*/
		template <typename T> inline T Rad2Deg() { return (T)180 / Pi<T>(); }
		//! @brief ラジアン角（弧度）から度数に変換 @code float deg = Rad2Deg<float>(2.0f * pi<float>()); // convert 2 * PI (radian) into degree @endcode
		template <typename T> inline T Rad2Deg(T degree) { return Rad2Deg() * degree; }

		/*! @brief 循環丸め @return tを循環する値として、tを0〜絶対値(length)に丸めた値を返します。例えば、Repeat(380.0,360.0)は20.0を返します。*/
		template <typename T> inline T Repeat( T t, T length ) { return t - std::floor(t/length)*length; }

		/*!	@brief truncate計算。 @note VC2010に std::trunc() が搭載されていないので実装しています。 std::trunc() がある環境ならそちらを使うべきです。*/
		template <typename T> inline T Trunc( T src ) { if ( T(0) < src ) return floor(src); return ceil(src); }
		/// @}
	}
	using namespace Math;


	namespace Polygon {
		///@addtogroup MQ0x-Polygon名前空間
		///@{
		
		///@cond
		struct VertexNormalBuffer;
		///@endcond

		/*! @brief 面法線をバッファリングします
		@details オブジェクト側のデータが更新されても FaceNormalBuffer の法線バッファは同期しません（形状を変更しない静的な処理の途中で、法線算出の重複や再計算を回避するために一時的に利用するのに向いています）。
		基本的に一つのオブジェクトに対して一つの FaceNormalBuffer が必要ですが、よりシビアなパフォーマンスを要求する場合、
		Clear() メソッドを介して新しいオブジェクトを設定し、確保済みのバッファ領域を解放せず値だけクリアして再利用し、ヒープの処理負荷を低減する事が可能です。*/
		struct FaceNormalBuffer {
			typedef std::vector<MQPoint>::size_type size_type;
			/// @brief 無効な法線か判定します。
			static bool IsInvalid( const MQPoint& src ) { return src.x >= std::numeric_limits<float>::infinity(); }
			/// @brief デフォルトコンストラクタ
			FaceNormalBuffer() : m_obj(NULL), m_buffer(0), invalid_value( std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() ) {}
			/// @brief コンストラクタ
			FaceNormalBuffer( const ::MQObject obj ) : m_obj( obj ), m_buffer(0),
				invalid_value( std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity(), std::numeric_limits<float>::infinity() ) {
				if ( obj != NULL ) {
					const int ctFaceMax = obj->GetFaceCount();
					m_buffer.resize( ctFaceMax );
					for ( int ctFace = 0; ctFace < ctFaceMax; ctFace++ ) m_buffer[ctFace].x = invalid_value.x;
				}
			}
			//! @brief バッファをクリアします。
			//! @param [in] isCompact ヒープを切り詰めるかどうか。
			//! @details ヒープを切り詰める時、設定されたオブジェクトの面数を参照して切り詰めます。オブジェクトが設定されていない時、ヒープサイズはゼロに切り詰められます。
			void Clear( const bool isCompact = false ) {
				if ( isCompact ) {
					size_type sz = 0; if ( m_obj != NULL ) sz = size_type(m_obj->GetFaceCount());
					std::vector<MQPoint>(sz).swap( m_buffer );
				}
				for ( size_type ctFace = 0; ctFace < m_buffer.size(); ctFace++ ) m_buffer[ctFace].x = invalid_value.x;
			}
			//! @brief 新しいオブジェクトを指定してバッファをクリアします。
			//! @param [in] isCompact ヒープを切り詰めるかどうか。
			//! @details ヒープを切り詰める時、設定されたオブジェクトの面数を参照して切り詰めます。オブジェクトが設定されていない時、ヒープサイズはゼロに切り詰められます。
			void Clear( const ::MQObject obj, const bool isCompact = false ) { m_obj = obj; Clear(isCompact); }
			//! @brief 不要なヒープ領域を切り詰めます。オブジェクトが設定されていない時、ヒープサイズはゼロに切り詰められます。
			void Compact() {
				size_type sz = 0; if ( m_obj != NULL ) sz = size_type(m_obj->GetFaceCount());
				m_buffer.resize(sz);
				m_buffer.shrink_to_fit();
			}
			//! @brief 関連付けられているMQObjectを取得します。
			const ::MQObject MQObject() const { return m_obj; }
			/*! @brief 面法線を取得します。
			@details インデックスが指定する面の法線は最初に参照された時に計算（初期化）されます。一度バッファされたデータは Clear() メソッドで再び未初期化状態に戻すまで保持されます。
			@return バッファされた面法線。法線は正規化済みです。なお、次のケースでは無効な法線が返ります。
			- オブジェクトが指定されていない時に、構築済みバッファの範囲外だったり、まだ初期化されていない要素を参照した時。
			- オブジェクトが指定されている時に、オブジェクトの面配列の範囲外を参照した時。
			- オブジェクトが指定されている時に、三角でも四角でもない面を参照した時。*/
			const MQPoint& operator [] ( size_type index ) {
				if ( m_obj == NULL ) {
					if ( (index < m_buffer.size()) && (IsInvalid(m_buffer[index])==false) ) return m_buffer[index];
				}
				else {
					const size_type ctFaceMax = size_type(m_obj->GetFaceCount());
					if ( index < ctFaceMax ) {
						const size_type registedSize = m_buffer.size();
						if ( registedSize < ctFaceMax ) {
							m_buffer.resize( ctFaceMax );
							for ( size_type ct = registedSize; ct < ctFaceMax; ct++ ) m_buffer[ct].x = invalid_value.x;
						}
						if ( IsInvalid(m_buffer[index]) ) {
							const int ctFacePointMax = m_obj->GetFacePointCount( index );
							if ( (ctFacePointMax==3) || (ctFacePointMax==4) ) {
								int v[4];
								m_obj->GetFacePointArray( index, v );
								if ( ctFacePointMax==3 )
									m_buffer[index] = GetNormal( m_obj->GetVertex(v[0]), m_obj->GetVertex(v[1]), m_obj->GetVertex(v[2]) );
								else if ( ctFacePointMax==4 )
									m_buffer[index] = GetQuadNormal( m_obj->GetVertex(v[0]), m_obj->GetVertex(v[1]), m_obj->GetVertex(v[2]), m_obj->GetVertex(v[3]) );
							}
						}
						return m_buffer[index];
					}
				}
				return invalid_value;
			}
		private:
			///@cond
			friend struct Polygon::VertexNormalBuffer;
			///@endcond
			const MQPoint invalid_value;
			::MQObject m_obj;
			std::vector<MQPoint> m_buffer;
		};

		/*! @brief 頂点法線（頂点を共有する全ての面法線の平均法線）をバッファリングします。
		@details オブジェクト側のデータが更新されても VertexNormalBuffer の法線バッファは同期しません（形状を変更しない静的な処理の途中で、法線算出の重複や再計算を回避するために一時的に利用するのに向いています）。
		基本的に一つのオブジェクトに対して一つの VertexNormalBuffer が必要ですが、よりシビアなパフォーマンスを要求する場合、
		Clear() メソッドを介して新しいオブジェクトを設定し、確保済みのバッファ領域を解放せず値だけクリアして再利用し、ヒープの処理負荷を低減する事が可能です。*/
		struct VertexNormalBuffer {
			typedef std::vector<MQPoint>::size_type size_type;
			/// @brief 無効な法線か判定します。
			static bool IsInvalid( const MQPoint& src ) { return FaceNormalBuffer::IsInvalid(src); }
			/// @brief デフォルトコンストラクタ
			VertexNormalBuffer() : m_face_normals( NULL ), m_buffer(0) {}
			/// @brief コンストラクタ
			VertexNormalBuffer( const ::MQObject obj ) : m_face_normals( obj ), m_buffer(0) { if (obj != NULL) Clear(obj); }
			//! @brief バッファをクリアします。
			//! @param [in] isCompact ヒープを切り詰めるかどうか。
			//! @details ヒープを切り詰める時、設定されたオブジェクトの頂点数と面数を参照して切り詰めます。オブジェクトが設定されていない時、ヒープサイズはゼロに切り詰められます。
			void Clear( const bool isCompact = false ) {
				if ( isCompact ) {
					size_type sz = 0;
					if ( m_face_normals.m_obj != NULL ) sz = size_type(m_face_normals.m_obj->GetVertexCount());
					std::vector<MQPoint>(sz).swap( m_buffer );
				}
				for ( size_type ctFace = 0; ctFace < m_buffer.size(); ctFace++ ) m_buffer[ctFace].x = m_face_normals.invalid_value.x;
				m_face_normals.Clear(isCompact);
			}
			//! @brief 新しいオブジェクトを指定してバッファをクリアします。
			//! @param [in] isCompact ヒープを切り詰めるかどうか。
			//! @details ヒープを切り詰める時、設定されたオブジェクトの頂点数と面数を参照して切り詰めます。オブジェクトが設定されていない時、ヒープサイズはゼロに切り詰められます。
			void Clear( const ::MQObject obj, const bool isCompact = false ) {
				if ( isCompact ) {
					size_type sz = 0; if ( obj != NULL ) sz = size_type(obj->GetVertexCount());
					std::vector<MQPoint>(sz).swap( m_buffer );
				}
				for ( size_type ctFace = 0; ctFace < m_buffer.size(); ctFace++ ) m_buffer[ctFace].x = m_face_normals.invalid_value.x;
				m_face_normals.Clear(obj,isCompact);
			}
			//! @brief 不要なヒープ領域を切り詰めます。
			//! @details 設定されたオブジェクトの頂点数と面数を参照して切り詰めます。オブジェクトが設定されていない時、ヒープサイズはゼロに切り詰められます。
			void Compact() {
				size_type sz = 0;
				if ( m_face_normals.m_obj != NULL ) sz = size_type(m_face_normals.m_obj->GetVertexCount());
				m_buffer.resize(sz);
				m_buffer.shrink_to_fit();
				m_face_normals.Compact();
			}
			/*! @brief 面法線を取得します。
			@details インデックスが指定する面の法線は最初に参照された時に計算（初期化）されます。一度バッファされたデータは Clear() メソッドで再び未初期化状態に戻すまで保持されます。
			VertexNormal() で頂点法線を取得する際、頂点を共有する面の FaceNormal() を呼び出すため、 VertexNormal() によって FaceNormal() が間接的に取得済み状態になっているケースがあります。
			@return バッファされた面法線。法線は正規化済みです。次のケースでは無効な法線が返ります。
			- オブジェクトが指定されていない時に、構築済みバッファの範囲外だったり、まだ初期化されていない要素を参照した時。
			- オブジェクトが指定されている時に、オブジェクトの面配列の範囲外を参照した時。
			- オブジェクトが指定されている時に、三角でも四角でもない面を参照した時。*/
			const MQPoint& FaceNormal( FaceNormalBuffer::size_type index ) { return m_face_normals[index]; }
			//! @brief 関連付けられているMQObjectを取得します。
			const ::MQObject MQObject() const { return m_face_normals.MQObject(); }
			/*! @brief 頂点法線（頂点を共有する全ての面法線の平均法線）を取得します。
			@details インデックスが指定する頂点の法線は最初に参照された時に計算（初期化）されます。一度バッファされたデータは Clear() メソッドで再び未初期化状態に戻すまで保持されます。
			@return バッファされた頂点法線。法線は正規化済みです。次のケースでは無効な法線が返ります。
			- オブジェクトが指定されていない時に、構築済みバッファの範囲外だったり、まだ初期化されていない要素を参照した時。
			- オブジェクトが指定されている時に、オブジェクトの頂点配列の範囲外を参照した時。
			- オブジェクトが指定されている時に、三角または四角の面にまったく利用されていない頂点を参照した時。*/
			const MQPoint& VertexNormal( size_type index ) {
				if ( m_face_normals.m_obj == NULL ) {
					if ( (index < m_buffer.size()) && (IsInvalid(m_buffer[index])==false) ) return m_buffer[index];
				}
				else {
					const size_type ctVertexMax = size_type(m_face_normals.m_obj->GetVertexCount());
					if ( index < ctVertexMax ) {
						const size_type registedSize = m_buffer.size();
						if ( registedSize < ctVertexMax ) {
							m_buffer.resize( ctVertexMax );
							for ( size_type ct = registedSize; ct < ctVertexMax; ct++ ) m_buffer[ct].x = m_face_normals.invalid_value.x;
						}
						MQPoint& ret = m_buffer[index]; // get [in,out] reference
						if ( IsInvalid(ret) ) {
							const std::vector<int>::size_type ctFaceMax = std::vector<int>::size_type(m_face_normals.m_obj->GetVertexRelatedFaces( index, NULL ));
							if (ctFaceMax == 1)
							{
								int face_index;
								m_face_normals.m_obj->GetVertexRelatedFaces( index, &face_index );
								ret = FaceNormal(FaceNormalBuffer::size_type(face_index));
							}
							else if ( 1 < ctFaceMax ) {
								std::vector<int> face_indexes( ctFaceMax );
								std::vector<int> vertexIndexesOfFace(4);
								m_face_normals.m_obj->GetVertexRelatedFaces( index, &face_indexes[0] );
								unsigned int ctAdd = 0;
								ret.zero(); // ret reference clear
								for ( std::vector<int>::size_type ct = 0; ct < ctFaceMax; ct++ ) // all check of related face
								{
									const MQPoint& n = FaceNormal(FaceNormalBuffer::size_type(face_indexes[ct]));
									if ( FaceNormalBuffer::IsInvalid(n) == false )
									{
										const std::vector<int>::size_type vertexCountOfFace = std::vector<int>::size_type(m_face_normals.m_obj->GetFacePointCount(face_indexes[ct]));
										if (vertexIndexesOfFace.size() < vertexCountOfFace) vertexIndexesOfFace.resize(vertexCountOfFace);
										m_face_normals.m_obj->GetFacePointArray(face_indexes[ct], &vertexIndexesOfFace[0]);
										int findCt = 0;
										std::vector<int>::size_type findPosition;
										for (std::vector<int>::size_type ct = 0; ct < vertexCountOfFace; ct++)
										{
											if (index == vertexIndexesOfFace[ct]) if (findCt++ == 0) findPosition = ct;
										}
										if (findCt != 1) continue;
										const int prevVertexIndex = vertexIndexesOfFace[(findPosition <= 0 ? vertexCountOfFace : findPosition) - 1];
										const int nextVertexIndex = vertexIndexesOfFace[(findPosition + 1) < vertexCountOfFace ? (findPosition + 1) : 0];
										const MQPoint vertex = m_face_normals.m_obj->GetVertex(index);
										MQPoint toPrevVertex = m_face_normals.m_obj->GetVertex(prevVertexIndex) - vertex;
										MQPoint toNextVertex = m_face_normals.m_obj->GetVertex(nextVertexIndex) - vertex;
										float cos = GetInnerProduct(toPrevVertex, toNextVertex) / (GetSize(toPrevVertex) * GetSize(toNextVertex));
										ret += (n * (1.0f - cos)); // n * (2.0 - (cos + 1.0))
										ctAdd++;
									}
								}
								if (0 < ctAdd) ret.normalize();
								else ret.x = m_face_normals.invalid_value.x;
							}
						}
						return ret;
					}
				}
				return m_face_normals.invalid_value;
			}
			//! @brief 頂点法線を取得します。 @details vertex_normal() を呼び出します。
			const MQPoint& operator [] ( size_type index ) { return VertexNormal(index); }
		private:
			FaceNormalBuffer m_face_normals;
			std::vector<MQPoint> m_buffer;
		};

		//! @brief 任意のオブジェクト群からuvポリゴンバッファを構築するクラスです。
		class UVFaceBuffer {
		public:

			//! @brief UV座標のデータ要素です。 @ref MQ0x::Polygon::UVFaceBuffer::UVPoint::Buffer "UVPoint::Buffer"構造体を使ってバッファリングされます。
			struct UVPoint {
				MQCoordinate uv;
				UVPoint( const MQCoordinate& initial_uv ) : uv(initial_uv) {}
				//! @brief @ref MQ0x::Polygon::UVFaceBuffer::UVPoint "UVPoint"バッファ構造体。同じuvが重複しないようにuv座標をバッファリングします。
				//! @details UVPoint::Bufferは単純な動的線形配列ではなく、uの値を0〜1の範囲に想定し、resolution定数を使ってハッシュキーにする分割配列です(※)。
				//! uv値から一意にハッシュを出して配列を細分化することで既存uv値の総当り検査や、拡張時の再配置コストを高速化した構造になっています。
				//! 一方、要素にアクセスするには専用のオフセットデータ型@ref MQ0x::Polygon::UVFaceBuffer::UVPoint::Buffer::Index "Index"構造体が必要です。
				//!	@details (※) u_key = u * resolution ただし、0 <= u_key <= (resolution-1)範囲外の場合は両端で@ref MQ0x::Math::Clamp() "Clamp()"処理。
				struct Buffer {
					typedef uint16_t resolution_type;				//!< @brief resolutionの型
					static const resolution_type resolution = 10;	//!< @brief resolution定数
				private:
					typedef std::vector<UVPoint> base_buffer_type;
					base_buffer_type m_buffer[resolution];
					/// @cond
					friend struct Index;
					/// @endcond
				public:
					//! @brief @ref MQ0x::Polygon::UVFaceBuffer::UVPoint::Buffer "UVPoint::Buffer"を参照するためのインデックス型
					//! @details 比較演算のために std::pair をpublic継承していますが、first/secondメンバへのアクセスは無効化してあります。
					//! 使用する時は、readonlyで抽象化されたハンドル型のように扱ってください。
					struct Index : public std::pair<resolution_type, base_buffer_type::size_type> {
						///@cond
						friend struct MQ0x::Polygon::UVFaceBuffer::UVPoint::Buffer;
						///@endcond
						typedef std::pair<resolution_type, base_buffer_type::size_type> base_type; //! < ベースクラス
						Index() : base_type( resolution, 0 ) {} //! < @brief デフォルトコンストラクタ(無効な値で初期化されます)
					private:
						Index( resolution_type first, base_buffer_type::size_type second ) : base_type(first, second) {}
						resolution_type first() const { return base_type::first; }
						base_buffer_type::size_type second() const { return base_type::second; }
					};
					//! @brief Index で指定されたバッファ要素(@ref MQ0x::Polygon::UVFaceBuffer::UVPoint "UVPoint")のアドレスを取得します
					//! @return indexが範囲外のときはNULL。それ以外は指定されたuvバッファ要素へのアドレス
					const UVPoint* GetAccessAt( const Index& index ) const {
						if ( ( index.first() < resolution ) && ( index.second() < m_buffer[index.first()].size() ) ) return &(m_buffer[index.first()][index.second()]);
						return NULL;
					}
					//! @brief 任意のuv値を記録するバッファ要素(@ref MQ0x::Polygon::UVFaceBuffer::UVPoint "UVPoint")を既存データから検索、または新規追加してインデックスを取得します。
					//! @param [in] epsilon 同じuvとして許容する軸あたりの誤差範囲。uもvも、どちらの軸でも差がepsilonより小さい場合、同じuv座標とみなす。
					//! @return すでに同じuv値が記録されている場合、その既存のインデックス。それ以外の場合は新規に追加されたインデックス。
					const Index GetIndexOf( const MQCoordinate &uv, const float epsilon ) {
						const float abs_e = std::abs(epsilon);
						const resolution_type first = std::min( resolution_type(std::max( uv.u * float(resolution), 0.0f)), resolution_type(resolution - 1) );
						const base_buffer_type::size_type size = m_buffer[first].size();
						for ( base_buffer_type::size_type ct = 0; ct < size; ct++ ) {
							const MQCoordinate& buffer_uv = m_buffer[first][ct].uv;
							if ( (std::abs(uv.u - buffer_uv.u) < abs_e) && (std::abs(uv.v - buffer_uv.v) < abs_e) ) return Index( first, ct );
						}
						m_buffer[first].push_back( UVPoint(uv) );
						return Index( first, size );
					}
					/// @brief バッファをクリアする
					/// @param [in] isCompact ヒープ領域を切り詰めるかどうか
					void Clear( const bool isCompact = false ) {
						for ( int ct = 0; ct < resolution; ct++ ) {
							if ( isCompact ) base_buffer_type().swap( m_buffer[ct] );
							else m_buffer[ct].clear();
						}
					}
					//!@brief 不要なヒープ領域を切り詰めます。
					void Compact() { for ( int ct = 0; ct < resolution; ct++ ) m_buffer[ct].shrink_to_fit(); }
					//!@brief 要素へのアクセス。この処理は範囲チェックを行いません。
					UVPoint& operator [] ( const Index& index ) { return m_buffer[index.first()][index.second()]; }
				};
			};

			//! @brief 面情報構造体
			struct Face {
				//! @brief 面情報内の頂点情報構造体
				struct Point {
					UVPoint::Buffer::Index index;	//!< @brief uvバッファ（uv座標）を参照するためのインデックス
					uint32_t color;					//!< @brief 頂点色
				};
				
				//! @brief 三角形のリストを格納する構造体です。
				struct Buffer {
				private:
					typedef std::vector<Face> buffer_type;
					friend class Polygon::UVFaceBuffer;
				public:
					//! @brief インデックス型
					typedef buffer_type::size_type Index;
					/// @brief インデックスバッファ型
					/// @details Face::Buffer::IndexBuffer構造体は、@ref Face::Bufferのインデックスを重複しないようにバッファする構造体です。
					struct IndexBuffer {
						//! @brief インデックス型
						typedef std::vector<Index>::size_type Index;
						//! @brief 読み取り専用の前進イテレータ
						typedef std::vector<Index>::const_iterator ConstIterator;
						//! @brief インデックスバッファの要素にアクセスします。 @details 範囲検査は行われないので、indexには必ず Count() より小さな値を指定してください。
						Face::Buffer::Index operator[] ( IndexBuffer::Index index ) const { return m_buffer[index]; }
						//! @brief インデックスバッファにインデックスを追加します。既に登録済みのインデックスが見つかる場合は追加されません。
						//! @return 新規に追加されたインデックス。あるいは登録済みだった時は既存のインデックス。
						Face::Buffer::IndexBuffer::Index Add( Face::Buffer::Index index ) {
							IndexBuffer::Index ret;
							if ( Contains( index, &ret ) == false ) {
								ret = m_buffer.size();
								m_buffer.push_back(index);
							}
							return ret;
						}
						//! @brief 読み取り専用・前進タイプの先頭イテレータを返します。
						ConstIterator Begin() const { return m_buffer.begin(); }
						//! @brief 要素を検索します。 @param [in] src 検索する要素 @param [out] NULL以外を指定すると、見つかったインデックスが記録されます。	
						bool Contains( const Face::Buffer::Index src, IndexBuffer::Index* find_index = NULL ) const {
							for ( Index index = 0; index < m_buffer.size(); index++ ) {
								if ( m_buffer[index] == src ) { if ( find_index != NULL ) *find_index = index; return true; }
							}
							return false;
						}
						//! @brief 要素数を取得します
						IndexBuffer::Index Count() const { return m_buffer.size(); }
						//! @brief 読み取り専用・前進タイプの終端イテレータを返します。
						ConstIterator End() const { return m_buffer.end(); }
					private:
						std::vector<Face::Buffer::Index> m_buffer;
					};
					/// @brief 要素にアクセスします。範囲外の値を参照するとNULLが返ります。
					const Face* operator [] ( Index index ) const { if ( index < m_buffer.size() ) return &m_buffer[index]; return NULL; }
					//! @brief 末尾に要素を追加します。
					void Add( const Face& add_item ) { m_buffer.push_back( add_item ); }
					//! @brief 先頭の要素番号を返します。現在のところ常に0を返します。
					Index BeginIndex() const { return 0; }
					/// @brief バッファをクリアします。isCompactをtrueに指定すると、ヒープ領域も切り詰められます。
					void Clear( const bool isCompact = false ) { if ( isCompact ) std::vector<Face>().swap( m_buffer ); else m_buffer.clear(); }
					//! @brief 不要なヒープ領域を切り詰めます。
					void Compact() { m_buffer.shrink_to_fit(); }
					//! @brief 配列の要素数を返します。
					Index Count() const { return m_buffer.size(); }
					//! @brief 終端の要素番号を返します。今のところ配列の要素数 Count() に等しい値が返ります。
					Index EndIndex() const { return m_buffer.size(); }
					//! @brief ヒープ領域をあらかじめ予約します。
					void Reserve( const Index size ) { m_buffer.reserve( size ); }
				private:
					buffer_type m_buffer;
				};
				//! @brief 面を保有するオブジェクトのユニークID
				UINT object_uid;
				//! @brief 面のユニークID
				UINT face_uid;
				//! @brief 面に含まれる頂点数を返します。 @details 現在のところ3または4を返します。
				std::size_t PointsCount() const { return m_szPoints; }
				//! @brief 任意の@ref UVPoint::Buffer::Indexをメンバに持つPoint要素を検索します。 @return 見つかった要素のアドレス。見つからない場合NULL。
				const Point* GetPointFrom( const UVPoint::Buffer::Index& search_index ) const {
					for ( std::size_t ct = 0; ct < m_szPoints; ct++ ) if ( m_points[ct].index == search_index ) return (m_points + ct);
					return NULL;
				}
				//! @brief 面に含まれる頂点配列の要素にアクセスします。 @details 範囲検査は行わないので、必ずPointsCount()より小さな値を指定してください。
				const Point& Points(std::size_t index) const { return m_points[index]; }
				Face() : m_szPoints(0) {}
			private:
				///@cond
				friend class Polygon::UVFaceBuffer;
				///@endcond
				std::size_t m_szPoints;
				Face::Point m_points[4];
			};

			/// @brief 辺情報 @details UV座標インデックスのペアと、参照元三角形インデックスのリストを返します。
			struct Edge {
				
				//! @brief UV座標インデックスのペア
				//! @details 両端のUV座標バッファインデックスを保持するペア構造体です。比較を単純にするため、小さい順にメンバに格納するようにしてあります。
				//! べースクラスのfirst/secondメンバへのアクセスは禁止してあり、その代わり読み取り専用のoperator[]を使って内容を参照します。
				//! first/second個別に書き換えは出来ないので、内容を変更する時は各種のオーバーロードされた代入演算子、またはコンストラクタを利用します。
				struct VertexPair : public std::pair<UVPoint::Buffer::Index, UVPoint::Buffer::Index> {
					typedef std::pair<UVPoint::Buffer::Index, UVPoint::Buffer::Index> base_type;
					VertexPair( const UVPoint::Buffer::Index& first, const UVPoint::Buffer::Index& second )
						: base_type( std::min(first, second), std::max(first, second) ) {}	///< @brief コンストラクタ
					VertexPair( const VertexPair& src ) : base_type( src[0], src[1] ) {}	///< @brief コピーコンストラクタ
					VertexPair( const UVPoint::Buffer::Index* pSrc ) { *this = pSrc; }		///< @brief コンストラクタ
					///@biref 代入演算子オーバーロード @param [in] pSrc 最低二つの要素が並んだIndex配列を指定してください。
					VertexPair& operator = ( const UVPoint::Buffer::Index* pSrc ) {
						if ( pSrc != NULL ) {
							if ( pSrc[0] < pSrc[1] ) {
								base_type::first = pSrc[0];
								base_type::second = pSrc[1];
							}
							else {
								base_type::first = pSrc[1];
								base_type::second = pSrc[0];
							}
						}
						return *this;
					}
					///@biref 代入演算子オーバーロード
					VertexPair& operator = ( const VertexPair& src ) { base_type::first = src[0]; base_type::second = src[1]; return *this; } 
					///@brief 要素アクセス。indexに0を指定すると、ペアメンバーのうちの小さい方の @ref MQ0x::Polygon::UVFaceBuffer::UVPoint::Buffer::Index "UVPoint::Buffer::Index" を取得します。そうでない場合、大きい方の UVPoint::Buffer::Index を取得します。
					UVPoint::Buffer::Index operator [](int index) const { return index == 0 ? base_type::first : base_type::second; }
					///@brief 値がペアメンバーに含まれているか検査します。含まれる場合trueを返します。
					bool Contains( const UVPoint::Buffer::Index& index ) const { return (base_type::first == index) || (base_type::second == index); }
				private:
					UVPoint::Buffer::Index first();		// kill access
					UVPoint::Buffer::Index second();	// kill access
				};

				//! @brief 辺のリストを格納する型
				struct Buffer {
				private:
					typedef std::vector<Edge> buffer_type;
				public:
					typedef buffer_type::const_iterator ConstIterator;	//!< @brief 読み取り専用の前進イテレータ。参照すると@ref MQ0x::Polygon::UVFaceBuffer::Edge "Edge"構造体を取得できます。
					//! @brief Edge要素を追加します。
					//! @details VertexPairが既に登録済みのときはその要素に対してindexが追加登録されます。そうでない場合は末尾に新規のEdge構造体が追加されます。
					void Add( const VertexPair& vertex_pair, const Face::Buffer::Index& index );
					ConstIterator Begin() const { return m_buffer.begin(); }	//!< @brief 読み取り専用・前進タイプの先頭イテレータを返します。
					/// @brief バッファをクリアします。isCompactをtrueに指定すると、ヒープ領域も切り詰められます。
					void Clear( const bool isCompact = false ) { if ( isCompact ) std::vector<Edge>().swap( m_buffer ); else m_buffer.clear(); }
					void Compact() { m_buffer.shrink_to_fit(); }				//!< @brief 不要なヒープ領域を切り詰めます。
					ConstIterator End() const { return m_buffer.end(); }		//!< @brief 読み取り専用・前進タイプの終端イテレータを返します。
				private:
					buffer_type m_buffer;
				};

				Edge( const VertexPair& v_pair, Face::Buffer::Index face_index ) : m_vertex_pair(v_pair) { m_owner_faces.Add(face_index); }
				Edge( const UVPoint::Buffer::Index* pSrc, Face::Buffer::Index face_index ) : m_vertex_pair(pSrc) {
					if ( pSrc != NULL ) m_owner_faces.Add(face_index);
				}
				/// @brief 保持している頂点インデックスペアの内容を任意のペアと比較します。
				bool operator == ( const VertexPair& src ) const { return (const VertexPair::base_type&)m_vertex_pair == (const VertexPair::base_type&)src; }
				/// @brief 保持している頂点インデックスペアを参照します。
				const VertexPair& IndexPair() const { return m_vertex_pair; }
				/// @brief 保持している頂点インデックスペアの要素（@ref MQ0x::Polygon::UVFaceBuffer::UVPoint::Buffer::Index "UVPoint::Buffer::Index"）を取得します。
				/// @param [in] index 0を指定すると小さい方のインデックスが返ります。それ以外は大きい方のインデックスが返ります。
				UVPoint::Buffer::Index IndexPair(int index) const { return m_vertex_pair[index]; }
				/// @brief 辺を共有する面のリストを、読み取り専用で参照します。
				/// @detailes 参照先は、面そのものではなくインデックスのバッファ（面バッファのインデックスの配列）になっています。詳しくは @ref Face::Buffer::IndexBuffer を参照してください。
				const Face::Buffer::IndexBuffer& Owners() const { return m_owner_faces; }
				/// @brief 辺を共有する面のリストから、要素を取得します。
				/// @details 取得される要素は、面そのものではなく面バッファのインデックスになっています。詳しくは @ref Face::Buffer::IndexBuffer を参照してください。
				Face::Buffer::Index Owners( const Face::Buffer::IndexBuffer::Index& index ) const { return m_owner_faces[index]; }
			private:
				///@cond
				friend struct Edge::Buffer;
				///@endcond
				VertexPair m_vertex_pair;
				Face::Buffer::IndexBuffer m_owner_faces;
			};

			struct Functors {
				/// @brief 基本的なUV座標変換関数オブジェクト
				/// @details UV座標および面頂点固有の頂点色に対して任意の変換を行います。変換関数はUVバッファへの登録前に実行され、変換後のUV座標がUVバッファに登録されます。
				struct BasicUVTransformFunctor {
					///@brief 変換ファンクタ
					///@param [in,out]	uv_coorinates	UV座標配列へのアクセス
					///@param [in,out]	colors			頂点色配列へのアクセス
					///@param [in]		obj				オーナーオブジェクト
					///@param [in]		count			uv_coorinates/colors/point_normalsの配列数(3または4)
					///@param [in]		face_index		オーナー面のインデックス
					///@param [in]		face_uid		オーナー面のユニークID
					///@return この面を有効なUVとする場合はtrue。そうでなければfalse。通常はtrueを返します。例えばあまりにも小さいUVポリゴンを無視したい時などにfalseを返す事が出来ます。
					bool operator()( MQCoordinate* const uv_coorinates, DWORD* const colors,
						const MQObject obj, const int count_of_points, const int face_index, const UINT face_uid ) { return true; }
				};
				
				/// @brief 法線データ付きUV座標変換関数オブジェクト
				/// @details UV座標および面頂点固有の頂点色に対して任意の変換を行います。変換関数はUVバッファへの登録前に実行され、変換後のUV座標がUVバッファに登録されます。
				struct NormaledUVTransformFunctor {
					///@brief 変換ファンクタ
					///@param [in,out]	uv_coorinates	UV座標配列へのアクセス
					///@param [in,out]	colors			頂点色配列へのアクセス
					///@param [in]		obj				オーナーオブジェクト
					///@param [in]		count			uv_coorinates/colors/point_normalsの配列数(3または4)
					///@param [in]		face_index		オーナー面のインデックス
					///@param [in]		face_uid		オーナー面のユニークID
					///@param [in]		normal			面法線へのアクセス(uv座標系ではなく立体モデル上の法線)
					///@param [in]		point_normals	正規化済みの頂点法線配列へのアクセス(uv座標系ではなく立体モデル上の法線で、頂点を共有する面法線の平均ベクトル)
					///@return この面を有効なUVとする場合はtrue。そうでなければfalse。通常はtrueを返します。例えばあまりにも小さいUVポリゴンを無視したい時などにfalseを返す事が出来ます。
					bool operator()( MQCoordinate* const uv_coorinates, DWORD* const colors,
						const MQObject obj, const int count_of_points, const int face_index, const UINT face_uid,
						const MQPoint& normal, MQPoint* const point_normals ) { return true; }
				};

				template <class _NormaledCoordinateTransformFunctor> struct CoordinateTransformFunctorFromNormaled {
					_NormaledCoordinateTransformFunctor functor;
					//! @brief BasicUVTransformFunctorタイプのスタンダードなファンクタ
					bool operator()(
						MQCoordinate* const uv_coorinates, DWORD* const colors,
						const MQObject obj, const int count_of_points, const int face_index, const UINT face_uid )
					{
						MQPoint v_normal_buffer[4];
						int v_index_buffer[4];
						obj->GetFacePointArray( face_index, v_index_buffer );
						for ( int ctFacePoint = 0; ctFacePoint < count_of_points; ctFacePoint++ ) {
							v_normal_buffer[ctFacePoint] = m_normal_buffer.VertexNormal( VertexNormalBuffer::size_type(v_index_buffer[ctFacePoint]) );
						}
						return functor( uv_coorinates, colors, obj, count_of_points, face_index, face_uid, m_normal_buffer.FaceNormal(face_index), v_normal_buffer );
					}
				private:
					VertexNormalBuffer m_normal_buffer;
				};
			};

			/// @brief デフォルトコンストラクタ
			UVFaceBuffer() : m_epsilon( std::numeric_limits<float>::epsilon() ) {}

			//! @brief 新しくオブジェクトを追加解析します。ファンクタを指定して、バッファ登録前のUV変換処理を行います。
			//! @param coordinateTrans 変換ファンクタを指定します。渡すべきファンクタはFunctors::BasicUVTransformFunctorをモデルにしてください。
			template <class _BasicUVTransformFunctor> void AddObject( const MQObject obj, _BasicUVTransformFunctor& coordinateTrans ) {
				if ( obj == NULL ) return;
				MQCoordinate coordinate_buffer[4];
				DWORD vertex_color_buffer[4];
				Face add_face;
				const int ctFaceMax = obj->GetFaceCount();
				const UINT obj_uid = obj->GetUniqueID();
				const float eps = m_epsilon;
				m_face_buffer.Reserve( m_face_buffer.Count() + (Face::Buffer::Index)ctFaceMax );
				add_face.object_uid = obj_uid;
				for ( int ctFace = 0; ctFace < ctFaceMax; ctFace++ ) {
					const UINT uidFace = obj->GetFaceUniqueID( ctFace );
					const int ctFacePointMax = obj->GetFacePointCount( ctFace );
					if ( (ctFacePointMax<3)||(4<ctFacePointMax) ) continue;
					obj->GetFaceCoordinateArray( ctFace, coordinate_buffer );
					for ( int ctFacePoint = 0; ctFacePoint < ctFacePointMax; ctFacePoint++ ) {
						vertex_color_buffer[ctFacePoint] = obj->GetFaceVertexColor( ctFace, ctFacePoint );
					}
					if ( coordinateTrans( coordinate_buffer, vertex_color_buffer, obj, ctFacePointMax, ctFace, uidFace ) == false ) continue;
					add_face.face_uid = uidFace;
					add_face.m_szPoints = ctFacePointMax;
					for ( int ctFacePoint = 0; ctFacePoint < ctFacePointMax; ctFacePoint++ ) {
						add_face.m_points[ctFacePoint].index = m_uv_buffer.GetIndexOf( coordinate_buffer[ctFacePoint], eps );
						add_face.m_points[ctFacePoint].color = vertex_color_buffer[ctFacePoint];
					}
					m_face_buffer.Add(add_face);
					for ( int ctFacePoint = 0; ctFacePoint < ctFacePointMax; ctFacePoint++ ) {
						int ctFacePointNext = (ctFacePoint < (ctFacePointMax-1)) ? ctFacePoint + 1 : 0;
						const Edge::VertexPair add_edge( add_face.m_points[ctFacePoint].index, add_face.m_points[ctFacePointNext].index );
						m_edge_buffer.Add( add_edge, m_face_buffer.Count()-1 );
					}
				}
			}
			/// @brief 新しくオブジェクトを追加解析します。バッファ登録前のUV変換処理は行いません。
			void AddObject( const MQObject obj ) { AddObject( obj, Functors::BasicUVTransformFunctor() ); }
			/// @brief 新しくオブジェクトを追加解析します（再帰的に追加します）。Functors::BasicUVTransformFunctorと同形のoperator()を持つ任意のファンクタを定義＆指定して、バッファ登録前のUV変換処理を行います。
			template <class _BasicUVTransformFunctor> void AddObjectRecursive(const MQDocument doc, const MQObject obj, _BasicUVTransformFunctor& coordinateTrans)
			{
				if ( (doc == NULL) || (obj == NULL) ) return;
				AddObject( obj, coordinateTrans );
				const int ctChild = doc->GetChildObjectCount(obj);
				for ( int indexCh = 0; indexCh < ctChild; indexCh++ ) AddObjectRecursive( doc, doc->GetChildObject( obj, indexCh ), coordinateTrans );
			}
			/// @brief 新しくオブジェクトを追加解析します（再帰的に追加します）。バッファ登録前のUV変換処理は行いません。
			void AddObjectRecursive(const MQDocument doc, const MQObject obj) { AddObjectRecursive(doc, obj, Functors::BasicUVTransformFunctor()); }

			/// @brief キャッシュされたUV情報を全てクリアします。
			/// @param [in] isCompact ヒープ領域を切り詰めるかどうか
			void Clear( const bool isCompact = false ) { m_edge_buffer.Clear(isCompact); m_face_buffer.Clear(isCompact); m_uv_buffer.Clear(isCompact); }
			/// @brief 不要なヒープ領域を切り詰めます。
			void Compact() { m_uv_buffer.Compact(); m_face_buffer.Compact(); m_edge_buffer.Compact(); }
			/// @brief Edge 構造体(辺情報)バッファを読み取り専用で参照します。
			const Edge::Buffer& EdgeBuffer() const { return m_edge_buffer; }
			//! @brief UV座標の一致判定の閾値です。u,vそれぞれの軸で差が閾値より小さければ一致とみなします。デフォルトではstd::numeric_limits<float>::epsilon()が設定されます。
			float Epsilon() const { return m_epsilon; }
			/// @brief 任意の Epsilon() を登録します。
			float Epsilon( float setValue ) { return m_epsilon = std::abs(setValue); }
			/// @brief 三角形リストからデータを取得します（インデックスがリスト範囲外の時はNULL）
			const Face* FaceBuffer( const Face::Buffer::Index& index ) const { return m_face_buffer[index]; }
			/// @brief 三角形リストを読み取り専用で参照します。
			const Face::Buffer& FaceBuffer() const { return m_face_buffer; }
			//! @brief UV座標バッファからデータを取得します（インデックスがバッファ範囲外の時はNULL）
			const UVPoint* UVBuffer( const UVPoint::Buffer::Index& index ) const { return m_uv_buffer.GetAccessAt(index); }

		private:
			float m_epsilon;
			UVPoint::Buffer m_uv_buffer;
			Face::Buffer m_face_buffer;
			Edge::Buffer m_edge_buffer;
		};
		/// @}
		/// @}

		///@cond
		inline void UVFaceBuffer::Edge::Buffer::Add( const Edge::VertexPair& vertex_pair, const Face::Buffer::Index& index ) {
			for ( buffer_type::iterator itr = m_buffer.begin(); itr != m_buffer.end(); itr++ ) {
				if ( *itr == vertex_pair ) { itr->m_owner_faces.Add( index ); return; }
			}
			m_buffer.push_back( Edge(vertex_pair, index ) );
		}
		///@endcond
	}

	/*!	@name グローバル
		@{ */

	//! @brief 各種の名前取得関数において、可変長バッファサイズの最低初期値のデフォルトを定義。
#ifdef _DEBUG 
	static const std::vector<char>::size_type GetNameInitialBufferSize = 2;
#else
	static const std::vector<char>::size_type GetNameInitialBufferSize = 32;
#endif

	//! @brief ドキュメントからマテリアルを削除。
	//! @return 引数がNULLまたはユニークIDの一致するマテリアルが見つからない場合は削除を行わずfalseを返します。それ以外はtrue
	inline bool DeleteMaterial( const MQDocument doc, const MQMaterial mat ) {
		int index = prv_impl::GetIdentifiedIndex(doc, mat);
		if ( index < 0 ) return false;
		doc->DeleteMaterial(index); return true;
	}
	//! @brief ドキュメントからオブジェクトを削除。
	//! @return 引数がNULLまたはユニークIDの一致するオブジェクトが見つからない場合は削除を行わずfalseを返します。それ以外はtrue
	inline bool DeleteObject( const MQDocument doc, const MQObject obj ) {
		int index = prv_impl::GetIdentifiedIndex(doc, obj);
		if ( index < 0 ) return false;
		doc->DeleteObject(index); return true;
	}
	/*!	@brief マテリアルクローンのための、カウントアップされた重複しない別名候補を取得
		@return 少なくとも探査時点で重複しない別名候補文字列。引数にNULLが指定されるなどエラー時には空の文字列が返る。
		@par 別名候補の命名規則
		例）obj > obj1 | obj00 > obj01 | obj0.99 > obj0.100
		- 重複は回避される
		- 元の名前の末尾に数字が無い場合は'1'が付与される。
		- 元の名前の末尾に0-9の数字列がある場合は、+1される。ただし0-9以外、例えば小数点などは数値形式としては考慮されない。
		- クローン候補名の末尾数字の桁数は、元の名前の末尾の数字列と同じかそれよりも一桁増える。
		.
		@attention MQSDK Rev3.10からMQDocument::GetUnusedMaterialName()が追加されました。この関数は下位互換、および今後のMQx独自仕様として残されます。
		@date 2013.02.04 MQSDK Rev3.10対応
		*/
	inline std::string GetCountUpCloneableUniqueName( const MQDocument doc, const MQMaterial src, std::vector<char>* const buf = NULL ) {
		return prv_impl::GetCountUpCloneableUniqueName(doc,src,buf);
	}
	/*!	@brief オブジェクトクローンのための、カウントアップされた重複しない別名候補を取得
		@return 少なくとも探査時点で重複しない別名候補文字列。引数にNULLが指定されるなどエラー時には空の文字列が返る。
		@par 別名候補の命名規則
		例）obj > obj1 | obj00 > obj01 | obj0.99 > obj0.100
		- 重複は回避される
		- 元の名前の末尾に数字が無い場合は'1'が付与される。
		- 元の名前の末尾に0-9の数字列がある場合は、+1される。ただし0-9以外、例えば小数点などは数値形式としては考慮されない。
		- クローン候補名の末尾数字の桁数は、元の名前の末尾の数字列と同じかそれよりも一桁増える。
		.
		@attention MQSDK Rev3.10からMQDocument::GetUnuseObjectName()が追加されました。この関数は下位互換、および今後のMQx独自仕様として残されます。
		@date 2013.02.04 MQSDK Rev3.10対応
	*/
	inline std::string GetCountUpCloneableUniqueName( const MQDocument doc, const MQObject src, std::vector<char>* const buf = NULL ) {
		return prv_impl::GetCountUpCloneableUniqueName(doc,src,buf);
	}
	//! @brief ドキュメントに登録されているマテリアルを名前で検索する
	//! @return 見つかったマテリアル。見つからない場合はNULL。
	inline MQMaterial GetMaterial( const MQDocument doc, const char* name ) { return prv_impl::GetNamed<MQMaterial>( doc, name ); }
	//! @brief ドキュメントに登録されているマテリアルをユニークIDで検索する
	//! @return 見つかったマテリアル。見つからない場合はNULL。
	//! @attention MQSDK Rev3.10からMQDocument::GetMaterialFromUniqueID()が追加されました。この関数は下位互換のために残されています。
	//!	@date 2013.02.04 MQSDK Rev3.10対応
	inline MQMaterial GetMaterial( const MQDocument doc, const UINT id ) {
		#if 0x0310 <= MQPLUGIN_VERSION
			if ( doc != NULL ) return doc->GetMaterialFromUniqueID(id);
			return NULL;
		#else
			return prv_impl::GetIdentified<MQMaterial>( doc, id );
		#endif
	}
	
	/// @cond
	std::string GetMaterialTextureName( const MQMaterial, DWORD );
	/// @endcond

	/// @brief 透明テクスチャのファイルパスを取得する。 GetMaterialTextureName() の map_type に MQMAPPING_ALPHA を指定するのと同じです。
	inline std::string GetMaterialAlphaName( const MQMaterial mat ) { return GetMaterialTextureName(mat,MQMAPPING_ALPHA); }
	/// @brief 凸凹テクスチャのファイルパスを取得する。 GetMaterialTextureName() の map_type に MQMAPPING_BUMP を指定するのと同じです。
	inline std::string GetMaterialBumpName( const MQMaterial mat ) { return GetMaterialTextureName(mat,MQMAPPING_BUMP); }
	/// @brief ドキュメントに登録されているマテリアルを名前で検索する。
	/// @return 見つかったマテリアルのインデックス。見つからない場合は-1
	inline int GetMaterialIndex( const MQDocument doc, const char* name ) { return prv_impl::GetNamedIndex<MQMaterial>( doc, name ); }
	/// @brief ドキュメントに登録されているマテリアルをユニークIDで検索する。
	/// @return 見つかったマテリアルのインデックス。見つからない場合は-1
	inline int GetMaterialIndex( const MQDocument doc, const UINT id ) { return prv_impl::GetIdentifiedIndex<MQMaterial>( doc, id ); }
	/*! @brief テクスチャのファイルパスを取得する。
	@param map_type 取得するテクスチャの種類を指定する
	- MQMAPPING_TEXTURE / MQMaterial::GetTextureName()を呼び出して模様画像パスを取得する
	- MQMAPPING_ALPHA / MQMaterial::GetAlphaName()を呼び出して透明画像パスを取得する
	- MQMAPPING_BUMP / MQMaterial::GetBumpName()を呼び出して凸凹画像パスを取得する
	@return マッピングのファイル名を相対パスで取得します（元々絶対パスで指定されている場合は絶対パスが返るそうです）。元々画像が設定されていない、あるいはmatにNULLを指定するなどなんらかの失敗時には、空の文字列が返ります。
	@details 得られたファイル名を絶対パスに変換するにはMQDocument::FindMappingFile()を使用します。*/
	inline std::string GetMaterialTextureName( const MQMaterial mat, const DWORD map_type = MQMAPPING_TEXTURE ) {
		if ( mat != NULL )
		{
			std::vector<char> buf;
			prv_impl::GetMaterialTextureName(&buf, mat, map_type);
			return std::string(&buf[0]);
		}
		return "";
	}
	/// @brief マテリアルの名前を取得する。
	/// @return マテリアルの名前。引数にNULLが指定されるなど、エラー時には空の文字列。
	inline std::string GetName( const MQMaterial mat ){ return prv_impl::GetName( mat ); }
	/// @brief オブジェクトの名前を取得する
	/// @return オブジェクトの名前。引数にNULLが指定されるなど、エラー時には空の文字列。
	inline std::string GetName( const MQObject obj ){ return prv_impl::GetName( obj ); }
	//! @brief ドキュメントに登録されているオブジェクトを名前で検索する
	//! @return 見つかったオブジェクト。見つからない場合はNULL。
	inline MQObject GetObject( const MQDocument doc, const char* name ) { return prv_impl::GetNamed<MQObject>( doc, name ); }
	//! @brief ドキュメントに登録されているオブジェクトをユニークIDで検索する
	//! @return 見つかったオブジェクト。見つからない場合はNULL。
	//! @attention MQSDK Rev3.10からMQDocument::GetObjectFromUniqueID()が追加されました。この関数は下位互換のために残されています。
	//!	@date 2013.02.04 MQSDK Rev3.10対応
	inline MQObject GetObject( const MQDocument doc, const UINT id ) {
		#if 0x0310 <= MQPLUGIN_VERSION
			if ( doc != NULL ) return doc->GetObjectFromUniqueID(id);
			return NULL;
		#else
			return prv_impl::GetIdentified<MQObject>(doc, id );
		#endif
	}
	//! @brief ドキュメントに登録されているオブジェクトを名前で検索する
	/// @return 見つかったオブジェクトのインデックス。見つからない場合は-1
	inline int GetObjectIndex( const MQDocument doc, const char* name ) { return prv_impl::GetNamedIndex<MQObject>( doc, name ); }
	/// @brief ドキュメントに登録されているオブジェクトをユニークIDで検索する。
	/// @return 見つかったオブジェクトのインデックス。見つからない場合は-1
	inline int GetObjectIndex( const MQDocument doc, const UINT id ) { return prv_impl::GetIdentifiedIndex<MQObject>(doc, id ); }

#if 0x0310 <= MQPLUGIN_VERSION

	/// @brief ドキュメントに登録されていないマテリアル名を取得する（MQDocument::GetUnusedMaterialNameのラッパー関数）。
	/// @return 取得した文字列。docがNULLの時は空の文字列。
	/// @attention MQSDK Rev3.10 から利用可能
	inline std::string GetUnusedMaterialName( const MQDocument doc, const char* base_name = NULL ) {
		return prv_impl::GetUnusedNameString<MQMaterial>( doc, base_name );
	}
	/// @brief ドキュメントに登録されていないマテリアル名を取得する（MQDocument::GetUnusedMaterialNameのラッパー関数）。
	/// @param base_name_material 元の名前を指定するマテリアル。NULLで省略するとbase_nameをNULLにしてMQDocument::GetUnusedMaterialNameを呼び出すのと同じ動作。
	/// @return 取得した文字列。docがNULLの時は空の文字列。
	/// @attention MQSDK Rev3.10 から利用可能
	inline std::string GetUnusedMaterialName( const MQDocument doc, const MQMaterial base_name_material ) {
		if ( base_name_material == NULL ) return prv_impl::GetUnusedNameString<MQMaterial>( doc );
		return prv_impl::GetUnusedNameString<MQMaterial>( doc, GetName( base_name_material ).c_str() );
	}
	/// @brief ドキュメントに登録されていないオブジェクト名を取得する（MQDocument::GetUnusedObjectNameのラッパー関数）。
	/// @return 取得した文字列。docがNULLの時は空の文字列。
	/// @attention MQSDK Rev3.10 から利用可能
	inline std::string GetUnusedObjectName( const MQDocument doc, const char* base_name = NULL ) {
		return prv_impl::GetUnusedNameString<MQObject>( doc, base_name );
	}
	/// @brief ドキュメントに登録されていないオブジェクト名を取得する（MQDocument::GetUnusedObjectNameのラッパー関数）。
	/// @param base_name_object 元の名前を指定するマテリアル。NULLで省略するとbase_nameをNULLにしてMQDocument::GetUnusedObjectNameを呼び出すのと同じ動作。
	/// @return 取得した文字列。docがNULLの時は空の文字列。
	/// @attention MQSDK Rev3.10 から利用可能
	inline std::string GetUnusedObjectName( const MQDocument doc, const MQObject base_name_object ) {
		if ( base_name_object == NULL ) return prv_impl::GetUnusedNameString<MQMaterial>( doc );
		return prv_impl::GetUnusedNameString<MQMaterial>( doc, GetName( base_name_object ).c_str() );
	}
	
#endif

	//! @}

	//! @}

	namespace prv_impl {}; // kill prv_impl access ( to private header implement trap )
};

#endif