#include "Mix/Tool/Win32/Core/Graphics/ObjectMesh.h"
#include "Mix/Tool/Win32/Core/Graphics/VertexBuffer.h"
#include "Mix/Tool/Win32/Core/Graphics/IndexBuffer.h"
#include "Mix/Tool/Win32/Core/Graphics/BlankMesh.h"
#include "Mix/Tool/Win32/Core/Graphics/Node.h"

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

ObjectMesh::ObjectMesh( Mix::Tool::Win32::Graphics::DrawObject* pDrawObject, Mix::Tool::Win32::Graphics::Node* pLinkNode ) : OptimizeMesh( pDrawObject, pLinkNode )
{
}

ObjectMesh::~ObjectMesh( void )
{
}

bool ObjectMesh::GetBoneAvaliable( void ) const
{
	return true;
}

unsigned int ObjectMesh::AddBone( const char* pName, const D3DXMATRIX& offsetMat )
{
	std::wstring nameW;

	AnsiToWide( pName, nameW );

	return AddBone( nameW.c_str(), offsetMat );
}

unsigned int ObjectMesh::AddBone( const wchar_t* pName, const D3DXMATRIX& offsetMat )
{
	unsigned int index = m_BoneList.size();

	OptimizeMesh::BONE bone;

	bone.name = pName;
	bone.pLinkNode = NULL;
	bone.offsetMat = offsetMat;

	m_BoneList.push_back( bone );

	return index;
}

unsigned int ObjectMesh::GetBoneCount( void ) const
{
	return m_BoneList.size();
}

const D3DXMATRIX* ObjectMesh::GetBoneMatList( void ) const
{
	if( m_BoneMatList.size() == 0 )
	{
		return NULL;
	}

	return &( m_BoneMatList[0] );
}

const OptimizeMesh::BONE* ObjectMesh::GetBoneByIndex( unsigned int index ) const
{
	MIX_ASSERT( m_BoneList.size() > index );

	return &( m_BoneList[index] );
}

const OptimizeMesh::BONE* ObjectMesh::GetBoneByName( const wchar_t* pName ) const
{
	if( ( pName == NULL ) ||
		( ::wcslen( pName ) == 0 ) )
	{
		return NULL;
	}

	std::vector<OptimizeMesh::BONE>::const_iterator it_begin = m_BoneList.begin();
	std::vector<OptimizeMesh::BONE>::const_iterator it_end = m_BoneList.end();
	std::vector<OptimizeMesh::BONE>::const_iterator it;

	for( it = it_begin; it != it_end; ++it )
	{
		if( ( *it ).name == pName )
		{
			return &( *it );
		}
	}

	return NULL;
}

bool ObjectMesh::OnBeforeBuild( OptimizeMesh::BUILD_CONFIG& cfg )
{
	unsigned int boneCount = m_BoneList.size();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ボーンの最適化
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( boneCount > 0 )
	{
		Mix::Tool::Win32::Graphics::POLYGON* pPolygonBegin = &( m_PolygonList[0] );
		Mix::Tool::Win32::Graphics::POLYGON* pPolygonEnd = pPolygonBegin + m_PolygonList.size();
		Mix::Tool::Win32::Graphics::POLYGON* pPolygon = pPolygonBegin;
		unsigned int* pIndex = NULL;
		unsigned int* pIndexEnd = NULL;

		std::vector<unsigned int> boneOptTable;
		std::vector<OptimizeMesh::BONE> boneList;
		unsigned int newIndex = 0;

		std::vector<OptimizeMesh::BONE>::iterator it_begin;
		std::vector<OptimizeMesh::BONE>::iterator it_end;
		std::vector<OptimizeMesh::BONE>::iterator it;

		/*
			初期化
		*/

		boneOptTable.resize( boneCount, 0 );
		boneList.reserve( boneCount );

		/*
			使用しているボーンをマーク
		*/

		while( pPolygon != pPolygonEnd )
		{
			const Mix::Tool::Win32::Graphics::VERTEX* pVertex = &( pPolygon->vertices[0] );
			const Mix::Tool::Win32::Graphics::VERTEX* pVertexEnd = pVertex + pPolygon->vertices.size();

			while( pVertex != pVertexEnd )
			{
				const Mix::Tool::Win32::Graphics::WEIGHT* pWeight = &( pVertex->weights[0] );
				const Mix::Tool::Win32::Graphics::WEIGHT* pWeightEnd = pWeight + Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT;

				while( pWeight != pWeightEnd )
				{
					if( pWeight->value > 0.0f )
					{
						boneOptTable[pWeight->index] = 0xFFFFFFFF;
					}
					pWeight++;
				}

				pVertex++;
			}

			pPolygon++;
		}

		/*
			ボーンリストを更新
		*/

		for( unsigned int i = 0; i < boneCount; i++ )
		{
			if( boneOptTable[i] == 0xFFFFFFFF )
			{
				boneList.push_back( m_BoneList[i] );
			}
		}

		m_BoneList.swap( boneList );
		boneCount = m_BoneList.size();

		/*
			ボーンに新たなインデックスを割り振る
		*/

		pIndex = &( boneOptTable[0] );
		pIndexEnd = pIndex + boneOptTable.size();
		while( pIndex != pIndexEnd )
		{
			if( *pIndex == 0xFFFFFFFF )
			{
				*pIndex = newIndex++;
			}

			pIndex++;
		}

		/*
			ポリゴンのボーンインデックスを更新
		*/

		pPolygon = pPolygonBegin;
		while( pPolygon != pPolygonEnd )
		{
			Mix::Tool::Win32::Graphics::VERTEX* pVertex = &( pPolygon->vertices[0] );
			Mix::Tool::Win32::Graphics::VERTEX* pVertexEnd = pVertex + pPolygon->vertices.size();

			while( pVertex != pVertexEnd )
			{
				Mix::Tool::Win32::Graphics::WEIGHT* pWeight = &( pVertex->weights[0] );
				Mix::Tool::Win32::Graphics::WEIGHT* pWeightEnd = pWeight + Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT;

				while( pWeight != pWeightEnd )
				{
					pWeight->index = boneOptTable[pWeight->index];
					pWeight++;
				}

				pVertex++;
			}

			pPolygon++;
		}
	}

	return true;
}

bool ObjectMesh::OnAfterBuild( OptimizeMesh::BUILD_CONFIG& cfg, const std::vector<OptimizeMesh::O_MATERIAL>& oMaterialList )
{
	unsigned int boneCount = m_BoneList.size();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ボーンの最終処理
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( boneCount > 0 )
	{
		/*
			ボーン行列テーブルを作成
		*/

		const OptimizeMesh::O_MATERIAL* pMaterial = &( oMaterialList[0] );
		const OptimizeMesh::O_MATERIAL* pMaterialEnd = pMaterial + oMaterialList.size();

		D3DXMATRIX identityMat;

		while( pMaterial != pMaterialEnd )
		{
			const OptimizeMesh::O_MATERIAL_BLOCK* pBlock = &( pMaterial->blockList[0] );
			const OptimizeMesh::O_MATERIAL_BLOCK* pBlockEnd = pBlock + pMaterial->blockList.size();

			while( pBlock != pBlockEnd )
			{
				m_BoneMatTable.insert( m_BoneMatTable.end(), pBlock->boneList.begin(), pBlock->boneList.end() );

				pBlock++;
			}

			pMaterial++;
		}

		::D3DXMatrixIdentity( &identityMat );
		m_BoneMatList.resize( m_BoneMatTable.size(), identityMat );

		/*
			ボーンとノードをリンク
		*/

		std::vector<OptimizeMesh::BONE>::iterator it_begin = m_BoneList.begin();
		std::vector<OptimizeMesh::BONE>::iterator it_end = m_BoneList.end();
		std::vector<OptimizeMesh::BONE>::iterator it;

		for( it = it_begin; it != it_end; ++it )
		{
			OptimizeMesh::BONE* pBone = &( *it );
			Mix::Tool::Win32::Graphics::Node* pNode = m_pObjectModel->FindNode( pBone->name.c_str() );

			if( pNode != NULL )
			{
				pNode->SetBone();
				pBone->pLinkNode = pNode;
			}
			else
			{
				LogPrint( LT_ERROR, L"      ボーンが存在しないノードを参照しています : LinkNodeName[%s]", pBone->name.c_str() );
				return false;
			}
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 頂点コレクション
	////////////////////////////////////////////////////////////////////////////////////////////////////

	LogPrint( LT_INFO,	L"      頂点の割り当て" );

	Mix::Tool::Win32::Graphics::BlankMesh blankMesh( m_PolygonList );
	const std::vector<Mix::Tool::Win32::Graphics::BLANK_VERTEX>& blankVertexList = blankMesh.GetVertexList();

	std::vector<D3DXVECTOR3> meshVertices;
	std::vector<std::vector<D3DXVECTOR3>> boneVerticesTable;

	/*
		メッシュのバーテックスリストの作成
	*/

	{
		size_t vertexCount = blankVertexList.size();

		const Mix::Tool::Win32::Graphics::BLANK_VERTEX* pBlankVertex = &( blankVertexList[0] );
		const Mix::Tool::Win32::Graphics::BLANK_VERTEX* pBlankVertexEnd = pBlankVertex + vertexCount;

		D3DXVECTOR3* pMeshVertex = NULL;

		meshVertices.resize( vertexCount );
		pMeshVertex = &( meshVertices[0] );

		while( pBlankVertex != pBlankVertexEnd )
		{
			*pMeshVertex = pBlankVertex->pos;

			pMeshVertex++;
			pBlankVertex++;
		}
	}

	LogPrint( LT_INFO,	L"        Node[%s] : VertexCount[%d] *", GetLinkNodeName(), meshVertices.size() );

	/*
		ボーン毎のバーテックスリストを作成
	*/

	if( boneCount > 0 )
	{
		const Mix::Tool::Win32::Graphics::BLANK_VERTEX* pVertex = &( blankVertexList[0] );
		const Mix::Tool::Win32::Graphics::BLANK_VERTEX* pVertexEnd = pVertex + blankVertexList.size();
		size_t reserveSize = blankVertexList.size() / boneCount + 1;

		//ボーンの数だけ確保確保
		boneVerticesTable.resize( boneCount );

		//ボーン毎の頂点リストの適当に予約
		for( size_t i = 0; i < boneVerticesTable.size(); i++ )
		{
			boneVerticesTable[i].reserve( reserveSize );
		}

		//ボーン毎の頂点リストを作成
		while( pVertex != pVertexEnd )
		{
#if 1
			if( pVertex->weights[0] > FLT_EPSILON )
			{
				boneVerticesTable[pVertex->indices[0]].push_back( pVertex->pos );
			}
#else
			const unsigned int* pIndex = &( pVertex->indices[0] );
			const unsigned int* pIndexEnd = pIndex + Mix::Tool::Win32::Graphics::MAX_VERTEX_WEIGHT;
			const float* pWeight = &( pVertex->weights[0] );

			while( ( pIndex != pIndexEnd ) && ( *pWeight > 0.0f ) )
			{
				verticesTable[*pIndex].push_back( pVertex->pos );

				pIndex++;
				pWeight++;
			}
#endif
			pVertex++;
		}

		//ログ
		for( size_t i = 0; i < boneCount; i++ )
		{
			LogPrint( LT_INFO,	L"        Node[%s] : VertexCount[%d]", m_BoneList[i].name.c_str(), boneVerticesTable[i].size() );
		}
	}

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

	if( boneCount == 0 )
	{
		//メッシュ( 自身 )
		m_LocalViewVolumeList.push_back( ObjectMesh::ComputeViewVolume( meshVertices ) );
	}
	else
	{
		//ボーン毎
		m_LocalViewVolumeList.reserve( m_BoneList.size() );

		for( unsigned i = 0; i < boneCount; i++ )
		{
			m_LocalViewVolumeList.push_back( ObjectMesh::ComputeViewVolume( boneVerticesTable[i] ) );
		}
	}

	/*
		メッシュのベースシェイプ
	*/

	if( meshVertices.size() > 0 )
	{
		GetLinkNodePtr()->AddBaseShape( GetLinkNodeName(), meshVertices );
	}

	/*
		ボーンノードのベースシェイプ
	*/

	if( boneCount > 0 )
	{
		for( unsigned int i = 0; i < boneCount; i++ )
		{
			size_t boneVertexCount = boneVerticesTable[i].size();

			if( boneVertexCount > 0 )
			{
				const OptimizeMesh::BONE& bone = m_BoneList[i];
				const D3DXMATRIX& offsetMat = bone.offsetMat;

				D3DXVECTOR3* pBoneVertex = &( boneVerticesTable[i][0] );
				D3DXVECTOR3* pBoneVertexEnd = pBoneVertex + boneVertexCount;

				D3DXVECTOR3 tempVec;

				while( pBoneVertex != pBoneVertexEnd )
				{
					*pBoneVertex++ = *D3DXVec3TransformCoord( &tempVec, pBoneVertex, &offsetMat );
				}

				bone.pLinkNode->AddBaseShape( GetLinkNodeName(), boneVerticesTable[i] );
			}
		}
	}

	return true;
}

void ObjectMesh::OnRefresh( void )
{
	bool bExistsBone = ( m_BoneList.size() > 0 );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ボーンを更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( bExistsBone == true )
	{
		MIX_ASSERT( m_BoneMatTable.size() == m_BoneMatList.size() );

		std::vector<OptimizeMesh::BONE>::iterator it_bone_begin = m_BoneList.begin();
		std::vector<OptimizeMesh::BONE>::iterator it_bone_end = m_BoneList.end();
		std::vector<OptimizeMesh::BONE>::iterator it_bone;

		unsigned int boneMatCount = m_BoneMatList.size();

		for( it_bone = it_bone_begin; it_bone != it_bone_end; ++it_bone )
		{
			OptimizeMesh::BONE* pBone = &( *it_bone );
			pBone->worldMat = pBone->offsetMat * pBone->pLinkNode->GetWorldMatrix();
		}

		for( unsigned int i = 0; i < boneMatCount; i++ )
		{
			m_BoneMatList[i] = m_BoneList[m_BoneMatTable[i]].worldMat;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ビューボリュームを更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( bExistsBone == true )
	{
		MIX_ASSERT( m_BoneList.size() == m_LocalViewVolumeList.size() );

		const ObjectMesh::VIEW_VOLUME* pLocalViewVolume = &( m_LocalViewVolumeList[0] );

		unsigned int vvCount = m_LocalViewVolumeList.size();
		unsigned int i;

		D3DXMATRIX wbMat;
		D3DXVECTOR4 tempPos;
		D3DXVECTOR3 pos;
		D3DXVECTOR3 vec;
		float radius;

		for( i = 0; i < vvCount; i++ )
		{
			wbMat = m_BoneList[i].worldMat;

			D3DXVec3Transform( &tempPos, &( pLocalViewVolume[i].pos ), &wbMat );
			pos = D3DXVECTOR3( tempPos.x, tempPos.y, tempPos.z );

			D3DXVec3TransformNormal( &vec, &( pLocalViewVolume[i].vec ), &wbMat );
			radius = ::D3DXVec3Length( &vec );

			if( i == 0 )
			{
				m_ViewVolume.pos = pos;
				m_ViewVolume.radius = radius;
			}
			else
			{
				D3DXVECTOR3 v = ( pos - m_ViewVolume.pos );
				float d2;
				float r2;

				d2 = ( ( v.x * v.x ) + ( v.y * v.y ) + ( v.z * v.z ) );

				r2 = ( radius - m_ViewVolume.radius );
				r2 *= r2;

				if( d2 <= r2 )
				{
					if( m_ViewVolume.radius <= radius )
					{
						m_ViewVolume.pos = pos;
						m_ViewVolume.radius = radius;
					}
				}
				else
				{
					float d;
					float r;

					d = ::sqrtf( d2 );
					r = ( ( d + m_ViewVolume.radius + radius ) * 0.5f );

					if( FLT_EPSILON < d )
					{
						m_ViewVolume.pos += ( ( ( r - m_ViewVolume.radius ) / d ) * v );
					}

					m_ViewVolume.radius = r;
				}
			}
		}
	}
	else if( m_LocalViewVolumeList.size() > 0 )
	{
		MIX_ASSERT( m_LocalViewVolumeList.size() == 1 );

		const ObjectMesh::VIEW_VOLUME* pLocalViewVolume = &( m_LocalViewVolumeList[0] );
		const D3DXMATRIX& worldMat = m_pLinkNode->GetWorldMatrix();

		D3DXVECTOR4 pos;
		D3DXVECTOR3 vec;

		D3DXVec3Transform( &pos, &( pLocalViewVolume->pos ), &worldMat );
		m_ViewVolume.pos = D3DXVECTOR3( pos.x, pos.y, pos.z );

		D3DXVec3TransformNormal( &vec, &( pLocalViewVolume->vec ), &worldMat );
		m_ViewVolume.radius = D3DXVec3Length( &vec );
	}
}

const wchar_t* ObjectMesh::GetLinkNodeName( void ) const
{
	return m_pLinkNode->GetName();
}
/*
void ObjectMesh::Update( const D3DXMATRIX& worldMat )
{
	bool bExistsBone = ( m_BoneList.size() > 0 );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ボーンを更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( bExistsBone == true )
	{
		MIX_ASSERT( m_BoneMatTable.size() == m_BoneMatList.size() );

		std::vector<OptimizeMesh::BONE>::iterator it_bone_begin = m_BoneList.begin();
		std::vector<OptimizeMesh::BONE>::iterator it_bone_end = m_BoneList.end();
		std::vector<OptimizeMesh::BONE>::iterator it_bone;

		unsigned int boneMatCount = m_BoneMatList.size();

		for( it_bone = it_bone_begin; it_bone != it_bone_end; ++it_bone )
		{
			OptimizeMesh::BONE* pBone = &( *it_bone );
			pBone->worldMat = pBone->offsetMat * pBone->pLinkNode->GetWorldMatrix();
		}

		for( unsigned int i = 0; i < boneMatCount; i++ )
		{
			m_BoneMatList[i] = m_BoneList[m_BoneMatTable[i]].worldMat;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ビューボリュームを更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( bExistsBone == true )
	{
		MIX_ASSERT( m_BoneList.size() == m_LocalViewVolumeList.size() );

		const ObjectMesh::VIEW_VOLUME* pLocalViewVolume = &( m_LocalViewVolumeList[0] );

		unsigned int vvCount = m_LocalViewVolumeList.size();
		unsigned int i;

		D3DXMATRIX wbMat;
		D3DXVECTOR4 tempPos;
		D3DXVECTOR3 pos;
		D3DXVECTOR3 vec;
		float radius;

		for( i = 0; i < vvCount; i++ )
		{
			wbMat = m_BoneList[i].worldMat;

			D3DXVec3Transform( &tempPos, &( pLocalViewVolume[i].pos ), &wbMat );
			pos = D3DXVECTOR3( tempPos.x, tempPos.y, tempPos.z );

			D3DXVec3TransformNormal( &vec, &( pLocalViewVolume[i].vec ), &wbMat );
			radius = ::D3DXVec3Length( &vec );

			if( i == 0 )
			{
				m_ViewVolume.pos = pos;
				m_ViewVolume.radius = radius;
			}
			else
			{
				D3DXVECTOR3 v = ( pos - m_ViewVolume.pos );
				float d2;
				float r2;

				d2 = ( ( v.x * v.x ) + ( v.y * v.y ) + ( v.z * v.z ) );

				r2 = ( radius - m_ViewVolume.radius );
				r2 *= r2;

				if( d2 <= r2 )
				{
					if( m_ViewVolume.radius <= radius )
					{
						m_ViewVolume.pos = pos;
						m_ViewVolume.radius = radius;
					}
				}
				else
				{
					float d;
					float r;

					d = ::sqrtf( d2 );
					r = ( ( d + m_ViewVolume.radius + radius ) * 0.5f );

					if( FLT_EPSILON < d )
					{
						m_ViewVolume.pos += ( ( ( r - m_ViewVolume.radius ) / d ) * v );
					}

					m_ViewVolume.radius = r;
				}
			}
		}
	}
	else if( m_LocalViewVolumeList.size() > 0 )
	{
		MIX_ASSERT( m_LocalViewVolumeList.size() == 1 );

		const ObjectMesh::VIEW_VOLUME* pLocalViewVolume = &( m_LocalViewVolumeList[0] );

		D3DXVECTOR4 pos;
		D3DXVECTOR3 vec;

		D3DXVec3Transform( &pos, &( pLocalViewVolume->pos ), &worldMat );
		m_ViewVolume.pos = D3DXVECTOR3( pos.x, pos.y, pos.z );

		D3DXVec3TransformNormal( &vec, &( pLocalViewVolume->vec ), &worldMat );
		m_ViewVolume.radius = D3DXVec3Length( &vec );
	}
}
*/
const Mix::Tool::Win32::Geometry::SPHERE& ObjectMesh::GetViewVolume( void ) const
{
	return m_ViewVolume;
}

bool ObjectMesh::Write( Mix::Tool::Win32::File::OutputStream& output )
{
	if( ( m_SubsetList.size() == 0 ) ||
		( m_pVertexBuffer == NULL ) ||
		( m_pIndexBuffer == NULL ) )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ヘッダ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	{
		ObjectMesh::MESH_DESC desc;

		desc.boneNum = m_BoneList.size();
		desc.boneMatNum = m_BoneMatTable.size();
		desc.viewVolumeNum = m_LocalViewVolumeList.size();
		desc.materialNum = m_SubsetList.size();
		desc.vertexStride = m_pVertexBuffer->GetStride();
		desc.vertexNum = m_pVertexBuffer->GetCount();
		desc.indexStride = m_pIndexBuffer->GetStride();
		desc.indexNum = m_pIndexBuffer->GetCount();

		if( output.Write( &desc, sizeof( desc ) ) == false )
		{
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ボーン
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_BoneList.size() > 0 )
	{
		std::vector<OptimizeMesh::BONE>::const_iterator it_begin = m_BoneList.begin();
		std::vector<OptimizeMesh::BONE>::const_iterator it_end = m_BoneList.end();
		std::vector<OptimizeMesh::BONE>::const_iterator it;

		std::vector<ObjectMesh::MESH_BONE> writeList;

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 書き込むデータを作成
		////////////////////////////////////////////////////////////////////////////////////////////////////

		writeList.reserve( m_BoneList.size() );

		for( it = it_begin; it != it_end; ++it )
		{
			const OptimizeMesh::BONE* pSrc = &( *it );
			ObjectMesh::MESH_BONE dst;

			::wcscpy_s( dst.linkNodeName, sizeof( dst.linkNodeName ) >> 1, pSrc->name.c_str() );
			::CopyMemory( &( dst.offsetMat[0][0] ), &( pSrc->offsetMat.m[0][0] ), sizeof( float[4][4] ) );

			writeList.push_back( dst );
		}

		////////////////////////////////////////////////////////////////////////////////////////////////////
		// 書き込む
		////////////////////////////////////////////////////////////////////////////////////////////////////

		if( output.Write( &( writeList[0] ), sizeof( ObjectMesh::MESH_BONE ) * writeList.size() ) == false )
		{
			return false;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ボーン行列
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_BoneMatTable.size() > 0 )
	{
		if( output.Write( &( m_BoneMatTable[0] ), sizeof( unsigned int ) * m_BoneMatTable.size() ) == false )
		{
			return false;
		}
	}

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

	if( m_LocalViewVolumeList.size() > 0 )
	{
		std::vector<ObjectMesh::MESH_VIEW_VOLUME> writeList;

		std::vector<ObjectMesh::VIEW_VOLUME>::iterator it_begin = m_LocalViewVolumeList.begin();
		std::vector<ObjectMesh::VIEW_VOLUME>::iterator it_end = m_LocalViewVolumeList.end();
		std::vector<ObjectMesh::VIEW_VOLUME>::iterator it;

		writeList.reserve( m_LocalViewVolumeList.size() );

		for( it = it_begin; it != it_end; ++it )
		{
			const ObjectMesh::VIEW_VOLUME* pSrc = &( *it );

			ObjectMesh::MESH_VIEW_VOLUME dst;

			dst.pos[0] = pSrc->pos.x;
			dst.pos[1] = pSrc->pos.y;
			dst.pos[2] = pSrc->pos.z;

			dst.vec[0] = pSrc->vec.x;
			dst.vec[1] = pSrc->vec.y;
			dst.vec[2] = pSrc->vec.z;

			writeList.push_back( dst );
		}

		if( output.Write( &( writeList[0] ), sizeof( ObjectMesh::MESH_VIEW_VOLUME ) * writeList.size() ) == false )
		{
			return false;
		}
	}

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

	if( WriteBlendMaterial( output ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// バーテックスバッファ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( WriteVertexBuffer( output ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// インデックスバッファ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( WriteIndexBuffer( output ) == false )
	{
		return false;
	}

	return true;
}

ObjectMesh::VIEW_VOLUME ObjectMesh::ComputeViewVolume( const std::vector<D3DXVECTOR3>& vertices )
{
	ObjectMesh::VIEW_VOLUME vv;

	vv.pos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
	vv.vec = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );

	if( vertices.size() == 0 )
	{
		return vv;
	}

	float vertexCountF = static_cast<float>( vertices.size() );
	float maxRadiusSQ = 0.0f;

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

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 中心座標を求める
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pVertex = pVertexBegin;

	while( pVertex != pVertexEnd )
	{
		vv.pos += *pVertex;
		pVertex++;
	}

	vv.pos /= vertexCountF;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 半径を求める
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pVertex = pVertexBegin;

	while( pVertex != pVertexEnd )
	{
		D3DXVECTOR3 vec = *pVertex - vv.pos;
		float radiusSQ = ::D3DXVec3LengthSq( &vec );

		if( maxRadiusSQ < radiusSQ )
		{
			vv.vec = vec;
			maxRadiusSQ = radiusSQ;
		}

		pVertex++;
	}

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

	return vv;
}

Mix::Tool::Win32::Object::TYPE ObjectMesh::GetType( void ) const
{
	return Mix::Tool::Win32::Object::GRAPHICS__OBJECT_MESH;
}

}}}}
