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

#include "Mix/Scene/IMaterial.h"
#include "Mix/Private/Scene/Common/Planter.h"

namespace Mix{ namespace Scene{ namespace Common{
	
////////////////////////////////////////////////////////////////////////////////////////////////////
// FlowerPackage : 定数
////////////////////////////////////////////////////////////////////////////////////////////////////

const wchar_t* FlowerPackage::FAILED_CREATE = L"フラワーパッケージの作成に失敗";
const wchar_t* FlowerPackage::FAILED_SET_MATERIAL = L"フラワーパッケージのマテリアルの設定に失敗";

const UInt32 FlowerPackage::VS_INPUT_SIGUNATURE =	( 1 << Mix::Graphics::VLS_POSITION ) |
													( 1 << Mix::Graphics::VLS_COLOR ) |
													( 1 << Mix::Graphics::VLS_NORMAL ) |
													( 1 << Mix::Graphics::VLS_TEXTURE );

const Mix::Vector3 FlowerPackage::SIMPLE_POS_TABLE[4] = 
{
	Mix::Vector3( -0.5f,  0.0f,  0.0f ),
	Mix::Vector3( -0.5f, +1.0f,  0.0f ),
	Mix::Vector3( +0.5f, +1.0f,  0.0f ),
	Mix::Vector3( +0.5f,  0.0f,  0.0f ),
};

const Mix::Vector3 FlowerPackage::CROSS1_POS_TABLE[16] =
{
	Mix::Vector3( -0.353553f, 0.000000f,  0.353553f ),
	Mix::Vector3( -0.353553f, 1.000000f,  0.353553f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),

	Mix::Vector3(  0.353553f, 0.000000f,  0.353553f ),
	Mix::Vector3(  0.353553f, 1.000000f,  0.353553f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),

	Mix::Vector3(  0.353553f, 0.000000f, -0.353553f ),
	Mix::Vector3(  0.353553f, 1.000000f, -0.353553f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),

	Mix::Vector3( -0.353553f, 0.000000f, -0.353553f ),
	Mix::Vector3( -0.353553f, 1.000000f, -0.353553f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),
};

const Mix::Vector3 FlowerPackage::CROSS2_POS_TABLE[24] =
{
	Mix::Vector3( -0.500000f, 0.000000f,  0.000000f ),
	Mix::Vector3( -0.500000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),

	Mix::Vector3( -0.250000f, 0.000000f,  0.433013f ),
	Mix::Vector3( -0.250000f, 1.000000f,  0.433013f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),

	Mix::Vector3(  0.250000f, 0.000000f,  0.433013f ),
	Mix::Vector3(  0.250000f, 1.000000f,  0.433013f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),

	Mix::Vector3(  0.500000f, 0.000000f, -0.000000f ),
	Mix::Vector3(  0.500000f, 1.000000f, -0.000000f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),

	Mix::Vector3(  0.250000f, 0.000000f, -0.433013f ),
	Mix::Vector3(  0.250000f, 1.000000f, -0.433013f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),

	Mix::Vector3( -0.250000f, 0.000000f, -0.433013f ),
	Mix::Vector3( -0.250000f, 1.000000f, -0.433013f ),
	Mix::Vector3(  0.000000f, 1.000000f,  0.000000f ),
	Mix::Vector3(  0.000000f, 0.000000f,  0.000000f ),
};

////////////////////////////////////////////////////////////////////////////////////////////////////
// FlowerPackage : クラス
////////////////////////////////////////////////////////////////////////////////////////////////////

Boolean FlowerPackage::CheckMaterial( Mix::Scene::IMaterial* pMaterial, const wchar_t* pMes, const wchar_t* pLabel, const wchar_t* pDebugName )
{
	MIX_ASSERT( pMaterial != NULL );

	UInt32 vis;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// タイプのチェック
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( pMaterial->GetType() != Mix::Scene::IMaterial::DEFAULT )
	{
		MIX_LOG_ERROR( L"%s : デフォルトマテリアルのみサポートしています : DebugName[%s]", pMes, MIX_SAFE_NAME( pDebugName ) );
		return False;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 入力シグネチャのチェック
	////////////////////////////////////////////////////////////////////////////////////////////////////

	vis = pMaterial->GetVertexInputSigunature( Mix::Scene::IMaterial::TR_SIMPLE );

	if( vis != FlowerPackage::VS_INPUT_SIGUNATURE )
	{
		if( MIX_TESTBIT( vis, ( 1 << Mix::Graphics::VLS_NORMAL ) ) == 0 )
		{
			MIX_LOG_ERROR( L"%s : シェードレスタイプのマテリアルは使用できません(法線) : DebugName[%s]", pMes, MIX_SAFE_NAME( pDebugName ) );
		}
		else if( MIX_TESTBIT( vis, ( 1 << Mix::Graphics::VLS_TEXTURE ) ) == 0 )
		{
			MIX_LOG_ERROR( L"%s : テクスチャマッピングが行われないマテリアルを設定しようとしました(UV座標) : DebugName[%s]", pMes, MIX_SAFE_NAME( pDebugName ) );
		}
		else if(	( MIX_TESTBIT( vis, ( 1 << Mix::Graphics::VLS_BINORMAL ) ) != 0 ) ||
					( MIX_TESTBIT( vis, ( 1 << Mix::Graphics::VLS_TANGENT ) ) != 0 ) )
		{
			MIX_LOG_ERROR( L"%s : バンプマッピングはサポートしていません(接線空間) : DebugName[%s]", pMes, MIX_SAFE_NAME( pDebugName ) );
		}
		else
		{
			MIX_LOG_ERROR( L"%s : 不正な入力シグネチャのマテリアルを設定しようとしました : DebugName[%s]", pMes, MIX_SAFE_NAME( pDebugName ) );
		}

		return False;
	}

	return True;
}

FlowerPackage* FlowerPackage::CreateInstance( Mix::Scene::IMaterial* pMaterial, UInt32 numModel, const Mix::Scene::IFlowerPackage::MODEL* models, const wchar_t* pDebugName )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_SCENE, FlowerPackage, pMaterial, numModel, models, pDebugName );
}

FlowerPackage::FlowerPackage( Mix::Scene::IMaterial* pMaterial, UInt32 numModel, const Mix::Scene::IFlowerPackage::MODEL* models, const wchar_t* pDebugName ) :
m_pMaterial( NULL )
{
	MIX_ASSERT( pMaterial != NULL );
	MIX_ASSERT( numModel > 0 );
	MIX_ASSERT( models != NULL );
	MIX_ASSERT( pDebugName != NULL );

//	const IFlowerPackage::MODEL* pSrcModel;
//	FlowerPackage::INTERNAL_MODEL* pDstModel;
//	FlowerPackage::INTERNAL_MODEL* pDstModelEnd;

	// デバッグ

#ifdef _DEBUG
	m_DebugName = pDebugName;
#endif //_DEBUG

	// マテリアル

	MIX_ADD_REF( pMaterial );
	m_pMaterial = pMaterial;

	// モデル
	m_ModelList.reserve( numModel );

	// テクスチャ座標の設定

	for( UInt32 i = 0; i < numModel; i++ )
	{
		FlowerPackage::INTERNAL_MODEL* dst;

		m_ModelList.push_back( FlowerPackage::INTERNAL_MODEL() );
		dst = &( m_ModelList.back() );
		dst->src = models[i];

		FillInternalModel( dst );
	}

	// テクスチャ座標のポインタを設定
/*
	pSrcModel = &( models[0] );
	pDstModel = &( m_ModelList[0] );
	pDstModelEnd = pDstModel + m_ModelList.size();

	while( pDstModel != pDstModelEnd )
	{
		const Mix::Vector2* texCoords = pDstModel->texCoords;
		FlowerPackage::INTERNAL_MODEL_DATA* dats = pDstModel->dats;

		switch( pSrcModel->type )
		{
		case IFlowerPackage::M_SIMPLE:
			dats[FlowerPackage::DAT_NEAR].texCoords = &( texCoords[FlowerPackage::TEX_COORD_SIMPLE] );
			dats[FlowerPackage::DAT_MID].texCoords = &( texCoords[FlowerPackage::TEX_COORD_SIMPLE] );
			dats[FlowerPackage::DAT_FAR].texCoords = &( texCoords[FlowerPackage::TEX_COORD_SIMPLE] );
			break;

		case IFlowerPackage::M_CROSS1:
		case IFlowerPackage::M_CROSS2:
			dats[FlowerPackage::DAT_NEAR].texCoords = &( texCoords[FlowerPackage::TEX_COORD_CROSS] );
			dats[FlowerPackage::DAT_MID].texCoords = &( texCoords[FlowerPackage::TEX_COORD_CROSS] );
			dats[FlowerPackage::DAT_FAR].texCoords = &( texCoords[FlowerPackage::TEX_COORD_SIMPLE] );
			break;

		default:
			MIX_ASSERT( pSrcModel->type <= IFlowerPackage::M_CROSS2 );
		}

		pSrcModel++;
		pDstModel++;
	}
*/
}

FlowerPackage::~FlowerPackage( void )
{
	MIX_ASSERT( m_PlanterList.size() == 0 );

	MIX_RELEASE( m_pMaterial );
}

void FlowerPackage::FillInternalModel( FlowerPackage::INTERNAL_MODEL* model )
{
	MIX_ASSERT( model != NULL );

	const Mix::Scene::IFlowerPackage::MODEL& src = model->src;
	const Mix::Vector2& srcUV0 = src.uv[0];
	const Mix::Vector2& srcUV1 = src.uv[1];

	Mix::Vector2* tex;
	FlowerPackage::INTERNAL_MODEL_DATA* dats;

	// SIMPLE

	tex = &( model->texCoords[FlowerPackage::TEX_COORD_SIMPLE] );

	tex[0].Set( srcUV0.x, srcUV1.y );
	tex[1].Set( srcUV0.x, srcUV0.y );
	tex[2].Set( srcUV1.x, srcUV0.y );
	tex[3].Set( srcUV1.x, srcUV1.y );

	// CROSS1 and CROSS2

	dats = model->dats;

	if( src.type != IFlowerPackage::M_SIMPLE )
	{
		Float32 srcHalfU = ( srcUV0.x + srcUV1.x ) * 0.5f;

		tex = &( model->texCoords[FlowerPackage::TEX_COORD_CROSS] );

		tex[0].Set( srcUV0.x, srcUV1.y );
		tex[1].Set( srcUV0.x, srcUV0.y );
		tex[2].Set( srcHalfU, srcUV0.y );
		tex[3].Set( srcHalfU, srcUV1.y );

		tex[4].Set( srcUV1.x, srcUV1.y );
		tex[5].Set( srcUV1.x, srcUV0.y );
		tex[6].Set( srcHalfU, srcUV0.y );
		tex[7].Set( srcHalfU, srcUV1.y );
	}

	switch( src.type )
	{
	case IFlowerPackage::M_SIMPLE:
		dats[FlowerPackage::DAT_NEAR].numTexCoord = 4;
		dats[FlowerPackage::DAT_NEAR].numPoint = 4;
		dats[FlowerPackage::DAT_NEAR].points = FlowerPackage::SIMPLE_POS_TABLE;
		dats[FlowerPackage::DAT_NEAR].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_SIMPLE] );

		dats[FlowerPackage::DAT_MID].numTexCoord = 4;
		dats[FlowerPackage::DAT_MID].numPoint = 4;
		dats[FlowerPackage::DAT_MID].points = FlowerPackage::SIMPLE_POS_TABLE;
		dats[FlowerPackage::DAT_MID].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_SIMPLE] );

		dats[FlowerPackage::DAT_FAR].numTexCoord = 4;
		dats[FlowerPackage::DAT_FAR].numPoint = 4;
		dats[FlowerPackage::DAT_FAR].points = FlowerPackage::SIMPLE_POS_TABLE;
		dats[FlowerPackage::DAT_FAR].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_SIMPLE] );

		break;

	case IFlowerPackage::M_CROSS1:
		dats[FlowerPackage::DAT_NEAR].numTexCoord = 8;
		dats[FlowerPackage::DAT_NEAR].numPoint = 16;
		dats[FlowerPackage::DAT_NEAR].points = FlowerPackage::CROSS1_POS_TABLE;
		dats[FlowerPackage::DAT_NEAR].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_CROSS] );

		dats[FlowerPackage::DAT_MID].numTexCoord = 8;
		dats[FlowerPackage::DAT_MID].numPoint = 16;
		dats[FlowerPackage::DAT_MID].points = FlowerPackage::CROSS1_POS_TABLE;
		dats[FlowerPackage::DAT_MID].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_CROSS] );

		dats[FlowerPackage::DAT_FAR].numTexCoord = 4;
		dats[FlowerPackage::DAT_FAR].numPoint = 4;
		dats[FlowerPackage::DAT_FAR].points = FlowerPackage::SIMPLE_POS_TABLE;
		dats[FlowerPackage::DAT_FAR].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_SIMPLE] );
		break;

	case IFlowerPackage::M_CROSS2:
		dats[FlowerPackage::DAT_NEAR].numTexCoord = 12;
		dats[FlowerPackage::DAT_NEAR].numPoint = 24;
		dats[FlowerPackage::DAT_NEAR].points = FlowerPackage::CROSS2_POS_TABLE;
		dats[FlowerPackage::DAT_NEAR].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_CROSS] );

		dats[FlowerPackage::DAT_MID].numTexCoord = 8;
		dats[FlowerPackage::DAT_MID].numPoint = 16;
		dats[FlowerPackage::DAT_MID].points = FlowerPackage::CROSS1_POS_TABLE;
		dats[FlowerPackage::DAT_MID].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_CROSS] );

		dats[FlowerPackage::DAT_FAR].numTexCoord = 4;
		dats[FlowerPackage::DAT_FAR].numPoint = 4;
		dats[FlowerPackage::DAT_FAR].points = FlowerPackage::SIMPLE_POS_TABLE;
		dats[FlowerPackage::DAT_FAR].texCoords = &( model->texCoords[FlowerPackage::TEX_COORD_SIMPLE] );
		break;

	default:
		MIX_ASSERT( src.type <= IFlowerPackage::M_CROSS2 );
	}
}

void FlowerPackage::NotifyMaterialChanged( void )
{
	size_t numPlanter = m_PlanterList.size();

	if( numPlanter > 0 )
	{
		Mix::Scene::Common::Planter** ppPlanter = &( m_PlanterList[0] );
		Mix::Scene::Common::Planter** ppPlanterEnd = ppPlanter + numPlanter;

		while( ppPlanter != ppPlanterEnd )
		{
			( *ppPlanter )->OnMaterialChanged();
			ppPlanter++;
		}
	}
}

void FlowerPackage::NotifyFlowerModelModified( UInt32 index )
{
	size_t numPlanter = m_PlanterList.size();

	if( numPlanter > 0 )
	{
		Mix::Scene::Common::Planter** ppPlanter = &( m_PlanterList[0] );
		Mix::Scene::Common::Planter** ppPlanterEnd = ppPlanter + numPlanter;

		while( ppPlanter != ppPlanterEnd )
		{
			( *ppPlanter )->OnFlowerModelModified( index );
			ppPlanter++;
		}
	}
}

void FlowerPackage::AttachPlanter( Mix::Scene::Common::Planter* pPlanter )
{
	MIX_ASSERT( pPlanter != NULL );
	MIX_ASSERT( Mix::STL::Vector_Contains( m_PlanterList, pPlanter ) == False );

	m_PlanterList.push_back( pPlanter );
}

void FlowerPackage::DetachPlanter( Mix::Scene::Common::Planter* pPlanter )
{
	MIX_ASSERT( pPlanter != NULL );
	MIX_ASSERT( Mix::STL::Vector_Contains( m_PlanterList, pPlanter ) == True );

	Mix::STL::Vector_FirstErase( m_PlanterList, pPlanter );
}

Mix::Scene::IMaterial* FlowerPackage::GetMaterialPtr( void ) const
{
	return m_pMaterial;
}

const Mix::Scene::Common::FlowerPackage::INTERNAL_MODEL* FlowerPackage::GetInternalModels( void ) const
{
	return &( m_ModelList[0] );
}

void FlowerPackage::GetMaterial( Mix::Scene::IMaterial** ppMaterial )
{
	MIX_ASSERT( ppMaterial != NULL );

	MIX_ADD_REF( m_pMaterial );
	( *ppMaterial ) = m_pMaterial;
}

Boolean FlowerPackage::SetMaterial( Mix::Scene::IMaterial* pMaterial )
{
	if( pMaterial == NULL )
	{
		return False;
	}

#ifdef _DEBUG
	if( FlowerPackage::CheckMaterial( pMaterial, FlowerPackage::FAILED_SET_MATERIAL, Mix::STR_DEBUGNAME, m_DebugName.GetConstPtr() ) == False )
	{
		return False;
	}
#endif //_DEBUG

	MIX_RELEASE( m_pMaterial );
	MIX_ADD_REF( pMaterial );
	m_pMaterial = pMaterial;

	NotifyMaterialChanged();

	return True;
}
	
UInt32 FlowerPackage::GetModelCount( void ) const
{
	return MIX_UIT_TO_UI32( m_ModelList.size() );
}

const Mix::Scene::IFlowerPackage::MODEL& FlowerPackage::GetModel( UInt32 index ) const
{
	MIX_ASSERT( m_ModelList.size() > index );

	return m_ModelList[index].src;
}

void FlowerPackage::SetModel( UInt32 index, const Mix::Scene::IFlowerPackage::MODEL& model )
{
	MIX_ASSERT( m_ModelList.size() > index );

	FlowerPackage::INTERNAL_MODEL* pModel = &( m_ModelList[index] );

	pModel->src = model;
	FillInternalModel( pModel );

	NotifyFlowerModelModified( index );
}

}}}
