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

#include "Mix/Memory.h"
#include "Mix/IO/IReader.h"
#include "Mix/Graphics/IDevice.h"

namespace Mix{ namespace Scene{ namespace Common{

const wchar_t* TerrainMesh::CREATE_FAILED = L"マップモデルメッシュの作成に失敗";

TerrainMesh* TerrainMesh::CreateInstance( Mix::Graphics::IDevice* pDevice, Mix::IO::IReader* pReader, const wchar_t* pName )
{
	MIX_ASSERT( pDevice != NULL );
	MIX_ASSERT( pReader != NULL );
	MIX_ASSERT( MIX_STR_LENGTH( pName ) > 0 );

	TerrainMesh* pMesh = MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, TerrainMesh );
	if( pMesh == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_OUTOFMEMORY, pName );
		return NULL;
	}

	MM_DESC desc;
	UInt32 vertexBuffSize;
	UInt32 indexBuffSize;
	Mix::Graphics::INDEX_FORMAT indexFormat;
	void* pTemp;
	Mix::String name;

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

	if( pReader->Read( &desc, sizeof( desc ) ) != sizeof( desc ) )
	{
		MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_ILLEGALFORMAT, pName );
		MIX_LIB_DELETE_T( TerrainMesh, pMesh );
		return NULL;
	}

	if( ( desc.vertexStride == 0 ) ||
		( desc.vertexNum == 0 ) ||
		( ( desc.indexStride != 2 ) && ( desc.indexStride != 4 ) ) ||
		( desc.indexNum == 0 ) )
	{
		MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_ILLEGALFORMAT, pName );
		MIX_LIB_DELETE_T( TerrainMesh, pMesh );
		return NULL;
	}

	vertexBuffSize = desc.vertexStride * desc.vertexNum;
	indexBuffSize = desc.indexStride * desc.indexNum;
	indexFormat = ( desc.indexStride == 2 )? Mix::Graphics::INDEX_USHORT : Mix::Graphics::INDEX_UINT;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 描画テーブル
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pMesh->m_DrawTable.reserve( desc.drawNum );

	for( UInt32 i = 0; i < desc.drawNum; i++ )
	{
		TerrainMesh::MM_DRAW_DESC drawDesc;
		TerrainMesh::DRAW* pDraw = NULL;

		if( pReader->Read( &drawDesc, sizeof( drawDesc ) ) != sizeof( drawDesc ) )
		{
			MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_ILLEGALFORMAT, pName );
			MIX_LIB_DELETE_T( TerrainMesh, pMesh );
			return NULL;
		}

		pMesh->m_DrawTable.push_back( TerrainMesh::DRAW() );
		pDraw = &( pMesh->m_DrawTable.back() );

		pDraw->materialSlotIndex = drawDesc.slotIndex;

		//不透明
		if( drawDesc.opSubsetNum > 0 )
		{
			UInt32 readSize = sizeof( TerrainMesh::OPACITY_SUBSET ) * drawDesc.opSubsetNum;

			pDraw->opSubsets.resize( drawDesc.opSubsetNum );

			if( pReader->Read( &( pDraw->opSubsets[0] ), readSize ) != readSize )
			{
				MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_ILLEGALFORMAT, pName );
				MIX_LIB_DELETE_T( TerrainMesh, pMesh );
				return NULL;
			}
		}

		//半透明
		for( UInt32 j = 0; j < Mix::Scene::MATERIAL_TRANSPARENCY_MAX; j++ )
		{
			UInt32 subsetNum = drawDesc.trSubsetNum[j];

			if( subsetNum == 0 )
			{
				continue;
			}

			UInt32 readSize = sizeof( TerrainMesh::TRANSPARENCY_SUBSET ) * subsetNum;

			pDraw->trSubsets[j].resize( subsetNum );

			if( pReader->Read( &( pDraw->trSubsets[j][0] ), readSize ) != readSize )
			{
				MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_ILLEGALFORMAT, pName );
				MIX_LIB_DELETE_T( TerrainMesh, pMesh );
				return NULL;
			}
		}
	}

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

	pTemp = MIX_LIB_MALLOC( Mix::Memory::SECTION_SCENE, vertexBuffSize );
	if( pTemp == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_OUTOFMEMORY, pName );
		MIX_LIB_FREE( pTemp );
		return NULL;
	}

	if( pReader->Read( pTemp, vertexBuffSize ) != vertexBuffSize )
	{
		MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_ILLEGALFORMAT, pName );
		MIX_LIB_FREE( pTemp );
		return NULL;
	}

	name.Sprintf( L"%s\\VertexBuffer", pName );
	if( pDevice->CreateVertexBuffer(	desc.vertexNum, desc.vertexStride,
										False, 0,
										pTemp,
										&( pMesh->m_pVertexBuffer ),
										name.GetConstPtr() ) == False )
	{
		MIX_LIB_FREE( pTemp );
		return NULL;
	}

	MIX_LIB_FREE( pTemp );

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

	pTemp = MIX_LIB_MALLOC( Mix::Memory::SECTION_SCENE, indexBuffSize );
	if( pTemp == NULL )
	{
		MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_OUTOFMEMORY, pName );
		MIX_LIB_FREE( pTemp );
		return NULL;
	}

	if( pReader->Read( pTemp, indexBuffSize ) != indexBuffSize )
	{
		MIX_LOG_ERROR( L"%s : %s : Name[%s]", CREATE_FAILED, Mix::STR_ILLEGALFORMAT, pName );
		MIX_LIB_FREE( pTemp );
		return NULL;
	}

	name.Sprintf( L"%s\\IndexBuffer", pName );
	if( pDevice->CreateIndexBuffer(	indexFormat, desc.indexNum,
									False, 0, pTemp,
									&( pMesh->m_pIndexBuffer ),
									name.GetConstPtr() ) == False )
	{
		MIX_LIB_FREE( pTemp );
		return NULL;
	}

	MIX_LIB_FREE( pTemp );

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

	return pMesh;
}

TerrainMesh::TerrainMesh( void )
{
}

TerrainMesh::~TerrainMesh( void )
{
}

const TerrainMesh::DrawTable& TerrainMesh::GetDrawTable( void ) const
{
	return m_DrawTable;
}

}}}
