#include "Mix/Private/Scene/Common/ActorLoader.h"

#include "Mix/IO/IReader.h"
#include "Mix/Dynamics/IManager.h"
#include "Mix/Dynamics/IBoxShape.h"
#include "Mix/Dynamics/ICapsuleShape.h"
#include "Mix/Dynamics/ISphereShape.h"
#include "Mix/Dynamics/ICompoundShape.h"
#include "Mix/Dynamics/IRigidBody.h"
#include "Mix/Dynamics/ISensor.h"
#include "Mix/Dynamics/IKinematicCharacter.h"
#include "Mix/Dynamics/IPointJoint.h"
#include "Mix/Dynamics/IHingeJoint.h"
#include "Mix/Dynamics/IBallJoint.h"
#include "Mix/Graphics/IManager.h"
#include "Mix/Graphics/IDevice.h"
#include "Mix/Graphics/IVertexBuffer.h"
#include "Mix/Graphics/IIndexBuffer.h"

#include "Mix/Private/Scene/Common/Manager.h"
#include "Mix/Private/Scene/Common/EffectPackage.h"
#include "Mix/Private/Scene/Common/ActorMesh.h"
#include "Mix/Private/Scene/Common/ActorNode.h"
#include "Mix/Private/Scene/Common/ActorModel.h"
#include "Mix/Private/Scene/Common/ActorCollider.h"
#include "Mix/Private/Scene/Common/ActorSensor.h"
#include "Mix/Private/Scene/Common/ActorKinematicCharacter.h"
#include "Mix/Private/Scene/Common/ActorDynamicsDirector.h"
#include "Mix/Private/Scene/Common/ActorDynamicsFigure.h"
#include "Mix/Private/Scene/Common/ActorDynamicsPart.h"
#include "Mix/Private/Scene/Common/MotionMixer.h"
#include "Mix/Private/Scene/Common/MotionController.h"
#include "Mix/Private/Scene/Common/MotionCurve.h"
#include "Mix/Private/Scene/Common/Motion.h"

//#define MIX_ACTOR_FORCE_KINEMATIC_COLLIDER
//#define MIX_ACTOR_LOADER_DISABLE_JOINT
//#define MIX_ACTOR_LOADER_DISABLE_SENSOR

namespace Mix{ namespace Scene{ namespace Common{

const wchar_t* ActorLoader::FAILED_CREATE = L"アクターモデルの作成に失敗";

ActorLoader::ActorLoader( void ) :
m_pDynamicsManager( NULL ),
m_pGraphicsDevice( NULL ),
m_pKinematicCharacter( NULL )
{
	Mix::Dynamics::IManager* pDynamicsMgr = Mix::Dynamics::GetManagerPtr();

	//ダイナミクスが無効にされている場合でも使用できるようにするため、アサートはださない
	MIX_ADD_REF( pDynamicsMgr );
	m_pDynamicsManager = pDynamicsMgr;

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

	Mix::Graphics::IManager* pGraphicsMgr = Mix::Graphics::GetManagerPtr();

	MIX_ASSERT( pGraphicsMgr != NULL );

	if( pGraphicsMgr->GetDevice( &m_pGraphicsDevice ) == False )
	{
		MIX_ASSERT( m_pGraphicsDevice != NULL );
	}
}

ActorLoader::~ActorLoader( void )
{
	MIX_RELEASE( m_pGraphicsDevice );
	MIX_RELEASE( m_pDynamicsManager );
}

Mix::Scene::IActorModel* ActorLoader::Create( Mix::Scene::Common::EffectPackage* pEffectPackage, Mix::IO::IReader* pReader )
{
	MIX_ASSERT( pEffectPackage != NULL );
	MIX_ASSERT( pReader != NULL );

	const wchar_t* pFilePath = pReader->GetFilePath();
	Mix::Scene::Common::ActorModel* pModel = NULL;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// インターフェースを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pModel = ActorModel::CreateInstance( pFilePath );
	if( pModel == NULL )
	{
		MIX_LOG_ERROR( Mix::STR_OUTOFMEMORY );
		return NULL;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 読み込み
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( Create( pEffectPackage, pReader, pModel ) == False )
	{
		MIX_RELEASE( pModel );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 後処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_RELEASE( m_pKinematicCharacter );

	if( m_JointList.size() > 0 )
	{
		for( ActorLoader::JointList::iterator it = m_JointList.begin(); it != m_JointList.end(); ++it )
		{
			MIX_RELEASE( ( *it ).ptr );
		}

		m_JointList.clear();
	}

	if( m_SensorList.size() > 0 )
	{
		for( ActorLoader::SensorList::iterator it = m_SensorList.begin(); it != m_SensorList.end(); ++it )
		{
			MIX_RELEASE( ( *it ) );
		}

		m_SensorList.clear();
	}

	if( m_ColliderList.size() > 0 )
	{
		for( ActorLoader::ColliderList::iterator it = m_ColliderList.begin(); it != m_ColliderList.end(); ++it )
		{
			MIX_RELEASE( ( *it ) );
		}

		m_ColliderList.clear();
	}

	if( m_ShapeList.size() > 0 )
	{
		for( ActorLoader::ShapeList::iterator it = m_ShapeList.begin(); it != m_ShapeList.end(); ++it )
		{
			MIX_RELEASE( ( *it ).ptr );
		}

		m_ShapeList.clear();
	}

	if( m_MeshList.size() > 0 )
	{
		for( ActorLoader::MeshList::iterator it = m_MeshList.begin(); it != m_MeshList.end(); ++it )
		{
			MIX_RELEASE( ( *it ) );
		}

		m_MeshList.clear();
	}

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

	return pModel;
}

Boolean ActorLoader::Create(	Mix::Scene::Common::EffectPackage* pEffectPackage,
								Mix::IO::IReader* pReader,
								Mix::Scene::Common::ActorModel* pModel )
{
	Mix::Scene::Common::Manager* pSceneMgr = Mix::Scene::GetInternalManagerPtr();

	MIX_ASSERT( pSceneMgr != NULL );

	const wchar_t* pFilePath = pReader->GetFilePath();

	UInt32 i;
	UInt32 j;
	UInt32 nodeByteSize;
	Mix::StringW tempStr;

	ActorLoader::MAM_FILE_HEADER_1_0_0_0 fileHeader;
	ActorLoader::MAM_DATA_HEADER_1_0_0_0 dataHeader;

	Mix::Scene::Common::ActorNode** nodeList;
	Mix::Scene::Common::ActorDynamicsDirector* pDynamicsDirector;
	Mix::Scene::Common::MotionMixer* pMotionMixer;

	UInt32 shapeIndex = 0;
	UInt32 colliderIndex = 0;
	UInt32 sensorIndex = 0;
	UInt32 jointIndex = 0;

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

	if( pReader->Read( &fileHeader, sizeof( fileHeader ) ) != sizeof( fileHeader ) )
	{
		return False;
	}

	if( fileHeader.magicNumber != ActorLoader::MAM_MAGICNUMBER )
	{
		return False;
	}

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

	if( pReader->Read( &dataHeader, sizeof( dataHeader ) ) != sizeof( dataHeader ) )
	{
		return False;
	}

	if( ( dataHeader.materialNum == 0 ) ||
		( dataHeader.meshNum == 0 ) ||
		( dataHeader.nodeNum == 0 ) )
	{
		MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
		return False;
	}

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

	if( pModel->Initialize( dataHeader.nodeNum ) == True )
	{
		pDynamicsDirector = pModel->GetDynamicsDirectorPtr();
		pMotionMixer = pModel->GetMotionMixerPtr();
	}
	else
	{
		MIX_LOG_ERROR( Mix::STR_OUTOFMEMORY );
		return False;
	}

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

	pModel->ReserveMaterialSlots( dataHeader.materialNum );

	for( i = 0; i < dataHeader.materialNum; i++ )
	{
		wchar_t slotName[32];
		Mix::Scene::IMaterial* pMaterial = NULL;

		if( pReader->Read( slotName, sizeof( slotName ) ) != sizeof( slotName ) )
		{
			MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
			return False;
		}

		tempStr.Sprintf( L"%s\\%s", pFilePath, slotName );

		pMaterial = pSceneMgr->CreateMaterialWithoutMagicNumber( pEffectPackage, pReader, tempStr.GetConstPtr() );
		if( pMaterial == NULL )
		{
			return False;
		}

		pModel->AddMaterialSlot( slotName, pMaterial );
	}

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

	m_MeshList.reserve( dataHeader.meshNum );

	for( i = 0; i < dataHeader.meshNum; i++ )
	{
		Mix::Scene::Common::ActorMesh* pMesh = NULL;

		tempStr.Sprintf( L"%s\\Mesh%d", pFilePath, i );

		pMesh = Mix::Scene::Common::ActorMesh::CreateInstance( m_pGraphicsDevice, pReader, tempStr.GetConstPtr() );
		if( pMesh == NULL )
		{
			MIX_LOG_ERROR( L"メッシュを作成できませんでした" );
			return False;
		}

		m_MeshList.push_back( pMesh );
	}

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

	pMotionMixer->ReserveControllerList( dataHeader.motionControllerNum );

	for( i = 0; i < dataHeader.motionControllerNum; i++ )
	{
		ActorLoader::MAM_MOTION_CONTROLLER_1_0_0_0 mc;

		if( pReader->Read( &mc, sizeof( mc ) ) != sizeof( mc ) )
		{
			MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
			return False;
		}

		Mix::Scene::Common::MotionController* pMotionController = NULL;
		
		pMotionController = pMotionMixer->AddController( mc.name, mc.priority );
		if( pMotionController == NULL )
		{
			MIX_LOG_ERROR( Mix::STR_OUTOFMEMORY );
			return False;
		}

		MIX_LOG_INFO( L"モーションコントローラーを作成 : Name[%s] Priority[%d] MotionCount[%d]", mc.name, mc.priority, mc.motionNum );

		for( j = 0; j < mc.motionNum; j++ )
		{
			Mix::Scene::Common::Motion* pMotion = Motion::CreateInstance( pReader, False, L"FilePath", pFilePath );
			if( pMotion != NULL )
			{
				pMotionController->AddMotion( pMotion );
			}
			else
			{
				return False;
			}
		}
	}

	pMotionMixer->CreateControllerIndexMap();

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

	if( dataHeader.kinematicCharacterNum > 0 )
	{
		if( m_pDynamicsManager != NULL )
		{
			MIX_ASSERT( m_pKinematicCharacter == NULL );

			m_TempBuffer.clear();
			m_TempBuffer.resize( sizeof( ActorLoader::MAM_KINEMATIC_CHARACTER_1_0_0_0 ) );

			if( pReader->Read( &( m_TempBuffer[0] ), MIX_UIT_TO_UI32( m_TempBuffer.size() ) ) != sizeof( ActorLoader::MAM_KINEMATIC_CHARACTER_1_0_0_0 ) )
			{
				MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
				return False;
			}

			const ActorLoader::MAM_KINEMATIC_CHARACTER_1_0_0_0* pSrc = reinterpret_cast<const ActorLoader::MAM_KINEMATIC_CHARACTER_1_0_0_0*>( &( m_TempBuffer[0] ) );
			Mix::Dynamics::IKinematicCharacter* pInternalKChar = NULL;

			if( m_pDynamicsManager->CreateKinematicCharacter( pSrc->height, pSrc->radius, pSrc->stepHeight, &pInternalKChar, pFilePath ) == True )
			{
				pInternalKChar->SetGravity( pSrc->garvity );
				pInternalKChar->SetMaxFallSpeed( pSrc->maxFallSpeed );
				pInternalKChar->SetInitalJumpSpeed( pSrc->initJumpSpeed );
				pInternalKChar->SetSlopeLimit( pSrc->slopeLimit );

				m_pKinematicCharacter = Mix::Scene::Common::ActorKinematicCharacter::CreateInstance( pInternalKChar, pSrc->loadMat, pSrc->storeMat );
				if( m_pKinematicCharacter == NULL )
				{
					MIX_LOG_ERROR( Mix::STR_OUTOFMEMORY );
					MIX_RELEASE( pInternalKChar );
					return False;
				}

				MIX_RELEASE( pInternalKChar );
			}
			else
			{
				return False;
			}
		}
		else
		{
			pReader->Seek( Mix::IO::SEEK_METHOD_CURRENT, sizeof( ActorLoader::MAM_KINEMATIC_CHARACTER_1_0_0_0 ) );
		}
	}

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

	if( dataHeader.shapeNum > 0 )
	{
		UInt32 buffSize = sizeof( ActorLoader::MAM_SHAPE_1_0_0_0 ) * dataHeader.shapeNum;

		if( m_pDynamicsManager != NULL )
		{
			m_TempBuffer.clear();
			m_TempBuffer.resize( buffSize );

			if( pReader->Read( &( m_TempBuffer[0] ), MIX_UIT_TO_UI32( m_TempBuffer.size() ) ) != buffSize )
			{
				MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
				return False;
			}

			const ActorLoader::MAM_SHAPE_1_0_0_0* pSrc = reinterpret_cast<const ActorLoader::MAM_SHAPE_1_0_0_0*>( &( m_TempBuffer[0] ) );
			const ActorLoader::MAM_SHAPE_1_0_0_0* pSrcEnd = pSrc + dataHeader.shapeNum;
			UInt32 debugIndex = 0;

			while( pSrc != pSrcEnd )
			{
				ActorLoader::SHAPE shape;

				shape.localRot = pSrc->localRotation;
				shape.localPos = pSrc->localPosition;
				shape.ptr = NULL;

				if( pSrc->type == ActorLoader::MAM_BOX_SHAPE )
				{
					const ActorLoader::MAM_BOX_SHAPE_DATA_1_0_0_0* pData = reinterpret_cast<const ActorLoader::MAM_BOX_SHAPE_DATA_1_0_0_0*>( &( pSrc->data[0] ) );
					Mix::Dynamics::IBoxShape* pBoxShape = NULL;

					tempStr.Sprintf( L"%s\\Shape%d_Box", pFilePath, debugIndex );

					if( m_pDynamicsManager->CreateBoxShape( pData->halfExtents, &pBoxShape, tempStr.GetConstPtr() ) == True )
					{
						shape.ptr = pBoxShape;
					}
					else
					{
						return False;
					}
				}
				else if( pSrc->type == ActorLoader::MAM_CAPSULE_SHAPE )
				{
					const ActorLoader::MAM_CAPSULE_SHAPE_DATA_1_0_0_0* pData = reinterpret_cast<const ActorLoader::MAM_CAPSULE_SHAPE_DATA_1_0_0_0*>( &( pSrc->data[0] ) );

					Mix::Dynamics::AXIS_TYPE axis;
					Mix::Dynamics::ICapsuleShape* pCapsuleShape = NULL;

					switch( pData->axis )
					{
					case ActorLoader::MAM_AXIS_X:
						axis = Mix::Dynamics::AXIS_X;
						break;
					case ActorLoader::MAM_AXIS_Y:
						axis = Mix::Dynamics::AXIS_Y;
						break;
					case ActorLoader::MAM_AXIS_Z:
						axis = Mix::Dynamics::AXIS_Z;
						break;

					default:
						MIX_ERROR( L"カプセルシェイプにサポートされていない軸を設定しようとしました : Axis[%d]", pData->axis );
						return False;
					}

					tempStr.Sprintf( L"%s\\Shape%d_Capsule", pFilePath, debugIndex );

					if( m_pDynamicsManager->CreateCapsuleShape( axis, pData->length, pData->radius, &pCapsuleShape, tempStr.GetConstPtr() ) == True )
					{
						shape.ptr = pCapsuleShape;
					}
					else
					{
						return False;
					}
				}
				else if( pSrc->type == ActorLoader::MAM_SPHERE_SHAPE )
				{
					const ActorLoader::MAM_SPHERE_SHAPE_DATA_1_0_0_0* pData = reinterpret_cast<const ActorLoader::MAM_SPHERE_SHAPE_DATA_1_0_0_0*>( &( pSrc->data[0] ) );
					Mix::Dynamics::ISphereShape* pSphereShape = NULL;

					tempStr.Sprintf( L"%s\\Shape%d_Sphere", pFilePath, debugIndex );

					if( m_pDynamicsManager->CreateSphereShape( pData->radius, &pSphereShape, tempStr.GetConstPtr() ) == True )
					{
						shape.ptr = pSphereShape;
					}
					else
					{
						return False;
					}
				}
				else
				{
					MIX_ERROR( L"サポートされないシェイプが定義されています : ShapeType[%d]", pSrc->type );
					return False;
				}

				m_ShapeList.push_back( shape );

				pSrc++;
				debugIndex++;
			}
		}
		else
		{
			pReader->Seek( Mix::IO::SEEK_METHOD_CURRENT, static_cast<UInt64>( buffSize ) );
		}
	}

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

	if( dataHeader.colliderNum > 0 )
	{
		UInt32 buffSize = sizeof( ActorLoader::MAM_COLLIDER_1_0_0_0 ) * dataHeader.colliderNum;

		if( m_pDynamicsManager != NULL )
		{
			m_TempBuffer.clear();
			m_TempBuffer.resize( buffSize );

			if( pReader->Read( &( m_TempBuffer[0] ), MIX_UIT_TO_UI32( m_TempBuffer.size() ) ) != buffSize )
			{
				MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
				return False;
			}

			const ActorLoader::MAM_COLLIDER_1_0_0_0* pSrc = reinterpret_cast<const ActorLoader::MAM_COLLIDER_1_0_0_0*>( &( m_TempBuffer[0] ) );
			const ActorLoader::MAM_COLLIDER_1_0_0_0* pSrcEnd = pSrc + dataHeader.colliderNum;

			while( pSrc != pSrcEnd )
			{
				Mix::Dynamics::IShape* pShape = NULL;
				Mix::Dynamics::IRigidBody* pObject = NULL;
				Mix::Scene::Common::ActorCollider* pCollider = NULL;

				/*
					シェイプの取得
				*/

				if( pSrc->shapeNum > 0 )
				{
					//複合
					Mix::Dynamics::ICompoundShape* pCompoundShape = NULL;

					tempStr.Sprintf( L"%s\\Collider\\%s", pFilePath, pSrc->name );

					if( m_pDynamicsManager->CreateCompoundShape( &pCompoundShape, tempStr.GetConstPtr() ) == True )
					{
						UInt32 shapeNum = pSrc->shapeNum;

						for( UInt32 i = 0; i < shapeNum; i++ )
						{
							const ActorLoader::SHAPE& shape = m_ShapeList[shapeIndex];

							if( pCompoundShape->AddChild( shape.ptr, shape.localRot, shape.localPos ) == False )
							{
								MIX_RELEASE( pCompoundShape );
								return False;
							}

							shapeIndex++;
						}

						pShape = pCompoundShape;
					}
					else
					{
						return False;
					}
				}
				else
				{
					MIX_ERROR( L"コライダーにシェイプが設定されていません : Collider[%s]", pSrc->name );
				}

				/*
					オブジェクトの作成
				*/

				tempStr.Sprintf( L"%s\\Collider\\%s", pFilePath, pSrc->name );

				if( m_pDynamicsManager->CreateRigidBody( pSrc->mass, pShape, &pObject, tempStr.GetConstPtr() ) == True )
				{
					Mix::Vector3 angularFactor;

					//物理マテリアル
					pObject->SetMaterial( Mix::Dynamics::MATERIAL( pSrc->id, pSrc->attr, pSrc->friction, pSrc->restitution ) );

#ifndef MIX_ACTOR_FORCE_KINEMATIC_COLLIDER

					//ステータス
					switch( pSrc->status )
					{
					case ActorLoader::MAM_CS_DEFAULT:
						pObject->SetStatus( Mix::Dynamics::IRigidBody::DEFAULT );
						break;
					case ActorLoader::MAM_CS_STATIC:
						pObject->SetStatus( Mix::Dynamics::IRigidBody::STATIC );
						break;
					case ActorLoader::MAM_CS_KINEMATIC:
						pObject->SetStatus( Mix::Dynamics::IRigidBody::KINEMATIC );
						break;

					default:
						MIX_ERROR( L"サポートされないステータスをコライダーに設定しようとしました : Collider[%s] Status[%d]", pSrc->name, pSrc->status );
					}

#else //MIX_ACTOR_FORCE_KINEMATIC_COLLIDER

					pObject->SetStatus( Mix::Dynamics::IRigidBody::KINEMATIC );
#endif

					//回転軸
					angularFactor.x = ( MIX_TESTBIT( pSrc->flags, ActorLoader::MAM_CF_ROT_X ) == ActorLoader::MAM_CF_ROT_X )? 1.0f : 0.0f;
					angularFactor.y = ( MIX_TESTBIT( pSrc->flags, ActorLoader::MAM_CF_ROT_Y ) == ActorLoader::MAM_CF_ROT_Y )? 1.0f : 0.0f;
					angularFactor.z = ( MIX_TESTBIT( pSrc->flags, ActorLoader::MAM_CF_ROT_Z ) == ActorLoader::MAM_CF_ROT_Z )? 1.0f : 0.0f;
					pObject->SetAngularFactor( angularFactor );

					//常にアクティブ
					if( MIX_TESTBIT( pSrc->flags, ActorLoader::MAM_CF_ALWAYS_ACTIVE ) == ActorLoader::MAM_CF_ALWAYS_ACTIVE )
					{
						pObject->SetAlwaysActive( true );
					}

					//トランスフォーム
					pObject->SetWorldTransform( pSrc->rotation, pSrc->position );
					pObject->ClearMotion();
				}
				else
				{
					MIX_RELEASE( pShape );
					return False;
				}

				/*
					コライダーの作成
				*/

				pCollider = Mix::Scene::Common::ActorCollider::CreateInstance(
					pSrc->name,
					pSrc->centerMatrix,
					pSrc->restoreMatrix,
					pObject,
					( MIX_TESTBIT( pSrc->flags, ActorLoader::MAM_CF_CAST_MOTION ) == ActorLoader::MAM_CF_CAST_MOTION ) );

				if( pCollider != NULL )
				{
					m_ColliderList.push_back( pCollider );
				}
				else
				{
					MIX_RELEASE( pObject );
					MIX_RELEASE( pShape );
					return False;
				}

				/*
					後処理
				*/

				MIX_RELEASE( pObject );
				MIX_RELEASE( pShape );

				pSrc++;
			}
		}
		else
		{
			pReader->Seek( Mix::IO::SEEK_METHOD_CURRENT, static_cast<UInt64>( buffSize ) );
		}

	}

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

	if( dataHeader.sensorNum > 0 )
	{
		UInt32 buffSize = sizeof( ActorLoader::MAM_SENSOR_1_0_0_0 ) * dataHeader.sensorNum;

		if( m_pDynamicsManager != NULL )
		{
			m_TempBuffer.clear();
			m_TempBuffer.resize( buffSize );

			if( pReader->Read( &( m_TempBuffer[0] ), MIX_UIT_TO_UI32( m_TempBuffer.size() ) ) != buffSize )
			{
				MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
				return False;
			}

#ifndef MIX_ACTOR_LOADER_DISABLE_SENSOR

			const ActorLoader::MAM_SENSOR_1_0_0_0* pSrc = reinterpret_cast<const ActorLoader::MAM_SENSOR_1_0_0_0*>( &( m_TempBuffer[0] ) );
			const ActorLoader::MAM_SENSOR_1_0_0_0* pSrcEnd = pSrc + dataHeader.sensorNum;

			while( pSrc != pSrcEnd )
			{
				Mix::Dynamics::IShape* pShape = NULL;
				Mix::Dynamics::ISensor* pObject = NULL;
				Mix::Scene::Common::ActorSensor* pSensor = NULL;

				/*
					シェイプの取得
				*/

				if( pSrc->shapeNum == 1 )
				{
					//単体
					pShape = m_ShapeList[shapeIndex].ptr;
					MIX_ADD_REF( pShape );

					shapeIndex++;
				}
				else if( pSrc->shapeNum > 1 )
				{
					//複合
					Mix::Dynamics::ICompoundShape* pCompoundShape = NULL;

					tempStr.Sprintf( L"%s\\Sensor\\%s", pFilePath, pSrc->name );

					if( m_pDynamicsManager->CreateCompoundShape( &pCompoundShape, tempStr.GetConstPtr() ) == True )
					{
						UInt32 shapeNum = pSrc->shapeNum;

						for( UInt32 i = 0; i < shapeNum; i++ )
						{
							const ActorLoader::SHAPE& shape = m_ShapeList[shapeIndex];

							if( pCompoundShape->AddChild( shape.ptr, shape.localRot, shape.localPos ) == False )
							{
								MIX_RELEASE( pCompoundShape );
								return False;
							}

							shapeIndex++;
						}

						pShape = pCompoundShape;
					}
					else
					{
						return False;
					}
				}
				else
				{
					MIX_ERROR( L"センサーにシェイプが設定されていません : Sensor[%s]", pSrc->name );
				}

				/*
					オブジェクトの作成
				*/

				tempStr.Sprintf( L"%s\\Sensor\\%s", pFilePath, pSrc->name );

				if( m_pDynamicsManager->CreateSensor( pShape, &pObject, tempStr.GetConstPtr() ) == True )
				{
					//物理マテリアル
					pObject->SetMaterial( Mix::Dynamics::MATERIAL( pSrc->id, pSrc->attr ) );

					//トランスフォーム
					pObject->SetWorldTransform( pSrc->rotation, pSrc->position );
				}
				else
				{
					MIX_RELEASE( pShape );
					return False;
				}

				/*
					センサーの作成
				*/

				pSensor = Mix::Scene::Common::ActorSensor::CreateInstance(
					pSrc->name,
					pSrc->centerMatrix,
					pObject );

				if( pSensor != NULL )
				{
					m_SensorList.push_back( pSensor );
				}
				else
				{
					MIX_RELEASE( pObject );
					MIX_RELEASE( pShape );
					return False;
				}

				/*
					後処理
				*/

				MIX_RELEASE( pObject );
				MIX_RELEASE( pShape );

				pSrc++;
			}

#endif //MIX_ACTOR_LOADER_DISABLE_SENSOR
		}
		else
		{
			pReader->Seek( Mix::IO::SEEK_METHOD_CURRENT, static_cast<UInt64>( buffSize ) );
		}
	}

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

	if( dataHeader.jointNum > 0 )
	{
		UInt32 buffSize = sizeof( ActorLoader::MAM_JOINT_1_0_0_0 ) * dataHeader.jointNum;

		if( m_pDynamicsManager != NULL )
		{
			m_TempBuffer.clear();
			m_TempBuffer.resize( buffSize );

			if( pReader->Read( &( m_TempBuffer[0] ), MIX_UIT_TO_UI32( m_TempBuffer.size() ) ) != buffSize )
			{
				MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
				return False;
			}

#ifndef MIX_ACTOR_LOADER_DISABLE_JOINT

			const ActorLoader::MAM_JOINT_1_0_0_0* pSrc = reinterpret_cast<const ActorLoader::MAM_JOINT_1_0_0_0*>( &( m_TempBuffer[0] ) );
			const ActorLoader::MAM_JOINT_1_0_0_0* pSrcEnd = pSrc + dataHeader.jointNum;

			while( pSrc != pSrcEnd )
			{
				MIX_ASSERT( ( pSrc->colliderA >= 0 ) && ( pSrc->colliderA < static_cast<int>( dataHeader.colliderNum ) ) );
				MIX_ASSERT( ( pSrc->colliderB >= 0 ) && ( pSrc->colliderB < static_cast<int>( dataHeader.colliderNum ) ) );

				UInt32 debugIndex = 0;

				Mix::Dynamics::IRigidBody* pRigidBodyA = m_ColliderList[pSrc->colliderA]->GetInternalRigidBodyPtr();
				Mix::Dynamics::IRigidBody* pRigidBodyB = ( pSrc->colliderB >= 0 )? m_ColliderList[pSrc->colliderB]->GetInternalRigidBodyPtr() : NULL;
				const Mix::Vector4& pivotA = pSrc->pivotA;
				const Mix::Vector4& pivotB = pSrc->pivotB;

				Mix::Dynamics::IJoint* pJoint = NULL;

				if( pSrc->type == ActorLoader::MAM_POINT_JOINT )
				{
					const ActorLoader::MAM_POINT_JOINT_DATA_1_0_0_0* pPointJointData = reinterpret_cast<const ActorLoader::MAM_POINT_JOINT_DATA_1_0_0_0*>( &( pSrc->data[0] ) );
					Mix::Dynamics::IPointJoint* pPointJoint = NULL;

					/*
						インターフェースの作成
					*/

					tempStr.Sprintf( L"%s\\Joint%d_Point", pFilePath, debugIndex );

					if( pRigidBodyB != NULL )
					{
						if( m_pDynamicsManager->CreatePointJoint(	pRigidBodyA,
																	pRigidBodyB,
																	pivotA,
																	pivotB,
																	&pPointJoint,
																	tempStr.GetConstPtr() ) == false )
						{
							return False;
						}
					}
					else
					{
						if( m_pDynamicsManager->CreatePointJoint(	pRigidBodyA,
																	pivotA,
																	&pPointJoint,
																	tempStr.GetConstPtr() ) == false )
						{
							return False;
						}
					}

					/*
						パラメータの設定
					*/

					if( MIX_FLOAT_IS_ZERO( pPointJointData->pivotSpring ) == False )
					{
						pPointJoint->SetPivotSpring( pPointJointData->pivotSpring );
					}

					if( MIX_FLOAT_IS_ZERO( pPointJointData->pivotDamper ) == False )
					{
						pPointJoint->SetPivotSpring( pPointJointData->pivotDamper );
					}

					pJoint = pPointJoint;
				}
				else if( pSrc->type == ActorLoader::MAM_HINGE_JOINT )
				{
					const ActorLoader::MAM_HINGE_JOINT_DATA_1_0_0_0* pHingeJointData = reinterpret_cast<const ActorLoader::MAM_HINGE_JOINT_DATA_1_0_0_0*>( &( pSrc->data[0] ) );
					Mix::Dynamics::IHingeJoint* pHingeJoint = NULL;

					/*
						インターフェースの作成
					*/

					tempStr.Sprintf( L"%s\\Joint%d_Hinge", pFilePath, debugIndex );

					if( pRigidBodyB != NULL )
					{
						if( m_pDynamicsManager->CreateHingeJoint(	pRigidBodyA,
																	pRigidBodyB,
																	pivotA,
																	pivotB,
																	pHingeJointData->axis,
																	&pHingeJoint,
																	tempStr.GetConstPtr() ) == False )
						{
							return False;
						}
					}
					else
					{
						if( m_pDynamicsManager->CreateHingeJoint(	pRigidBodyA,
																	pivotA,
																	pHingeJointData->axis,
																	&pHingeJoint,
																	tempStr.GetConstPtr() ) == False )
						{
							return False;
						}
					}

					/*
						パラメータの設定
					*/

					pHingeJoint->SetAxis( pHingeJointData->axis );
					pHingeJoint->SetLowerLimit( pHingeJointData->lowerLimit );
					pHingeJoint->SetUpperLimit( pHingeJointData->upperLimit );

					if( MIX_FLOAT_IS_ZERO( pHingeJointData->limitSpring ) == False )
					{
						pHingeJoint->SetLimitSpring( pHingeJointData->limitSpring );
					}

					if( MIX_FLOAT_IS_ZERO( pHingeJointData->limitDamper ) == False )
					{
						pHingeJoint->SetLimitSpring( pHingeJointData->limitDamper );
					}

					pJoint = pHingeJoint;
				}
				else if( pSrc->type == ActorLoader::MAM_BALL_JOINT )
				{
					const ActorLoader::MAM_BALL_JOINT_DATA_1_0_0_0* pBallJointData = reinterpret_cast<const ActorLoader::MAM_BALL_JOINT_DATA_1_0_0_0*>( &( pSrc->data[0] ) );
					Mix::Dynamics::IBallJoint* pBallJoint = NULL;

					/*
						インターフェースの作成
					*/

					tempStr.Sprintf( L"%s\\Joint%d_Ball", pFilePath, debugIndex );

					if( pRigidBodyB != NULL )
					{
						if( m_pDynamicsManager->CreateBallJoint(	pRigidBodyA,
																	pRigidBodyB,
																	pivotA,
																	pivotB,
																	pBallJointData->twistAxis,
																	pBallJointData->swingAxis,
																	&pBallJoint,
																	tempStr.GetConstPtr() ) == False )
						{
							return False;
						}
					}
					else
					{
						if( m_pDynamicsManager->CreateBallJoint(	pRigidBodyA,
																	pivotA,
																	pBallJointData->twistAxis,
																	pBallJointData->swingAxis,
																	&pBallJoint,
																	tempStr.GetConstPtr() ) == False )
						{
							return False;
						}
					}

					/*
						パラメータの設定
					*/

					pBallJoint->SetTwistAxis( pBallJointData->twistAxis );
					pBallJoint->SetTwistLimit( pBallJointData->twistLimit );

					pBallJoint->SetSwingAxis( pBallJointData->swingAxis );
					pBallJoint->SetSwingLimit1( pBallJointData->swingLimit1 );
					pBallJoint->SetSwingLimit2( pBallJointData->swingLimit2 );

					if( MIX_FLOAT_IS_ZERO( pBallJointData->pivotSpring ) == False )
					{
						pBallJoint->SetPivotSpring( pBallJointData->pivotSpring );
					}

					if( MIX_FLOAT_IS_ZERO( pBallJointData->pivotDamper ) == False )
					{
						pBallJoint->SetPivotSpring( pBallJointData->pivotDamper );
					}

					if( MIX_FLOAT_IS_ZERO( pBallJointData->limitSpring ) == False )
					{
						pBallJoint->SetLimitSpring( pBallJointData->limitSpring );
					}

					if( MIX_FLOAT_IS_ZERO( pBallJointData->limitDamper ) == False )
					{
						pBallJoint->SetLimitSpring( pBallJointData->limitDamper );
					}

					pJoint = pBallJoint;
				}
				else
				{
					MIX_ERROR( L"サポートされないジョイントが定義されています : JointType[%d]", pSrc->type );
					return False;
				}

				m_JointList.push_back( ActorLoader::JOINT( ( MIX_TESTBIT( pSrc->flags, ActorLoader::MAM_JF_COLLISION_DISABLED ) == ActorLoader::MAM_JF_COLLISION_DISABLED ), pSrc->localPivotB, pJoint ) );

				pSrc++;
				debugIndex++;
			}

#endif //MIX_ACTOR_LOADER_DISABLE_JOINT
		}
		else
		{
			pReader->Seek( Mix::IO::SEEK_METHOD_CURRENT, static_cast<UInt64>( buffSize ) );
		}
	}

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

	if( dataHeader.mainFrameNum > 0 )
	{
		const ActorLoader::MAM_MAIN_FRAME_1_0_0_0* mamMainFrame;
		Mix::Matrix4x4 pivotMat;

		m_TempBuffer.clear();
		m_TempBuffer.resize( sizeof( ActorLoader::MAM_MAIN_FRAME_1_0_0_0 ) );

		if( pReader->Read( &( m_TempBuffer[0] ), MIX_UIT_TO_UI32( m_TempBuffer.size() ) ) == sizeof( ActorLoader::MAM_MAIN_FRAME_1_0_0_0 ) )
		{
			mamMainFrame = reinterpret_cast<const ActorLoader::MAM_MAIN_FRAME_1_0_0_0*>( &( m_TempBuffer[0] ) );
		}
		else
		{
			MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
			return False;
		}

		/*
			ピボット行列
		*/

		switch( mamMainFrame->coordinateSystem )
		{
		case ActorLoader::MAM_CS_LH:
			//左手座標系
			pivotMat.SetScaling( +mamMainFrame->scaling.x, +mamMainFrame->scaling.y, +mamMainFrame->scaling.z );
			break;
		case ActorLoader::MAM_CS_RH:
			//右手座標系
			pivotMat.SetScaling( +mamMainFrame->scaling.x, +mamMainFrame->scaling.y, -mamMainFrame->scaling.z );
			break;

		default:
			MIX_ERROR( L"サポートされない座標系が指定されています : CoordinateSystem[%d]", mamMainFrame->coordinateSystem );
			return False;
		}

		pivotMat *= Mix::Matrix4x4( mamMainFrame->rotation );
		pivotMat.SetRow( 3, mamMainFrame->translation );

		pModel->SetPivotMatrix( pivotMat );

		/*
			ダイナミクス
		*/

		if( m_pDynamicsManager != NULL )
		{
			Mix::Scene::Common::ActorDynamicsFigure* pDynamicsFigure = NULL;

			//フィギュアの作成
			pDynamicsFigure = Mix::Scene::Common::ActorDynamicsFigure::CreateInstance();
			if( pDynamicsFigure == NULL )
			{
				MIX_LOG_ERROR( Mix::STR_OUTOFMEMORY );
				return False;
			}

			//レシーブモーション
			pDynamicsFigure->SetReceiveMotionMatrix( mamMainFrame->receiveMotionMatrix );

			//キネマティックキャラクター
			if( m_pKinematicCharacter != NULL )
			{
				pDynamicsFigure->SetCharacter( m_pKinematicCharacter );
			}

			//コライダー
			if( mamMainFrame->colliderNum > 0 )
			{
				MIX_ASSERT( ( mamMainFrame->colliderNum == 1 ) && ( colliderIndex < m_ColliderList.size() ) );
				MIX_ASSERT( m_ColliderList[colliderIndex]->IsCastMotion() == False );

				pDynamicsFigure->SetCollider( m_ColliderList[colliderIndex] );

				colliderIndex += mamMainFrame->colliderNum;
			}

#ifndef MIX_ACTOR_LOADER_DISABLE_SENSOR

			//センサー
			if( mamMainFrame->sensorNum > 0 )
			{
				UInt32 startIndex = sensorIndex;
				UInt32 endIndex = startIndex + mamMainFrame->sensorNum;

				MIX_ASSERT( ( startIndex < m_SensorList.size() ) && ( endIndex <= m_SensorList.size() ) );

				for( UInt32 i = startIndex; i < endIndex; i++ )
				{
					pDynamicsFigure->AddSensor( m_SensorList[i] );
				}

				pDynamicsFigure->FinishSensors( mamMainFrame->sensorNum );

				sensorIndex += mamMainFrame->sensorNum;
			}

#endif //MIX_ACTOR_LOADER_DISABLE_SENSOR

			//ファイナライズ
			pModel->SetDynamicsFigure( pDynamicsFigure );
			pDynamicsDirector->SetFigure( pDynamicsFigure );

			MIX_RELEASE( pDynamicsFigure );
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノード & モーションミキサー
	////////////////////////////////////////////////////////////////////////////////////////////////////

#ifdef _DEBUG
		Mix::String debCastMotionNodeName = L"";
#endif //_DEBUG

	const ActorLoader::MAM_NODE_1_0_0_0* mamNodes = NULL;

	m_TempBuffer.clear();
	m_TempBuffer.resize( sizeof( ActorLoader::MAM_NODE_1_0_0_0 ) * dataHeader.nodeNum );

	nodeByteSize = sizeof( ActorLoader::MAM_NODE_1_0_0_0 ) * dataHeader.nodeNum;

	if( pReader->Read( &( m_TempBuffer[0] ), MIX_UIT_TO_UI32( m_TempBuffer.size() ) ) == nodeByteSize )
	{
		mamNodes = reinterpret_cast<const ActorLoader::MAM_NODE_1_0_0_0*>( &( m_TempBuffer[0] ) );
	}
	else
	{
		MIX_LOG_ERROR( Mix::STR_ILLEGALFORMAT );
		return False;
	}

	nodeList = pModel->GetNodeList();
	if( nodeList == NULL )
	{
		MIX_LOG_ERROR( Mix::STR_OUTOFMEMORY );
		return False;
	}

	pMotionMixer->ReservePoseTable( dataHeader.nodeNum );

	for( i = 0; i < dataHeader.nodeNum; i++ )
	{
		const ActorLoader::MAM_NODE_1_0_0_0& srcNode = mamNodes[i];
		Mix::Scene::Common::ActorNode* pDstNode = nodeList[i];

		/*
			基本
		*/

		Mix::Matrix4x4 geometricMat;
		Mix::Matrix4x4 localMat;

		geometricMat.SetScaling( srcNode.geometricS );
		geometricMat *= Mix::Matrix4x4( srcNode.geometricR );
		geometricMat.m30 = srcNode.geometricT.x;
		geometricMat.m31 = srcNode.geometricT.y;
		geometricMat.m32 = srcNode.geometricT.z;
		geometricMat.m33 = 1.0f;

		localMat.SetScaling( srcNode.localS );
		localMat *= Mix::Matrix4x4( srcNode.localR );
		localMat.m30 = srcNode.localT.x;
		localMat.m31 = srcNode.localT.y;
		localMat.m32 = srcNode.localT.z;
		localMat.m33 = 1.0f;

		pDstNode->SetParent( srcNode.parent, ( srcNode.parent >= 0 )? nodeList[srcNode.parent] : NULL );
		pDstNode->ReserveChilds( srcNode.childCount );

		pDstNode->SetName( srcNode.name );
		pDstNode->SetGeometricMatrix( geometricMat );
		pDstNode->SetDefLocalMatrix( localMat );
		pDstNode->SetMesh( ( srcNode.meshIndex >= 0 )? m_MeshList[srcNode.meshIndex] : NULL );

		/*
			ダイナミクス
		*/

		if( m_pDynamicsManager != NULL )
		{
			Mix::Scene::Common::ActorDynamicsPart* pDynamicsPart = NULL;

			//パートの作成
			if( ( srcNode.colliderNum > 0 ) ||
				( srcNode.sensorNum > 0 ) ||
				( srcNode.jointNum > 0 ) )
			{
				pDynamicsPart = Mix::Scene::Common::ActorDynamicsPart::CreateInstance();
				if( pDynamicsPart == NULL )
				{
					MIX_LOG_ERROR( Mix::STR_OUTOFMEMORY );
					return False;
				}
			}

			//コライダー
			if( srcNode.colliderNum > 0 )
			{
				MIX_ASSERT( pDynamicsPart != NULL );
				MIX_ASSERT( ( srcNode.colliderNum == 1 ) && ( colliderIndex < m_ColliderList.size() ) );

				Mix::Scene::Common::ActorCollider* pCollider = m_ColliderList[colliderIndex];

#ifdef _DEBUG
				if( ( pCollider->IsCastMotion() == True ) &&
					( debCastMotionNodeName.GetNum() > 0 ) )
				{
					MIX_ERROR( L"アクターモデルにキャストモーション属性を持つノードが複数存在しています : FirstNode[%s] CurrentNode[%s]", debCastMotionNodeName.GetConstPtr(), srcNode.name );
				}
#endif //_DEBUG

				if( pCollider->IsCastMotion() == True )
				{
					//キャストモーションクラスター
					MIX_ASSERT( pModel->GetDynamicsFigurePtr() != NULL );
					pModel->GetDynamicsFigurePtr()->SetCastMotionCluster( pDynamicsPart );
#ifdef _DEBUG
					debCastMotionNodeName = srcNode.name;
#endif //_DEBUG
				}

				pDynamicsPart->SetCollider( pCollider );

				colliderIndex += srcNode.colliderNum;
			}

#ifndef MIX_ACTOR_LOADER_DISABLE_SENSOR

			//センサー
			if( srcNode.sensorNum > 0 )
			{
				MIX_ASSERT( pDynamicsPart != NULL );

				UInt32 startIndex = sensorIndex;
				UInt32 endIndex = startIndex + srcNode.sensorNum;

				MIX_ASSERT( ( startIndex < m_SensorList.size() ) && ( endIndex <= m_SensorList.size() ) );

				for( UInt32 i = startIndex; i < endIndex; i++ )
				{
					pDynamicsPart->AddSensor( m_SensorList[i] );
				}

				pDynamicsPart->FinishSensors( srcNode.sensorNum );

				sensorIndex += srcNode.sensorNum;
			}

#endif //MIX_ACTOR_LOADER_DISABLE_SENSOR

#ifndef MIX_ACTOR_LOADER_DISABLE_JOINT

			//ジョイント
			if( srcNode.jointNum > 0 )
			{
				MIX_ASSERT( pDynamicsPart != NULL );
				MIX_ASSERT( ( srcNode.jointNum == 1 ) && ( jointIndex < m_JointList.size() ) );

				const ActorLoader::JOINT& joint = m_JointList[jointIndex];

				pDynamicsPart->SetJoint( joint.bCollisionDisabled, joint.localPivotB, joint.ptr );

				jointIndex += srcNode.jointNum;
			}

#endif //MIX_ACTOR_LOADER_DISABLE_JOINT

			//ファイナライズ
			if( pDynamicsPart != NULL )
			{
				pDstNode->SetDynamicsPart( pDynamicsPart );
				pDynamicsDirector->AddPart( pDynamicsPart );
				MIX_RELEASE( pDynamicsPart );
			}
		}

		/*
			モーションミキサー
		*/

		pMotionMixer->AddPose(	srcNode.localS,
								srcNode.localR,
								srcNode.localT,
								pDstNode->GetLocalMatrixPtr(),
								pDstNode->GetRevisionPtr() );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ファイナライズ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pModel->Finalize();

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

	return True;
}

}}}
