#include"CModelFile.h"
#include"../Storage/DefaultFunction/LoadLWO.h"
#include"../Auxiliary/CString.h"

#include"CGraphic.h"
#include"CRenderMessageImpl3.h"


namespace Maid
{



CModelFile::CModelFile()
{
	m_State = STATE_EMPTY;
}

CModelFile::~CModelFile()
{
	Delete();
}

void CModelFile::Load( const mstring& FileName )
{
	Delete();
	m_ModelFile.Load( FileName );

	m_State = STATE_LOADING_MODEL;

	IsNowLoading();
}

void CModelFile::Delete()
{
	m_ModelFile.Delete();
	m_TextureMap.clear();
	m_State = STATE_EMPTY;
}

mstring CModelFile::GetFileName() const
{
	return m_ModelFile.GetFileName();
}


bool CModelFile::IsNowLoading()
{
	switch( m_State )
	{
	case STATE_EMPTY: { return false; }break;

	case STATE_LOADING_MODEL:
		{
			if( m_ModelFile.IsNowLoading() ) { return true; }

			//	モデルの読み込みが終わったら、テクスチャの読み込み

			const MODELDATA& info = m_ModelFile.GetOption();

			//	テクスチャのロード
			for( int i=0; i<(int)info.Texture.size(); ++i )
			{
				//	ライトウェーブの外部ファイルパスは絶対パスの時があったりして
				//	やっかいなので、lwoファイルと同じ位置にあるファイルのみにしてしまう。

				const int no = info.Texture[i].No;
				const mstring filename = info.Texture[i].FilePath;

				const mstring dir_lwo = CString::GetDirectory(m_ModelFile.GetFileName());
				const mstring file_tex = CString::GetFileName(filename);

				mstring path;

				if( dir_lwo.empty() )	{ path = file_tex; }
				else					{ path = dir_lwo+MAIDTEXT("/")+file_tex; }
				const MySTL::string s = CString::ConvertMAIDtoSJIS(path);


				m_TextureMap[no].Load( path );
			}

			m_State = STATE_LOADING_TEXTURE;
		}

	case STATE_LOADING_TEXTURE:
		{
			//	読み込み中のテクスチャがあったらまだ。
			for( MySTL::map<int,CTextureFile>::iterator ite=m_TextureMap.begin();
					ite!=m_TextureMap.end(); ++ite )
			{
				if( ite->second.IsNowLoading() ) { return true; }
			}

			//	なかったら終了
			m_State = STATE_WORKING;
		}

	case STATE_WORKING: { return false; }break;
	}

	MAID_ASSERT( true, MAIDTEXT("ここはありえない") );

	return false;
}


int CModelFile::GetLayerCount()const
{
	MAID_ASSERT( m_State!=STATE_WORKING, "まだ読み込んでません" );

	return (int)m_ModelFile.GetOption().Layer.size();
}

CModelFile::LAYERINFO CModelFile::GetLayer( int no, float time )const
{
	LAYERINFO ret;

	const MODELDATA::LAYER& layer = m_ModelFile.GetOption().Layer[no];

	ret.VertexCount = layer.VertexCount;
	ret.Point  = CVertexModel(layer.PointID);
	ret.Normal = CVertexModel(layer.NormalID);

	ret.Primitive.resize( layer.Primitive.size() );

	for( int i=0; i<(int)layer.Primitive.size(); ++i )
	{
		LAYERINFO::PRIMITIVE& dst = ret.Primitive[i];
		const MODELDATA::LAYER::PRIMITIVE& src = layer.Primitive[i];
		const MODELDATA::MATERIAL& mat = m_ModelFile.GetOption().Material[src.MaterialNo];

		dst.Index = CIndexModel( src.IndexID );
		dst.Count = src.IndexCount;

		if( !src.ColorUVID.empty() )
		{
			dst.ColorUV = CVertexModel( src.ColorUVID );
		}
		if( mat.ColorTextureNo!=MODELDATA::MATERIAL::TEXTURE_NONE )
		{
			MySTL::map<int,CTextureFile>::const_iterator ite=m_TextureMap.find(mat.ColorTextureNo);
			const CTextureFile& tex = ite->second;
			dst.ColorTex = CTextureModel( tex.GetID(),tex.GetSize(),tex.GetPixelFormat() );
		}

		dst.Color.SetR( mat.ColorRDefault );
		dst.Color.SetG( mat.ColorGDefault );
		dst.Color.SetB( mat.ColorBDefault );

		dst.Alpha = 1.0f-mat.Trance;	//	データは透明度、ゲームは不透明度
										//	なので変換する
	}

	return ret;
}

CModelFile::_CModelFile::_CModelFile()
	:IModelFile()
{

}

CModelFile::_CModelFile::_CModelFile( const _CModelFile& rha )
	:IModelFile(rha)
{

}

void CModelFile::_CModelFile::LoadedDelete( const mstring& FileName )
{
	const MODELDATA& info = GetOption();

	for( int i=0; i<(int)info.Layer.size(); ++i )
	{
		const MODELDATA::LAYER& layer = info.Layer[i];

		DelVertex( layer.PointID );
		DelVertex( layer.NormalID );

		for( int j=0; j<(int)layer.Primitive.size(); ++j )
		{
			const MODELDATA::LAYER::PRIMITIVE& pri = layer.Primitive[j];

			DelIndex ( pri.IndexID );
			DelVertex( pri.ColorUVID );
		}
	}
}

void CModelFile::_CModelFile::LoadEnd( const SPSTORAGEFUNCTION_RETURNPARAM& param, MODELDATA& info )
{
	const mstring FileName = GetFileName();

	LoadLWOReturn* pRet = static_cast<LoadLWOReturn*>(param.get());


	//	モデルのセット
	info.Layer.resize( pRet->Layer.size() );
	for( int i=0; i<(int)pRet->Layer.size(); ++i )
	{
		MODELDATA::LAYER& layer = info.Layer[i];
		const LoadLWOReturn::LAYER& layer_src = pRet->Layer[i];

		const mstring LayerID = FileName + MAIDTEXT(":layer") + CString::ItoA(i);

		layer.VertexCount = layer_src.VertexCount;

		layer.PointID = LayerID+ MAIDTEXT(":point");
		PostVertex( layer_src.pPoint,  layer.PointID, VERTEXFORMAT_XYZ    );

		layer.NormalID = LayerID+ MAIDTEXT(":normal");
		PostVertex( layer_src.pNormal,  layer.NormalID, VERTEXFORMAT_NORMAL    );

		layer.Primitive.resize( layer_src.Primitive.size() );

		for( int j=0; j<(int)layer_src.Primitive.size(); ++j )
		{
			const mstring PrimID = LayerID + MAIDTEXT(":Prim") + CString::ItoA(j);

			const LoadLWOReturn::LAYER::PRIMITIVE& pri_src = layer_src.Primitive[j];
			MODELDATA::LAYER::PRIMITIVE& pri = layer.Primitive[j];

			pri.IndexID   = PrimID;
			pri.IndexCount= (int)pri_src.pIndex->size() / layer_src.IndexStride;
			pri.MaterialNo= pri_src.MaterialNo;

			PostIndex ( pri_src.pIndex, pri.IndexID, layer_src.IndexStride );

			if( pri_src.pColorUV.get()!=NULL )
			{
				pri.ColorUVID = PrimID+MAIDTEXT(":ColorUV");
				PostVertex( pri_src.pColorUV, pri.ColorUVID, VERTEXFORMAT_TEX1 );
			}
		}
	}

	//	マテリアルのセット
	info.Material.resize( pRet->Material.size() );
	for( int i=0; i<(int)pRet->Material.size(); ++i )
	{
		MODELDATA::MATERIAL& mat = info.Material[i];
		const LoadLWOReturn::MATERIAL& mat_src = pRet->Material[i];

		mat.ColorTextureNo= mat_src.ColorTextureNo;
		mat.ColorRDefault = mat_src.ColorRDefault;
		mat.ColorGDefault = mat_src.ColorGDefault;
		mat.ColorBDefault = mat_src.ColorBDefault;
		mat.Trance = mat_src.Trance;
	}

	//	テクスチャのセット
	for( int i=0; i<(int)pRet->Texture.size(); ++i )
	{
		MODELDATA::TEXTURE dat;
		dat.No = pRet->Texture[i].No;
		dat.FilePath = pRet->Texture[i].FilePath;

		info.Texture.push_back( dat );
	}
}

void CModelFile::_CModelFile::PostVertex( const SPBINARY& pBinary, const mstring& name, VERTEXFORMAT fmt )
{
	if( pBinary.get()==NULL ) { return ; }

	GlobalPointer<CGraphic>::Get()->RegistVertex( name, pBinary, fmt );
}

void CModelFile::_CModelFile::PostIndex ( const SPBINARY& pBinary, const mstring& name, int IndexStride )
{
	if( pBinary.get()==NULL ) { return ; }

	GlobalPointer<CGraphic>::Get()->RegistIndex( name, pBinary, IndexStride );
}

void CModelFile::_CModelFile::DelVertex( const mstring& name )
{
	if( name.empty() ) { return ; }
	GlobalPointer<CGraphic>::Get()->DeleteVertex( name );
}

void CModelFile::_CModelFile::DelIndex ( const mstring& name )
{
	if( name.empty() ) { return ; }
	GlobalPointer<CGraphic>::Get()->DeleteIndex( name );
}


}

