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

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

BlankMesh::BlankMesh( void )
{
}

BlankMesh::BlankMesh( const std::vector<Mix::Tool::Win32::Graphics::POLYGON>& polygonList )
{
	Build( polygonList );
}

BlankMesh::~BlankMesh( void )
{
}

void BlankMesh::Build( const std::vector<Mix::Tool::Win32::Graphics::POLYGON>& polygonList )
{
	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クリア
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_VertexList.clear();
	m_IndexList.clear();

	if( polygonList.size() == 0 )
	{
		return;
	}

	m_VertexList.reserve( polygonList.size() * 3 );
	m_IndexList.reserve( polygonList.size() * 3 );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 変数宣言
	////////////////////////////////////////////////////////////////////////////////////////////////////

	const Mix::Tool::Win32::Graphics::POLYGON* pPolygon = &( polygonList[0] );
	const Mix::Tool::Win32::Graphics::POLYGON* pPolygonEnd = pPolygon + polygonList.size();

	std::vector<Mix::Tool::Win32::Graphics::VERTEX> vertexList;
	std::vector<BlankMesh::O_FACE> faceList;
//	std::vector<Mix::Tool::Win32::Graphics::VERTEX> combineVertexList;
	std::vector<unsigned int> vertexOptTable;
	std::vector<BlankMesh::O_INDEX_INFO> indexInfoList;
	unsigned int combineVertexCount;
	unsigned int newIndex;
	unsigned int vertexCount;
	unsigned int optVertexCount;
	BlankMesh::O_FACE* pFaceStart;
	BlankMesh::O_FACE* pFaceEnd;
	BlankMesh::O_FACE* pFace;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 頂点リスト、フェイスリストを作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	vertexList.reserve( polygonList.size() * 3 );
	faceList.reserve( polygonList.size() );

	{
		unsigned int index = 0;

		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 )
			{
				vertexList.push_back( *pVertex );
				pVertex++;
			}

			faceList.push_back( BlankMesh::O_FACE( ( index + 0 ), ( index + 1 ), ( index + 2 ) ) );
			index += 3;

			pPolygon++;
		}
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 最適化の準備
	////////////////////////////////////////////////////////////////////////////////////////////////////

	vertexCount = vertexList.size();
	optVertexCount = 0;

	pFaceStart = &( faceList[0] );
	pFaceEnd = pFaceStart + faceList.size();
	pFace = NULL;

//	combineVertexList.reserve( 8 );
	vertexOptTable.reserve( vertexCount * 2 );

	for( unsigned i = 0; i < vertexCount; i++ )
	{
		vertexOptTable.push_back( i );
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 頂点の結合、最適化テーブルの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pFace = pFaceStart;
	while( pFace != pFaceEnd )
	{
		unsigned int* pIndex =  &( pFace->indices[0] );
		unsigned int* pIndexEnd = ( pIndex + 3 );

		while( pIndex != pIndexEnd )
		{
			if( *pIndex != vertexOptTable[*pIndex] )
			{
				//すでに新規インデックスが割り振られているのでスキップ
				pIndex++;
				continue;
			}

			unsigned int compIndex = vertexList.size();
			Mix::Tool::Win32::Graphics::VERTEX* pSrcVertex = &( vertexList[*pIndex] );

			//結合用に自分を入れておく
			combineVertexCount = 1;
//			combineVertexList.clear();
//			combineVertexList.push_back( *pSrcVertex );

			for( unsigned int i = 0; i < vertexCount; i++ )
			{
				if( i == ( *pIndex ) )
				{
					continue;
				}

				Mix::Tool::Win32::Graphics::VERTEX* pDstVertex = &( vertexList[i] );

				if( pSrcVertex->pos == pDstVertex->pos )
				{
					//相手に新規インデックスを割り振る
					vertexOptTable[i] = compIndex;

					//結合する頂点を追加
					combineVertexCount++;
//					combineVertexList.push_back( *pDstVertex );
				}
			}

//			if( combineVertexList.size() > 1 )
			if( combineVertexCount > 1 )
			{
//				Mix::Tool::Win32::Graphics::VERTEX* pCombineVertex = &( combineVertexList[0] );

				//自分に新規インデックスを割り振る
				vertexOptTable[*pIndex] = compIndex;

				//結合した頂点を追加
//				vertexList.push_back( *pCombineVertex );
				vertexList.push_back( *pSrcVertex );
			}

			pIndex++;
		}

		pFace++;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 頂点リスト、インデックスリストを作成する
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pFace = pFaceStart;

	indexInfoList.resize( vertexList.size(), BlankMesh::O_INDEX_INFO() );
	newIndex = 0;

	while( pFace != pFaceEnd )
	{
		unsigned int* pIndex = &( pFace->indices[0] );
		unsigned int* pIndexEnd = ( pIndex + 3 );

		while( pIndex != pIndexEnd )
		{
			unsigned int oldIndex = vertexOptTable[*pIndex];
			BlankMesh::O_INDEX_INFO* pIndexInfo = &( indexInfoList[oldIndex] );
					
			if( pIndexInfo->bAssign == false )
			{
				const Mix::Tool::Win32::Graphics::VERTEX src = vertexList[oldIndex];
				Mix::Tool::Win32::Graphics::BLANK_VERTEX dst;

				dst.pos = src.pos;

				for( unsigned int i = 0; i < MAX_VERTEX_WEIGHT; i++ )
				{
					dst.indices[i] = src.weights[i].index;
					dst.weights[i] = src.weights[i].value;
				}

				pIndexInfo->value = newIndex;
				pIndexInfo->bAssign = true;

				m_VertexList.push_back( dst );
				m_IndexList.push_back( newIndex );

				newIndex++;
				optVertexCount++;
			}
			else
			{
				m_IndexList.push_back( pIndexInfo->value );
			}

			pIndex++;
		}

		pFace++;
	}
}

const std::vector<Mix::Tool::Win32::Graphics::BLANK_VERTEX>& BlankMesh::GetVertexList( void ) const
{
	return m_VertexList;
}

const std::vector<unsigned int>& BlankMesh::GetIndexList( void ) const
{
	return m_IndexList;
}

Mix::Tool::Win32::Object::TYPE BlankMesh::GetType( void ) const
{
	return Mix::Tool::Win32::Object::GRAPHICS__BLANK_MESH;
}

}}}}
