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

#include "Mix/Tool/Win32/Core/Dynamics/Design/Part.h"
#include "Mix/Tool/Win32/Core/Graphics/LineHelper.h"
#include "Mix/Tool/Win32/Core/Graphics/Mesh.h"
#include "Mix/Tool/Win32/Core/Graphics/Model.h"

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

Node::Node(	Model* pModel,
			int index,
			const char* pName,
			Node* pParent,
			const D3DXMATRIX geoMat,
			const D3DXVECTOR3& localS,
			const D3DXQUATERNION& localR,
			const D3DXVECTOR3& localT ) :

m_pModel( pModel ),
m_Index( index ),
m_pParent( pParent ),
m_Attr( Mix::Tool::Win32::Graphics::Node::EMPTY ),
m_MeshIndex( -1 ),
m_pMesh( NULL ),
m_GeometricMat( geoMat ),
m_DefLocalS( localS ),
m_DefLocalR( localR ),
m_DefLocalT( localT ),
m_LocalS( localS ),
m_LocalR( localR ),
m_LocalT( localT ),
m_pDynamicsPartDesigner( NULL )
{
	//名前
	if( AnsiToWide( pName, m_Name ) == false )
	{
		m_Name = L"名前の変換に失敗";
	}

	//ジオメトリック行列
	D3DXMatrixDecompose( &m_GeometricS, &m_GeometricR, &m_GeometricT, &m_GeometricMat );

	//ローカル行列
	m_DefLocalMat = m_LocalMat = Node::ComputeTransform( m_DefLocalS, m_DefLocalR, m_DefLocalT );

	//ワールド行列
	if( m_pParent != NULL )
	{
		m_WorldMat = m_GeometricMat * m_LocalMat * m_pParent->m_WorldMat;
	}
	else
	{
		m_WorldMat = m_GeometricMat * m_LocalMat;
	}

	//親に子として追加
	if( m_pParent != NULL )
	{
		m_pParent->m_ChildList.push_back( this );
	}
}

Node::Node(	Model* pModel,
			int index,
			const wchar_t* pName,
			Node* pParent,
			const D3DXMATRIX geoMat,
			const D3DXVECTOR3& localS,
			const D3DXQUATERNION& localR,
			const D3DXVECTOR3& localT ) :
m_pModel( pModel ),
m_Index( index ),
m_Name( pName ),
m_pParent( pParent ),
m_Attr( Mix::Tool::Win32::Graphics::Node::EMPTY ),
m_MeshIndex( -1 ),
m_pMesh( NULL ),
m_GeometricMat( geoMat ),
m_DefLocalS( localS ),
m_DefLocalR( localR ),
m_DefLocalT( localT ),
m_LocalS( localS ),
m_LocalR( localR ),
m_LocalT( localT ),
m_pDynamicsPartDesigner( NULL )
{
	//名前
	m_Name = pName;

	//ローカル行列
	m_DefLocalMat = m_LocalMat = Node::ComputeTransform( m_DefLocalS, m_DefLocalR, m_DefLocalT );

	//ワールド行列
	if( m_pParent != NULL )
	{
		m_WorldMat = m_GeometricMat * m_LocalMat * m_pParent->m_WorldMat;
	}
	else
	{
		m_WorldMat = m_GeometricMat * m_LocalMat;
	}

	//親に子として追加
	if( m_pParent != NULL )
	{
		m_pParent->m_ChildList.push_back( this );
	}
}

Node::~Node( void )
{
}

void Node::SetEmpty( void )
{
	m_Attr = Node::EMPTY;
	m_MeshIndex = -1;
	m_pMesh = NULL;
}

void Node::SetMesh( int index, Mix::Tool::Win32::Graphics::Mesh* pPtr )
{
	m_Attr = Node::MESH;
	m_MeshIndex = index;
	m_pMesh = pPtr;
}

void Node::SetBone( void )
{
	m_Attr = Node::BONE;
	m_MeshIndex = -1;
	m_pMesh = NULL;
}

void Node::AddBaseShape( const wchar_t* pName, const std::vector<D3DXVECTOR3>& vertices )
{
	if( ( pName == NULL ) ||
		( ::wcslen( pName ) == 0 ) ||
		( vertices.size() == 0 ) )
	{
		return;
	}

	if( vertices.size() <= 1 )
	{
		//一個は点なのでベースシェイプとはしない
		return;
	}
	else
	{
		//平面、点はベースシェイプとしない
		const D3DXVECTOR3* pVertex = &( vertices[0] );
		const D3DXVECTOR3* pVertexEnd = pVertex + vertices.size();
		D3DXVECTOR3 aabbMin( +FLT_MAX, +FLT_MAX, +FLT_MAX );
		D3DXVECTOR3 aabbMax( -FLT_MAX, -FLT_MAX, -FLT_MAX );

		while( pVertex != pVertexEnd )
		{
			aabbMin = Mix::Tool::Win32::Min( aabbMin, *pVertex );
			aabbMax = Mix::Tool::Win32::Max( aabbMax, *pVertex );

			pVertex++;
		}

		if( ( MIX_FLOAT_IS_ZERO( aabbMax.x - aabbMin.x ) == true ) ||
			( MIX_FLOAT_IS_ZERO( aabbMax.y - aabbMin.y ) == true ) ||
			( MIX_FLOAT_IS_ZERO( aabbMax.z - aabbMin.z ) == true ) )
		{
			return;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ベースシェイプの OBB を求める
	////////////////////////////////////////////////////////////////////////////////////////////////////

	Node::SHAPE_CONTEXT ctx;

	Node::BaseShape_Phase1_Initialize( ctx );
	Node::BaseShape_Phase2_Center_Append( vertices, ctx );
	Node::BaseShape_Phase2_Center_Finish( ctx );
	Node::BaseShape_Phase3_Matrix_Append( vertices, ctx );
	Node::BaseShape_Phase3_Matrix_Finish( ctx );
	Node::BaseShape_Phase4_OBB_Append( vertices, ctx );
	Node::BaseShape_Phase4_OBB_Finish( ctx );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ベースシェイプを追加
	////////////////////////////////////////////////////////////////////////////////////////////////////

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

	baseShape.name = pName;
	baseShape.obb = ctx.obb;

	m_BaseShapeList.push_back( baseShape );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 頂点を追加
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_VertexList.insert( m_VertexList.end(), vertices.begin(), vertices.end() );
}

void Node::FinalizeBaseShape( void )
{
	size_t baseShapeCount = m_BaseShapeList.size();
	bool bApplyScaling = true;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ベースシェイプの調整
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( baseShapeCount == 0 )
	{
		/*
			適当に入れる
		*/

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

		baseShape.name = m_Name;
		baseShape.obb.pos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
		baseShape.obb.axis[0] = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
		baseShape.obb.axis[1] = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
		baseShape.obb.axis[2] = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
		baseShape.obb.len = D3DXVECTOR3( 0.01f, 0.01f, 0.01f );

		m_BaseShapeList.push_back( baseShape );

		bApplyScaling = false;
	}
	else if( baseShapeCount == 1 )
	{
		/*
			ベースのシェイプの名前を自身に変更
		*/

		m_BaseShapeList[0].name = m_Name;
	}
	else
	{
		/*
			全てのベースシェイプを囲む OBB を求める
		*/

		Node::SHAPE_CONTEXT ctx;

		Node::BaseShape_Phase1_Initialize( ctx );
		Node::BaseShape_Phase2_Center_Append( m_VertexList, ctx );
		Node::BaseShape_Phase2_Center_Finish( ctx );
		Node::BaseShape_Phase3_Matrix_Append( m_VertexList, ctx );
		Node::BaseShape_Phase3_Matrix_Finish( ctx );
		Node::BaseShape_Phase4_OBB_Append( m_VertexList, ctx );
		Node::BaseShape_Phase4_OBB_Finish( ctx );

		/*
			ベースシェイプを先頭に挿入
		*/

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

		baseShape.name = m_Name;
		baseShape.obb = ctx.obb;

		m_BaseShapeList.insert( m_BaseShapeList.begin(), baseShape );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ソート
	////////////////////////////////////////////////////////////////////////////////////////////////////

	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( bApplyScaling == true )
	{
		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::vector<Mix::Tool::Win32::Graphics::BASE_SHAPE>::iterator it;

		D3DXMATRIX scalingMat = BaseShape_GetScalingMatrix();
		D3DXVECTOR3 tempVec;

		for( it = it_begin; it != it_end; ++it )
		{
			Mix::Tool::Win32::Graphics::BASE_SHAPE* pBaseShape = &( *it );
			pBaseShape->obb.len = *D3DXVec3TransformCoord( &tempVec, &( pBaseShape->obb.len ), &scalingMat );
		}
	}
}

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

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

	return &( m_BaseShapeList[index] );
}

Mix::Tool::Win32::Geometry::OBB Node::GetObb( int baseShapeIndex )
{
	if( ( baseShapeIndex < 0 ) ||
		( static_cast<int>( m_BaseShapeList.size() ) <= baseShapeIndex ) )
	{
		Mix::Tool::Win32::Geometry::OBB dummy;

		dummy.pos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
		dummy.axis[0] = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
		dummy.axis[1] = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
		dummy.axis[2] = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
		dummy.len = D3DXVECTOR3( 0.1f, 0.1f, 0.1f );

		return dummy;
	}

	return m_BaseShapeList[baseShapeIndex].obb;
}

Mix::Tool::Win32::Geometry::OBB Node::GetObb( int depth, bool bMeshOnly )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ノード階層を下って OBB を作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	Node::SHAPE_CONTEXT ctx;

	Node::BaseShape_Phase1_Initialize( ctx );

	Node::BaseShape_Node_Append( Node::BaseShape_Phase2_Center_Append, this, depth, ctx, bMeshOnly );
	Node::BaseShape_Phase2_Center_Finish( ctx );

	Node::BaseShape_Node_Append( Node::BaseShape_Phase3_Matrix_Append, this, depth, ctx, bMeshOnly );
	Node::BaseShape_Phase3_Matrix_Finish( ctx );

	Node::BaseShape_Node_Append( Node::BaseShape_Phase4_OBB_Append, this, depth, ctx, bMeshOnly );
	Node::BaseShape_Phase4_OBB_Finish( ctx );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// OBB のスケーリング
	////////////////////////////////////////////////////////////////////////////////////////////////////

	D3DXMATRIX scalingMat = BaseShape_GetScalingMatrix();
	D3DXVECTOR3 tempVec;

	ctx.obb.len = *D3DXVec3TransformCoord( &tempVec, &( ctx.obb.len ), &scalingMat );

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

	return ctx.obb;
}

Mix::Tool::Win32::Geometry::OBB Node::GetObb( const D3DXMATRIX& mat )
{
	D3DXVECTOR3 aabbMin( +FLT_MAX, +FLT_MAX, +FLT_MAX );
	D3DXVECTOR3 aabbMax( -FLT_MAX, -FLT_MAX, -FLT_MAX );

	Mix::Tool::Win32::Geometry::OBB obb;

	ComputeBaseShape_ApplyGeometricMatrix( mat, this, aabbMin, aabbMax );

	obb.axis[0] = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
	obb.axis[1] = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
	obb.axis[2] = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
	obb.len = D3DXVECTOR3( ( aabbMax.x - aabbMin.x ) * 0.5f, ( aabbMax.y - aabbMin.y ) * 0.5f, ( aabbMax.z - aabbMin.z ) * 0.5f );
	obb.pos = D3DXVECTOR3( ( aabbMin.x + aabbMax.x ) * 0.5f, ( aabbMin.y + aabbMax.y ) * 0.5f, ( aabbMin.z + aabbMax.z ) * 0.5f );

	return obb;
}

void Node::ComputeBaseShape_ApplyGeometricMatrix( const D3DXMATRIX& parentMat, Mix::Tool::Win32::Graphics::Node* pNode, D3DXVECTOR3& aabbMin, D3DXVECTOR3& aabbMax )
{
	size_t vertexCount = pNode->m_VertexList.size();
	D3DXMATRIX mat = pNode->GetGeometricMatrix() * pNode->GetDefLocalTransform() * parentMat;
	int childCount = pNode->GetChildCount();

	if( vertexCount > 0 )
	{
		const D3DXVECTOR3* pVertex = &( pNode->m_VertexList[0] );
		const D3DXVECTOR3* pVertexEnd = pVertex + vertexCount;

		while( pVertex != pVertexEnd )
		{
			D3DXVECTOR3 vertex;

			D3DXVec3TransformCoord( &vertex, pVertex, &mat );

			if( aabbMin.x > vertex.x ) { aabbMin.x = vertex.x; }
			if( aabbMin.y > vertex.y ) { aabbMin.y = vertex.y; }
			if( aabbMin.z > vertex.z ) { aabbMin.z = vertex.z; }

			if( aabbMax.x < vertex.x ) { aabbMax.x = vertex.x; }
			if( aabbMax.y < vertex.y ) { aabbMax.y = vertex.y; }
			if( aabbMax.z < vertex.z ) { aabbMax.z = vertex.z; }

			pVertex++;
		}
	}

	for( int i = 0; i < childCount; i++ )
	{
		Node* pChildNode = pNode->GetChildPtr( i );
		ComputeBaseShape_ApplyGeometricMatrix( mat, pChildNode, aabbMin, aabbMax );
	}
}

Mix::Tool::Win32::Graphics::Node::ATTRIBUTE Node::GetAttribute( void ) const
{
	return m_Attr;
}

Mix::Tool::Win32::Graphics::Model* Node::GetModelPtr() const
{
	return m_pModel;
}

int Node::GetIndex( void ) const
{
	return m_Index;
}

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

int Node::GetMeshIndex( void ) const
{
	return m_MeshIndex;
}

Mix::Tool::Win32::Graphics::Mesh* Node::GetMeshPtr( void ) const
{
	return m_pMesh;
}

void Node::SetDynamicsPartDesignerPtr( Mix::Tool::Win32::Dynamics::Design::Part* pPartDesigner )
{
	m_pDynamicsPartDesigner = pPartDesigner;
}

Mix::Tool::Win32::Dynamics::Design::Part* Node::GetDynamicsPartDesignerPtr( void ) const
{
	return m_pDynamicsPartDesigner;
}

Mix::Tool::Win32::Graphics::Node* Node::GetParentPtr( void ) const
{
	return m_pParent;
}

int Node::GetChildCount( void ) const
{
	return static_cast<int>( m_ChildList.size() );
}

Mix::Tool::Win32::Graphics::Node* Node::GetChildPtr( int index ) const
{
	if( static_cast<int>( m_ChildList.size() ) <= index )
	{
		return NULL;
	}

	return m_ChildList[index];
}

const D3DXVECTOR3& Node::GetGeometricScaling( void ) const
{
	return m_GeometricS;
}

const D3DXQUATERNION& Node::GetGeometricRotation( void ) const
{
	return m_GeometricR;
}

const D3DXVECTOR3& Node::GetGeometricTranslation( void ) const
{
	return m_GeometricT;
}

const D3DXMATRIX& Node::GetGeometricMatrix( void ) const
{
	return m_GeometricMat;
}

const D3DXVECTOR3& Node::GetDefLocalScaling( void ) const
{
	return m_DefLocalS;
}

const D3DXQUATERNION& Node::GetDefLocalRotation( void ) const
{
	return m_DefLocalR;
}

const D3DXVECTOR3& Node::GetDefLocalTranslation( void ) const
{
	return m_DefLocalT;
}

const D3DXMATRIX& Node::GetDefLocalTransform( void ) const
{
	return m_DefLocalMat;
}

const D3DXVECTOR3& Node::GetLocalScaling( void ) const
{
	return m_LocalS;
}

void Node::SetLocalScaling( const D3DXVECTOR3& scaling )
{
	m_LocalS = scaling;
}

const D3DXQUATERNION& Node::GetLocalRotation( void ) const
{
	return m_LocalR;
}

void Node::SetLocalRotation( const D3DXQUATERNION& rotation )
{
	m_LocalR = rotation;
}

const D3DXVECTOR3& Node::GetLocalTranslation( void ) const
{
	return m_LocalT;
}

void Node::SetLocalTranslation( const D3DXVECTOR3& translation )
{
	m_LocalT = translation;
}

void Node::SetLocalTransform( const D3DXVECTOR3& scaling, const D3DXQUATERNION& rotation, const D3DXVECTOR3& translation )
{
	m_LocalS = scaling;
	m_LocalR = rotation;
	m_LocalT = translation;
}

void Node::SetLocalTransform( const D3DXVECTOR3& scaling, const D3DXQUATERNION& rotation, const D3DXVECTOR3& translation, float ratio )
{
	D3DXVec3Lerp( &m_LocalS, &m_LocalS, &scaling, ratio );
	D3DXQuaternionSlerp( &m_LocalR, &m_LocalR, &rotation, ratio );
	D3DXVec3Lerp( &m_LocalT, &m_LocalT, &translation, ratio );
}

const D3DXMATRIX& Node::GetLocalMatrix( void ) const
{
	return m_LocalMat;
}

const D3DXMATRIX& Node::GetWorldMatrix( void ) const
{
	return m_WorldMat;
}

#if 0

void Node::Reset( const D3DXMATRIX& parentWorldMat )
{
	ResetWorldMatrix( parentWorldMat );
	RefreshMesh();
}

void Node::ResetWorldMatrix( const D3DXMATRIX& parentWorldMat )
{
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child_begin = m_ChildList.begin();
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child_end = m_ChildList.end();
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 自身を処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	//ローカル
	m_LocalS = m_DefLocalS;
	m_LocalR = m_DefLocalR;
	m_LocalT = m_DefLocalT;
	m_LocalMat = Node::ComputeTransform( m_LocalS, m_LocalR, m_LocalT );

	//ワールド( Geometric * Local * ParentWorld )
	m_WorldMat = m_GeometricMat * m_LocalMat * parentWorldMat;

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

	for( it_child = it_child_begin; it_child != it_child_end; ++it_child )
	{
		( *it_child )->ResetWorldMatrix( m_WorldMat );
	}
}

#endif

void Node::Refresh( const D3DXMATRIX& parentWorldMat )
{
	RefreshWorldMatrix( parentWorldMat );
	RefreshMesh();
}

void Node::RefreshWorldMatrix( const D3DXMATRIX& parentWorldMat )
{
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child_begin = m_ChildList.begin();
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child_end = m_ChildList.end();
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child;

	D3DXMATRIX tempMat;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 行列の更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( m_pDynamicsPartDesigner != NULL ) &&
		( m_pDynamicsPartDesigner->IsWorldMatrixRefreshed() == true ) )
	{
		D3DXMATRIX invParentWorldMat;

		// ワールド
		m_WorldMat = m_pDynamicsPartDesigner->GetWorldMatrix();

		// ローカル
		D3DXMatrixInverse( &invParentWorldMat, NULL, ( m_pParent != NULL )? &m_pParent->GetWorldMatrix() : &m_pModel->GetWorldMatrix() );
		D3DXMatrixMultiply( &m_LocalMat, &m_WorldMat, &invParentWorldMat );
	}
	else
	{
		// ローカル
		m_LocalMat = Node::ComputeTransform( m_LocalS, m_LocalR, m_LocalT );

		// ワールド( Geometric * Local * ParentWorld )
		m_WorldMat = m_GeometricMat * m_LocalMat * parentWorldMat;
	}

	//ローカルのリセット
	m_LocalS = m_DefLocalS;
	m_LocalR = m_DefLocalR;
	m_LocalT = m_DefLocalT;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイナミクス : パートデザイナーの更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( m_pDynamicsPartDesigner != NULL ) &&
		( m_pDynamicsPartDesigner->IsWorldMatrixRefreshed() == false ) )
	{
		m_pDynamicsPartDesigner->SetWorldMatrix( m_WorldMat );
	}

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

	for( it_child = it_child_begin; it_child != it_child_end; ++it_child )
	{
		( *it_child )->RefreshWorldMatrix( m_WorldMat );
	}
}

void Node::RefreshMesh( void )
{
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child_begin = m_ChildList.begin();
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child_end = m_ChildList.end();
	std::vector<Mix::Tool::Win32::Graphics::Node*>::iterator it_child;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// メッシュの更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pMesh != NULL )
	{
		m_pMesh->OnRefresh();
	}

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

	for( it_child = it_child_begin; it_child != it_child_end; ++it_child )
	{
		( *it_child )->RefreshMesh();
	}
}

void Node::Draw( const Node::DRAW_EVENT_ARGS& args )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ボーン
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( args.bDrawBone == true )
	{
		int childCount = GetChildCount();

		if( childCount > 0 )
		{
			const D3DXMATRIX& worldMat = GetWorldMatrix();
			D3DXVECTOR3 tailPos( worldMat._41, worldMat._42, worldMat._43 );
			D3DXVECTOR3 headPos;
			D3DXVECTOR4 color;

			args.pLineHelper->IdentityMatrix();
			args.pLineHelper->SetColor( Lerp_B( args.boneColor, args.selectedColor ) );

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

				if( pChildNode->GetAttribute() == Mix::Tool::Win32::Graphics::Node::BONE )
				{
					const D3DXMATRIX& childWorldMat = pChildNode->GetWorldMatrix();
					
					headPos.x = childWorldMat._41;
					headPos.y = childWorldMat._42;
					headPos.z = childWorldMat._43;

					args.pLineHelper->AddPoints( tailPos, headPos );
				}
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ダイナミクス : パートデザイナー
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pDynamicsPartDesigner != NULL )
	{
		m_pDynamicsPartDesigner->Draw(	args.pLineHelper,
										args.bDrawCollision,
										args.bDrawCollision,
										args.bDrawJoint,
										args.selectedColor,
										args.dynSensorColor,
										args.dynBodyColor,
										args.dynJointAxisColor,
										args.dynJointBallColor,
										args.dynJointLimitColor,
										args.dynJointScale,
										args.axisScale,
										false );
	}
}

D3DXMATRIX Node::ComputeTransform( const D3DXVECTOR3& scaling, const D3DXQUATERNION& rotation, const D3DXVECTOR3& translation )
{
	D3DXMATRIX mat;
	D3DXMATRIX tempMat;

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

	D3DXMatrixIdentity( &mat );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// スケーリング
	////////////////////////////////////////////////////////////////////////////////////////////////////

	D3DXMatrixScaling( &mat, scaling.x, scaling.y, scaling.z );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ローテーション
	////////////////////////////////////////////////////////////////////////////////////////////////////

	mat *= *D3DXMatrixRotationQuaternion( &tempMat, &rotation );

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

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

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

	return mat;
}

D3DXMATRIX Node::BaseShape_GetScalingMatrix( void )
{
	D3DXVECTOR3 worldS;
	D3DXQUATERNION worldR;
	D3DXVECTOR3 worldT;
	D3DXMATRIX tempMat;

	D3DXMatrixDecompose( &worldS, &worldR, &worldT, &m_WorldMat );

	return *D3DXMatrixScaling( &tempMat, fabsf( worldS.x ), fabsf( worldS.y ), fabsf( worldS.z ) );
}

void Node::BaseShape_Node_Append( void ( *pFunc )( const std::vector<D3DXVECTOR3>&, Node::SHAPE_CONTEXT& ), Node* pNode, int maxDepth, Node::SHAPE_CONTEXT& ctx, bool bMeshOnly )
{
	D3DXMATRIX mat;
	std::vector<D3DXVECTOR3> work;

	D3DXMatrixIdentity( &mat );

	BaseShape_Node_Append( pFunc, mat, pNode, maxDepth, ctx, bMeshOnly, 0, work );
}

void Node::BaseShape_Node_Append( void ( *pFunc )( const std::vector<D3DXVECTOR3>&, Node::SHAPE_CONTEXT& ), const D3DXMATRIX& mat, Node* pNode, Node::SHAPE_CONTEXT& ctx )
{
	std::vector<D3DXVECTOR3> work;

	BaseShape_Node_Append( pFunc, mat, pNode, 0, ctx, false, 0, work );
}

void Node::BaseShape_Node_Append( void ( *pFunc )( const std::vector<D3DXVECTOR3>&, Node::SHAPE_CONTEXT& ), const D3DXMATRIX& mat, Node* pNode, int maxDepth, Node::SHAPE_CONTEXT& ctx, bool bMeshOnly, int depth, std::vector<D3DXVECTOR3>& work )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// フェイズを処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( ( bMeshOnly == false ) ||
		( ( bMeshOnly == true ) && ( pNode->GetAttribute() == Node::MESH ) ) )
	{
		/*
			頂点を変換
		*/

		size_t vertexCount = pNode->m_VertexList.size();

		if( vertexCount > 0 )
		{
			D3DXVECTOR3* pSrcVertex = &( pNode->m_VertexList[0] );
			D3DXVECTOR3* pSrcVertexEnd = pSrcVertex + vertexCount;
			D3DXVECTOR3* pDstVertex = NULL;

			work.clear();
			work.resize( vertexCount );

			pDstVertex = &( work[0] );

			while( pSrcVertex != pSrcVertexEnd )
			{
				D3DXVec3TransformCoord( pDstVertex, pSrcVertex, &mat );

				pSrcVertex++;
				pDstVertex++;
			}

			/*
				ファンクションの実行
			*/

			( *pFunc )( work, ctx );
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 子のフェイズを処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( maxDepth > depth )
	{
		int childCount = pNode->GetChildCount();

		for( int i = 0; i < childCount; i++ )
		{
			Node* pChildNode = pNode->GetChildPtr( i );

			Node::BaseShape_Node_Append(	pFunc,
											pChildNode->GetDefLocalTransform() * mat,
											pChildNode,
											maxDepth,
											ctx,
											bMeshOnly,
											depth + 1,
											work );
		}
	}
}

void Node::BaseShape_Phase1_Initialize( Node::SHAPE_CONTEXT& ctx )
{
	ctx.vertexCount = 0;

	ctx.center = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );

	ctx.c00 = 0.0f;
	ctx.c11 = 0.0f;
	ctx.c22 = 0.0f;
	ctx.c01 = 0.0f;
	ctx.c02 = 0.0f;
	ctx.c12 = 0.0f;

	D3DXMatrixIdentity( &( ctx.vcMat ) );

	D3DXMatrixIdentity( &( ctx.eigenMat ) );

	ctx.obbMin = D3DXVECTOR3( +FLT_MAX, +FLT_MAX, +FLT_MAX );
	ctx.obbMax = D3DXVECTOR3( -FLT_MAX, -FLT_MAX, -FLT_MAX );

	ctx.obb.pos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
	ctx.obb.axis[0] = D3DXVECTOR3( 1.0f, 0.0f, 0.0f );
	ctx.obb.axis[1] = D3DXVECTOR3( 0.0f, 1.0f, 0.0f );
	ctx.obb.axis[2] = D3DXVECTOR3( 0.0f, 0.0f, 1.0f );
	ctx.obb.len = D3DXVECTOR3( 0.5f, 0.5f, 0.5f );
}

void Node::BaseShape_Phase2_Center_Append( const std::vector<D3DXVECTOR3>& vertices, Node::SHAPE_CONTEXT& ctx )
{
	if( vertices.size() == 0 )
	{
		return;
	}

	const D3DXVECTOR3* pVertex = &( vertices[0] );
	const D3DXVECTOR3* pVertexEnd = pVertex + vertices.size();

	while( pVertex != pVertexEnd )
	{
		ctx.center += *pVertex;
		ctx.vertexCount++;

		pVertex++;
	}
}

void Node::BaseShape_Phase2_Center_Finish( Node::SHAPE_CONTEXT& ctx )
{
	if( ctx.vertexCount == 0 )
	{
		return;
	}

	ctx.center /= static_cast<float>( ctx.vertexCount );
}

void Node::BaseShape_Phase3_Matrix_Append( const std::vector<D3DXVECTOR3>& vertices, Node::SHAPE_CONTEXT& ctx )
{
	if( vertices.size() == 0 )
	{
		return;
	}

	const D3DXVECTOR3* pVertex = &( vertices[0] );
	const D3DXVECTOR3* pVertexEnd = pVertex + vertices.size();

	const float cx = ctx.center.x;
	const float cy = ctx.center.y;
	const float cz = ctx.center.z;

	while( pVertex != pVertexEnd )
	{
		const D3DXVECTOR3& pos = *pVertex;

		ctx.c00 += ( pos.x - cx ) * ( pos.x - cx );
		ctx.c11 += ( pos.y - cy ) * ( pos.y - cy );
		ctx.c22 += ( pos.z - cz ) * ( pos.z - cz );
		ctx.c01 += ( pos.x - cx ) * ( pos.y - cy );
		ctx.c02 += ( pos.x - cx ) * ( pos.z - cz );
		ctx.c12 += ( pos.y - cy ) * ( pos.z - cz );

		pVertex++;
	}
}

void Node::BaseShape_Phase3_Matrix_Finish( Node::SHAPE_CONTEXT& ctx )
{
	if( ctx.vertexCount == 0 )
	{
		return;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 分散共分散行列を求める
	////////////////////////////////////////////////////////////////////////////////////////////////////

	float invSizeF = 1.0f / static_cast<float>( ctx.vertexCount );

	ctx.c00 *= invSizeF;
	ctx.c11 *= invSizeF;
	ctx.c22 *= invSizeF;
	ctx.c01 *= invSizeF;
	ctx.c02 *= invSizeF;
	ctx.c12 *= invSizeF;

	ctx.vcMat._11 = ctx.c00;
	ctx.vcMat._12 = ctx.c01;
	ctx.vcMat._13 = ctx.c02;
	ctx.vcMat._21 = ctx.c01;
	ctx.vcMat._22 = ctx.c11;
	ctx.vcMat._23 = ctx.c12;
	ctx.vcMat._31 = ctx.c02;
	ctx.vcMat._32 = ctx.c12;
	ctx.vcMat._33 = ctx.c22;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// Jacobi法に基づいて、固有行列を求める
	////////////////////////////////////////////////////////////////////////////////////////////////////

	int loop;
	int i;
	int p;
	int q;
	float max;
	float app, apq, aqq;
	float alpha, beta, gamma;
	float ab2;
	float s, c;
	float temp;

	loop = 0;

	do
	{
		max = Jacobi_GetMax( ctx.vcMat, p, q );
#if 0
		if( MIX_FLOAT_IS_ZERO( max ) == true )
		{
			break;
		}
#endif
		app = ctx.vcMat.m[p][p];
		apq = ctx.vcMat.m[p][q];
		aqq = ctx.vcMat.m[q][q];

		alpha = ( app - aqq ) / 2.0f;
		beta = -apq;

		ab2 = alpha * alpha + beta * beta;
		if( MIX_FLOAT_IS_ZERO( ab2 ) == false )
		{
			gamma = ::fabs( alpha ) / ::sqrtf( alpha * alpha + beta * beta );
		}
		else
		{
			gamma = 0.0f;
		}

		s = ::sqrtf( ( 1.0f - gamma ) / 2.0f );
		c = ::sqrtf( ( 1.0f + gamma ) / 2.0f );
		if( ( alpha * beta ) < 0.0f )
		{
			s = -s;
		}

		for( i = 0; i < 3; i++ )
		{
			temp = c * ctx.vcMat.m[p][i] - s * ctx.vcMat.m[q][i];
			ctx.vcMat.m[q][i] = s * ctx.vcMat.m[p][i] + c * ctx.vcMat.m[q][i];
			ctx.vcMat.m[p][i] = temp;
		}

		for( i = 0; i < 3; i++ )
		{
			ctx.vcMat.m[i][p] = ctx.vcMat.m[p][i];
			ctx.vcMat.m[i][q] = ctx.vcMat.m[q][i];
		}

		ctx.vcMat.m[p][p] = ( c * c * app ) + ( s * s * aqq ) - ( 2.0f * s * c * apq );
		ctx.vcMat.m[p][q] = ( s * c * ( app - aqq ) ) + ( ( c * c - s*s) * apq );
		ctx.vcMat.m[q][p] = ( s * c * ( app - aqq ) ) + ( ( c * c - s * s ) * apq );
		ctx.vcMat.m[q][q] = ( s * s * app ) + ( c * c * aqq ) + ( 2.0f * s * c * apq );

		for( i = 0; i < 3; i++ )
		{
			temp = ( c * ctx.eigenMat.m[i][p] ) - ( s * ctx.eigenMat.m[i][q] );
			ctx.eigenMat.m[i][q] = ( s * ctx.eigenMat.m[i][p] ) + ( c * ctx.eigenMat.m[i][q] );
			ctx.eigenMat.m[i][p] = temp;
		}

	}while( ( max > FLT_EPSILON ) && ( ++loop < Node::JACOBI_MAX_LOOP ) );
}

void Node::BaseShape_Phase4_OBB_Append( const std::vector<D3DXVECTOR3>& vertices, Node::SHAPE_CONTEXT& ctx )
{
	if( vertices.size() == 0 )
	{
		return;
	}

	const D3DXVECTOR3* pVertex = &( vertices[0] );
	const D3DXVECTOR3* pVertexEnd = pVertex + vertices.size();

	D3DXVECTOR3 xv( ctx.eigenMat._11, ctx.eigenMat._21, ctx.eigenMat._31 );
	D3DXVECTOR3 yv( ctx.eigenMat._12, ctx.eigenMat._22, ctx.eigenMat._32 );
	D3DXVECTOR3 zv( ctx.eigenMat._13, ctx.eigenMat._23, ctx.eigenMat._33 );

	while( pVertex != pVertexEnd )
	{
		float lx = ::D3DXVec3Dot( pVertex, &xv );
		float ly = ::D3DXVec3Dot( pVertex, &yv );
		float lz = ::D3DXVec3Dot( pVertex, &zv );

		if( ctx.obbMin.x > lx ) { ctx.obbMin.x = lx; }
		if( ctx.obbMin.y > ly ) { ctx.obbMin.y = ly; }
		if( ctx.obbMin.z > lz ) { ctx.obbMin.z = lz; }

		if( ctx.obbMax.x < lx ) { ctx.obbMax.x = lx; }
		if( ctx.obbMax.y < ly ) { ctx.obbMax.y = ly; }
		if( ctx.obbMax.z < lz ) { ctx.obbMax.z = lz; }

		pVertex++;
	}
}

void Node::BaseShape_Phase4_OBB_Finish( Node::SHAPE_CONTEXT& ctx )
{
	if( ctx.vertexCount == 0 )
	{
		return;
	}

	D3DXVECTOR3 xv( ctx.eigenMat._11, ctx.eigenMat._21, ctx.eigenMat._31 );
	D3DXVECTOR3 yv( ctx.eigenMat._12, ctx.eigenMat._22, ctx.eigenMat._32 );
	D3DXVECTOR3 zv( ctx.eigenMat._13, ctx.eigenMat._23, ctx.eigenMat._33 );

	//中心
	ctx.obb.pos =	( xv * ( ( ctx.obbMin.x + ctx.obbMax.x ) * 0.5f ) ) +
					( yv * ( ( ctx.obbMin.y + ctx.obbMax.y ) * 0.5f ) ) +
					( zv * ( ( ctx.obbMin.z + ctx.obbMax.z ) * 0.5f ) );

	//軸
	ctx.obb.axis[0] = xv;
	ctx.obb.axis[1] = yv;
	ctx.obb.axis[2] = zv;

	//長さ
	ctx.obb.len = ( ctx.obbMax - ctx.obbMin ) * 0.5f;
}

float Node::Jacobi_GetMax( const D3DXMATRIX& mat, int& p, int& q )
{
	int i;
	int j;
	float max;
	float temp;
	
	max = ::fabs( mat._12 );
	p = 0;
	q = 1;

	for( i = 0; i < 3; i++ )
	{
		for( j = ( i + 1 ); j < 3; j++ )
		{
			temp = ::fabs( mat.m[i][j] );

			if( temp > max )
			{
				max = temp;
				p = i;
				q = j;
			}
		}
	}

	return max;
}

Mix::Tool::Win32::Object::TYPE Node::GetType( void ) const
{
	return Mix::Tool::Win32::Object::GRAPHICS__NODE;
}

}}}}
