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

#include <algorithm>
#include <shlwapi.h>

#include "Mix/Tool/Win32/Core/Path.h"
#include "Mix/Tool/Win32/Core/Directory.h"

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

#include "Mix/Tool/Win32/Core/Dynamics/Factory.h"
#include "Mix/Tool/Win32/Core/Dynamics/BoxShape.h"
#include "Mix/Tool/Win32/Core/Dynamics/CapsuleShape.h"
#include "Mix/Tool/Win32/Core/Dynamics/SphereShape.h"
#include "Mix/Tool/Win32/Core/Dynamics/RigidBody.h"
#include "Mix/Tool/Win32/Core/Dynamics/KinematicCharacter.h"
#include "Mix/Tool/Win32/Core/Dynamics/PointJoint.h"
#include "Mix/Tool/Win32/Core/Dynamics/HingeJoint.h"
#include "Mix/Tool/Win32/Core/Dynamics/BallJoint.h"
#include "Mix/Tool/Win32/Core/Dynamics/Design/Actor.h"
#include "Mix/Tool/Win32/Core/Dynamics/Design/Part.h"

#include "Mix/Tool/Win32/Core/Graphics/Manager.h"
#include "Mix/Tool/Win32/Core/Graphics/Material.h"
#include "Mix/Tool/Win32/Core/Graphics/MotionController.h"
#include "Mix/Tool/Win32/Core/Graphics/Node.h"
#include "Mix/Tool/Win32/Core/Graphics/ObjectMesh.h"
#include "Mix/Tool/Win32/Core/Graphics/Camera.h"

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

const wchar_t* ObjectModel::UNASSIGNED_TEXT = L"未割り当て";
const wchar_t* ObjectModel::DEF_MOTION_CTRL_NAME = L"New";

////////////////////////////////////////////////////////////////////////////////////////////////////
// ObjectModel::MOTION_CTRL_SORT
////////////////////////////////////////////////////////////////////////////////////////////////////

bool ObjectModel::MOTION_CTRL_SORT::operator()( const Mix::Tool::Win32::Graphics::MotionController* l, const Mix::Tool::Win32::Graphics::MotionController* r )
{
	return ( l->GetPriority() > r->GetPriority() );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// ObjectModel
////////////////////////////////////////////////////////////////////////////////////////////////////

ObjectModel::ObjectModel( void ) :
m_Name( L"" ),
m_MotionDirectoryPath( L"" ),
m_Scaling( 1.0f, 1.0f, 1.0f ),
m_Rotation( 0.0f, 0.0f, 0.0f, 1.0f ),
m_Translation( 0.0f, 0.0f, 0.0f ),
m_pUnassignedMotionCtrl( NULL ),
m_pSelectedNode( NULL ),
m_pSelectedMesh( NULL ),
m_RTFlags( Mix::Tool::Win32::Graphics::MOTION_RT_ROTATION | Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION ),
m_RTNodeIndex( 0 ),
m_RTTHoriz( MOTION_RT_H_XZ ),
m_RTTVert( MOTION_RT_V_Y ),
m_pDynamicsActorDesigner( NULL )
{
	m_pUnassignedMotionCtrl = new Mix::Tool::Win32::Graphics::MotionController( ObjectModel::UNASSIGNED_TEXT );
	m_pUnassignedMotionCtrl->SetObjectModel( this );

	m_pDynamicsActorDesigner = Mix::Tool::Win32::Dynamics::Factory::CreateActor();

	D3DXMatrixIdentity( &m_PivotMat );
	D3DXMatrixIdentity( &m_InvPivotMat );
}

ObjectModel::~ObjectModel( void )
{
	if( m_MeshList.size() > 0 )
	{
		for( MeshList::iterator it = m_MeshList.begin(); it != m_MeshList.end(); ++it )
		{
			MIX_DELETE( ( *it ) );
		}

		m_MeshList.clear();
	}

	if( m_NodeList.size() > 0 )
	{
		for( ObjectModel::NodeList::iterator it = m_NodeList.begin(); it != m_NodeList.end(); ++it )
		{
			MIX_DELETE( ( *it ) );
		}

		m_NodeList.clear();
	}

	m_NodeIndexMap.clear();

	if( m_MotionCtrlList.size() > 0 )
	{
		for( ObjectModel::MotionControllerList::iterator it = m_MotionCtrlList.begin(); it != m_MotionCtrlList.end(); ++it )
		{
			MIX_DELETE( ( *it ) );
		}

		m_MotionCtrlList.clear();
	}

	MIX_DELETE( m_pUnassignedMotionCtrl );
	MIX_DELETE( m_pDynamicsActorDesigner );
}

bool ObjectModel::Import( const ObjectModel::IMPORT_CONFIG& cfg )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 変数宣言
	////////////////////////////////////////////////////////////////////////////////////////////////////

	static const FbxTime::EMode TIME_MODE_TABLE[2] =
	{
		FbxTime::eFrames30,
		FbxTime::eFrames60,
	};

	FBX fbx;
	FBX::COMPUTING_TRANSFORMATION_MATRIX fbxCTM;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 開始
	////////////////////////////////////////////////////////////////////////////////////////////////////

	LogPrint( LT_INFO, L"----------------------------------------------------------------------------------------------------" );
	LogPrint( LT_INFO, L"  オブジェクトモデルの作成 : Source[FBX] FilePath[%s]", cfg.pFilePath );
	LogPrint( LT_INFO, L"" );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 名前を取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( Mix::Tool::Win32::Path::GetFileNameWithoutExtension( cfg.pFilePath, m_Name ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// FBXを読み込む
	////////////////////////////////////////////////////////////////////////////////////////////////////

	switch( cfg.opt )
	{
	case Mix::Tool::Win32::Graphics::Model::IO_FBX_MAYA:
		fbxCTM = FBX::CTM_MAYA;
		break;
	case Mix::Tool::Win32::Graphics::Model::IO_FBX_3D_STUDIO_MAX:
		fbxCTM = FBX::CTM_3DS_MAX;
		break;
	default:
		fbxCTM = FBX::CTM_MAYA;
		break;
	}

	if( fbx.Load( cfg.pFilePath, fbxCTM, this ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ピボット行列
	////////////////////////////////////////////////////////////////////////////////////////////////////

	D3DXMATRIX tempMat;
	D3DXMATRIX rotMat;

	/*
		スケーリング
	*/

	m_Scaling.x = cfg.scaling;
	m_Scaling.y = cfg.scaling;
	m_Scaling.z = cfg.scaling;

	/*
		ローテーション
	*/

	D3DXMatrixIdentity( &tempMat );
	D3DXMatrixIdentity( &rotMat );

	rotMat *= *D3DXMatrixRotationX( &tempMat, D3DXToRadian( cfg.rotation.x ) );
	rotMat *= *D3DXMatrixRotationY( &tempMat, D3DXToRadian( cfg.rotation.y ) );
	rotMat *= *D3DXMatrixRotationZ( &tempMat, D3DXToRadian( cfg.rotation.z ) );

	D3DXQuaternionRotationMatrix( &m_Rotation, &rotMat );

	/*
		トランスレーション
	*/

	m_Translation = cfg.translation;

	/*
		トランスフォーム
	*/

	const D3DXVECTOR3& pivotScale = fbx.GetPivotScale();

	D3DXMatrixIdentity( &tempMat );
	D3DXMatrixIdentity( &m_PivotMat );

	D3DXMatrixScaling( &m_PivotMat, pivotScale.x * cfg.scaling, pivotScale.y * cfg.scaling, pivotScale.z * cfg.scaling );

	m_PivotMat *= *D3DXMatrixRotationX( &tempMat, D3DXToRadian( cfg.rotation.x ) );
	m_PivotMat *= *D3DXMatrixRotationY( &tempMat, D3DXToRadian( cfg.rotation.y ) );
	m_PivotMat *= *D3DXMatrixRotationZ( &tempMat, D3DXToRadian( cfg.rotation.z ) );

	m_PivotMat._41 = cfg.translation.x;
	m_PivotMat._42 = cfg.translation.y;
	m_PivotMat._43 = cfg.translation.z;
	m_PivotMat._44 = 1.0f;

	D3DXMatrixInverse( &m_InvPivotMat, NULL, &m_PivotMat );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノードを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( FBX_LoadNode( fbx, fbx.GetRootNode(), NULL, cfg ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーションを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( fbx.LoadMotion( TIME_MODE_TABLE[cfg.motionTimeMode], m_pUnassignedMotionCtrl ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 最適化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( Optimize( cfg, fbx.IsInvertZ() ) == false )
	{
		return false;
	}

	return true;
}

bool ObjectModel::ImportFinalize( void )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアルを作成( 次の最適化でリフレッシュされるので、描画オブジェクトには通知しない )
	////////////////////////////////////////////////////////////////////////////////////////////////////

	DrawObject::UpdateAllMaterialSlot();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( ObjectModel::MeshList::iterator it = m_MeshList.begin(); it != m_MeshList.end(); ++it )
	{
		Mix::Tool::Win32::Graphics::ObjectMesh* pMesh = ( *it );

		if( pMesh->RefreshBuffer() == false )
		{
			return false;
		}
	}

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

	return true;
}

const wchar_t* ObjectModel::GetName( void ) const
{
	return m_Name.c_str();
}

Mix::Tool::Win32::Graphics::Node* ObjectModel::GetRootNode( void )
{
	if( m_NodeList.size() == 0 )
	{
		return NULL;
	}

	return m_NodeList[0];
}

void ObjectModel::SelectedMeshByKey( unsigned int key )
{
	if( ( key > 0 ) &&
		( m_MeshList.size() >= key ) )
	{
		m_pSelectedMesh = m_MeshList[key - 1];
		m_pSelectedNode = m_pSelectedMesh->GetLinkNodePtr();
	}
	else
	{
		m_pSelectedNode = NULL;
		m_pSelectedMesh = NULL;
	}
}

void ObjectModel::SelectedNode( Mix::Tool::Win32::Graphics::Node* pNode )
{
	m_pSelectedNode = pNode;

	if( m_pSelectedNode != NULL )
	{
		if( m_pSelectedNode->GetAttribute() == Node::MESH )
		{
			m_pSelectedMesh = static_cast<Mix::Tool::Win32::Graphics::ObjectMesh*>( m_pSelectedNode->GetMeshPtr() );
		}
		else
		{
			m_pSelectedMesh = NULL;
		}
	}
	else
	{
		m_pSelectedMesh = NULL;
	}
}

bool ObjectModel::SaveModel( void )
{
	const wchar_t* pFilePath = Model::GetModelFilePath();

	LogPrint( LT_INFO, L"----------------------------------------------------------------------------------------------------" );
	LogPrint( LT_INFO, L"  アクターモデルの保存 : FilePath[%s]", ( pFilePath != NULL )? pFilePath : L"" );
	LogPrint( LT_INFO, L"" );

	if( Model::IsAvailableSaveModel() == false )
	{
		LogPrint( LT_ERROR, L"  ファイルパスが設定されていません" );
		return false;
	}

	Mix::Tool::Win32::File::OutputStream output;

	std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int> dynColliderMap;

	std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0> dynColliderShapeList;
	std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0> dynSensorShapeList;
	std::vector<Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0> dynColliderList;
	std::vector<Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0> dynSensorList;
	std::vector<Mix::Tool::Win32::Graphics::MAM_JOINT_1_0_0_0> dynJointList;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイナミクス : 保存する情報を収集
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ObjectModel::SaveModel_CollectDynamics( this,
												dynColliderShapeList,
												dynSensorShapeList,
												dynColliderList,
												dynColliderMap,
												dynSensorList,
												dynJointList ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 中間ログ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	LogPrint( LT_INFO, L"  マテリアル[%d]", GetMaterialSlotCount() );
	LogPrint( LT_INFO, L"  メッシュ[%d]", m_MeshList.size() );
	LogPrint( LT_INFO, L"  モーションコントローラー[%d]", m_MotionCtrlList.size() );
	LogPrint( LT_INFO, L"  キネマティックキャラクター[%s]", ( m_pDynamicsActorDesigner->KinematicCharacter_Get() != NULL )? L"True" : L"False" );
	LogPrint( LT_INFO, L"  シェイプ(コライダー)[%d]", dynColliderShapeList.size() );
	LogPrint( LT_INFO, L"  シェイプ(センサー)[%d]", dynSensorShapeList.size() );
	LogPrint( LT_INFO, L"  コライダー[%d]", dynColliderList.size() );
	LogPrint( LT_INFO, L"  センサー[%d]", dynSensorList.size() );
	LogPrint( LT_INFO, L"  ジョイント[%d]", dynJointList.size() );
	LogPrint( LT_INFO, L"  メインフレーム[True]" );
	LogPrint( LT_INFO, L"  ノード[%d]", m_NodeList.size() );

#if 0
	const D3DXMATRIX& rmMat = m_pDynamicsActorDesigner->GetReceiveMotionMatrix();

	LogPrint( LT_INFO, L"  ReceiveMotionMatrix" );
	LogPrint( LT_INFO, L"  {" );
	LogPrint( LT_INFO, L"    %f %f %f %f", rmMat._11, rmMat._12, rmMat._13, rmMat._14 );
	LogPrint( LT_INFO, L"    %f %f %f %f", rmMat._21, rmMat._22, rmMat._23, rmMat._24 );
	LogPrint( LT_INFO, L"    %f %f %f %f", rmMat._31, rmMat._32, rmMat._33, rmMat._34 );
	LogPrint( LT_INFO, L"    %f %f %f %f", rmMat._41, rmMat._42, rmMat._43, rmMat._44 );
	LogPrint( LT_INFO, L"  }" );
#endif


	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ファイルを開く
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( Directory::Create( pFilePath, true ) == false )
	{
		LogPrint( LT_ERROR, L"  ディレクトリの作成中にエラーが発生しました" );
		return false;
	}

	if( output.Open( pFilePath ) == false )
	{
		LogPrint( LT_ERROR, L"  ファイルの作成中にエラーが発生しました" );
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ファイルヘッダ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	{
		MAM_FILE_HEADER_1_0_0_0 fileHeader;

		fileHeader.magicNumber = MAM_MAGICNUMBER;
		fileHeader.version = MAM_VERSION;

		if( output.Write( &fileHeader, sizeof( fileHeader ) ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( ファイルヘッダ )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// データヘッダ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	{
		MAM_DATA_HEADER_1_0_0_0 dataHeader;

		dataHeader.materialNum = GetMaterialSlotCount();
		dataHeader.meshNum = m_MeshList.size();
		dataHeader.motionControllerNum = m_MotionCtrlList.size();
		dataHeader.kinematicCharacterNum = ( m_pDynamicsActorDesigner->KinematicCharacter_Get() != NULL )? 1 : 0;
		dataHeader.shapeNum = dynColliderShapeList.size() + dynSensorShapeList.size();
		dataHeader.colliderNum = dynColliderList.size();
		dataHeader.sensorNum = dynSensorList.size();
		dataHeader.jointNum = dynJointList.size();
		dataHeader.mainFrameNum = 1;
		dataHeader.nodeNum = m_NodeList.size();

		if( output.Write( &dataHeader, sizeof( dataHeader ) ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( データヘッダ )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアル
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( DrawObject::WriteAllMaterials( pFilePath, output ) == false )
	{
		LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( マテリアル )" );
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( ObjectModel::MeshList::iterator it = m_MeshList.begin(); it != m_MeshList.end(); ++it )
	{
		if( ( *it )->Write( output ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( メッシュ )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーションコントローラー
	////////////////////////////////////////////////////////////////////////////////////////////////////

	{
		ObjectModel::MotionControllerList::iterator it_begin = m_MotionCtrlList.begin();
		ObjectModel::MotionControllerList::iterator it_end = m_MotionCtrlList.end();
		ObjectModel::MotionControllerList::iterator it;

		for( it = it_begin; it != it_end; ++it )
		{
			Mix::Tool::Win32::Graphics::MotionController* pMotionCtrl = ( *it );

			if( pMotionCtrl->WriteDefault( pFilePath, output ) == false )
			{
				LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( モーションコントローラー )" );
				return false;
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// キネマティックキャラクター
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pDynamicsActorDesigner->KinematicCharacter_Get() != NULL )
	{
		Mix::Tool::Win32::Dynamics::KinematicCharacter* src = m_pDynamicsActorDesigner->KinematicCharacter_Get();

		MAM_KINEMATIC_CHARACTER_1_0_0_0 dst;

		CopyMemory( &( dst.loadMat[0][0] ), &( m_pDynamicsActorDesigner->KinematicCharacter_GetLoadMatrix().m[0][0] ), sizeof( float[4][4] ) );
		CopyMemory( &( dst.storeMat[0][0] ), &( m_pDynamicsActorDesigner->KinematicCharacter_GetStoreMatrix().m[0][0] ), sizeof( float[4][4] ) );

		dst.height = src->GetHeight();
		dst.radius = src->GetRadius();

		dst.garvity = src->GetGravity();
		dst.maxFallSpeed = src->GetMaxFallSpeed();
		dst.initJumpSpeed = src->GetInitJumpSpeed();

		dst.stepHeight = src->GetStepOffset();
		dst.slopeLimit = src->GetSlopeLimit();

		dst.reserve = 0;

		if( output.Write( &dst, sizeof( dst ) ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( キネマティックキャラクター )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// シェイプ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( dynColliderShapeList.size() > 0 )
	{
		if( output.Write( &( dynColliderShapeList[0] ), sizeof( Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0 ) * dynColliderShapeList.size() ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( コライダーシェイプ )" );
			return false;
		}
	}

	if( dynSensorShapeList.size() > 0 )
	{
		if( output.Write( &( dynSensorShapeList[0] ), sizeof( Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0 ) * dynSensorShapeList.size() ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( センサーシェイプ )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// コライダー
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( dynColliderList.size() > 0 )
	{
		if( output.Write( &( dynColliderList[0] ), sizeof( Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0 ) * dynColliderList.size() ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( コライダー )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// センサー
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( dynSensorList.size() > 0 )
	{
		if( output.Write( &( dynSensorList[0] ), sizeof( Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0 ) * dynSensorList.size() ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( センサー )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ジョイント
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( dynJointList.size() > 0 )
	{
		if( output.Write( &( dynJointList[0] ), sizeof( Mix::Tool::Win32::Graphics::MAM_JOINT_1_0_0_0 ) * dynJointList.size() ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( ジョイント )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メインフレーム
	////////////////////////////////////////////////////////////////////////////////////////////////////

	{
		MAM_MAINFRAME_1_0_0_0 mainFrame;

		/*
			ピボット
		*/

		mainFrame.scaling[0] = m_Scaling.x; 
		mainFrame.scaling[1] = m_Scaling.y;
		mainFrame.scaling[2] = m_Scaling.z;
		mainFrame.scaling[3] = 1.0f;

		mainFrame.rotation[0] = m_Rotation.x;
		mainFrame.rotation[1] = m_Rotation.y;
		mainFrame.rotation[2] = m_Rotation.z;
		mainFrame.rotation[3] = m_Rotation.w;

		mainFrame.translation[0] = m_Translation.x;
		mainFrame.translation[1] = m_Translation.y;
		mainFrame.translation[2] = m_Translation.z;
		mainFrame.translation[3] = 1.0f;

		/*
			ダイナミクス
		*/

		if( m_pDynamicsActorDesigner->GetCoordinateSystem() == Mix::Tool::Win32::Dynamics::Design::Basic::LEFT_HANDED )
		{
			mainFrame.coordinateSystem = MAM_CS_LH;
		}
		else
		{
			mainFrame.coordinateSystem = MAM_CS_RH;
		}

		mainFrame.colliderNum = ( m_pDynamicsActorDesigner->Collider_IsAvailable() == true )? 1 : 0;
		mainFrame.sensorNum = m_pDynamicsActorDesigner->Sensor_CountAvailable();

		CopyMemory( &( mainFrame.receiveMotionMatrix[0][0] ), &( m_pDynamicsActorDesigner->GetReceiveMotionMatrix().m[0][0] ), sizeof( float[4][4] ) );

		/*
			その他
		*/

		mainFrame.reserve = 0;

		/*
			書き込み
		*/

		if( output.Write( &mainFrame, sizeof( mainFrame ) ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( メインフレーム )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノード
	////////////////////////////////////////////////////////////////////////////////////////////////////

	{
		ObjectModel::NodeList::iterator it_begin = m_NodeList.begin();
		ObjectModel::NodeList::iterator it_end = m_NodeList.end();
		ObjectModel::NodeList::iterator it;

		std::vector<MAM_NODE_1_0_0_0> dstNodeList;

		dstNodeList.reserve( m_NodeList.size() );

		for( it = it_begin; it != it_end; ++it )
		{
			const Mix::Tool::Win32::Graphics::Node* src = ( *it );
			const Mix::Tool::Win32::Dynamics::Design::Part* dynSrc = src->GetDynamicsPartDesignerPtr();

			const D3DXVECTOR3& geometricS = src->GetGeometricScaling();
			const D3DXQUATERNION& geometricR = src->GetGeometricRotation();
			const D3DXVECTOR3& geometricT = src->GetGeometricTranslation();

			const D3DXVECTOR3& defLocalS = src->GetDefLocalScaling();
			const D3DXQUATERNION& defLocalR = src->GetDefLocalRotation();
			const D3DXVECTOR3& defLocalT = src->GetDefLocalTranslation();

			MAM_NODE_1_0_0_0 dst;

			//名前
			if( ::wcslen( src->GetName() ) < MAX_NAME_SIZE )
			{
				::wcscpy_s( dst.name, sizeof( dst.name ) >> 1, src->GetName() );
			}
			else
			{
				LogPrint( LT_ERROR, L"  ノードの名前は%d文字以下にしてください : Node[%d]", _MAX_NAME_SIZE, src->GetName() );
				return false;
			}

			//ジオトリックトランスフォーム
			dst.geometricS[0] = geometricS.x; dst.geometricS[1] = geometricS.y; dst.geometricS[2] = geometricS.z; dst.geometricS[3] = 1.0f;
			dst.geometricR[0] = geometricR.x; dst.geometricR[1] = geometricR.y; dst.geometricR[2] = geometricR.z; dst.geometricR[3] = geometricR.w;
			dst.geometricT[0] = geometricT.x; dst.geometricT[1] = geometricT.y; dst.geometricT[2] = geometricT.z; dst.geometricT[3] = 1.0f;

			//ローカルトランスフォーム
			dst.localS[0] = defLocalS.x; dst.localS[1] = defLocalS.y; dst.localS[2] = defLocalS.z; dst.localS[3] = 1.0f;
			dst.localR[0] = defLocalR.x; dst.localR[1] = defLocalR.y; dst.localR[2] = defLocalR.z; dst.localR[3] = defLocalR.w;
			dst.localT[0] = defLocalT.x; dst.localT[1] = defLocalT.y; dst.localT[2] = defLocalT.z; dst.localT[3] = 0.0f;

			//メッシュインデックス
			dst.meshIndex = src->GetMeshIndex();

			//ダイナミクス
			dst.colliderNum = ( dynSrc->Collider_IsAvailable() == true )? 1 : 0;
			dst.sensorNum = dynSrc->Sensor_CountAvailable();
			dst.jointNum = ( dynSrc->Joint_Get() != NULL )? 1 : 0;

			//親子
			dst.parent = ( src->GetParentPtr() != NULL )? src->GetParentPtr()->GetIndex() : -1;
			dst.childCount = src->GetChildCount();

			dstNodeList.push_back( dst );
		}

		if( output.Write( &( dstNodeList[0] ), sizeof( MAM_NODE_1_0_0_0 ) * dstNodeList.size() ) == false )
		{
			LogPrint( LT_ERROR, L"  書き込み中にエラーが発生しました( ノード )" );
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ファイルを閉じる
	////////////////////////////////////////////////////////////////////////////////////////////////////

	output.Close();

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

	return true;
}

bool ObjectModel::SaveModel_CollectDynamics(	Mix::Tool::Win32::Graphics::ObjectModel* pModel,
												std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& colliderShapeList,
												std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& sensorShapeList,
												std::vector<Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0>& colliderList,
												std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>& colliderMap,
												std::vector<Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0>& sensorList,
												std::vector<Mix::Tool::Win32::Graphics::MAM_JOINT_1_0_0_0>& jointList )
{
	Mix::Tool::Win32::Graphics::Node* pRootNode = pModel->GetRootNode();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 収集
	////////////////////////////////////////////////////////////////////////////////////////////////////

	ObjectModel::SaveModel_CollectDynamics_Basic(	pModel->m_Name.c_str(),
													pModel->GetDynamicsActorDesignerPtr(),
													colliderShapeList,
													sensorShapeList,
													colliderList,
													colliderMap,
													sensorList );

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

	if( pRootNode != NULL )
	{
		if( ObjectModel::SaveModel_CollectDynamics( pRootNode,
													colliderShapeList,
													sensorShapeList,
													colliderList,
													colliderMap,
													sensorList,
													jointList ) == false )
		{
			return false;
		}
	}

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

	return true;
}

bool ObjectModel::SaveModel_CollectDynamics(	Mix::Tool::Win32::Graphics::Node* pNode,
												std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& colliderShapeList,
												std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& sensorShapeList,
												std::vector<Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0>& colliderList,
												std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>& colliderMap,
												std::vector<Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0>& sensorList,
												std::vector<Mix::Tool::Win32::Graphics::MAM_JOINT_1_0_0_0>& jointList )
{
	int childCount = pNode->GetChildCount();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 収集
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ObjectModel::SaveModel_CollectDynamics_Basic(	pNode->GetName(),
														pNode->GetDynamicsPartDesignerPtr(),
														colliderShapeList,
														sensorShapeList,
														colliderList,
														colliderMap,
														sensorList ) == false )
	{
		return false;
	}

	if( ObjectModel::SaveModel_CollectDynamics_Part(	pNode->GetName(),
														pNode->GetDynamicsPartDesignerPtr(),
														colliderMap,
														jointList ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 子を処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( int i = 0; i < childCount; i++ )
	{
		Mix::Tool::Win32::Graphics::Node* pChildNode = pNode->GetChildPtr( i );

		if( ObjectModel::SaveModel_CollectDynamics(	pChildNode,
													colliderShapeList,
													sensorShapeList,
													colliderList,
													colliderMap,
													sensorList,
													jointList ) == false )
		{
			return false;
		}
	}

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

	return true;
}

bool ObjectModel::SaveModel_CollectDynamics_Basic(	const wchar_t* pNodeName,
													Mix::Tool::Win32::Dynamics::Design::Basic* pBasic,
													std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& colliderShapeList,
													std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& sensorShapeList,
													std::vector<Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0>& colliderList,
													std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>& colliderMap,
													std::vector<Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0>& sensorList )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// コライダー
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pBasic->Collider_IsAvailable() == true )
	{
		const Mix::Tool::Win32::Dynamics::Design::Basic::OBJECT* pObj = pBasic->Collider_GetPtr();
		if( Mix::Tool::Win32::Graphics::MAX_NAME_SIZE <= pObj->name.size() )
		{
			//文字数多すぎ
			unsigned int maxNameSize = Mix::Tool::Win32::Graphics::MAX_NAME_SIZE - 1;
			LogPrint( LT_ERROR, L"  コライダーの名前は、%d文字以下にしてください : Node[%s] Collider[%s]", maxNameSize, pNodeName, pObj->name.c_str());
			return false;
		}

		const Mix::Tool::Win32::Dynamics::RigidBody* pRigidBody = pObj->pRigidBody;
		const Mix::Tool::Win32::Dynamics::MATERIAL& rbMaterial = pRigidBody->GetMaterial();
		int shapeCount = pRigidBody->GetShapeHandleCount();

		/*
			シェイプ
		*/

		if( SaveModel_CollectDynamics_Shapes( pNodeName, L"Collider", pObj->name.c_str(), pObj, colliderShapeList ) == false )
		{
			return false;
		}

		/*
			パラメータ
		*/

		Mix::Tool::Win32::Graphics::MAM_COLLIDER_1_0_0_0 mamCollider;

		//名前
		::wcscpy_s( mamCollider.name, Mix::Tool::Win32::Graphics::MAX_NAME_SIZE, pObj->name.c_str() );

		//シェイプ数
		mamCollider.shapeNum = static_cast<unsigned int>( shapeCount );

		//物理マテリアル
		mamCollider.id = rbMaterial.id;
		mamCollider.attr = rbMaterial.attr;
		mamCollider.friction = rbMaterial.friction;
		mamCollider.restitution = rbMaterial.restitution;

		//ステータス
		switch( pObj->colliderType )
		{
		case Mix::Tool::Win32::Dynamics::Design::Basic::DEFAULT:
			mamCollider.status = Mix::Tool::Win32::Graphics::MAM_CS_DEFAULT;
			break;
		case Mix::Tool::Win32::Dynamics::Design::Basic::STATIC:
			mamCollider.status = Mix::Tool::Win32::Graphics::MAM_CS_STATIC;
			break;
		case Mix::Tool::Win32::Dynamics::Design::Basic::KINEMATIC:
			mamCollider.status = Mix::Tool::Win32::Graphics::MAM_CS_KINEMATIC;
			break;

		default:
			return false;
		}

		//質量
		if( pObj->colliderType != Mix::Tool::Win32::Dynamics::Design::Basic::STATIC )
		{
			mamCollider.mass = pRigidBody->GetMass();
		}
		else
		{
			mamCollider.mass = 0.0f;
		}

		//フラグ
		if( pObj->colliderType != Mix::Tool::Win32::Dynamics::Design::Basic::STATIC )
		{
			mamCollider.flags = 0;

			if( MIX_TEST_BIT( pObj->rotAxisFlags, Mix::Tool::Win32::Dynamics::Design::Basic::RA_X ) == Mix::Tool::Win32::Dynamics::Design::Basic::RA_X ) { mamCollider.flags |= Mix::Tool::Win32::Graphics::MAM_CF_ROT_X; }
			if( MIX_TEST_BIT( pObj->rotAxisFlags, Mix::Tool::Win32::Dynamics::Design::Basic::RA_Y ) == Mix::Tool::Win32::Dynamics::Design::Basic::RA_Y ) { mamCollider.flags |= Mix::Tool::Win32::Graphics::MAM_CF_ROT_Y; }
			if( MIX_TEST_BIT( pObj->rotAxisFlags, Mix::Tool::Win32::Dynamics::Design::Basic::RA_Z ) == Mix::Tool::Win32::Dynamics::Design::Basic::RA_Z ) { mamCollider.flags |= Mix::Tool::Win32::Graphics::MAM_CF_ROT_Z; }

			if( pRigidBody->GetAlwaysActive() == true ) { mamCollider.flags |= Mix::Tool::Win32::Graphics::MAM_CF_ALWAYS_ACTIVE; }

			if( pBasic->Collider_IsCastMotion() == true ) { mamCollider.flags |= Mix::Tool::Win32::Graphics::MAM_CF_CAST_MOTION; }
		}
		else
		{
			mamCollider.flags = 0;
		}

/*		if( shapeCount == 1 )
		{
			//一つの場合は再計算
			const Mix::Tool::Win32::Dynamics::Design::Basic::SHAPE* pShape = &( pObj->shapeMap.begin()->second );

			D3DXMATRIX centerMat;
			D3DXMATRIX restoreMat;
			D3DXQUATERNION rot;
			D3DXVECTOR3 pos;

			pBasic->Utility_ComputeSimpleTransform( pShape->rot, pShape->pos, centerMat, restoreMat, rot, pos );

			::CopyMemory( &( mamCollider.centerMatrix[0][0] ), &( centerMat.m[0][0] ), sizeof( float[4][4] ) );
			::CopyMemory( &( mamCollider.restoreMatrix[0][0] ), &( restoreMat.m[0][0] ), sizeof( float[4][4] ) );

			mamCollider.rotation[0] = rot.x;
			mamCollider.rotation[1] = rot.y;
			mamCollider.rotation[2] = rot.z;
			mamCollider.rotation[3] = rot.w;

			mamCollider.position[0] = pos.x;
			mamCollider.position[1] = pos.y;
			mamCollider.position[2] = pos.z;
			mamCollider.position[3] = 1.0f;
		}
		else
*/		{
			//複数の場合はそのまま使用( コンパウンド )
			const D3DXQUATERNION& rot = pObj->initalColliderRot;
			const D3DXVECTOR3& pos = pObj->initalColliderPos;

			::CopyMemory( &( mamCollider.centerMatrix[0][0] ), &( pObj->centerMat.m[0][0] ), sizeof( float[4][4] ) );
			::CopyMemory( &( mamCollider.restoreMatrix[0][0] ), &( pObj->restoreMat.m[0][0] ), sizeof( float[4][4] ) );

			mamCollider.rotation[0] = rot.x;
			mamCollider.rotation[1] = rot.y;
			mamCollider.rotation[2] = rot.z;
			mamCollider.rotation[3] = rot.w;

			mamCollider.position[0] = pos.x;
			mamCollider.position[1] = pos.y;
			mamCollider.position[2] = pos.z;
			mamCollider.position[3] = 1.0f;
		}

		colliderMap.insert( std::pair<const Mix::Tool::Win32::Dynamics::RigidBody*, int>( pRigidBody, static_cast<int>( colliderList.size() ) ) );
		colliderList.push_back( mamCollider );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// センサー
	////////////////////////////////////////////////////////////////////////////////////////////////////

	int sensorCount = pBasic->Sensor_GetCount();

	for( int i = 0; i < sensorCount; i++ )
	{
		if( pBasic->Sensor_IsAvailale( i ) == true )
		{
			const Mix::Tool::Win32::Dynamics::Design::Basic::OBJECT* pObj = pBasic->Sensor_GetPtr( i );
			if( Mix::Tool::Win32::Graphics::MAX_NAME_SIZE <= pObj->name.size() )
			{
				unsigned int maxNameSize = Mix::Tool::Win32::Graphics::MAX_NAME_SIZE - 1;
				LogPrint( LT_ERROR, L"  センサーの名前は、%d文字以下にしてください : Node[%s] Sensor[%s]", maxNameSize, pNodeName, pObj->name.c_str() );
				return false;
			}

			const Mix::Tool::Win32::Dynamics::RigidBody* pRigidBody = pObj->pRigidBody;
			const Mix::Tool::Win32::Dynamics::MATERIAL& rbMaterial = pRigidBody->GetMaterial();
			int shapeCount = pRigidBody->GetShapeHandleCount();

			/*
				シェイプ
			*/

			if( SaveModel_CollectDynamics_Shapes( pNodeName, L"Sensor", pObj->name.c_str(), pObj, sensorShapeList ) == false )
			{
				return false;
			}

			/*
				パラメータ
			*/

			Mix::Tool::Win32::Graphics::MAM_SENSOR_1_0_0_0 mamSensor;

			::wcscpy_s( mamSensor.name, Mix::Tool::Win32::Graphics::MAX_NAME_SIZE, pObj->name.c_str() );
			mamSensor.shapeNum = static_cast<unsigned int>( shapeCount );
			mamSensor.id = rbMaterial.id;
			mamSensor.attr = rbMaterial.attr;
			mamSensor.reserve = 0;

			if( shapeCount == 1 )
			{
				//一つの場合は再計算
				const Mix::Tool::Win32::Dynamics::Design::Basic::SHAPE* pShape = &( pObj->shapeMap.begin()->second );

				D3DXMATRIX centerMat;
				D3DXMATRIX restoreMat;
				D3DXQUATERNION rot;
				D3DXVECTOR3 pos;

				pBasic->Utility_ComputeSimpleTransform( pShape->rot, pShape->pos, centerMat, restoreMat, rot, pos );

				::CopyMemory( &( mamSensor.centerMatrix[0][0] ), &( centerMat.m[0][0] ), sizeof( float[4][4] ) );

				mamSensor.rotation[0] = rot.x;
				mamSensor.rotation[1] = rot.y;
				mamSensor.rotation[2] = rot.z;
				mamSensor.rotation[3] = rot.w;

				mamSensor.position[0] = pos.x;
				mamSensor.position[1] = pos.y;
				mamSensor.position[2] = pos.z;
				mamSensor.position[3] = 1.0f;
			}
			else
			{
				//複数の場合はそのまま使用( コンパウンド )
				const D3DXQUATERNION& rot = pObj->initalColliderRot;
				const D3DXVECTOR3& pos = pObj->initalColliderPos;

				::CopyMemory( &( mamSensor.centerMatrix[0][0] ), &( pObj->centerMat.m[0][0] ), sizeof( float[4][4] ) );

				mamSensor.rotation[0] = rot.x;
				mamSensor.rotation[1] = rot.y;
				mamSensor.rotation[2] = rot.z;
				mamSensor.rotation[3] = rot.w;

				mamSensor.position[0] = pos.x;
				mamSensor.position[1] = pos.y;
				mamSensor.position[2] = pos.z;
				mamSensor.position[3] = 1.0f;
			}

			sensorList.push_back( mamSensor );
		}
	}

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

	return true;
}

bool ObjectModel::SaveModel_CollectDynamics_Shapes(	const wchar_t* pNodeName,
													const wchar_t* pRigidBodyType,
													const wchar_t* pRigidBodyName,
													const void* pSrc,
													std::vector<Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0>& shapeList )
{
	const Mix::Tool::Win32::Dynamics::Design::Basic::OBJECT* pObj = static_cast<const Mix::Tool::Win32::Dynamics::Design::Basic::OBJECT*>( pSrc );
	const Mix::Tool::Win32::Dynamics::RigidBody* pRigidBody = pObj->pRigidBody;
	int shapeCount = pObj->pRigidBody->GetShapeHandleCount();
	bool bCompound = ( pObj->type == Mix::Tool::Win32::Dynamics::Design::Basic::COLLIDER ) || ( shapeCount > 1 );

	for( int i = 0; i < shapeCount; i++ )
	{
		HANDLE hShape = pRigidBody->GetShapeHandle( i );
		Mix::Tool::Win32::Dynamics::Shape* pShape = pRigidBody->GetShape( hShape );
		Mix::Tool::Win32::Object::TYPE objType = pShape->GetType();

		Mix::Tool::Win32::Graphics::MAM_SHAPE_1_0_0_0 mamShape;

		/*
			初期化
		*/

		ZeroMemory( &mamShape, sizeof( mamShape ) );

		/*
			トランスフォーム
		*/

		if( bCompound == true )
		{
			//コンパウンドシェイプの場合はそのまま使用
			D3DXQUATERNION rot;
			D3DXVECTOR3 pos;

			if( pRigidBody->GetShapeRotation( hShape, rot ) == false )
			{
				LogPrint( LT_ERROR, L"  RigidBody::GetShapeRotation がエラーを返しました : Node[%s] %s[%s]", pNodeName, pRigidBodyType, pRigidBodyName );
				return false;
			}

			if( pRigidBody->GetShapePosition( hShape, pos ) == false )
			{
				LogPrint( LT_ERROR, L"  RigidBody::GetShapePosition がエラーを返しました : Node[%s] %s[%s]", pNodeName, pRigidBodyType, pRigidBodyName );
				return false;
			}

			mamShape.localRotation[0] = rot.x;
			mamShape.localRotation[1] = rot.y;
			mamShape.localRotation[2] = rot.z;
			mamShape.localRotation[3] = rot.w;

			mamShape.localPosition[0] = pos.x;
			mamShape.localPosition[1] = pos.y;
			mamShape.localPosition[2] = pos.z;
			mamShape.localPosition[3] = 1.0f;
		}
		else
		{
			//一つの場合は、リジッドボディでトランスフォームするので、初期値にしておく( 使用はしない )
			mamShape.localRotation[0] = 0.0f;
			mamShape.localRotation[1] = 0.0f;
			mamShape.localRotation[2] = 0.0f;
			mamShape.localRotation[3] = 1.0f;

			mamShape.localPosition[0] = 0.0f;
			mamShape.localPosition[1] = 0.0f;
			mamShape.localPosition[2] = 0.0f;
			mamShape.localPosition[3] = 1.0f;
		}

		/*
			固有パラメータ
		*/

		if( objType == Mix::Tool::Win32::Object::DYNAMICS__BOX_SHAPE )
		{
			//ボックスシェイプ
			const Mix::Tool::Win32::Dynamics::BoxShape* pBoxShape = static_cast<const Mix::Tool::Win32::Dynamics::BoxShape*>( pShape );
			D3DXVECTOR3 halfExtents = pBoxShape->GetHalfExtents();
			Mix::Tool::Win32::Graphics::MAM_BOX_SHAPE_DATA_1_0_0_0* pBoxShapeData = reinterpret_cast<Mix::Tool::Win32::Graphics::MAM_BOX_SHAPE_DATA_1_0_0_0*>( &( mamShape.data[0] ) );

			mamShape.type = Mix::Tool::Win32::Graphics::MAM_BOX_SHAPE;

			pBoxShapeData->halfExtents[0] = halfExtents.x;
			pBoxShapeData->halfExtents[1] = halfExtents.y;
			pBoxShapeData->halfExtents[2] = halfExtents.z;
		}
		else if( objType == Mix::Tool::Win32::Object::DYNAMICS__CAPSULE_SHAPE )
		{
			//カプセルシェイプ
			const Mix::Tool::Win32::Dynamics::CapsuleShape* pCapsuleShape = static_cast<const Mix::Tool::Win32::Dynamics::CapsuleShape*>( pShape );
			Mix::Tool::Win32::Graphics::MAM_CAPSULE_SHAPE_DATA_1_0_0_0* pCapsuleShapeData = reinterpret_cast<Mix::Tool::Win32::Graphics::MAM_CAPSULE_SHAPE_DATA_1_0_0_0*>( &( mamShape.data[0] ) );

			mamShape.type = Mix::Tool::Win32::Graphics::MAM_CAPSULE_SHAPE;

			switch( pCapsuleShape->GetAxis() )
			{
			case Mix::Tool::Win32::Dynamics::aX:
				pCapsuleShapeData->axis = Mix::Tool::Win32::Graphics::MAM_AXIS_X;
				break;
			case Mix::Tool::Win32::Dynamics::aY:
				pCapsuleShapeData->axis = Mix::Tool::Win32::Graphics::MAM_AXIS_Y;
				break;
			case Mix::Tool::Win32::Dynamics::aZ:
				pCapsuleShapeData->axis = Mix::Tool::Win32::Graphics::MAM_AXIS_Z;
				break;

			default:
				return false;
			}

			pCapsuleShapeData->length = pCapsuleShape->GetLength();
			pCapsuleShapeData->radius = pCapsuleShape->GetRadius();
		}
		else if( objType == Mix::Tool::Win32::Object::DYNAMICS__SPHERE_SHAPE )
		{
			//スフィアシェイプ
			const Mix::Tool::Win32::Dynamics::SphereShape* pSphereShape = static_cast<const Mix::Tool::Win32::Dynamics::SphereShape*>( pShape );
			Mix::Tool::Win32::Graphics::MAM_SPHERE_SHAPE_DATA_1_0_0_0* pSphereShapeData = reinterpret_cast<Mix::Tool::Win32::Graphics::MAM_SPHERE_SHAPE_DATA_1_0_0_0*>( &( mamShape.data[0] ) );

			mamShape.type = Mix::Tool::Win32::Graphics::MAM_SPHERE_SHAPE;

			pSphereShapeData->radius = pSphereShape->GetRadius();
		}
		else
		{
			LogPrint( LT_ERROR, L"  サポートされないシェイプが定義されています : Node[%s] %s[%s] ObjectType[%d]", pNodeName, pRigidBodyType, pRigidBodyName, objType );
			return false;
		}

		/*
			追加
		*/

		shapeList.push_back( mamShape );
	}

	return true;
}

bool ObjectModel::SaveModel_CollectDynamics_Part(	const wchar_t* pNodeName,
													Mix::Tool::Win32::Dynamics::Design::Part* pPart,
													std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>& colliderMap,
													std::vector<Mix::Tool::Win32::Graphics::MAM_JOINT_1_0_0_0>& jointList )
{
	Mix::Tool::Win32::Dynamics::Joint* pJoint = pPart->Joint_Get();

	if( pJoint == NULL )
	{
		return true;
	}

	if( pJoint->GetRigidBodyA() == NULL )
	{
		LogPrint( LT_ERROR, L"  不正なジョイントが定義されています : Node[%s]", pNodeName );
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ジョイント
	////////////////////////////////////////////////////////////////////////////////////////////////////

	std::map<const Mix::Tool::Win32::Dynamics::RigidBody*, int>::iterator it_index;

	MAM_JOINT_1_0_0_0 mamJoint;

	::ZeroMemory( &mamJoint, sizeof( mamJoint ) );

	/*
		フラグ
	*/

	mamJoint.flags = 0;

	//接続されたコライダー同士の衝突を無効
	if( pJoint->GetCollisionDisabled() == true ) { mamJoint.flags |= Mix::Tool::Win32::Graphics::MAM_JF_COLLISION_DISABLE; }

	/*
		コライダーＡ
	*/

	it_index = colliderMap.find( pJoint->GetRigidBodyA() );
	mamJoint.colliderA = ( it_index != colliderMap.end() )? it_index->second : -1;
	if( mamJoint.colliderA >= 0 )
	{
		const D3DXVECTOR3& pivot = pJoint->GetPivotA();

		mamJoint.pivotA[0] = pivot.x;
		mamJoint.pivotA[1] = pivot.y;
		mamJoint.pivotA[2] = pivot.z;
		mamJoint.pivotA[3] = 1.0f;
	}
	else
	{
		//そんなわけない
		LogPrint( LT_ERROR, L"  ジョイントのフレームが不正です : Node[%s]", pNodeName );
		return false;
	}

	/*
		コライダーＢ
	*/

	it_index = colliderMap.find( pJoint->GetRigidBodyB() );
	mamJoint.colliderB = ( it_index != colliderMap.end() )? it_index->second : -1;
	if( mamJoint.colliderB >= 0 )
	{
		const D3DXVECTOR3& pivot = pJoint->GetPivotB();

		mamJoint.pivotB[0] = pivot.x;
		mamJoint.pivotB[1] = pivot.y;
		mamJoint.pivotB[2] = pivot.z;
		mamJoint.pivotB[3] = 1.0f;
	}
	else
	{
		//存在しない場合は、ワールドの座標を渡すので 0 にしておく
		mamJoint.pivotB[0] = 0.0f;
		mamJoint.pivotB[1] = 0.0f;
		mamJoint.pivotB[2] = 0.0f;
		mamJoint.pivotB[3] = 1.0f;
	}

	/*
		ローカルピボット行列Ｂ
	*/

	::CopyMemory( &( mamJoint.localPivotMatB[0][0] ), &( pPart->Joint_GetLocalPivotB() ), sizeof( float[4][4] ) );

	/*
		固有パラメータ
	*/

	Mix::Tool::Win32::Object::TYPE objType = pJoint->GetType();

	if( objType == Mix::Tool::Win32::Object::DYNAMICS__POINT_JOINT )
	{
		const Mix::Tool::Win32::Dynamics::PointJoint* pPointJoint = static_cast<const Mix::Tool::Win32::Dynamics::PointJoint*>( pJoint );
		Mix::Tool::Win32::Graphics::MAM_POINT_JOINT_DATA_1_0_0_0* pPointJointData = reinterpret_cast<Mix::Tool::Win32::Graphics::MAM_POINT_JOINT_DATA_1_0_0_0*>( &( mamJoint.data[0] ) );

		mamJoint.type = Mix::Tool::Win32::Graphics::MAM_POINT_JOINT;

		pPointJointData->pivotSpring = pPointJoint->GetSpring();
		pPointJointData->pivotDamper = pPointJoint->GetDamper();
	}
	else if( objType == Mix::Tool::Win32::Object::DYNAMICS__HINGE_JOINT )
	{
		const Mix::Tool::Win32::Dynamics::HingeJoint* pHingeJoint = static_cast<const Mix::Tool::Win32::Dynamics::HingeJoint*>( pJoint );
		const D3DXVECTOR3& axis = pHingeJoint->GetNormalizeAxis();

		Mix::Tool::Win32::Graphics::MAM_HINGE_JOINT_DATA_1_0_0_0* pHingeJointData = reinterpret_cast<Mix::Tool::Win32::Graphics::MAM_HINGE_JOINT_DATA_1_0_0_0*>( &( mamJoint.data[0] ) );

		mamJoint.type = Mix::Tool::Win32::Graphics::MAM_HINGE_JOINT;

		pHingeJointData->axis[0] = axis.x;
		pHingeJointData->axis[1] = axis.y;
		pHingeJointData->axis[2] = axis.z;
		pHingeJointData->axis[3] = 1.0f;
		pHingeJointData->lowerLimit = pHingeJoint->GetLowerLimit();
		pHingeJointData->upperLimit = pHingeJoint->GetUpperLimit();
		pHingeJointData->limitSpring = pHingeJoint->GetLimitSpring();
		pHingeJointData->limitDamper = pHingeJoint->GetLimitDamper();
	}
	else if( objType == Mix::Tool::Win32::Object::DYNAMICS__BALL_JOINT )
	{
		const Mix::Tool::Win32::Dynamics::BallJoint* pBallJoint = static_cast<const Mix::Tool::Win32::Dynamics::BallJoint*>( pJoint );
		const D3DXVECTOR3& twistAxis = pBallJoint->GetNormalizeTwistAxis();
		const D3DXVECTOR3& swingAxis = pBallJoint->GetNormalizeSwingAxis();

		Mix::Tool::Win32::Graphics::MAM_BALL_JOINT_DATA_1_0_0_0* pBallJointData = reinterpret_cast<Mix::Tool::Win32::Graphics::MAM_BALL_JOINT_DATA_1_0_0_0*>( &( mamJoint.data[0] ) );

		mamJoint.type = Mix::Tool::Win32::Graphics::MAM_BALL_JOINT;

		pBallJointData->twistAxis[0] = twistAxis.x;
		pBallJointData->twistAxis[1] = twistAxis.y;
		pBallJointData->twistAxis[2] = twistAxis.z;
		pBallJointData->twistAxis[3] = 1.0f;
		pBallJointData->swingAxis[0] = swingAxis.x;
		pBallJointData->swingAxis[1] = swingAxis.y;
		pBallJointData->swingAxis[2] = swingAxis.z;
		pBallJointData->swingAxis[3] = 1.0f;
		pBallJointData->twistLimit = pBallJoint->GetTwistLimit();
		pBallJointData->swingLimit1 = pBallJoint->GetSwingLimit1();
		pBallJointData->swingLimit2 = pBallJoint->GetSwingLimit2();
		pBallJointData->pivotSpring = pBallJoint->GetSpring();
		pBallJointData->pivotDamper = pBallJoint->GetDamper();
		pBallJointData->limitSpring = pBallJoint->GetLimitSpring();
		pBallJointData->limitDamper = pBallJoint->GetLimitDamper();
	}
	else
	{
		LogPrint( LT_ERROR, L"  サポートされないジョイントが定義されています : Node[%s] ObjectType[%d]", pNodeName, objType );
		return false;
	}

	/*
		追加
	*/

	jointList.push_back( mamJoint );

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

	return true;
}

bool ObjectModel::Optimize( const ObjectModel::IMPORT_CONFIG& cfg, bool bInvertZ )
{
	unsigned int key = 1;
	unsigned int meshCount = m_MeshList.size();
	unsigned int meshIndex = 1;
	unsigned int vertexCount = 0;
	unsigned int indexCount = 0;
	OptimizeMesh::BUILD_CONFIG buildCfg;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノードの事前処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_NodeList.size() > 0 )
	{
		for( ObjectModel::NodeList::iterator it = m_NodeList.begin(); it != m_NodeList.end(); ++it )
		{
			const Mix::Tool::Win32::Graphics::Node* pNode = ( *it );
			m_NodeIndexMap.insert( std::pair<std::wstring, int>( pNode->GetName(), pNode->GetIndex() ) );
		}

		//ベースシェイプのスケールを求めるためにここでワールド行列を更新しておく
		m_NodeList[0]->RefreshWorldMatrix( m_PivotMat );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュの最適化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	LogPrint( LT_INFO, L"" );
	LogPrint( LT_INFO, L"  メッシュの最適化" );

	buildCfg.type = cfg.meshBuildType;
	buildCfg.bSmooting = cfg.bSmooting;
	buildCfg.smootingAngle = ::cosf( D3DX_PI * cfg.smootingAngle / 180.0f );
	buildCfg.pUserPtr = NULL;

	for( ObjectModel::MeshList::iterator it = m_MeshList.begin(); it != m_MeshList.end(); ++it, meshIndex++ )
	{
		Mix::Tool::Win32::Graphics::ObjectMesh* pMesh = ( *it );
	
		LogPrint( LT_INFO, L"    %s[%d/%d] : PolygonCount[%d]", pMesh->GetLinkNodeName(), meshIndex, meshCount, pMesh->GetPolygonCount() );

		if( pMesh->Build( buildCfg ) == true )
		{
			pMesh->SetKey( key++ );

			vertexCount += pMesh->GetVertexCount();
			indexCount += pMesh->GetIndexCount();
		}
		else
		{
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイナミクス : ベースシェイプのファイナライズ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_NodeList.size() > 0 )
	{
		/*
			パート( すべて )
		*/

		LogPrint( LT_INFO, L"  ダイナミクス : パートベースシェイプのファイナライズ" );

		for( ObjectModel::NodeList::iterator it = m_NodeList.begin(); it != m_NodeList.end(); ++it )
		{
			Mix::Tool::Win32::Graphics::Node* pNode = ( *it );

			//ファイナライズ
			pNode->FinalizeBaseShape();

			if( pNode->GetBaseShapeCount() > 0 )
			{
				int baseShapeCount = pNode->GetBaseShapeCount();
				int baseShapeLast = baseShapeCount - 1;

				ObjectModel::LogBaseShape( L"    Part", pNode->GetBaseShapePtr( 0 ) );

				for( int i = 1; i < baseShapeCount; i++ )
				{
					ObjectModel::LogBaseShape( ( i == baseShapeLast )? L"    └ Detail" : L"    ├ Detail", pNode->GetBaseShapePtr( i ) );
				}
			}
		}

		LogPrint( LT_INFO, L"" );

		/*
			フィギュア( メッシュのみ )
		*/

		LogPrint( LT_INFO, L"  ダイナミクス : フィギュアのベースシェイプのファイナライズ" );

		Mix::Tool::Win32::Graphics::Node* pRootNode = m_NodeList[0];
		Mix::Tool::Win32::Graphics::BASE_SHAPE wholeBaseShape;

		D3DXMATRIX rootMat;
		D3DXMatrixIdentity( &rootMat );

		//全体を包むベースシェイプを追加
		wholeBaseShape.name = m_Name;
		wholeBaseShape.obb = pRootNode->GetObb( rootMat );
		m_BaseShapeList.push_back( wholeBaseShape );

		//メッシュ単位のベースシェイプを収集
		CollectActorBaseShape( rootMat, pRootNode );

		//メッシュ単位のベースシェイプをソート
		if( m_BaseShapeList.size() > 2 )
		{
			//先頭は全体を包むベースシェイプであり、デフォルトセンタートランスフォームになるのでソート対象からはずす
			std::vector<Mix::Tool::Win32::Graphics::BASE_SHAPE>::iterator it_begin = ++m_BaseShapeList.begin();
			std::vector<Mix::Tool::Win32::Graphics::BASE_SHAPE>::iterator it_end = m_BaseShapeList.end();

			std::sort( it_begin, it_end, Mix::Tool::Win32::Graphics::BASE_SHAPE() );
		}

		if( m_BaseShapeList.size() > 0 )
		{
			size_t baseShapeCount = m_BaseShapeList.size();
			size_t baseShapeLast = baseShapeCount - 1;

			ObjectModel::LogBaseShape( L"    Actor", &wholeBaseShape );

			for( size_t i = 0; i < baseShapeCount; i++ )
			{
				ObjectModel::LogBaseShape( ( i == baseShapeLast )? L"    └ Detail" : L"    ├ Detail", &( m_BaseShapeList[i] ) );
			}
		}

		LogPrint( LT_INFO, L"" );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイナミクス : デザイナの構築
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pDynamicsActorDesigner != NULL )
	{
		Mix::Tool::Win32::Dynamics::Design::Basic::COORDINATE_SYSTEM coordinateSystem;
		D3DXMATRIX initalWorldMat;
		D3DXQUATERNION defCenterRot;
		D3DXVECTOR3 defCenterPos;

		/*
			初期化に必要なパラメータを求める
		*/

		//座標系
		if( bInvertZ == true )
		{
			coordinateSystem = Mix::Tool::Win32::Dynamics::Design::Basic::RIGHT_HANDED;
		}
		else
		{
			coordinateSystem = Mix::Tool::Win32::Dynamics::Design::Basic::LEFT_HANDED;
		}

		//ワールド行列の初期値
		D3DXMatrixMultiply( &initalWorldMat, &m_PivotMat, &GetWorldMatrix() );

		//デフォルトセンタートランスフォーム
		if( m_BaseShapeList.size() > 0 )
		{
			const Mix::Tool::Win32::Geometry::OBB& obb = m_BaseShapeList[0].obb;

			D3DXQuaternionIdentity( &defCenterRot );
			defCenterPos = obb.pos;
		}
		else
		{
			D3DXQuaternionIdentity( &defCenterRot );
			defCenterPos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
		}

		/*
			初期化
		*/

		m_pDynamicsActorDesigner->Initialize( coordinateSystem, initalWorldMat, defCenterRot, defCenterPos );

		/*
			パートツリーを構築
		*/

		Mix::Tool::Win32::Graphics::Node* pRootNode = GetRootNode();

		if( pRootNode != NULL )
		{
			OnRefresh();

			if( BuildDynamicsPartTree( NULL, pRootNode ) == false )
			{
				return false;
			}

			OnRefresh();
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// リザルト
	////////////////////////////////////////////////////////////////////////////////////////////////////

	LogPrint( LT_INFO, L"  リザルト" );
	LogPrint( LT_INFO, L"    VertexCount[%d/%d]", vertexCount, indexCount );
	LogPrint( LT_INFO, L"    PolygonCount[%d]", indexCount / 3 );
	LogPrint( LT_INFO, L"" );

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

	return true;
}

void ObjectModel::CollectActorBaseShape( const D3DXMATRIX& parentWorldMat, Mix::Tool::Win32::Graphics::Node* pNode )
{
	D3DXMATRIX worldMat = pNode->GetGeometricMatrix() * pNode->GetDefLocalTransform() * parentWorldMat;
	int childCount = pNode->GetChildCount();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュの場合のみ取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( pNode->GetAttribute() == Node::MESH ) &&
		( pNode->GetBaseShapeCount() > 0 ) )
	{
		const Mix::Tool::Win32::Graphics::BASE_SHAPE* pSrc = pNode->GetBaseShapePtr( 0 );

		const D3DXVECTOR3& len = pSrc->obb.len;
		const D3DXVECTOR3* axis = pSrc->obb.axis;
		const D3DXVECTOR3& pos = pSrc->obb.pos;

		D3DXVECTOR3 tempVec;
		D3DXMATRIX tempMat;
		D3DXMATRIX obbMat;

		Mix::Tool::Win32::Graphics::BASE_SHAPE baseShape;

		obbMat._11 = axis[0].x; obbMat._12 = axis[0].y; obbMat._13 = axis[0].z; obbMat._14 = 0.0f;
		obbMat._21 = axis[1].x; obbMat._22 = axis[1].y; obbMat._23 = axis[1].z; obbMat._24 = 0.0f;
		obbMat._31 = axis[2].x; obbMat._32 = axis[2].y; obbMat._33 = axis[2].z; obbMat._34 = 0.0f;
		obbMat._41 = pos.x;     obbMat._42 = pos.y;     obbMat._43 = pos.z;     obbMat._44 = 1.0f;

		obbMat = *D3DXMatrixMultiply( &tempMat, &obbMat, &worldMat );

		baseShape.name        = pNode->GetName();
		baseShape.obb.len     = D3DXVECTOR3( len.x, len.y, len.z );
		baseShape.obb.axis[0] = *D3DXVec3Normalize( &tempVec, &D3DXVECTOR3( obbMat._11, obbMat._12, obbMat._13 ) );
		baseShape.obb.axis[1] = *D3DXVec3Normalize( &tempVec, &D3DXVECTOR3( obbMat._21, obbMat._22, obbMat._23 ) );
		baseShape.obb.axis[2] = *D3DXVec3Normalize( &tempVec, &D3DXVECTOR3( obbMat._31, obbMat._32, obbMat._33 ) );
		baseShape.obb.pos     = D3DXVECTOR3( obbMat._41, obbMat._42, obbMat._43 );

		m_BaseShapeList.push_back( baseShape );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 子を処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( int i = 0; i < childCount; i++ )
	{
		CollectActorBaseShape( worldMat, pNode->GetChildPtr( i ) );
	}
}

bool ObjectModel::BuildDynamicsPartTree( Mix::Tool::Win32::Dynamics::Design::Part* pParentPartDesigner, Mix::Tool::Win32::Graphics::Node* pNode )
{
	int childCount = pNode->GetChildCount();
	
	const D3DXMATRIX& worldMat = pNode->GetWorldMatrix();

	D3DXQUATERNION centerR;
	D3DXVECTOR3 centerT;

	Mix::Tool::Win32::Dynamics::Design::Part* pPartDesigner;

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

	if( pNode->GetBaseShapeCount() > 0 )
	{
		const Mix::Tool::Win32::Geometry::OBB& obb = pNode->GetBaseShapePtr( 0 )->obb;

		centerR = D3DXQUATERNION( 0.0f, 0.0f, 0.0f, 1.0f );
//		centerR = Mix::Tool::Win32::AxisToQuaternion( obb.axis[0], obb.axis[1], obb.axis[2] );
		centerT = obb.pos;
	}
	else
	{
		Mix::Tool::Win32::Graphics::Node* pParentNode = pNode->GetParentPtr();

		if( pParentNode != NULL )
		{
			//パート
			centerR = D3DXQUATERNION( 0.0f, 0.0f, 0.0f, 1.0f );
			D3DXVec3Lerp( &centerT, &( pParentNode->GetLocalTranslation() ), &( pNode->GetLocalTranslation() ), 0.5f );
		}
		else
		{
			//アクター
			if( m_BaseShapeList.size() > 0 )
			{
				//ベースシェイプを所持している
				centerR = D3DXQUATERNION( 0.0f, 0.0f, 0.0f, 1.0f );
				centerT = m_BaseShapeList[0].obb.pos;
			}
			else
			{
				//ベースシェイプを所持していない( こういうことはないはず )
				centerR = D3DXQUATERNION( 0.0f, 0.0f, 0.0f, 1.0f );
				centerT = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
			}
		}
	}

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

	if( pParentPartDesigner != NULL )
	{
		pPartDesigner = pParentPartDesigner->AddChild( pNode->GetLocalTranslation(), worldMat, centerR, centerT );
	}
	else
	{
		pPartDesigner = m_pDynamicsActorDesigner->CreateRoot( pNode->GetLocalTranslation(), worldMat, centerR, centerT );
	}

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

	if( pPartDesigner != NULL )
	{
		pNode->SetDynamicsPartDesignerPtr( pPartDesigner );
	}
	else
	{
		return false;
	}

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

	for( int i = 0; i < childCount; i++ )
	{
		Mix::Tool::Win32::Graphics::Node* pChildNode = pNode->GetChildPtr( i );

		if( BuildDynamicsPartTree( pPartDesigner, pChildNode ) == false )
		{
			return false;
		}
	}

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

	return true;
}

Mix::Tool::Win32::Graphics::Node* ObjectModel::FindNode( const wchar_t* pName )
{
	if( ( pName == NULL ) ||
		( ::wcslen( pName ) == 0 ) )
	{
		return NULL;
	}

	int nodeIndex = GetNodeIndexByName( pName );
	if( nodeIndex <= 0 )
	{
		return NULL;
	}

	MIX_ASSERT( m_NodeList.size() > static_cast<size_t>( nodeIndex ) );

	return m_NodeList[nodeIndex];
}

bool ObjectModel::CreateMotionControllerName( Mix::Tool::Win32::Graphics::MotionController* pMotionCtrl, const wchar_t* pRequestName, std::wstring& name )
{
	return CreateUniqueName( pMotionCtrl, m_MotionCtrlList.begin(), m_MotionCtrlList.end(), pRequestName, name );
}

unsigned int ObjectModel::GetMeshCount( void ) const
{
	return m_MeshList.size();
}

Mix::Tool::Win32::Graphics::ObjectMesh* ObjectModel::GetMesh( unsigned int index ) const
{
	if( m_MeshList.size() <= index )
	{
		return NULL;
	}

	return m_MeshList[index];
}

Mix::Tool::Win32::Graphics::Node* ObjectModel::GetNode( const wchar_t* pName )
{
	return FindNode( pName );
}

int ObjectModel::GetNodeIndexByName( const wchar_t* pName ) const
{
	ObjectModel::NodeIndexMap::const_iterator it = m_NodeIndexMap.find( pName );
	if( it == m_NodeIndexMap.end() )
	{
		return -1;
	}

	return it->second;
}

unsigned int ObjectModel::GetMotionControllerCount( void ) const
{
	return m_MotionCtrlList.size();
}

Mix::Tool::Win32::Graphics::MotionController* ObjectModel::GetMotionControllerByIndex( unsigned int index )
{
	if( m_MotionCtrlList.size() <= index )
	{
		return NULL;
	}

	return m_MotionCtrlList[index];
}

Mix::Tool::Win32::Graphics::MotionController* ObjectModel::GetUnassignedMotionController( void )
{
	return m_pUnassignedMotionCtrl;
}

Mix::Tool::Win32::Graphics::MotionController* ObjectModel::AddMotionController( void )
{
	Mix::Tool::Win32::Graphics::MotionController* pMotionCtrl = new Mix::Tool::Win32::Graphics::MotionController( m_NodeList.size() );
	if( pMotionCtrl != NULL )
	{
		pMotionCtrl->SetObjectModel( this );
		pMotionCtrl->SetName( ObjectModel::DEF_MOTION_CTRL_NAME );
		m_MotionCtrlList.push_back( pMotionCtrl );
	}
	else
	{
		return NULL;
	}

	return pMotionCtrl;
}

void ObjectModel::RemoveMotionController( Mix::Tool::Win32::Graphics::MotionController* pMotionController )
{
	MIX_ASSERT( pMotionController != NULL );

	if( pMotionController == m_pUnassignedMotionCtrl )
	{
		m_pUnassignedMotionCtrl->SetObjectModel( NULL );
		m_pUnassignedMotionCtrl = NULL;
	}
	else
	{
		ObjectModel::MotionControllerList::iterator it_begin = m_MotionCtrlList.begin();
		ObjectModel::MotionControllerList::iterator it_end = m_MotionCtrlList.end();
		ObjectModel::MotionControllerList::iterator it;

		for( it = it_begin; it != it_end; ++it )
		{
			if( ( *it ) == pMotionController )
			{
				break;
			}
		}

		MIX_ASSERT( it != it_end );

		( *it )->SetObjectModel( NULL );
		m_MotionCtrlList.erase( it );
	}
}

void ObjectModel::SetRootTransformActive( unsigned int flags )
{
	m_RTFlags = flags;
}

unsigned int ObjectModel::GetRootTransformActive( void ) const
{
	return m_RTFlags;
}

void ObjectModel::SetRootTransformNodeIndex( int nodeIndex )
{
	int nodeCount = static_cast<int>( m_NodeList.size() );

	if( ( nodeIndex >= 0 ) &&
		( nodeIndex < nodeCount ) )
	{
		m_RTNodeIndex = nodeIndex;
	}
	else
	{
		m_RTNodeIndex = 0;
	}
}

int ObjectModel::GetRootTransformNodeIndex( void ) const
{
	return m_RTNodeIndex;
}

const wchar_t* ObjectModel::GetRootTransformNodeName( void ) const
{
	return m_NodeList[m_RTNodeIndex]->GetName();
}

void ObjectModel::SetRootRotationAxis( MOTION_RT_AXIS axis )
{
	m_RTRAxis = axis;
}

const MOTION_RT_AXIS& ObjectModel::GetRootRotationAxis( void ) const
{
	return m_RTRAxis;
}

void ObjectModel::SetRootTranslationHorizonal( MOTION_RT_HORIZONAL horiz )
{
	m_RTTHoriz = horiz;
}

MOTION_RT_HORIZONAL ObjectModel::GetRootTranslationHorizonal( void ) const
{
	return m_RTTHoriz;
}

void ObjectModel::SetRootTranslationVertical( MOTION_RT_VERTICAL vert )
{
	m_RTTVert = vert;
}

MOTION_RT_VERTICAL ObjectModel::GetRootTranslationVertical( void ) const
{
	return m_RTTVert;
}

void ObjectModel::SetRootTranslationAxis( MOTION_RT_AXIS axis )
{
	m_RTTAxis = axis;
}

const MOTION_RT_AXIS& ObjectModel::GetRootTranslationAxis( void ) const
{
	return m_RTTAxis;
}

void ObjectModel::UpdateRootTransform( void )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 割り当てられたモーションのルートトランスフォームを更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( ObjectModel::MotionControllerList::iterator it = m_MotionCtrlList.begin(); it != m_MotionCtrlList.end(); ++it )
	{
		( *it )->UpdateRootTransform();
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 未割り当てモーションのルートトランスフォームを更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pUnassignedMotionCtrl->UpdateRootTransform();
}

void ObjectModel::ResetPose( void )
{
	Model::ResetWorldMatrix();

	if( m_pDynamicsActorDesigner != NULL )
	{
		m_pDynamicsActorDesigner->Reset();
	}
}

void ObjectModel::Jump( void )
{
	if( m_pDynamicsActorDesigner != NULL )
	{
		Mix::Tool::Win32::Dynamics::KinematicCharacter* pKinematicCharacter = m_pDynamicsActorDesigner->KinematicCharacter_Get();

		if( ( pKinematicCharacter != NULL ) &&
			( pKinematicCharacter->IsInWorld() == true ) )
		{
			pKinematicCharacter->Jump();
		}
	}
}

bool ObjectModel::SaveMotions( void )
{
	for( ObjectModel::MotionControllerList::iterator it = m_MotionCtrlList.begin(); it != m_MotionCtrlList.end(); ++it )
	{
		if( ( *it )->SaveFile() == false )
		{
			return false;
		}
	}

	return true;
}

int ObjectModel::GetBaseShapeCount( void ) const
{
	return m_BaseShapeList.size();
}

Mix::Tool::Win32::Graphics::BASE_SHAPE* ObjectModel::GetBaseShapePtr( int index )
{
	if( ( index < 0 ) ||
		( static_cast<int>( m_BaseShapeList.size() ) <= index ) )
	{
		return NULL;
	}

	return &( m_BaseShapeList[index] );
}

Mix::Tool::Win32::Dynamics::Design::Actor* ObjectModel::GetDynamicsActorDesignerPtr( void )
{
	return m_pDynamicsActorDesigner;
}

void ObjectModel::OnUpdate( void )
{
	if( ( m_NodeList.size() == 0 ) ||
		( m_pDynamicsActorDesigner == NULL ) )
	{
		return;
	}

//	D3DXVECTOR3 angularOffset( 0.0f, 0.0f, 0.0f );
	D3DXQUATERNION angularVelocity( 0.0f, 0.0f, 0.0f, 1.0f );
	D3DXVECTOR3 linearVelocity( 0.0f, 0.0f, 0.0f );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーション : ブレンドリストを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pDynamicsActorDesigner->GetMode() != Mix::Tool::Win32::Dynamics::Design::Basic::RAGDOLL )
	{
		std::sort( m_MotionCtrlList.begin(), m_MotionCtrlList.end(), ObjectModel::MOTION_CTRL_SORT() );

		ObjectModel::MotionControllerList::iterator it_mc_begin = m_MotionCtrlList.begin();
		ObjectModel::MotionControllerList::iterator it_mc_end = m_MotionCtrlList.end();
		ObjectModel::MotionControllerList::iterator it_mc;

		for( it_mc = it_mc_begin; it_mc != it_mc_end; ++it_mc )
		{
			Mix::Tool::Win32::Graphics::MotionController* pMotionCtrl = ( *it_mc );

			pMotionCtrl->OnUpdateBodyTransform( m_BTBlendList );
			pMotionCtrl->OnUpdateRootTransform( m_RTBlendList );
			pMotionCtrl->OnUpdateTime( 1.0f );
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーション : ボディトランスフォーム
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_BTBlendList.size() > 0 )
	{
		std::sort( m_BTBlendList.begin(), m_BTBlendList.end(), Mix::Tool::Win32::Graphics::BT_BLEND() ); 

		ObjectModel::BTBlendList::iterator it_btb_begin = m_BTBlendList.begin();
		ObjectModel::BTBlendList::iterator it_btb_end = m_BTBlendList.end();
		ObjectModel::BTBlendList::iterator it_btb;

		for( it_btb = it_btb_begin; it_btb != it_btb_end; ++it_btb )
		{
			const Mix::Tool::Win32::Graphics::BT_BLEND* pb = &( *it_btb );
			Mix::Tool::Win32::Graphics::Node* pNode = m_NodeList[pb->nodeIndex];

			pNode->SetLocalTransform( pb->scaling, pb->rotation, pb->translation, pb->ratio );
		}

		m_BTBlendList.clear();
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// モーション : ルートトランスフォーム
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_RTBlendList.size() > 0 )
	{
		std::sort( m_RTBlendList.begin(), m_RTBlendList.end(), Mix::Tool::Win32::Graphics::RT_BLEND() ); 

		ObjectModel::RTBlendList::iterator it_rtb_begin = m_RTBlendList.begin();
		ObjectModel::RTBlendList::iterator it_rtb_end = m_RTBlendList.end();
		ObjectModel::RTBlendList::iterator it_rtb;

		//速度をブレンド
		for( it_rtb = it_rtb_begin; it_rtb != it_rtb_end; ++it_rtb )
		{
			const Mix::Tool::Win32::Graphics::RT_BLEND* pb = &( *it_rtb );

			//回転速度
			if( MIX_TEST_BIT( m_RTFlags, Mix::Tool::Win32::Graphics::MOTION_RT_ROTATION ) != 0 )
			{
				D3DXQuaternionSlerp( &angularVelocity, &angularVelocity, &( pb->angularVelocity ), pb->ratio );
			}

			//線形速度
			if( MIX_TEST_BIT( m_RTFlags, Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION ) != 0 )
			{
				D3DXVec3Lerp( &linearVelocity, &linearVelocity, &( pb->linearVelocity ), pb->ratio );
			}
		}

		if( m_pDynamicsActorDesigner->Update_NeedVelocity() == true )
		{
			//アクターに線形速度を設定( 回転速度は適用できない )
			m_pDynamicsActorDesigner->Update_SetVelocity( angularVelocity, linearVelocity );
		}
		else
		{
#if 1
			D3DXMATRIX tempMat;

			D3DXVECTOR3 worldS;
			D3DXQUATERNION worldR;
			D3DXVECTOR3 worldT;

			D3DXMATRIX worldMat;

			Mix::Tool::Win32::Matrix_Decompose( GetWorldMatrix(), &worldS, &worldR, &worldT );

			if( MIX_TEST_BIT( m_RTFlags, Mix::Tool::Win32::Graphics::MOTION_RT_ROTATION ) != 0 )
			{
				D3DXQUATERNION tempQuat;

				worldR = *D3DXQuaternionMultiply( &tempQuat, &worldR, &angularVelocity );
				worldR = *D3DXQuaternionNormalize( &tempQuat, &worldR );
			}

			if( MIX_TEST_BIT( m_RTFlags, Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION ) != 0 )
			{
				D3DXVECTOR3 tempVec;
				D3DXMATRIX rotMat;

				D3DXMatrixRotationQuaternion( &rotMat, &worldR );
				linearVelocity = *D3DXVec3TransformNormal( &tempVec, &linearVelocity, &rotMat );

				worldT = *D3DXVec3Add( &tempVec, &worldT, &linearVelocity );
			}

			D3DXMatrixScaling( &worldMat, worldS.x, worldS.y, worldS.z );
			worldMat *= *D3DXMatrixRotationQuaternion( &tempMat, &worldR );
			worldMat._41 = worldT.x; worldMat._42 = worldT.y; worldMat._43 = worldT.z; worldMat._44 = 1.0f;

			SetWorldMatrix( worldMat );

#else

			D3DXMATRIX kineticMat;
			D3DXMATRIX worldMat;

			//運動行列を初期化
			D3DXMatrixIdentity( &kineticMat );

			//回転運動を適用
			if( MIX_TEST_BIT( m_RTFlags, Mix::Tool::Win32::Graphics::MOTION_RT_ROTATION ) != 0 )
			{
				D3DXMATRIX rotMat;
				D3DXMATRIX transMat;
				D3DXMATRIX tempMat;

				//軸を移動
				D3DXMatrixTranslation( &kineticMat, -angularOffset.x, -angularOffset.y, -angularOffset.z );

				//回転
				D3DXMatrixRotationQuaternion( &rotMat, &angularVelocity );
				kineticMat = *D3DXMatrixMultiply( &tempMat, &kineticMat, &rotMat );

				//軸を戻す
				D3DXMatrixTranslation( &transMat, angularOffset.x, angularOffset.y, angularOffset.z );
				kineticMat = *D3DXMatrixMultiply( &tempMat, &kineticMat, &transMat );
			}

			//線形運動を適用
			if( MIX_TEST_BIT( m_RTFlags, Mix::Tool::Win32::Graphics::MOTION_RT_TRANSLATION ) != 0 )
			{
				D3DXMATRIX transMat;
				D3DXMATRIX tempMat;

				D3DXMatrixTranslation( &transMat, linearVelocity.x, linearVelocity.y, linearVelocity.z );
				kineticMat = *D3DXMatrixMultiply( &tempMat, &kineticMat, &transMat );
			}

			//ワールド行列に運動行列を適用
			D3DXMatrixMultiply( &worldMat, &kineticMat, &GetWorldMatrix() );
			SetWorldMatrix( worldMat );

#endif
		}

		//クリア
		m_RTBlendList.clear();
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイナミクス : アクターの更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pDynamicsActorDesigner->Update();
}

void ObjectModel::OnRefresh( void )
{
	if( ( m_NodeList.size() == 0 ) ||
		( m_pDynamicsActorDesigner == NULL ) )
	{
		return;
	}

	D3DXMATRIX rootMat;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ルート : リフレッシュ
	//   オブジェクトモデル : ルート行列を求める
	//   ダイナミクス : アクターをリフレッシュ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pDynamicsActorDesigner->Refresh();

	if( m_pDynamicsActorDesigner->IsWorldMatrixRefreshed() == true )
	{
		D3DXMATRIX worldMat;

		rootMat = m_pDynamicsActorDesigner->GetWorldMatrix();

		D3DXMatrixMultiply( &worldMat, &m_InvPivotMat, &rootMat );
		SetWorldMatrix( worldMat );
	}
	else
	{
		D3DXMatrixMultiply( &rootMat, &m_PivotMat, &GetWorldMatrix() );

		m_pDynamicsActorDesigner->SetWorldMatrix( rootMat );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノード : リフレッシュ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_NodeList[0]->Refresh( rootMat );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ライト : 描画に使用するパラメータを求める
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_MeshList.size() > 0 )
	{
		MeshList::iterator it_mesh_begin = m_MeshList.begin();
		MeshList::iterator it_mesh_end = m_MeshList.end();
		MeshList::iterator it_mesh;

		Mix::Tool::Win32::Geometry::SPHERE rlVolume;

		/*
			初期化
		*/

		rlVolume.pos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
		rlVolume.radius = 1000.0f;

		/*
			中心を求める
		*/

		for( it_mesh = it_mesh_begin; it_mesh != it_mesh_end; ++it_mesh )
		{
			Mix::Tool::Win32::Graphics::ObjectMesh* pMesh = ( *it_mesh );
			const Mix::Tool::Win32::Geometry::SPHERE& viewVolume = pMesh->GetViewVolume();

			rlVolume.pos += viewVolume.pos;
		}

		rlVolume.pos /= static_cast<float>( m_MeshList.size() );

		/*
			半径を求める
		*/

		for( it_mesh = it_mesh_begin; it_mesh != it_mesh_end; ++it_mesh )
		{
			Mix::Tool::Win32::Graphics::ObjectMesh* pMesh = ( *it_mesh );
			const Mix::Tool::Win32::Geometry::SPHERE& viewVolume = pMesh->GetViewVolume();

			D3DXVECTOR3 vec;
			float vecLen;

			vec = viewVolume.pos - rlVolume.pos;
			vecLen = D3DXVec3Length( &vec );

			vec = viewVolume.pos * viewVolume.radius - rlVolume.pos;
			D3DXVec3Normalize( &vec, &vec );

			vec = vec * ( vecLen + viewVolume.radius );

			vecLen = ::D3DXVec3Length( &vec );
			if( rlVolume.radius < vecLen )
			{
				rlVolume.radius = vecLen;
			}
		}

		SetRotationLightVolume( rlVolume );
	}
}

void ObjectModel::OnDraw( DrawObject::DRAW_EVENT_ARGS& args )
{
	const D3DXMATRIX& viewMat = args.pCamera->GetViewMatrix();

	ObjectModel::NodeList::iterator it_node_begin = m_NodeList.begin();
	ObjectModel::NodeList::iterator it_node_end = m_NodeList.end();
	ObjectModel::NodeList::iterator it_node;

	ObjectModel::MeshList::iterator it_mesh_begin = m_MeshList.begin();
	ObjectModel::MeshList::iterator it_mesh_end = m_MeshList.end();
	ObjectModel::MeshList::iterator it_mesh;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノード
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( it_node = it_node_begin; it_node != it_node_end; ++it_node )
	{
		Mix::Tool::Win32::Graphics::Node* pNode = ( *it_node );
		Mix::Tool::Win32::Graphics::Node::DRAW_EVENT_ARGS ndArgs;

		ndArgs.pLineHelper = args.pLineHelper;

		ndArgs.bDrawBone = ( MIX_TEST_BIT( args.flags, DrawObject::DF_BONE ) == DrawObject::DF_BONE );
		ndArgs.bDrawCollision = ( MIX_TEST_BIT( args.flags, DrawObject::DF_COLLISION ) == DrawObject::DF_COLLISION );
		ndArgs.bDrawJoint = ( MIX_TEST_BIT( args.flags, DrawObject::DF_JOINT ) == DrawObject::DF_JOINT );

		ndArgs.selectedColor = ( pNode == m_pSelectedNode )? args.selectColor : D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 0.0f );
		ndArgs.boneColor = args.boneColor;
		ndArgs.dynSensorColor = args.sensorColor;
		ndArgs.dynBodyColor = args.collisionColor;
		ndArgs.dynJointAxisColor = args.jointAxisColor;
		ndArgs.dynJointBallColor = args.jointBallColor;
		ndArgs.dynJointLimitColor = args.jointLimitColor;

		ndArgs.axisScale = args.axisScale;
		ndArgs.dynJointScale = args.jointScale;

		pNode->Draw( ndArgs );
	}

	/*
		選択されたノード、もしくわモデルの描画
	*/

	args.pLineHelper->IdentityColor();
	args.pLineHelper->SetMatrix( ( m_pSelectedNode != NULL )? m_pSelectedNode->GetWorldMatrix() : GetWorldMatrix() );
	args.pLineHelper->AddAxis( D3DXVECTOR3( 0.0f, 0.0f, 0.0f ), args.axisScale );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイナミクス : アクターデザイナの
	//                パートはノード側で描画する
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pDynamicsActorDesigner != NULL )
	{
		m_pDynamicsActorDesigner->Draw( args.pLineHelper,
										( MIX_TEST_BIT( args.flags, DrawObject::DF_COLLISION ) == DrawObject::DF_COLLISION ),
										( MIX_TEST_BIT( args.flags, DrawObject::DF_COLLISION ) == DrawObject::DF_COLLISION ),
										( MIX_TEST_BIT( args.flags, DrawObject::DF_COLLISION ) == DrawObject::DF_COLLISION ),
										( MIX_TEST_BIT( args.flags, DrawObject::DF_JOINT ) == DrawObject::DF_JOINT ),
										( m_pSelectedNode == NULL )? args.selectColor : D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 0.0f ),
										args.kinematicCharacterColor,
										args.sensorColor,
										args.collisionColor,
										args.jointAxisColor,
										args.jointBallColor,
										args.jointLimitColor,
										args.jointScale,
										args.axisScale,
										false );



	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	for( it_mesh = it_mesh_begin; it_mesh != it_mesh_end; ++it_mesh )
	{
		Mix::Tool::Win32::Graphics::ObjectMesh* pMesh = ( *it_mesh );

		if( args.pCamera->Contains( pMesh->GetViewVolume() ) == true )
		{
			/*
				ボディ
			*/

			if( MIX_TEST_BIT( args.flags, DrawObject::DF_BODY ) == DrawObject::DF_BODY )
			{
				const D3DXMATRIX& worldMat = pMesh->GetLinkNodePtr()->GetWorldMatrix();

				//カラーのレンダリング
				pMesh->OnDrawColor(	viewMat,
									worldMat,
									*( args.pOpacitySubsets ),
									*( args.pTransparencySubsets ),
									*( args.pRefractSubsets ) );

				//セレクトマップのレンダリング
				pMesh->OnDrawSelectMap(	viewMat,
										worldMat,
										*( args.pSelectMapSubsets ) );

				//セレクトのレンダリング
				if( pMesh == m_pSelectedMesh )
				{
					pMesh->OnDrawSelectColor(	viewMat,
												worldMat,
												*( args.pSelectSubsets ) );
				}
			}

			/*
				ビューボリューム
			*/

			if( MIX_TEST_BIT( args.flags, DrawObject::DF_VIEWVOLUME ) == DrawObject::DF_VIEWVOLUME )
			{
				args.pLineHelper->SetColor( args.viewVolumeColor );
				args.pLineHelper->IdentityMatrix();
				args.pLineHelper->AddSphere( pMesh->GetViewVolume() );
			}
		}
	}
}

void ObjectModel::OnRefreshMesh( unsigned int materialSlotIndex )
{
	for( ObjectModel::MeshList::iterator it = m_MeshList.begin(); it != m_MeshList.end(); ++it )
	{
		( *it )->RefreshBuffer( materialSlotIndex );
	}
}

const Mix::Tool::Win32::Graphics::Node* ObjectModel::GetRootTransformConstant( D3DXMATRIX& baseMat, D3DXMATRIX& castMat, D3DXQUATERNION& invDefWorldRot, D3DXVECTOR3& defWorldPos )
{
	if( ( m_RTNodeIndex < 0 ) &&
		( static_cast<int>( m_NodeList.size() ) <= m_RTNodeIndex ) )
	{
		return NULL;
	}

	const Mix::Tool::Win32::Graphics::Node* pNode = m_NodeList[m_RTNodeIndex];

	D3DXMATRIX tempMat;
	D3DXQUATERNION tempQuat;

	D3DXMATRIX defWorldMat;

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// ベース行列( ルートに指定された一つ前のワールド行列 )を求める
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	baseMat = m_PivotMat;
	GetRootTransformConstant( pNode->GetParentPtr(), baseMat );

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// ルートに指定されたノードのワールド行列を求める
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	defWorldMat = *D3DXMatrixMultiply( &tempMat, &( pNode->GetDefLocalTransform() ), &baseMat );

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// ルートノードから真下(XZ平面)に投影するための行列を求める
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	D3DXMATRIX initalWorldMat;

	D3DXMatrixTranslation( &initalWorldMat, defWorldMat._41, 0.0f, defWorldMat._43 );

	castMat = Mix::Tool::Win32::Matrix_ExcludeScaling( defWorldMat );
	castMat = *D3DXMatrixInverse( &tempMat, NULL, &castMat );
	castMat = *D3DXMatrixMultiply( &tempMat, &initalWorldMat, &castMat );

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 回転の差分を求めるための初期回転の逆クォータニオンを求める
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	D3DXMATRIX rootMat;

	rootMat = *D3DXMatrixMultiply( &tempMat, &castMat, &defWorldMat );
	Mix::Tool::Win32::Matrix_Decompose( rootMat, NULL, &invDefWorldRot, NULL );
	invDefWorldRot = *D3DXQuaternionInverse( &tempQuat, &invDefWorldRot );

	//////////////////////////////////////////////////////////////////////////////////////////////////////////////
	// 位置の差分を求めるための初期座標を求める
	//////////////////////////////////////////////////////////////////////////////////////////////////////////////

	Mix::Tool::Win32::Matrix_Decompose( defWorldMat, NULL, NULL, &defWorldPos );

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

	return pNode;
}

void ObjectModel::GetRootTransformConstant( const Mix::Tool::Win32::Graphics::Node* pNode, D3DXMATRIX& baseMat )
{
	if( pNode != NULL )
	{
		D3DXMATRIX tempMat;

		GetRootTransformConstant( pNode->GetParentPtr(), baseMat );

		baseMat = *D3DXMatrixMultiply( &tempMat, &( pNode->GetDefLocalTransform() ), &baseMat );
	}
}
/*
const Mix::Tool::Win32::Graphics::Node* ObjectModel::GetRootTransformConstant( D3DXQUATERNION& baseRotation, D3DXMATRIX& baseTranslation ) const
{
	if( ( m_RTNodeIndex < 0 ) &&
		( static_cast<int>( m_NodeList.size() ) <= m_RTNodeIndex ) )
	{
		return NULL;
	}

	const Mix::Tool::Win32::Graphics::Node* pNode = m_NodeList[m_RTNodeIndex];

	D3DXMATRIX rotMat;

	D3DXQuaternionIdentity( &baseRotation );
	baseTranslation = m_PivotMat;

	GetRootTransformConstant( pNode->GetParentPtr(), baseRotation, baseTranslation );

	return pNode;
}

void ObjectModel::GetRootTransformConstant( const Mix::Tool::Win32::Graphics::Node* pNode, D3DXQUATERNION& baseRotation, D3DXMATRIX& baseTranslation ) const
{
	if( pNode != NULL )
	{
		GetRootTransformConstant( pNode->GetParentPtr(), baseRotation, baseTranslation );

		D3DXQuaternionMultiply( &baseRotation, &( pNode->GetDefLocalRotation() ), &baseRotation );
		baseTranslation = pNode->GetDefLocalTransform() * baseTranslation;
//		D3DXMatrixMultiply( &baseTranslation, &( pNode->GetDefLocalTransform() ), &baseTranslation );
	}
}
*/
Mix::Tool::Win32::Graphics::Node* ObjectModel::GetRootTransformNodePtr( void ) const
{
	if( ( m_RTNodeIndex < 0 ) &&
		( static_cast<int>( m_NodeList.size() ) <= m_RTNodeIndex ) )
	{
		return NULL;
	}

	return m_NodeList[m_RTNodeIndex];
}
/*
void ObjectModel::ApplyPivot( D3DXQUATERNION& rotation )
{
	D3DXMATRIX rotMat;
	D3DXMATRIX tempMat;

	D3DXMatrixRotationQuaternion( &rotMat, &rotation );

	for( unsigned int i = 0; i < 3; i++ )
	{
		tempMat.m[i][0] += rotMat.m[i][0] * m_PivotMat.m[0][0] + rotMat.m[i][1] * m_PivotMat.m[1][0] + rotMat.m[i][2] * m_PivotMat.m[2][0];
		tempMat.m[i][1] += rotMat.m[i][0] * m_PivotMat.m[0][1] + rotMat.m[i][1] * m_PivotMat.m[1][1] + rotMat.m[i][2] * m_PivotMat.m[2][1];
		tempMat.m[i][2] += rotMat.m[i][0] * m_PivotMat.m[0][2] + rotMat.m[i][1] * m_PivotMat.m[1][2] + rotMat.m[i][2] * m_PivotMat.m[2][2];
	}

	::D3DXQuaternionRotationMatrix( &rotation, &tempMat );
}

void ObjectModel::ApplyPivot( D3DXMATRIX& mat )
{
	mat *= m_PivotMat;
//	D3DXMatrixMultiply( &mat, &mat, &m_PivotMat );
}
*/
D3DXMATRIX ObjectModel::ComputeRootMatrix( void )
{
	D3DXMATRIX tempMat;

	return *D3DXMatrixMultiply( &tempMat, &m_PivotMat, &GetWorldMatrix() );
}

void ObjectModel::LogBaseShape( const wchar_t* pTitle, const Mix::Tool::Win32::Graphics::BASE_SHAPE* pBaseShape )
{
	D3DXQUATERNION quat = Mix::Tool::Win32::ToQuaternion( pBaseShape->obb.axis[0], pBaseShape->obb.axis[1], pBaseShape->obb.axis[2] );
	D3DXVECTOR3 rot = Mix::Tool::Win32::ToEulerDegreeZYX( quat );

	LogPrint( LT_INFO, L"%s[%s] : Rotation(%f,%f,%f) Position(%f,%f,%f) HalfExtens(%f,%f,%f)",
		pTitle,
		pBaseShape->name.c_str(),
		rot.x, rot.y, rot.z,
		pBaseShape->obb.pos.x, pBaseShape->obb.pos.y, pBaseShape->obb.pos.z,
		pBaseShape->obb.len.x, pBaseShape->obb.len.y, pBaseShape->obb.len.z );
}

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

bool ObjectModel::FBX_LoadNode( FBX& fbx, FbxNode* pFbxNode, Mix::Tool::Win32::Graphics::Node* pParentNode, const ObjectModel::IMPORT_CONFIG& cfg )
{
	int childCount = pFbxNode->GetChildCount();
	Mix::Tool::Win32::Graphics::Node* pNode = NULL;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノードを追加
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pNode = new Mix::Tool::Win32::Graphics::Node(
		this,
		static_cast<int>( m_NodeList.size() ),
		pFbxNode->GetName(),
		pParentNode,
		fbx.GetGeometricMatrix( pFbxNode ),
		fbx.GetLocalScale( pFbxNode ),
		fbx.GetLocalRotation( pFbxNode ),
		fbx.GetLocalTranslation( pFbxNode ) );

	m_NodeList.push_back( pNode );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュの処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( FBX::GetNodeType( pFbxNode ) == FbxNodeAttribute::eMesh )
	{
		if( FBX_LoadMesh( fbx, pFbxNode, pNode, cfg ) == false )
		{
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ログ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	{
		const D3DXVECTOR3& scale = pNode->GetDefLocalScaling();
		D3DXVECTOR3 rot = Mix::Tool::Win32::ToEulerDegreeXYZ( pNode->GetDefLocalRotation() );
		const D3DXVECTOR3& translation = pNode->GetDefLocalTranslation();

		LogPrint( LT_INFO, L"  FBX : ノード : Name[%s] Parent[%s] : S(%f,%f,%f) R(%f,%f,%f) T(%f,%f,%f)",
			pNode->GetName(),
			( pParentNode != NULL )? pParentNode->GetName() : L"",
			scale.x, scale.y, scale.z,
			rot.x, rot.y, rot.z,
			translation.x, translation.y, translation.z );
	}

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

	for( int i = 0; i < childCount; i++ )
	{
		if( FBX_LoadNode( fbx, pFbxNode->GetChild( i ), pNode, cfg ) == false )
		{
			return false;
		}
	}

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

	return true;
}

bool ObjectModel::FBX_LoadMesh( FBX& fbx, FbxNode* pFbxNode, Mix::Tool::Win32::Graphics::Node* pNode, const ObjectModel::IMPORT_CONFIG& cfg )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	Mix::Tool::Win32::Graphics::ObjectMesh* pMesh = new Mix::Tool::Win32::Graphics::ObjectMesh( this, pNode );
	if( pMesh == NULL )
	{
		LogPrint( LT_ERROR, L"  FBX : システムメモリが不足しています" );
		return false;
	}
	
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュを読み込む
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( fbx.TriangulateInPlace( pFbxNode, pNode->GetName() ) == true )
	{
		bool bTransform = false;
		bool bPolygonNormal = ( ( cfg.meshBuildType == Mix::Tool::Win32::Graphics::MESH_BUILD_OPTIMIZE ) && ( cfg.bSmooting == true ) );

		if( fbx.LoadMesh(	pFbxNode,
							bTransform,
							bPolygonNormal,
							pMesh,
							pNode->GetName() ) == true )
		{
			pNode->SetMesh( static_cast<int>( m_MeshList.size() ), pMesh );
			m_MeshList.push_back( pMesh );
		}
		else
		{
			delete pMesh;
		}
	}

	return true;
}

}}}}
