#pragma once

#pragma warning ( disable: 4996 )	//deprecated でマークされている関数を無視( FBX用 )

#include <set>
#include "fbxsdk.h"

#include "Mix/Tool/Win32/Core/Object.h"

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

	class DrawObject;
	class OptimizeMesh;
	class Motion;
	class MotionController;

	//FBXクラス
	class FBX : public Mix::Tool::Win32::Object
	{
	public:
		//変換行列の計算タイプ列挙定数
		enum COMPUTING_TRANSFORMATION_MATRIX
		{
			CTM_MAYA	= 0,
			CTM_3DS_MAX	= 1,
		};

	private:
		enum VALUE { DEF_MATERIAL_MAX_NO = 999, };	//デフォルトマテリアル名の最大番号
		static const char DEF_MATERIAL_NAME[16];	//デフォルトマテリアル名

		static const FbxLongLong FPS_TABLE[FbxTime::eModesCount]; //フレーム数テーブル

		//アナライズパラメータ構造体
		struct ANALYZE_PARAM
		{
			unsigned int totalPolygonCount;			//トータルポリゴン数( 三角形分割されていない状態 )
			bool notAssignMaterialPolygon;			//マテリアルを割り当てられていないポリゴンがある場合は true
			std::set<std::string> materialNameList;	//マテリアル名リスト

			ANALYZE_PARAM( void )
			{
				totalPolygonCount = 0;
				notAssignMaterialPolygon = false;
			}
		};

	private:
		FbxManager* m_pSdkMgr;
		FbxIOSettings* m_pIOSetting;
		FbxImporter* m_pImporter;
		FbxScene* m_pScene;
		FbxNode* m_pRootNode;

		FBX::COMPUTING_TRANSFORMATION_MATRIX m_CTM;
		std::wstring m_DirPath;
		int m_TotalPolygonCount;
		bool m_bInvertZ;
		D3DXVECTOR3 m_PivotScale;
		D3DXMATRIX m_PivotScaleMat;

	private:
		bool LoadMotion(FbxTime::EMode fbxTimeMode, FbxNode* pFbxNode, FbxAnimLayer* pFbxAnimLayer, Mix::Tool::Win32::Graphics::Motion* pMotion);
		bool LoadMotionChannels(FbxTime::EMode fbxTimeMode, FbxNode* pFbxNode, FbxAnimLayer* pFbxAnimLayer, Mix::Tool::Win32::Graphics::Motion* pMotion);
		bool LoadMotionCurveKeys(FbxTime::EMode fbxTimeMode, FbxAnimCurve* pFbxAnimCurve, std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& curveKeyList);

		unsigned int GetCurveKeyCount(	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& x,
										std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& y,
										std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& z );

		int GetMotionLastTime(	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& x,
								std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& y,
								std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& z );

		bool GetMotionCurveValue(	const std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& curveKeyList,
									int time,
									float defValue,
									float& value );

		bool GetMotionCurveValue(	const std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& x,
									const std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& y,
									const std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& z,
									int time,
									float defValue,
									D3DXVECTOR3& value );

		void Analyze( FbxNode* pFbxNode, FBX::ANALYZE_PARAM& param );

		static void CreateQuaternion( const D3DXVECTOR3& rad, D3DXQUATERNION& value );
		static void CreateRotationMatrix( FbxEuler::EOrder fbxRotOrder, const D3DXVECTOR3& rad, D3DXMATRIX& value );

	public:
		FBX( void );
		~FBX( void );

		//ロード関係
		bool Load( const wchar_t* pFileName, FBX::COMPUTING_TRANSFORMATION_MATRIX ctm, Mix::Tool::Win32::Graphics::DrawObject* pDrawObject );
		bool IsLoad( void ) const;

		//アンロード
		void Unload( void );

		//ルートノードを取得
		FbxNode* GetRootNode( void ) const;

		//トータルポリゴン数を取得
		int GetTotalPolygonCount( void ) const;

		//ノードのメッシュを三角形化
		bool TriangulateInPlace( FbxNode* pFbxNode, const wchar_t* pName );

		//モーションを読み込む
		bool LoadMotion( FbxTime::EMode fbxTimeMode, Mix::Tool::Win32::Graphics::MotionController* pMotionController );

	public:
		//指定したローテーションオーダーでクォータニオンを求めます
		D3DXQUATERNION CreateQuaternion(FbxEuler::EOrder fbxRotOrder, const FbxVector4& deg);
		D3DXQUATERNION CreateQuaternion(FbxEuler::EOrder fbxRotOrder, const D3DXVECTOR3& deg);

		//Zを反転する必要があるかどうかの取得
		// true の場合は 右手座標系
		// false の場合は 左手座標系
		bool IsInvertZ( void ) const;

		//ピボットのスケールを取得
		const D3DXVECTOR3& GetPivotScale( void ) const;

		//メッシュを読み込む
		//※マテリアルの更新は行われません
		bool LoadMesh( FbxNode* pFbxNode, bool transformEnabled, bool polygonNormal, Mix::Tool::Win32::Graphics::OptimizeMesh* pMesh, const wchar_t* pName );

		//ノードのジオメトリック行列の取得
		D3DXMATRIX GetGeometricMatrix( FbxNode* pFbxNode );

		//ノードのローカルスケールを取得
		D3DXVECTOR3 GetLocalScale( FbxNode* pFbxNode );
		//ノードのローカルローテーションを取得
		D3DXQUATERNION GetLocalRotation( FbxNode* pFbxNode );
		//ノードのローカルトランスレーションを取得
		D3DXVECTOR3 GetLocalTranslation( FbxNode* pFbxNode );
		//ノードのローカル行列を取得
		D3DXMATRIX GetLocalMatrix( FbxNode* pFbxNode );

		//ノードの属性タイプを取得
		//不明な場合は FbxNodeAttribute::eUNIDENTIFIED を返します
		static FbxNodeAttribute::EType GetNodeType(FbxNode* pNode);

		//指定したローテーションオーダーで行列を求めます
		static D3DXMATRIX CreateRotationMatrix(FbxEuler::EOrder fbxRotOrder, const FbxVector4& deg);
		static D3DXMATRIX CreateRotationMatrix(FbxEuler::EOrder fbxRotOrder, const D3DXVECTOR3& deg);

		//指定されたオーダーを回転を乗算( r0 * r1 )
		//fbxRotOrder : ローテーションオーダー
		//r0          : 乗算先
		//r1          : 乗算元のXYZ軸の角度( ラジアン )
		static D3DXQUATERNION MultiplyRotation(FbxEuler::EOrder fbxRotOrder, const D3DXQUATERNION& r0, const D3DXVECTOR3& r1);

		//行列をD3DXの行列に変換
		static D3DXMATRIX ToD3DXMatrix(const FbxAMatrix& fbxMat);

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

}}}}
