#include "Mix/Tool/Win32/Core/Dynamics/Design/Terrain.h"

#include "Mix/Tool/Win32/Core/Graphics/BlankMesh.h"
#include "Mix/Tool/Win32/Core/Graphics/MaterialSlot.h"
#include "Mix/Tool/Win32/Core/Graphics/Material.h"
#include "Mix/Tool/Win32/Core/Graphics/OctreeModel.h"
#include "Mix/Tool/Win32/Core/Dynamics/Factory.h"
#include "Mix/Tool/Win32/Core/Dynamics/StaticMesh.h"

namespace Mix{ namespace Tool{ namespace Win32{ namespace Dynamics{ namespace Design{

Terrain::Terrain( void ) :
m_pOctreeModel( NULL ),
m_pStaticMesh( NULL ),
m_bImported( false )
{
	ZeroMemory( &m_OctreeModelConfig, sizeof( m_OctreeModelConfig ) );
}

Terrain::~Terrain( void )
{
	Destroy();
}

void Terrain::SetOctreeModelConfig( const Terrain::OCTREE_MODEL_CONFIG& cfg )
{
	m_OctreeModelConfig = cfg;
}

bool Terrain::Import( const wchar_t* pFilePath, unsigned int serializeCapacity )
{
	if( m_bImported == true )
	{
		//インポートする前は必ず Destroy で破棄すること
		//このメソッドが別スレッドで呼び出されるため、描画を停止させる( GetOctreeModelPtr() == NULL )
		return false;
	}

	Mix::Tool::Win32::Graphics::BlankMesh blankMesh;
	unsigned int materialSlotNum;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 八分木モデルの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pOctreeModel = new Mix::Tool::Win32::Graphics::OctreeModel( L"マップコリジョン", true );
	if( m_pOctreeModel != NULL )
	{
		Mix::Tool::Win32::Graphics::OctreeModel::IMPORT_CONFIG omCfg;

		omCfg.pFilePath = pFilePath;
		omCfg.opt = m_OctreeModelConfig.opt;
		omCfg.scaling = m_OctreeModelConfig.scaling;
		omCfg.rotation = m_OctreeModelConfig.rotation;
		omCfg.translation = m_OctreeModelConfig.translation;
		omCfg.cellSize = m_OctreeModelConfig.cellSize;
		omCfg.cellError = m_OctreeModelConfig.cellError;
		omCfg.bSmooting = true;
		omCfg.smootingAngle = 0.0f;
		omCfg.meshBuildType = Mix::Tool::Win32::Graphics::MESH_BUILD_OPTIMIZE;

		if( m_pOctreeModel->Import( omCfg, &blankMesh ) == true )
		{
			materialSlotNum = m_pOctreeModel->GetMaterialSlotCount();
		}
		else
		{
			Destroy();
			return false;
		}
	}
	else
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// スタティックメッシュの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pStaticMesh = Mix::Tool::Win32::Dynamics::Factory::CreateStaticMesh();
	if( m_pStaticMesh != NULL )
	{
		const void* vertices = &( blankMesh.GetVertexList()[0] );
		unsigned int vertexStride = sizeof( Mix::Tool::Win32::Graphics::BLANK_VERTEX );
		unsigned int vertexNum = blankMesh.GetVertexList().size();
		const unsigned int* polygonIndices = &( blankMesh.GetIndexList()[0] );
		unsigned int polygonNum = blankMesh.GetIndexList().size() / 3;
		unsigned int materialNum = materialSlotNum;
		unsigned int capacity = serializeCapacity;

		if( m_pStaticMesh->Load( vertices, vertexStride, vertexNum, polygonIndices, NULL, polygonNum, NULL, materialNum, capacity ) == false )
		{
			Destroy();
			return false;
		}
	}
	else
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// パート、マテリアルリストの作成
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_PartList.reserve( materialSlotNum );
	m_MaterialList.reserve( materialSlotNum );

	for( unsigned int i = 0; i < materialSlotNum; i++ )
	{
		Mix::Tool::Win32::Graphics::MaterialSlot* pMaterialSlot = m_pOctreeModel->GetMaterialSlotByIndex( i );
		Mix::Tool::Win32::Graphics::Material* pMaterial = pMaterialSlot->GetDefault();

		Terrain::PART part;
		Mix::Tool::Win32::Dynamics::MATERIAL material;

		part.name = pMaterialSlot->GetName();
		part.color = pMaterial->GetDiffuseColor();
		part.imageFilePath = pMaterial->GetDiffuseTextureFileName();
		m_PartList.push_back( part );

		material.id = 0;
		material.attr = 0;
		material.friction = 0.5f;
		material.restitution = 0.0f;
		m_MaterialList.push_back( material );
	}

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

	return true;
}

bool Terrain::ImportFinalize( void )
{
	if( ( m_pOctreeModel == NULL ) ||
		( m_pStaticMesh == NULL ) )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 八分木モデルのファイナライズ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_pOctreeModel->ImportFinalize() == true )
	{
		m_bImported = true;
	}
	else
	{
		Destroy();
		return false;
	}

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

	return true;
}

bool Terrain::IsImported( void ) const
{
	return m_bImported;
}

void Terrain::Destroy( void )
{
	m_PartList.clear();
	m_MaterialList.clear();
	MIX_DELETE( m_pStaticMesh );
	MIX_DELETE( m_pOctreeModel );

	m_bImported = false;
}

unsigned int Terrain::GetShapeSize( void ) const
{
	return ( m_pStaticMesh != NULL )? m_pStaticMesh->GetShapeBufferSize() : 0;
}

unsigned int Terrain::GetPolygonNum( void ) const
{
	return ( m_pStaticMesh != NULL )? m_pStaticMesh->GetPolygonNum() : 0;
}

unsigned int Terrain::GetPartNum( void ) const
{
	return m_PartList.size();
}

const Terrain::PART* Terrain::Part_Get( int index ) const
{
	if( ( index < 0 ) ||
		( static_cast<int>( m_PartList.size() ) <= index ) )
	{
		return NULL;
	}

	return &( m_PartList[index] );
}

bool Terrain::Part_SetMaterial( int partIndex, const Mix::Tool::Win32::Dynamics::MATERIAL& material )
{
	if( ( partIndex < 0 ) ||
		( static_cast<int>( m_MaterialList.size() ) <= partIndex ) )
	{
		return false;
	}

	m_MaterialList[partIndex] = material;

	return true;
}

bool Terrain::Write( Mix::Tool::Win32::File::OutputStream& output )
{
	if( ( m_pStaticMesh == NULL ) ||
		( m_pStaticMesh->GetShapeBufferPtr() == 0 ) ||
		( m_pStaticMesh->GetShapeBufferSize() == 0 ) ||
		( m_PartList.size() == 0 ) ||
		( m_MaterialList.size() == 0 ) )
	{
		return false;
	}

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

	if( output.Write( m_pStaticMesh->GetShapeBufferPtr(), m_pStaticMesh->GetShapeBufferSize() ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// ポリゴンのマテリアル参照テーブル
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( output.Write( m_pStaticMesh->GetPolygonMaterials(), sizeof( unsigned int ) * m_pStaticMesh->GetPolygonNum() ) == false )
	{
		return false;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// マテリアルリスト
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( output.Write( m_pStaticMesh->GetMaterials(), sizeof( Mix::Tool::Win32::Dynamics::MATERIAL ) * m_pStaticMesh->GetMaterialNum() ) == false )
	{
		return false;
	}

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

	return true;
}

Mix::Tool::Win32::Graphics::OctreeModel* Terrain::GetOctreeModelPtr( void )
{
	return m_pOctreeModel;
}

}}}}}
