#include "Mix/Tool/Win32/Core/Graphics/FBX.h"

#include <string>
#include <sstream>
#include <algorithm>

#include "Mix/Tool/Win32/Core/Path.h"
#include "Mix/Tool/Win32/Core/Graphics/MaterialSlot.h"
#include "Mix/Tool/Win32/Core/Graphics/Material.h"
#include "Mix/Tool/Win32/Core/Graphics/Motion.h"
#include "Mix/Tool/Win32/Core/Graphics/MotionCurve.h"
#include "Mix/Tool/Win32/Core/Graphics/MotionController.h"
#include "Mix/Tool/Win32/Core/Graphics/OptimizeMesh.h"
#include "Mix/Tool/Win32/Core/Graphics/DrawObject.h"

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

////////////////////////////////////////////////////////////////////////////////////////////////////
// FBX : 定数
////////////////////////////////////////////////////////////////////////////////////////////////////

const char FBX::DEF_MATERIAL_NAME[16] = "DefaultMaterial";

const FbxLongLong FBX::FPS_TABLE[FbxTime::eModesCount] =
{
	0,
	120,
	100,
	60,
	50,
	48,
	30,
	30,
	30,
	30,
	25,
	24,
	1000,
	24,
	0,
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// FBX
////////////////////////////////////////////////////////////////////////////////////////////////////

FBX::FBX( void ) :
m_pSdkMgr( NULL ),
m_pIOSetting( NULL ),
m_pImporter( NULL ),
m_pScene( NULL ),
m_pRootNode( NULL ),
m_CTM( FBX::CTM_MAYA ),
m_bInvertZ( false ),
m_PivotScale( 1.0f, 1.0f, 1.0f )
{
}

FBX::~FBX( void )
{
	Unload();
}

bool FBX::Load( const wchar_t* pFileName, FBX::COMPUTING_TRANSFORMATION_MATRIX ctm, Mix::Tool::Win32::Graphics::DrawObject* pDrawObject )
{
	if( ( pFileName == NULL ) ||
		( ::wcslen( pFileName ) == 0 ) ||
		( pDrawObject == NULL ) )
	{
		return false;
	}

	Mix::Tool::Win32::Path::PATH_TYPE pathType;
	std::string fileNameA;
	FBX::ANALYZE_PARAM param;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 解放
	////////////////////////////////////////////////////////////////////////////////////////////////////

	Unload();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	//トランスフォームの計算方法
	m_CTM = ctm;

	//ディレクトリパスの取得
	pathType = Mix::Tool::Win32::Path::GetType( pFileName );
	if( pathType == Mix::Tool::Win32::Path::PATH_ABSOLUTE )
	{
		if( Mix::Tool::Win32::Path::GetDirectoryName( pFileName, m_DirPath ) == false )
		{
			LogPrint( LT_ERROR, L"  FBX : ディレクトリパスの取得に失敗 : FileName[%s]", pFileName );
			return false;
		}
	}
	else if( pathType == Mix::Tool::Win32::Path::PATH_RELATIVE )
	{
		m_DirPath.resize( 2048 );
		if( ::GetCurrentDirectoryW( m_DirPath.size(), &( m_DirPath[0] ) ) == 0 )
		{
			LogPrint( LT_ERROR, L"  FBX : カレントディレクトリパスの取得に失敗 : FileName[%s]", pFileName );
			return false;
		}
	}
	else
	{
		LogPrint( LT_ERROR, L"  FBX : ファイル名が不正です : FileName[%s]", pFileName );
		return false;
	}

	//ファイル名をANSIに変換
	if( Mix::Tool::Win32::WideToAnsi( pFileName, fileNameA ) == false )
	{
		return false;
	}

	//マネージャを作成
	m_pSdkMgr = FbxManager::Create();
	if( m_pSdkMgr == NULL )
	{
		return false;
	}

	//IO設定を作成
	m_pIOSetting = FbxIOSettings::Create( m_pSdkMgr, IOSROOT );
	if( m_pIOSetting != NULL )
	{
		m_pSdkMgr->SetIOSettings( m_pIOSetting );
	}
	else
	{
		Unload();
		return false;
	}

	//インポーターを作成
	m_pImporter = FbxImporter::Create( m_pSdkMgr, "" );
	if( m_pImporter == NULL )
	{
		Unload();
		return false;
	}

	//ファイルをインポート
	if( m_pImporter->Initialize( fileNameA.c_str(), -1, m_pSdkMgr->GetIOSettings() ) == false )
	{
		Unload();
		return false;
	}

	//シーンを作成
	m_pScene = FbxScene::Create( m_pSdkMgr, "" );
	if( m_pImporter->Import( m_pScene ) == false )
	{
		Unload();
		return false;
	}

//	FbxAxisSystem testAS( FbxAxisSystem::YAxis, FbxAxisSystem::ParityEven, FbxAxisSystem::LeftHanded );
//	testAS.ConvertScene( m_pScene );

	//軸システム
	FbxAxisSystem axisSystem = m_pScene->GetGlobalSettings().GetAxisSystem();
	if( axisSystem == ::FbxAxisSystem::MayaZUp )
	{
		LogPrint( LT_INFO, L"  FBX : インフォメーション : AxisSystem[MayaZUp]" );
		m_bInvertZ = true;
		m_PivotScale = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
	}
	else if( axisSystem == ::FbxAxisSystem::MayaYUp )
	{
		LogPrint( LT_INFO, L"  FBX : インフォメーション : AxisSystem[MayaYUp]" );
		m_bInvertZ = true;
		m_PivotScale = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
	}
	else if( axisSystem == ::FbxAxisSystem::Max )
	{
		LogPrint( LT_INFO, L"  FBX : インフォメーション : AxisSystem[Max]" );
		m_bInvertZ = true;
		m_PivotScale = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
	}
	else if( axisSystem == ::FbxAxisSystem::Motionbuilder )
	{
		LogPrint( LT_INFO, L"  FBX : インフォメーション : AxisSystem[Motionbuilder]" );
		m_bInvertZ = true;
		m_PivotScale = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
	}
	else if( axisSystem == ::FbxAxisSystem::OpenGL )
	{
		LogPrint( LT_INFO, L"  FBX : インフォメーション : AxisSystem[OpenGL]" );
		m_bInvertZ = true;
		m_PivotScale = D3DXVECTOR3( 1.0f, 1.0f, -1.0f );
	}
	else if( axisSystem == ::FbxAxisSystem::DirectX )
	{
		LogPrint( LT_INFO, L"  FBX : インフォメーション : AxisSystem[DirectX]" );
		m_bInvertZ = false;
		m_PivotScale = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
	}
	else if( axisSystem == ::FbxAxisSystem::Lightwave )
	{
		LogPrint( LT_INFO, L"  FBX : インフォメーション : AxisSystem[Lightwave]" );
		m_bInvertZ = false;
		m_PivotScale = D3DXVECTOR3( 1.0f, 1.0f, 1.0f );
	}

	::D3DXMatrixScaling( &m_PivotScaleMat, m_PivotScale.x, m_PivotScale.y, m_PivotScale.z );

	//ルートノードを取得
	m_pRootNode = m_pScene->GetRootNode();
	if( m_pRootNode == NULL )
	{
		Unload();
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノードを探索して、情報を収集
	////////////////////////////////////////////////////////////////////////////////////////////////////

	Analyze( m_pRootNode, param );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 総ポリゴン数
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_TotalPolygonCount = param.totalPolygonCount;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアルリストの初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( param.notAssignMaterialPolygon == true )
	{
		//マテリアルを割り当てられていないポリゴンあるため、デフォルトのマテリアルを追加

		int i;

		std::set<std::string>& materialNameList = param.materialNameList;
		std::set<std::string>::iterator it_end = materialNameList.end();
		std::set<std::string>::iterator it;
		std::ostringstream uniqName( DEF_MATERIAL_NAME );

		//ユニークな名前を決定
		for( i = 0; i <= FBX::DEF_MATERIAL_MAX_NO; i++ )
		{
			it = materialNameList.find( uniqName.str() );
			if( it != it_end )
			{
				uniqName << FBX::DEF_MATERIAL_NAME << L"_" << i;
			}
			else
			{
				break;
			}
		}

		if( i > FBX::DEF_MATERIAL_MAX_NO )
		{
			//デフォルトマテリアル名の決定に失敗
			return false;
		}

		pDrawObject->AddMaterialSlot( uniqName.str().c_str() );
	}

	return true;
}

bool FBX::IsLoad( void ) const
{
	return ( m_pSdkMgr != NULL );
}

void FBX::Unload( void )
{
	m_pRootNode = NULL;

	if( m_pScene != NULL )
	{
		m_pScene->Destroy();
		m_pScene = NULL;
	}

	if( m_pImporter != NULL )
	{
		m_pImporter->Destroy();
		m_pImporter = NULL;
	}

	if( m_pIOSetting != NULL )
	{
		m_pIOSetting->Destroy();
		m_pIOSetting = NULL;
	}

	if( m_pSdkMgr != NULL )
	{
		m_pSdkMgr->Destroy();
		m_pSdkMgr = NULL;
	}
}

FbxNode* FBX::GetRootNode( void ) const
{
	return m_pRootNode;
}

int FBX::GetTotalPolygonCount( void ) const
{
	return m_TotalPolygonCount;
}

bool FBX::TriangulateInPlace( FbxNode* pFbxNode, const wchar_t* pName )
{
	FbxGeometryConverter fbxGeometryConverter( m_pSdkMgr );

	if( fbxGeometryConverter.Triangulate( pFbxNode->GetNodeAttribute(), true ) == false )
	{
		LogPrint( LT_ERROR, L"FBX : ポリゴンの三角形化に失敗しました : NodeName[%s]", pName );
		return false;
	}

	return true;
}

bool FBX::LoadMotion( FbxTime::EMode fbxTimeMode, Mix::Tool::Win32::Graphics::MotionController* pMotionController )
{
	if ((fbxTimeMode == FbxTime::eDefaultMode) ||
		(fbxTimeMode == FbxTime::eCustom) ||
		(fbxTimeMode == FbxTime::eModesCount) ||
		( pMotionController == NULL ) )
	{
		return false;
	}

	int i;
	int animStackCount = m_pScene->GetSrcObjectCount<FbxAnimStack>();
	bool bSuccess = true;

	for (i = 0; (i < animStackCount) && (bSuccess == true); i++)
	{
		FbxAnimStack* pFbxAnimAtack = m_pScene->GetSrcObject<FbxAnimStack>(i);
		/*
		if (pFbxAnimAtack->GetNameOnly().Compare(FBXSDK_TAKENODE_DEFAULT_NAME) == 0)
		{
			continue;
		}
		*/
		int animLayerNum = pFbxAnimAtack->GetMemberCount<FbxAnimLayer>();

		if (animLayerNum > 0)
		{
			FbxAnimLayer* pFbxAnimLayer = pFbxAnimAtack->GetMember<FbxAnimLayer>();
			Mix::Tool::Win32::Graphics::Motion* pMotion = pMotionController->Add(pFbxAnimAtack->GetName(), static_cast<float>(FBX::FPS_TABLE[fbxTimeMode]));

			if (pMotion != NULL)
			{
				if (LoadMotion(fbxTimeMode, m_pRootNode, pFbxAnimLayer, pMotion) == true)
				{
					pMotion->Finish();

					LogPrint(LT_INFO, L"  FBX : モーション : Name[%s] LastTime[%f]", pMotion->GetName(), pMotion->GetLastTime());
				}
				else
				{
					bSuccess = false;
				}
			}
			else
			{
				bSuccess = false;
			}
		}
	}

	return bSuccess;
}

bool FBX::LoadMotion(FbxTime::EMode fbxTimeMode, FbxNode* pFbxNode, FbxAnimLayer* pFbxAnimLayer, Mix::Tool::Win32::Graphics::Motion* pMotion)
{
	int childCount = pFbxNode->GetChildCount();
	int i;

	if (LoadMotionChannels(fbxTimeMode, pFbxNode, pFbxAnimLayer, pMotion) == false)
	{
		return false;
	}

	for( i = 0; i < childCount; i++ )
	{
		if( LoadMotion( fbxTimeMode, pFbxNode->GetChild( i ), pFbxAnimLayer, pMotion ) == false )
		{
			return false;
		}
	}

	return true;
}

bool FBX::LoadMotionChannels(FbxTime::EMode fbxTimeMode, FbxNode* pFbxNode, FbxAnimLayer* pFbxAnimLayer, Mix::Tool::Win32::Graphics::Motion* pMotion)
{
	int i;
	unsigned int j;

	FbxAnimCurveNode* pFbxAnimCurveNodeS;
	FbxAnimCurveNode* pFbxAnimCurveNodeR;
	FbxAnimCurveNode* pFbxAnimCurveNodeT;

	FbxAnimCurve* pFbxAnimCurve;
	FbxString fbxChannelName;

	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> sx;
	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> sy;
	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> sz;
	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> rx;
	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> ry;
	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> rz;
	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> tx;
	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> ty;
	std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY> tz;

	Mix::Tool::Win32::Graphics::MotionCurve* pCurve;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pFbxAnimCurveNodeS = pFbxNode->LclScaling.GetCurveNode(pFbxAnimLayer);
	pFbxAnimCurveNodeR = pFbxNode->LclRotation.GetCurveNode(pFbxAnimLayer);
	pFbxAnimCurveNodeT = pFbxNode->LclTranslation.GetCurveNode(pFbxAnimLayer);

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// スケーリングのカーブキーを取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pFbxAnimCurveNodeS != NULL )
	{
		for( j = 0; j < pFbxAnimCurveNodeS->GetChannelsCount(); j++ )
		{
			pFbxAnimCurve = pFbxAnimCurveNodeS->GetCurve( j, 0, pFbxAnimCurveNodeS->GetName() );
			if( pFbxAnimCurve != NULL )
			{
				fbxChannelName = pFbxAnimCurveNodeS->GetChannelName( j );

				if( fbxChannelName.Compare( FBXSDK_CURVENODE_COMPONENT_X ) == 0 )
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, sx );
				}
				else if (fbxChannelName.Compare(FBXSDK_CURVENODE_COMPONENT_Y) == 0)
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, sy );
				}
				else if (fbxChannelName.Compare(FBXSDK_CURVENODE_COMPONENT_Z) == 0)
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, sz );
				}
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ローテーションのカーブキーを取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pFbxAnimCurveNodeR != NULL )
	{
		for( j = 0; j < pFbxAnimCurveNodeR->GetChannelsCount(); j++ )
		{
			pFbxAnimCurve = pFbxAnimCurveNodeR->GetCurve( j, 0, pFbxAnimCurveNodeR->GetName() );
			if( pFbxAnimCurve != NULL )
			{
				fbxChannelName = pFbxAnimCurveNodeR->GetChannelName( j );

				if (fbxChannelName.Compare(FBXSDK_CURVENODE_COMPONENT_X) == 0)
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, rx );
				}
				else if (fbxChannelName.Compare(FBXSDK_CURVENODE_COMPONENT_Y) == 0)
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, ry );
				}
				else if (fbxChannelName.Compare(FBXSDK_CURVENODE_COMPONENT_Z) == 0)
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, rz );
				}
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// トランスレーションのカーブキーを取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pFbxAnimCurveNodeT != NULL )
	{
		for( j = 0; j < pFbxAnimCurveNodeT->GetChannelsCount(); j++ )
		{
			pFbxAnimCurve = pFbxAnimCurveNodeT->GetCurve( j, 0, pFbxAnimCurveNodeT->GetName() );
			if( pFbxAnimCurve != NULL )
			{
				fbxChannelName = pFbxAnimCurveNodeT->GetChannelName( j );

				if (fbxChannelName.Compare(FBXSDK_CURVENODE_COMPONENT_X) == 0)
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, tx );
				}
				else if (fbxChannelName.Compare(FBXSDK_CURVENODE_COMPONENT_Y) == 0)
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, ty );
				}
				else if (fbxChannelName.Compare(FBXSDK_CURVENODE_COMPONENT_Z) == 0)
				{
					LoadMotionCurveKeys( fbxTimeMode, pFbxAnimCurve, tz );
				}
			}
		}
	}

	if( ( sx.size() == 0 ) &&
		( sy.size() == 0 ) &&
		( sz.size() == 0 ) &&
		( rx.size() == 0 ) &&
		( ry.size() == 0 ) &&
		( rz.size() == 0 ) &&
		( tx.size() == 0 ) &&
		( ty.size() == 0 ) &&
		( tz.size() == 0 ) )
	{
		return true;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// カーブを追加
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pCurve = pMotion->AddCurve( pFbxNode->GetName() );
	if( pCurve != NULL )
	{
		pCurve->ReserveKeyList( GetCurveKeyCount( sx, sy, sz ),
								GetCurveKeyCount( rx, ry, rz ),
								GetCurveKeyCount( tx, ty, tz ) );
	}
	else
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// カーブにスケーリングを設定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( sx.size() > 0 ) ||
		( sy.size() > 0 ) ||
		( sz.size() > 0 ) )
	{
		int lastTime = GetMotionLastTime( sx, sy, sz );

		for( i = 0; i <= lastTime; i++ )
		{
			D3DXVECTOR3 value;

			if( GetMotionCurveValue( sx, sy, sz, i, 1.0f, value ) == true )
			{
				pCurve->AddScalingKey( i, value );
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// カーブにローテーションを設定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( rx.size() > 0 ) ||
		( ry.size() > 0 ) ||
		( rz.size() > 0 ) )
	{
		int lastTime;
		FbxEuler::EOrder rotOrder;

		lastTime = GetMotionLastTime( rx, ry, rz );
		pFbxNode->GetRotationOrder( FbxNode::eSourcePivot, rotOrder );

		for( i = 0; i <= lastTime; i++ )
		{
			D3DXVECTOR3 temp;

			if( GetMotionCurveValue( rx, ry, rz, i, 0.0f, temp ) == true )
			{
				pCurve->AddRotationKey( i, CreateQuaternion( rotOrder, temp ) );
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// カーブにトランスレーションを設定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( tx.size() > 0 ) ||
		( ty.size() > 0 ) ||
		( tz.size() > 0 ) )
	{
		int lastTime = GetMotionLastTime( tx, ty, tz );

		for( i = 0; i <= lastTime; i++ )
		{
			D3DXVECTOR3 value;

			if( GetMotionCurveValue( tx, ty, tz, i, 0.0f, value ) == true )
			{
				pCurve->AddTranslationKey( i, value );
			}
		}
	}

	return true;
}

bool FBX::LoadMotionCurveKeys( FbxTime::EMode fbxTimeMode, FbxAnimCurve* pFbxAnimCurve, std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& curveKeyList )
{
	int i;
	int time;
	float value;
	bool bInit;
	FbxLongLong fps;
	int hour;
	int minute;
	int second;
	int frame;
	int field;
	int residual;
	Mix::Tool::Win32::Graphics::CURVE_KEY curveKey;

	bInit = false;
	curveKey.time = 0;
	curveKey.value = 0.0f;

	fps = FBX::FPS_TABLE[fbxTimeMode];

	for( i = 0; i < pFbxAnimCurve->KeyGetCount(); i++ )
	{
		pFbxAnimCurve->KeyGetTime( i ).GetTime( hour, minute, second, frame, field, residual, fbxTimeMode );

		time = static_cast<int>( ( hour * fps * fps * fps ) + ( minute * fps * fps ) + ( second * fps ) + frame );
		value = static_cast<float>( pFbxAnimCurve->KeyGetValue( i ) );

		if( ( bInit == false ) ||
			( ( curveKey.time != time ) && ( curveKey.value != value ) ) )
		{
			curveKey.time = time;
			curveKey.value = value;

			curveKeyList.push_back( curveKey );

			bInit = true;
		}
	}

	return bInit;
}

unsigned int FBX::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 )
{
	unsigned int count = 0;

	if( count < x.size() ) { count = x.size(); }
	if( count < y.size() ) { count = y.size(); }
	if( count < z.size() ) { count = z.size(); }

	return count;
}

int FBX::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 )
{
	int lastTime = 0;

	if( ( x.size() > 0 ) && ( x.back().time > lastTime ) ) { lastTime = x.back().time; }
	if( ( y.size() > 0 ) && ( y.back().time > lastTime ) ) { lastTime = y.back().time; }
	if( ( z.size() > 0 ) && ( z.back().time > lastTime ) ) { lastTime = z.back().time; }

	return lastTime;
}

bool FBX::GetMotionCurveValue(	const std::vector<Mix::Tool::Win32::Graphics::CURVE_KEY>& curveKeyList,
								int time,
								float defValue,
								float& value )
{
	int keyCount = static_cast<int>( curveKeyList.size() );
	bool bFindTime = false;

	value = defValue;

	if( keyCount > 0 )
	{
		const Mix::Tool::Win32::Graphics::CURVE_KEY* pCurveKeys =  &( curveKeyList[0] );

		pCurveKeys = &( curveKeyList[0] );

		if( time <= pCurveKeys[0].time )
		{
			value = pCurveKeys[0].value;
			bFindTime = ( time == pCurveKeys[0].time );
		}
		else if( time >= pCurveKeys[keyCount - 1].time )
		{
			value = pCurveKeys[keyCount - 1].value;
			bFindTime = ( time == pCurveKeys[keyCount - 1].time );
		}
		else
		{
			int left = 0;
			int right = keyCount - 1;
			int middle;

			for( ;; )
			{
				middle = ( left + ( ( right - left ) / 2 ) );

				if( time < pCurveKeys[middle].time )
				{
					right = ( middle - 1 );
				}
				else if ( time > pCurveKeys[middle + 1].time )
				{
					left = ( middle + 1 );
				}
				else
				{
					const Mix::Tool::Win32::Graphics::CURVE_KEY& ck1 = pCurveKeys[middle + 0];
					const Mix::Tool::Win32::Graphics::CURVE_KEY& ck2 = pCurveKeys[middle + 1];
					float t = static_cast<float>( time );
					float t1 = static_cast<float>( ck1.time );
					float t2 = static_cast<float>( ck2.time );
					float rate = ( ( t - t1 ) / ( t2 - t1 ) );

					value = ck1.value + ( ( ck2.value - ck1.value ) * rate );
					bFindTime = ( ( pCurveKeys[middle].time == time ) || ( pCurveKeys[middle + 1].time == time ) );

					break;
				}
			}
		}
	}

	return bFindTime;
}

bool FBX::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 )
{
	float vx;
	float vy;
	float vz;
	bool bx;
	bool by;
	bool bz;

	bx = GetMotionCurveValue( x, time, defValue, vx );
	by = GetMotionCurveValue( y, time, defValue, vy );
	bz = GetMotionCurveValue( z, time, defValue, vz );

	if( ( bx == false ) &&
		( by == false ) &&
		( bz == false ) )
	{
		return false;
	}

	value.x = vx;
	value.y = vy;
	value.z = vz;

	return true;
}

void FBX::Analyze( FbxNode* pFbxNode, FBX::ANALYZE_PARAM& param )
{
	int i;
	FbxNodeAttribute* pFbxNodeAttr = pFbxNode->GetNodeAttribute();

	if( pFbxNodeAttr != NULL )
	{
		if( pFbxNodeAttr->GetAttributeType() == FbxNodeAttribute::eMesh )
		{
			FbxMesh* pFbxMesh = FbxCast<FbxMesh>( pFbxNode->GetNodeAttribute() );

			//ポリゴン数
			param.totalPolygonCount += pFbxMesh->GetPolygonCount();

			//マテリアル
			if( param.notAssignMaterialPolygon == false )
			{
				int materialCount = pFbxNode->GetMaterialCount();
				FbxLayer* pFbxLayer = pFbxMesh->GetLayer( 0 );

				if( materialCount > 0 )
				{
					FbxLayerElementMaterial* pFbxMaterials = pFbxLayer->GetMaterials();

					if( pFbxMaterials != NULL )
					{
						FbxLayerElementMaterial::EMappingMode mappingMode = pFbxMaterials->GetMappingMode();

						if( mappingMode == FbxLayerElementMaterial::eByPolygon )
						{
							if( pFbxMesh->GetPolygonCount() != pFbxMaterials->GetIndexArray().GetCount() )
							{
								//ポリゴン数とマテリアルを割り当てているポリゴンの数が一致しない場合
								param.notAssignMaterialPolygon = true;
							}
						}
					}
					else
					{
						//バグ(起こりえないはず)
						param.notAssignMaterialPolygon = true;
					}

					//デフォルトマテリアル名の決定に必要なマテリアル名を列挙
					for( i = 0; i < materialCount; i++ )
					{
						FbxSurfaceMaterial* pFbxMaterial = pFbxNode->GetMaterial( i );
						param.materialNameList.insert( pFbxMaterial->GetName() );
					}
				}
				else
				{
					//マテリアルが存在しない場合
					param.notAssignMaterialPolygon = true;
				}
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 子ノードを処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( i = 0; i < pFbxNode->GetChildCount(); i++ )
	{
		Analyze( pFbxNode->GetChild( i ), param );
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// FBX : ユーティリティ
////////////////////////////////////////////////////////////////////////////////////////////////////

FbxNodeAttribute::EType FBX::GetNodeType( FbxNode* pNode )
{
	if( pNode == NULL )
	{
		return FbxNodeAttribute::eUnknown;
	}

	FbxNodeAttribute* pNodeAttr = pNode->GetNodeAttribute();

	if( pNodeAttr == NULL )
	{
		return FbxNodeAttribute::eUnknown;
	}

	return pNodeAttr->GetAttributeType();
}

bool FBX::LoadMesh( FbxNode* pFbxNode, bool transformEnabled, bool polygonNormal, Mix::Tool::Win32::Graphics::OptimizeMesh* pMesh, const wchar_t* pNodeName )
{
	if( ( pFbxNode == NULL ) ||
		( pMesh == NULL ) )
	{
		return false;
	}

	int i;
	int j;
	int k;
	int polygonOffset;
	int controlPointCount;
	int deformerCount;
	int polygonCount;
	int vertexIndex;
	int materialCount;
	FbxNodeAttribute* pFbxNodeAttr;
	FbxMesh* pFbxMesh;
	FbxLayer* pFbxLayer;
	FbxLayerElementVertexColor* pFbxVertexColors;
	FbxLayerElementNormal* pFbxNormals;
	FbxLayerElementUV* pFbxUVs;
	FbxAMatrix fbxXMatrix = pFbxNode->EvaluateGlobalTransform();
	FbxMatrix fbxMatrix( fbxXMatrix );
	FbxMatrix fbxRotationMatrix( FbxVector4(), fbxXMatrix.GetQ(), FbxVector4( 1.0, 1.0, 1.0 ) );
	std::vector<std::vector<Mix::Tool::Win32::Graphics::WEIGHT>> vertexWeightList;
	Mix::Tool::Win32::Graphics::DrawObject* pDrawObject;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pDrawObject = pMesh->GetDrawObjectPtr();
	if( pDrawObject == NULL )
	{
		LogPrint( LT_ERROR, L"  FBX : 描画オブジェクトの取得( OptimizeMesh::GetDrawObject )に失敗しました : NodeName[%s]", pNodeName );
		return false;
	}

	pFbxNodeAttr = pFbxNode->GetNodeAttribute();
	if( ( pFbxNodeAttr == NULL ) ||
		( pFbxNodeAttr->GetAttributeType() != FbxNodeAttribute::eMesh ) )
	{
		LogPrint( LT_ERROR, L"  FBX : ノード属性の取得に失敗しました : NodeName[%s]", pNodeName );
		return false;
	}

	pFbxMesh = FbxCast<FbxMesh>( pFbxNodeAttr );
	if( pFbxMesh == NULL )
	{
		LogPrint( LT_ERROR, L"  FBX : 取得したノードはメッシュを所持していません : NodeName[%s]", pNodeName );
		return false;
	}

	pFbxLayer = pFbxMesh->GetLayer( 0 );
	if( pFbxLayer != NULL )
	{
		pFbxVertexColors = pFbxLayer->GetVertexColors();
		pFbxNormals = pFbxLayer->GetNormals();
		pFbxUVs = pFbxLayer->GetUVs();
	}

	controlPointCount = pFbxMesh->GetControlPointsCount();
	if( controlPointCount == 0 )
	{
		LogPrint( LT_ERROR, L"  FBX : FbxMesh::GetControlPointsCount が 0 を返しました : 頂点が存在しません : NodeName[%s]", pNodeName );
		return false;
	}

	deformerCount = pFbxMesh->GetDeformerCount();
	materialCount = pFbxNode->GetMaterialCount();

	polygonOffset = pMesh->GetPolygonCount();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 頂点毎のウェイト配列を作成する
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pMesh->GetBoneAvaliable() == true )
	{
		vertexWeightList.resize( controlPointCount );

		for( i = 0; i < deformerCount; i++ )
		{
			FbxDeformer* pDeformer = pFbxMesh->GetDeformer( i );

			if( pDeformer->GetDeformerType() != FbxDeformer::eSkin )
			{
				continue;
			}

			FbxSkin* pSkin = FbxCast<FbxSkin>( pDeformer );
			int clusterCount = pSkin->GetClusterCount();

			for( j = 0; j < clusterCount; j++ )
			{
				int indicesCount;
				int* pIndices;
				double* pWeights;
				unsigned int boneIndex;
				Mix::Tool::Win32::Graphics::BONE bone;
				D3DXMATRIX boneMat;
				D3DXMATRIX boneLinkMat;
				FbxCluster* pFbxCluster;
				FbxNode* pFbxBoneNode;
				FbxAMatrix fbxBoneMat;
				FbxAMatrix fbxBoneLinkMat;

				////////////////////////////////////////////////////////////////////////////////////////////////////
				// 初期化
				////////////////////////////////////////////////////////////////////////////////////////////////////

				pFbxCluster = pSkin->GetCluster( j );
				pFbxBoneNode = pFbxCluster->GetLink();
				pFbxCluster->GetTransformMatrix( fbxBoneMat );
				pFbxCluster->GetTransformLinkMatrix( fbxBoneLinkMat );

				////////////////////////////////////////////////////////////////////////////////////////////////////
				// ボーンを追加
				////////////////////////////////////////////////////////////////////////////////////////////////////

				boneMat = ToD3DXMatrix( fbxBoneMat );
				D3DXMatrixInverse( &boneLinkMat, NULL, &( ToD3DXMatrix( fbxBoneLinkMat ) ) );

				boneIndex = pMesh->AddBone( pFbxBoneNode->GetName(), ( boneMat * boneLinkMat ) );

				////////////////////////////////////////////////////////////////////////////////////////////////////
				// 頂点毎のウェイトを設定
				////////////////////////////////////////////////////////////////////////////////////////////////////

				indicesCount = pFbxCluster->GetControlPointIndicesCount();
				pIndices = pFbxCluster->GetControlPointIndices();
				pWeights = pFbxCluster->GetControlPointWeights();

				for( k = 0; k < indicesCount; k++ )
				{
					Mix::Tool::Win32::Graphics::WEIGHT weight;

					weight.index = boneIndex;
					weight.value = static_cast<float>( pWeights[k] );

					vertexWeightList[pIndices[k]].push_back( weight );
				}
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 頂点毎のウェイトを正規化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pMesh->GetBoneAvaliable() == true )
	{
		for( i = 0; i < controlPointCount; i++ )
		{
			std::vector<Mix::Tool::Win32::Graphics::WEIGHT>& weights = vertexWeightList[i];

			if( vertexWeightList[i].size() == 0 )
			{
				weights.resize( Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT );

				weights[0].index = 0;
				weights[1].index = 0;
				weights[2].index = 0;
				weights[3].index = 0;
				weights[0].value = 1.0f;
				weights[1].value = 0.0f;
				weights[2].value = 0.0f;
				weights[3].value = 0.0f;
			}
			else
			{
				float weightDiv = 0.0f;

				weights.push_back( Mix::Tool::Win32::Graphics::WEIGHT() );
				weights.push_back( Mix::Tool::Win32::Graphics::WEIGHT() );
				weights.push_back( Mix::Tool::Win32::Graphics::WEIGHT() );
				std::sort( weights.begin(), weights.end(), Mix::Tool::Win32::Graphics::WEIGHT() );
				weights.resize( Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT );

				for( j = 0; j < Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT; j++ )
				{
					weightDiv += weights[j].value;
				}

				for( j = 0; j < Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT; j++ )
				{
					weights[j].value /= weightDiv;
				}
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ポリゴンリストを作成する
	////////////////////////////////////////////////////////////////////////////////////////////////////

	polygonCount = pFbxMesh->GetPolygonCount();
	vertexIndex = 0;

	for( i = 0; i < polygonCount; i++ )
	{
		int polygonPointCount;
		Mix::Tool::Win32::Graphics::POLYGON polygon;
		Mix::Tool::Win32::Graphics::VERTEX tmpV;

		polygonPointCount = pFbxMesh->GetPolygonSize( i );
		polygon.materialNo = 0;
		polygon.vertices.reserve( polygonPointCount );

		for( j = 0; j < polygonPointCount; j++ )
		{
			int k;
			int controlPointIndex = pFbxMesh->GetPolygonVertex( i, j );
			int vertexColorIndex;
			int normalIndex;
			int textureIndex;
			FbxVector4 fbxPos;
			FbxColor fbxVertexColor;
			FbxVector4 fbxNormal;
			FbxVector2 fbxTexCoord;
			Mix::Tool::Win32::Graphics::VERTEX vertex;

			//座標
			fbxPos = pFbxMesh->GetControlPoints()[controlPointIndex];

			//頂点カラー
			if( pFbxVertexColors != NULL )
			{
				switch( pFbxVertexColors->GetMappingMode() )
				{
				case FbxLayerElement::eByControlPoint:
					switch( pFbxNormals->GetReferenceMode() )
					{
					case FbxLayerElement::eDirect:
						vertexColorIndex = controlPointIndex;
						fbxVertexColor = pFbxVertexColors->GetDirectArray().GetAt( vertexColorIndex );
						break;

					case FbxLayerElement::eIndexToDirect:
						vertexColorIndex = pFbxVertexColors->GetIndexArray().GetAt( controlPointIndex );
						fbxVertexColor = pFbxVertexColors->GetDirectArray().GetAt( vertexColorIndex );
						break;
						
					default:
						LogPrint( LT_ERROR, L"  FBX : 頂点カラーの参照モードが不正です : ファイルが正常かどうか確認してください : NodeName[%s]", pNodeName );
						return false;
					}
					break;

				case FbxLayerElement::eByPolygonVertex:
					switch( pFbxNormals->GetReferenceMode() )
					{
					case FbxLayerElement::eDirect:
					case FbxLayerElement::eIndexToDirect:
						vertexColorIndex = pFbxVertexColors->GetIndexArray().GetAt( vertexIndex );
						fbxVertexColor = pFbxVertexColors->GetDirectArray().GetAt( vertexColorIndex );
						break;

					default:
						LogPrint( LT_ERROR, L"  FBX : 頂点カラーの参照モードが不正です : ファイルが正常かどうか確認してください : NodeName[%s]", pNodeName );
						return false;
					}
					break;

				default:
					LogPrint( LT_ERROR, L"  FBX : 頂点カラーのマッピングモードが不正です : 頂点単位、ポリゴン単位のサポートしています : NodeName[%s]", pNodeName );
					fbxVertexColor.Set( 1.0, 1.0, 1.0, 1.0 );
				}
			}
			else
			{
				fbxVertexColor.Set( 1.0, 1.0, 1.0, 1.0 );
			}

			//法線
			if( pFbxNormals != NULL )
			{
				switch( pFbxNormals->GetMappingMode() )
				{
				//頂点単位
				case FbxLayerElement::eByControlPoint:
					switch( pFbxNormals->GetReferenceMode() )
					{
					case FbxLayerElement::eDirect:
						normalIndex = controlPointIndex;
						fbxNormal = pFbxNormals->GetDirectArray().GetAt( normalIndex );
						break;

					case FbxLayerElement::eIndexToDirect:
						normalIndex = pFbxNormals->GetIndexArray().GetAt( controlPointIndex );
						fbxNormal = pFbxNormals->GetDirectArray().GetAt( normalIndex );
						break;
						
					default:
						LogPrint( LT_ERROR, L"  FBX : 法線の参照モードが不正です : ファイルが正常かどうか確認してください : NodeName[%s]", pNodeName );
						return false;
					}
					break;

				//ポリゴン単位
				case FbxLayerElement::eByPolygonVertex:
					switch( pFbxNormals->GetReferenceMode() )
					{
					case FbxLayerElement::eDirect:
						normalIndex = vertexIndex;
						fbxNormal = pFbxNormals->GetDirectArray().GetAt( normalIndex );
						break;

					case FbxLayerElement::eIndexToDirect:
						normalIndex = pFbxNormals->GetIndexArray().GetAt( vertexIndex );
						fbxNormal = pFbxNormals->GetDirectArray().GetAt( normalIndex );
						break;

					default:
						LogPrint( LT_ERROR, L"  FBX : 法線の参照モードが不正です : ファイルが正常かどうか確認してください : NodeName[%s]", pNodeName );
						return false;
					}
					break;

				default:
					LogPrint( LT_ERROR, L"  FBX : 法線のマッピングモードが不正です : 頂点単位、ポリゴン単位のサポートしています : NodeName[%s]", pNodeName );
					return false;
				}
			}
			else
			{
				//ポリゴンが形成された時点で算出
				fbxNormal.Set( 0.0, 0.0, 0.0, 1.0 );
			}

			//テクスチャ座標
			if( pFbxUVs != NULL )
			{
				switch( pFbxUVs->GetMappingMode() )
				{
				//頂点単位
				case FbxLayerElement::eByControlPoint:
					switch( pFbxUVs->GetReferenceMode() )
					{
					case FbxLayerElement::eDirect:
						textureIndex = controlPointIndex;
						fbxTexCoord = pFbxUVs->GetDirectArray().GetAt( textureIndex );
						break;

					case FbxLayerElement::eIndexToDirect:
						textureIndex = pFbxUVs->GetIndexArray().GetAt( controlPointIndex );
						fbxTexCoord = pFbxUVs->GetDirectArray().GetAt( textureIndex );
						break;

					default:
						LogPrint( LT_ERROR, L"  FBX : ＵＶの参照モードが不正です : ファイルが正常かどうか確認してください : NodeName[%s]", pNodeName );
						return false;
					}
					break;

				//ポリゴン単位
				case FbxLayerElement::eByPolygonVertex:
					switch( pFbxUVs->GetReferenceMode() )
					{
					case FbxLayerElement::eDirect:
					case FbxLayerElement::eIndexToDirect:
						textureIndex = pFbxMesh->GetTextureUVIndex( i, j );
						fbxTexCoord = pFbxUVs->GetDirectArray().GetAt( textureIndex );
						break;

					default:
						LogPrint( LT_ERROR, L"  FBX : ＵＶの参照モードが不正です : ファイルが正常かどうか確認してください : NodeName[%s]", pNodeName );
						return false;
					}
					break;

				default:
					LogPrint( LT_ERROR, L"  FBX : ＵＶのマッピングモードが不正です : 頂点単位、ポリゴン単位のみサポートしています : NodeName[%s]", pNodeName );
					return false;
				}
			}
			else
			{
				fbxTexCoord.Set( 0.0, 0.0 );
			}

			//必要に応じてトランスフォーム
			if( transformEnabled == true )
			{
				fbxPos = fbxMatrix.MultNormalize( fbxPos );

				fbxNormal = fbxRotationMatrix.MultNormalize( fbxNormal );
				fbxNormal.Normalize();
			}

			//座標
			vertex.pos.x = static_cast<float>( fbxPos.mData[0] );
			vertex.pos.y = static_cast<float>( fbxPos.mData[1] );
			vertex.pos.z = static_cast<float>( fbxPos.mData[2] );

			//頂点カラー
			vertex.color.x = static_cast<float>( fbxVertexColor.mRed );
			vertex.color.y = static_cast<float>( fbxVertexColor.mGreen );
			vertex.color.z = static_cast<float>( fbxVertexColor.mBlue );
			vertex.color.w = static_cast<float>( fbxVertexColor.mAlpha );

			//法線
			vertex.normal.x = static_cast<float>( fbxNormal.mData[0] );
			vertex.normal.y = static_cast<float>( fbxNormal.mData[1] );
			vertex.normal.z = static_cast<float>( fbxNormal.mData[2] );

			//テクスチャ
			vertex.tex.x = static_cast<float>( fbxTexCoord.mData[0] );
			vertex.tex.y = ( 1.0f - static_cast<float>( fbxTexCoord.mData[1] ) );

			//ウェイト
			if( pMesh->GetBoneAvaliable() == true )
			{
				std::vector<Mix::Tool::Win32::Graphics::WEIGHT>& weights = vertexWeightList[controlPointIndex];

				for( k = 0; k < Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT; k++ )
				{
					vertex.weights[k] = weights[k];
				}
			}
			else
			{
				for( k = 0; k < Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT; k++ )
				{
					vertex.weights[k].index = 0;
					vertex.weights[k].value = 0.0f;
				}
			}

			//必要に応じてピボットスケールを適用
			if( transformEnabled == true )
			{
				D3DXVECTOR3 tempVec;

				vertex.pos = *D3DXVec3TransformNormal( &tempVec, &( vertex.pos ), &m_PivotScaleMat );
				vertex.normal = *D3DXVec3TransformNormal( &tempVec, &( vertex.normal ), &m_PivotScaleMat );
			}

			polygon.vertices.push_back( vertex );

			vertexIndex++;
		}

		//法線情報が存在しない場合、ポリゴン単位の法線指定( スムージング用 )がある場合の処置
		if( ( pFbxNormals == NULL ) ||
			( polygonNormal == true ) )
		{
			Mix::Tool::Win32::Graphics::VERTEX* pVertex = &( polygon.vertices[0] );
			Mix::Tool::Win32::Graphics::VERTEX* pVertexEnd = pVertex + polygon.vertices.size();

			D3DXVECTOR3 v0 = polygon.vertices[1].pos - polygon.vertices[0].pos;
			D3DXVECTOR3 v1 = polygon.vertices[polygon.vertices.size() - 1].pos - polygon.vertices[0].pos;
			D3DXVECTOR3 normal;

			D3DXVec3Cross( &normal, &v0, &v1 );
			D3DXVec3Normalize( &normal, &normal );

			if( transformEnabled == true )
			{
				while( pVertex != pVertexEnd )
				{
					pVertex->normal = -normal;
					pVertex++;
				}
			}
			else
			{
				while( pVertex != pVertexEnd )
				{
					pVertex->normal = normal;
					pVertex++;
				}
			}
		}

		//インバート
		if( m_bInvertZ == true )
		{
			VERTEX tempVertex = polygon.vertices[0];
			polygon.vertices[0] = polygon.vertices[2];
			polygon.vertices[2] = tempVertex;
		}

		//ポリゴンを追加
		pMesh->AddPolygon( polygon );
	}

	//ログ
	LogPrint( LT_INFO, L"  FBX : メッシュ : NodeName[%s] PolygonCount[%d]", pNodeName, pMesh->GetPolygonCount() );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアルを処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( materialCount > 0 )
	{
		FbxLayerElementMaterial* pFbxMaterials = pFbxLayer->GetMaterials();
		FbxLayerElementMaterial::EReferenceMode refernceMode = pFbxMaterials->GetReferenceMode();
		FbxLayerElementMaterial::EMappingMode mappingMode = pFbxMaterials->GetMappingMode();

		if( refernceMode != FbxLayerElementMaterial::eIndexToDirect )
		{
			//サポートされないマテリアルの参照方法
			LogPrint( LT_ERROR, L"  FBX : マテリアルの参照モードが不正です : ファイルが正常かどうか確認してください : NodeName[%s]", pNodeName );
			return false;
		}

		//マテリアルを追加
		for ( i = 0; i < materialCount; i++ )
		{
			FbxSurfaceMaterial* pFbxMaterial;
			FbxProperty prop;
			FbxDouble propD1;
			FbxDouble3 propD3;
			FbxTexture::EWrapMode wrapMode;

			const char* pMaterialNameA;
			std::wstring textureFileName;
			D3DXVECTOR4 diffuseColor;
			D3DXVECTOR4 specularColor;
			D3DXVECTOR4 ambientColor;
			D3DXVECTOR4 emissiveColor;
			Mix::Tool::Win32::Graphics::Material* pMaterial;

			bool bTransparency;

			//マテリアルを取得
			pFbxMaterial = pFbxNode->GetMaterial( i );

			//マテリアル名を取得し、同一名のマテリアルがあった場合はスキップ
			pMaterialNameA = pFbxMaterial->GetName();
			if( pDrawObject->GetMaterialSlotByName( pMaterialNameA ) != NULL )
			{
				continue;
			}

			//マテリアルを追加
			pMaterial = pDrawObject->AddMaterialSlot( pMaterialNameA );
			if( pMaterial == NULL )
			{
				std::wstring temp;

				Mix::Tool::Win32::AnsiToWide( pMaterialNameA, temp );

				LogPrint( LT_ERROR, L"  FBX : 描画オブジェクトへのマテリアルの追加に失敗 : NodeName[%s] MaterialName[%s]", pNodeName, temp.c_str() );
				return false;
			}

			//自動更新を無効にする
			pMaterial->SetAutoUpdate( false );

			//マテリアルカラーを取得
			if ( pFbxMaterial->GetClassId().Is( FbxSurfacePhong::ClassId ) )
			{
				//フォン
				FbxSurfacePhong* pPhong = static_cast<FbxSurfacePhong*>( pFbxMaterial );
				float diffuseAlpha;

				//不透明度
				propD1 = pPhong->TransparencyFactor;
				diffuseAlpha = ( 1.0f - static_cast<float>( propD1 ) );
				if( ::fabs( 1.0f - diffuseAlpha ) <= FLT_EPSILON )
				{
					diffuseAlpha = 1.0f;
				}

				//アンビエントカラー
				propD3 = pPhong->Ambient;
				propD1 = pPhong->AmbientFactor;
				ambientColor.x = static_cast<float>( propD3[0] * propD1 );
				ambientColor.y = static_cast<float>( propD3[1] * propD1 );
				ambientColor.z = static_cast<float>( propD3[2] * propD1 );
				ambientColor.w = 1.0f;

				//ディフューズカラー
				propD3 = pPhong->Diffuse;
				propD1 = pPhong->DiffuseFactor;
				diffuseColor.x = static_cast<float>( propD3[0] * propD1 );
				diffuseColor.y = static_cast<float>( propD3[1] * propD1 );
				diffuseColor.z = static_cast<float>( propD3[2] * propD1 );
				diffuseColor.w = diffuseAlpha;

				//スペキュラーカラー
				propD3 = pPhong->Specular;
				propD1 = pPhong->SpecularFactor;
				specularColor.x = static_cast<float>( propD3[0] * propD1 );
				specularColor.y = static_cast<float>( propD3[1] * propD1 );
				specularColor.z = static_cast<float>( propD3[2] * propD1 );
				specularColor.w = static_cast<float>( pPhong->Shininess );

				//エミッシブカラー
				propD3 = pPhong->Emissive;
				propD1 = pPhong->EmissiveFactor;
				emissiveColor.x = static_cast<float>( propD3[0] * propD1 );
				emissiveColor.y = static_cast<float>( propD3[1] * propD1 );
				emissiveColor.z = static_cast<float>( propD3[2] * propD1 );
				emissiveColor.w = 0.0f;

				//スペキュラ有り( フォン )
				pMaterial->SetSpecularType( Mix::Tool::Win32::Graphics::SPECULAR_PHONG );
			}
			else if( pFbxMaterial->GetClassId().Is( FbxSurfaceLambert::ClassId ) )
			{
				//ランバート
				FbxSurfaceLambert* pLambert = static_cast<FbxSurfaceLambert*>( pFbxMaterial );
				float diffuseAlpha;

				//不透明度
				propD1 = pLambert->TransparencyFactor;
				diffuseAlpha = ( 1.0f - static_cast<float>( propD1 ) );
				if( ::fabs( 1.0f - diffuseAlpha ) <= FLT_EPSILON )
				{
					diffuseAlpha = 1.0f;
				}

				//アンビエントカラー
				propD3 = pLambert->Ambient;
				propD1 = pLambert->AmbientFactor;
				ambientColor.x = static_cast<float>( propD3[0] * propD1 );
				ambientColor.y = static_cast<float>( propD3[1] * propD1 );
				ambientColor.z = static_cast<float>( propD3[2] * propD1 );
				ambientColor.w = 1.0f;

				//ディフューズカラー
				propD3 = pLambert->Diffuse;
				propD1 = pLambert->DiffuseFactor;
				diffuseColor.x = static_cast<float>( propD3[0] * propD1 );
				diffuseColor.y = static_cast<float>( propD3[1] * propD1 );
				diffuseColor.z = static_cast<float>( propD3[2] * propD1 );
				diffuseColor.w = diffuseAlpha;

				//スペキュラーカラー
				specularColor.x = 0.0f;
				specularColor.y = 0.0f;
				specularColor.z = 0.0f;
				specularColor.w = 0.0f;

				//エミッシブカラー
				propD3 = pLambert->Emissive;
				propD1 = pLambert->EmissiveFactor;
				emissiveColor.x = static_cast<float>( propD3[0] * propD1 );
				emissiveColor.y = static_cast<float>( propD3[1] * propD1 );
				emissiveColor.z = static_cast<float>( propD3[2] * propD1 );
				emissiveColor.w = 0.0f;

				//スペキュラ無し
				pMaterial->SetSpecularType( Mix::Tool::Win32::Graphics::SPECULAR_NONE );
			}
			else
			{
				//サポートされないマテリアル( ランバート、フォンのみ対応 )
				LogPrint( LT_ERROR, L"  FBX : マテリアルが不正です : ランバート、フォンのみサポートしています : NodeName[%s]", pNodeName );
				return false;
			}

			//半透明？
			bTransparency = ( diffuseColor.w != 1.0f );

			//テクスチャファイル名を取得( ディフューズ一枚のみ取得 )
			wrapMode = FbxTexture::eRepeat;
			prop = pFbxMaterial->FindProperty( FbxSurfaceMaterial::sDiffuse );
			if( prop.IsValid() == true )
			{
				int layeredTextureCount = prop.GetSrcObjectCount( FbxLayeredTexture::ClassId );

				if( layeredTextureCount > 0 )
				{
					for( j = 0; ( j < layeredTextureCount ) && ( textureFileName.size() == 0 ); j++ )
					{
		                FbxLayeredTexture* pLayeredTexture = FbxCast<FbxLayeredTexture>( prop.GetSrcObject( FbxLayeredTexture::ClassId, j ) );
					    int textureCount = pLayeredTexture->GetSrcObjectCount( FbxTexture::ClassId );

						for ( k = 0; ( k < textureCount ) && ( textureFileName.size() == 0 ); k++ )
						{
							FbxFileTexture* pTexture = FbxCast<FbxFileTexture>( pLayeredTexture->GetSrcObject( FbxFileTexture::ClassId, k ) );
							if ( pTexture != NULL )
							{
								Mix::Tool::Win32::AnsiToWide( pTexture->GetFileName(), textureFileName );
								wrapMode = pTexture->GetWrapModeU();
							}
						}
					}
				}
				else
				{
					for ( j = 0; ( j < prop.GetSrcObjectCount( FbxTexture::ClassId ) ) && ( textureFileName.size() == 0 ); j++ )
					{
		                FbxFileTexture* pTexture = FbxCast<FbxFileTexture>( prop.GetSrcObject( FbxTexture::ClassId, j ) );
						if ( pTexture != NULL )
						{
							Mix::Tool::Win32::AnsiToWide( pTexture->GetFileName(), textureFileName );
							wrapMode = pTexture->GetWrapModeU();
						}
					}
				}
			}

			if( textureFileName.size() > 0 )
			{
				Mix::Tool::Win32::Path::PATH_TYPE pathType = Mix::Tool::Win32::Path::GetType( textureFileName.c_str() );
				if( pathType == Mix::Tool::Win32::Path::PATH_RELATIVE )
				{
					std::wstring temp = textureFileName;
					Mix::Tool::Win32::Path::Combine( m_DirPath.c_str(), temp.c_str(), textureFileName );
				}
			}

			pMaterial->SetBlendMode( ( bTransparency == false )? Mix::Tool::Win32::Graphics::BLEND_COPY : Mix::Tool::Win32::Graphics::BLEND_NORMAL );

			pMaterial->SetTransparency( bTransparency );
			pMaterial->SetBackculling( true );

			pMaterial->SetDiffuseColor( diffuseColor );
			pMaterial->SetSpecularColor( specularColor );
			pMaterial->SetAmbientColor( ambientColor );
			pMaterial->SetEmissiveColor( emissiveColor );

			pMaterial->SetTextureAddressType((wrapMode == FbxTexture::eRepeat) ? D3DTADDRESS_WRAP : D3DTADDRESS_CLAMP);

			pMaterial->SetDiffuseTextureFileName( textureFileName.c_str() );
			pMaterial->SetSpecularTextureFileName();
			pMaterial->SetEmissiveTextureFileName();
			pMaterial->SetBumpTextureFileName();

			//自動更新を有効にする
			//この段階では、デバイスリソースは作成されていない
			pMaterial->SetAutoUpdate( true );

			//ログ
			LogPrint( LT_INFO, L"  FBX : マテリアル : Name[%s]", pDrawObject->GetMaterialSlotByName( pMaterialNameA )->GetName() );
		}

		//ポリゴンにマテリアルを割り当てる
		if( mappingMode == FbxLayerElementMaterial::eAllSame )
		{
			//全てのポリゴンに同じマテリアルを割り当てる
			int material = pDrawObject->GetMaterialSlotIndex( pFbxNode->GetMaterial( pFbxMaterials->GetIndexArray().GetAt( 0 ) )->GetName() );

			pMesh->SetPolygonMaterial( polygonOffset, polygonCount, material );
		}
		else if( mappingMode == FbxLayerElementMaterial::eByPolygon )
		{
			//ポリゴン単位でマテリアルを割り当てる
			int indexCount = pFbxMaterials->GetIndexArray().GetCount();

			for ( i = 0; i < indexCount; i++ )
			{
				int material = pDrawObject->GetMaterialSlotIndex( pFbxNode->GetMaterial( pFbxMaterials->GetIndexArray().GetAt( i ) )->GetName() );

				pMesh->SetPolygonMaterial( ( polygonOffset + i ), 1, material );
			}
		}
		else
		{
			//サポートされないマテリアルのマッピングモード
			LogPrint( LT_ERROR, L"  FBX : マテリアルのマッピングモードが不正です : ポリゴン単位のみサポートしています : NodeName[%s]", pNodeName );
			return false;
		}
	}

	return true;
}

D3DXQUATERNION FBX::CreateQuaternion(FbxEuler::EOrder fbxRotOrder, const FbxVector4& deg)
{
	D3DXVECTOR3 tempDeg;

	tempDeg.x = static_cast<float>( deg.mData[0] );
	tempDeg.y = static_cast<float>( deg.mData[1] );
	tempDeg.z = static_cast<float>( deg.mData[2] );

	return CreateQuaternion( fbxRotOrder, tempDeg );
}

D3DXQUATERNION FBX::CreateQuaternion(FbxEuler::EOrder fbxRotOrder, const D3DXVECTOR3& deg)
{
	D3DXVECTOR3 rad;
	D3DXQUATERNION ret;

	rad.x = D3DXToRadian( deg.x );
	rad.y = D3DXToRadian( deg.y );
	rad.z = D3DXToRadian( deg.z );

	if( fbxRotOrder == eSphericXYZ )
	{
		CreateQuaternion( rad, ret );
	}
	else
	{
		D3DXMATRIX mat;

		CreateRotationMatrix( fbxRotOrder, rad, mat );
		D3DXQuaternionRotationMatrix( &ret, &mat );
	}

	return ret;
}

D3DXMATRIX FBX::CreateRotationMatrix(FbxEuler::EOrder fbxRotOrder, const FbxVector4& deg)
{
	D3DXVECTOR3 tempDeg;

	tempDeg.x = static_cast<float>( deg.mData[0] );
	tempDeg.y = static_cast<float>( deg.mData[1] );
	tempDeg.z = static_cast<float>( deg.mData[2] );

	return CreateRotationMatrix( fbxRotOrder, tempDeg );
}

D3DXMATRIX FBX::CreateRotationMatrix(FbxEuler::EOrder fbxRotOrder, const D3DXVECTOR3& deg)
{
	D3DXVECTOR3 rad;
	D3DXMATRIX ret;

	rad.x = D3DXToRadian( deg.x );
	rad.y = D3DXToRadian( deg.y );
	rad.z = D3DXToRadian( deg.z );

	if( fbxRotOrder == eSphericXYZ )
	{
		D3DXQUATERNION quat;

		CreateQuaternion( rad, quat );
		::D3DXMatrixRotationQuaternion( &ret, &quat );
	}
	else
	{
		CreateRotationMatrix( fbxRotOrder, rad, ret );
	}

	return ret;
}

bool FBX::IsInvertZ( void ) const
{
	return m_bInvertZ;
}

const D3DXVECTOR3& FBX::GetPivotScale( void ) const
{
	return m_PivotScale;
}

D3DXVECTOR3 FBX::GetLocalScale( FbxNode* pFbxNode )
{
	FbxVector4 fbxTemp;

	fbxTemp = pFbxNode->EvaluateLocalScaling();

	return D3DXVECTOR3( static_cast<float>( fbxTemp.mData[0] ), static_cast<float>( fbxTemp.mData[1] ), static_cast<float>( fbxTemp.mData[2] ) );
}

D3DXQUATERNION FBX::MultiplyRotation(FbxEuler::EOrder fbxRotOrder, const D3DXQUATERNION& r0, const D3DXVECTOR3& r1)
{
	D3DXQUATERNION tempQuat;

	if( fbxRotOrder == eSphericXYZ )
	{
		CreateQuaternion( r1, tempQuat );
	}
	else
	{
		D3DXMATRIX tempMat;

		CreateRotationMatrix( fbxRotOrder, r1, tempMat );
		D3DXQuaternionRotationMatrix( &tempQuat, &tempMat );
	}

	return r0 * tempQuat;
}

D3DXMATRIX FBX::GetGeometricMatrix( FbxNode* pFbxNode )
{
	FbxEuler::EOrder fbxRotOrder;
	D3DXMATRIX geoMat;

	pFbxNode->GetRotationOrder( FbxNode::eSourcePivot, fbxRotOrder );

	if( m_CTM == FBX::CTM_MAYA )
	{
		//Maya( ピボット、オフセットはサポートしていません )

		FbxVector4 fbxVec;
		FbxDouble3 fbxPropD3;

		D3DXQUATERNION localRotQuat;
		D3DXMATRIX localRotMat;
		D3DXMATRIX invLocalRotMat;

		D3DXVECTOR3 RPreRad;
		D3DXMATRIX RPreMat;

		//ローカル行列
		localRotQuat = GetLocalRotation( pFbxNode );
		D3DXMatrixRotationQuaternion( &localRotMat, &localRotQuat );
		D3DXMatrixInverse( &invLocalRotMat, NULL, &localRotMat );

		//RPre
		fbxPropD3 = pFbxNode->PreRotation;
		RPreRad.x = D3DXToRadian( static_cast<float>( fbxPropD3[0] ) );
		RPreRad.y = D3DXToRadian( static_cast<float>( fbxPropD3[1] ) );
		RPreRad.z = D3DXToRadian( static_cast<float>( fbxPropD3[2] ) );
		CreateRotationMatrix( fbxRotOrder, RPreRad, RPreMat );

		//ジオメトリック行列
		geoMat = localRotMat * RPreMat;
		geoMat = geoMat * invLocalRotMat;
	}
	else if( m_CTM == FBX::CTM_3DS_MAX )
	{
		//3DStudioMax

		FbxVector4 geoT = pFbxNode->GetGeometricTranslation(FbxNode::eSourcePivot);
		FbxVector4 geoR = pFbxNode->GetGeometricRotation(FbxNode::eSourcePivot);
		FbxVector4 geoS = pFbxNode->GetGeometricScaling(FbxNode::eSourcePivot);

		FbxAMatrix fbxGeoMat;
		FbxVector4 r1;
		FbxVector4 r2;
		FbxVector4 r3;
		FbxVector4 r4;

		//ベースになるジオメトリック行列を求める
		fbxGeoMat.SetT( geoT );
		fbxGeoMat.SetR( geoR );
		fbxGeoMat.SetS( geoS );

		//ベースになるジオメトリック行列の行を取得
		r1 = fbxGeoMat.GetRow( 0 );
		r2 = fbxGeoMat.GetRow( 1 );
		r3 = fbxGeoMat.GetRow( 2 );
		r4 = fbxGeoMat.GetRow( 3 );

		//ジオメトリック行列
		geoMat._11 = static_cast<float>( r1.mData[0] );
		geoMat._12 = static_cast<float>( r1.mData[1] );
		geoMat._13 = static_cast<float>( r1.mData[2] );
		geoMat._14 = static_cast<float>( r1.mData[3] );
		geoMat._21 = static_cast<float>( r2.mData[0] );
		geoMat._22 = static_cast<float>( r2.mData[1] );
		geoMat._23 = static_cast<float>( r2.mData[2] );
		geoMat._24 = static_cast<float>( r2.mData[3] );
		geoMat._31 = static_cast<float>( r3.mData[0] );
		geoMat._32 = static_cast<float>( r3.mData[1] );
		geoMat._33 = static_cast<float>( r3.mData[2] );
		geoMat._34 = static_cast<float>( r3.mData[3] );
		geoMat._41 = static_cast<float>( r4.mData[0] );
		geoMat._42 = static_cast<float>( r4.mData[1] );
		geoMat._43 = static_cast<float>( r4.mData[2] );
		geoMat._44 = static_cast<float>( r4.mData[3] );
	}
	else
	{
		D3DXMatrixIdentity( &geoMat );
	}

	return geoMat;
}

D3DXQUATERNION FBX::GetLocalRotation( FbxNode* pFbxNode )
{
#if 0
	FbxRotationOrder fbxRotOrder;
	FbxVector4 fbxVec;
	FbxPropertyDouble3 fbxPropD3;

	D3DXVECTOR3 radR;
	D3DXVECTOR3 radRPre;
	D3DXQUATERNION quat;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 必要なパラメータを初期化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	D3DXQuaternionIdentity( &quat );

	pFbxNode->GetRotationOrder( FbxNode::eSOURCE_SET, fbxRotOrder );

	////////////////////////////////////////////////////////////////////////////////////////////////////

	D3DXMATRIX tempMat;
	D3DXMATRIX localMat;
	D3DXMATRIX invLocalMat;
	D3DXMATRIX rotMat;

	fbxVec = pFbxNode->EvaluateLocalRotation();
	radR.x = D3DXToRadian( static_cast<float>( fbxVec.mData[0] ) );
	radR.y = D3DXToRadian( static_cast<float>( fbxVec.mData[1] ) );
	radR.z = D3DXToRadian( static_cast<float>( fbxVec.mData[2] ) );
	CreateRotationMatrix( fbxRotOrder, radR, localMat );

	fbxPropD3 = pFbxNode->PreRotation;
	radRPre.x = D3DXToRadian( static_cast<float>( fbxPropD3.Get()[0] ) );
	radRPre.y = D3DXToRadian( static_cast<float>( fbxPropD3.Get()[1] ) );
	radRPre.z = D3DXToRadian( static_cast<float>( fbxPropD3.Get()[2] ) );
	CreateRotationMatrix( fbxRotOrder, radRPre, rotMat );

	rotMat = localMat * rotMat;
	D3DXMatrixInverse( &invLocalMat, NULL, &localMat );
	rotMat = rotMat * invLocalMat;

	D3DXQuaternionRotationMatrix( &quat, &rotMat );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// R
	////////////////////////////////////////////////////////////////////////////////////////////////////

	fbxVec = pFbxNode->EvaluateLocalRotation();
	radR.x = D3DXToRadian( static_cast<float>( fbxVec.mData[0] ) );
	radR.y = D3DXToRadian( static_cast<float>( fbxVec.mData[1] ) );
	radR.z = D3DXToRadian( static_cast<float>( fbxVec.mData[2] ) );

	quat = MultiplyRotation( fbxRotOrder, quat, radR );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// RPre
	////////////////////////////////////////////////////////////////////////////////////////////////////
/*
	fbxPropD3 = pFbxNode->PreRotation;
	radRPre.x = D3DXToRadian( static_cast<float>( fbxPropD3.Get()[0] ) );
	radRPre.y = D3DXToRadian( static_cast<float>( fbxPropD3.Get()[1] ) );
	radRPre.z = D3DXToRadian( static_cast<float>( fbxPropD3.Get()[2] ) );

	quat = MultiplyRotation( fbxRotOrder, quat, radRPre );
*/
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノーマライズ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	D3DXQuaternionNormalize( &quat, &quat );

	////////////////////////////////////////////////////////////////////////////////////////////////////

	return quat;

#else

	FbxEuler::EOrder fbxRotOrder;
	FbxVector4 fbxVec;
	D3DXVECTOR3 rad;
	D3DXQUATERNION quat;

	pFbxNode->GetRotationOrder( FbxNode::eSourcePivot, fbxRotOrder );

	fbxVec = pFbxNode->EvaluateLocalRotation();
	rad.x = D3DXToRadian( static_cast<float>( fbxVec.mData[0] ) );
	rad.y = D3DXToRadian( static_cast<float>( fbxVec.mData[1] ) );
	rad.z = D3DXToRadian( static_cast<float>( fbxVec.mData[2] ) );

	if( fbxRotOrder == eSphericXYZ )
	{
		CreateQuaternion( rad, quat );
	}
	else
	{
		D3DXMATRIX rotMat;

		CreateRotationMatrix( fbxRotOrder, rad, rotMat );
		D3DXQuaternionRotationMatrix( &quat, &rotMat );
	}

	return quat;

#endif
}

D3DXVECTOR3 FBX::GetLocalTranslation( FbxNode* pFbxNode )
{
	FbxVector4 fbxTemp;

	fbxTemp = pFbxNode->EvaluateLocalTranslation();

	return D3DXVECTOR3( static_cast<float>( fbxTemp.mData[0] ), static_cast<float>( fbxTemp.mData[1] ), static_cast<float>( fbxTemp.mData[2] ) );
}

D3DXMATRIX FBX::GetLocalMatrix( FbxNode* pFbxNode )
{
	D3DXVECTOR3 ls = GetLocalScale( pFbxNode );
	D3DXQUATERNION lr = GetLocalRotation( pFbxNode );
	D3DXVECTOR3 lt = GetLocalTranslation( pFbxNode );
	D3DXMATRIX tempMat;
	D3DXMATRIX mat;

	//初期化
	D3DXMatrixIdentity( &mat );

	//スケーリング
	D3DXMatrixScaling( &mat, ls.x, ls.y, ls.z );

	//ローテーション
	D3DXMatrixIdentity( &tempMat );
	mat *= *D3DXMatrixRotationQuaternion( &tempMat, &lr );

	//トランスレーション
	D3DXMatrixIdentity( &tempMat );
	mat *= *D3DXMatrixTranslation( &tempMat, lt.x, lt.y, lt.z );

	return mat;
}

D3DXMATRIX FBX::ToD3DXMatrix( const FbxAMatrix& fbxMat )
{
	FbxVector4 r0 = fbxMat.GetRow( 0 );
	FbxVector4 r1 = fbxMat.GetRow( 1 );
	FbxVector4 r2 = fbxMat.GetRow( 2 );
	FbxVector4 r3 = fbxMat.GetRow( 3 );

	D3DXMATRIX mat;

	mat._11 = static_cast<float>( r0.mData[0] );
	mat._12 = static_cast<float>( r0.mData[1] );
	mat._13 = static_cast<float>( r0.mData[2] );
	mat._14 = static_cast<float>( r0.mData[3] );

	mat._21 = static_cast<float>( r1.mData[0] );
	mat._22 = static_cast<float>( r1.mData[1] );
	mat._23 = static_cast<float>( r1.mData[2] );
	mat._24 = static_cast<float>( r1.mData[3] );

	mat._31 = static_cast<float>( r2.mData[0] );
	mat._32 = static_cast<float>( r2.mData[1] );
	mat._33 = static_cast<float>( r2.mData[2] );
	mat._34 = static_cast<float>( r2.mData[3] );

	mat._41 = static_cast<float>( r3.mData[0] );
	mat._42 = static_cast<float>( r3.mData[1] );
	mat._43 = static_cast<float>( r3.mData[2] );
	mat._44 = static_cast<float>( r3.mData[3] );

	return mat;
}

void FBX::CreateQuaternion( const D3DXVECTOR3& rad, D3DXQUATERNION& value )
{
	float u = rad.x * 0.5f;
	float v = rad.y * 0.5f;
	float w = rad.z * 0.5f;
	float su = sinf( u );
	float sv = sinf( v );
	float sw = sinf( w );
	float cu = cosf( u );
	float cv = cosf( v );
	float cw = cosf( w );

	value.x = ( su * cv * cw );
	value.y = ( ( sv * cu ) + ( sw * su ) );
	value.z = ( ( sw * cu ) - ( sv * su ) );
	value.w = ( cu * cv * cw );
}

void FBX::CreateRotationMatrix(FbxEuler::EOrder fbxRotOrder, const D3DXVECTOR3& rad, D3DXMATRIX& value)
{
	D3DXMATRIX rxMat;
	D3DXMATRIX ryMat;
	D3DXMATRIX rzMat;

	D3DXMatrixRotationX( &rxMat, rad.x );
	D3DXMatrixRotationY( &ryMat, rad.y );
	D3DXMatrixRotationZ( &rzMat, rad.z );

	switch( fbxRotOrder )
	{
	case FbxEuler::eOrderXYZ:
		value = rxMat * ryMat * rzMat;
		break;
	case FbxEuler::eOrderXZY:
		value = rxMat * rzMat * ryMat;
		break;
	case FbxEuler::eOrderYZX:
		value = ryMat * rzMat * rxMat;
		break;
	case FbxEuler::eOrderYXZ:
		value = ryMat * rxMat * rzMat;
		break;
	case FbxEuler::eOrderZXY:
		value = rzMat * rxMat * ryMat;
		break;
	case FbxEuler::eOrderZYX:
		value = rzMat * ryMat * rxMat;
		break;
	}
}

Mix::Tool::Win32::Object::TYPE FBX::GetType( void ) const
{
	return Mix::Tool::Win32::Object::GRAPHICS__FBX;
}

}}}}
