#include"CGraphic.h"


namespace Maid
{
	using namespace RenderMessage;



/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! モデルの描画
/*!
 	@param	Model	[i ]	表示するモデル
 	@param	Pos		[i ]	座標
 */
void CGraphic::BltModel  ( const CModelFile& Model, const POINT3DF& Pos, unt08 Alpha )
{
	const MATRIX4DF mat = MATRIX4DF().SetTranslate( Pos.x, Pos.y, Pos.z );

	BltModel( Model, mat, Alpha );
}

void CGraphic::BltModelS ( const CModelFile& Model, const POINT3DF& Pos, const SIZE3DF& Scale, unt08 Alpha )
{
	const MATRIX4DF mat =
						  MATRIX4DF().SetScale( Scale.w, Scale.h, Scale.d )
						* MATRIX4DF().SetTranslate( Pos.x, Pos.y, Pos.z );
	BltModel( Model, mat, Alpha );
}

void CGraphic::BltModelR ( const CModelFile& Model, const POINT3DF& Pos, float Rotate, const VECTOR3DF& vec, unt08 Alpha )
{
	const MATRIX4DF mat = 
						  MATRIX4DF().SetRotationXYZ( Rotate, vec )
						* MATRIX4DF().SetTranslate( Pos.x, Pos.y, Pos.z );
	BltModel( Model, mat, Alpha );
}

void CGraphic::BltModelSR( const CModelFile& Model, const POINT3DF& Pos, const SIZE3DF& Scale, float Rotate, const VECTOR3DF& vec, unt08 Alpha )
{
	const MATRIX4DF mat = 
						  MATRIX4DF().SetScale( Scale.w, Scale.h, Scale.d )
						* MATRIX4DF().SetRotationXYZ( Rotate, vec )
						* MATRIX4DF().SetTranslate( Pos.x, Pos.y, Pos.z );
	BltModel( Model, mat, Alpha );

}

void CGraphic::BltModel  ( const CModelFile& Model, const MATRIX4DF& world, unt08 Alpha )
{
	SetRenderStateZWriteEnable(true);
	SetRenderStateZTestEnable(true);
	SetCullingMode(CULLINGMODE_LEFT);
	SetSamplerStateMagFilter( 0, m_FilterType );
	SetSamplerStateMinFilter( 0, m_FilterType );


	const MATRIX4DF mat = world * m_CameraMatrix;

	UnsetAllTexture();

	//	まずは半透明のないモデルの描画
	SetRenderStateZWriteFunc( CMPTYPE_LESSEQUAL );
	for( int i=0; i<Model.GetLayerCount(); ++i )
	{
		const CModelFile::LAYERINFO info = Model.GetLayer(i,0);

		SetVertex( info.Point, 0 );
		SetVertex( info.Normal, 1 );

		for( int j=0; j<(int)info.Primitive.size(); ++j )
		{
			const CModelFile::LAYERINFO::PRIMITIVE& pri = info.Primitive[j];
			if( pri.Alpha>=1.0f && Alpha==0xFF ) { continue;}

			BltPrimitive( info.Primitive[j], mat, info.VertexCount, Alpha );
		}
	}

	//	次に半透明があるモデルの描画
	SetRenderStateZWriteFunc( CMPTYPE_LESS );
	for( int i=0; i<Model.GetLayerCount(); ++i )
	{
		const CModelFile::LAYERINFO info = Model.GetLayer(i,0);

		SetVertex( info.Point, 0 );
		SetVertex( info.Normal, 1 );

		for( int j=0; j<(int)info.Primitive.size(); ++j )
		{
			const CModelFile::LAYERINFO::PRIMITIVE& pri = info.Primitive[j];
			if( !(pri.Alpha>=1.0f && Alpha==0xFF) ) { continue;}
			BltPrimitive( info.Primitive[j], mat, info.VertexCount, Alpha );
		}
	}

}

void CGraphic::BltPrimitive( const CModelFile::LAYERINFO::PRIMITIVE& pri, const MATRIX4DF& mat, int VertexCount, unt08 Alpha )
{
	SetIndex( pri.Index );

	const int count = pri.Count / 3;
	VECTOR4DF Color;

	CVertexShader& vs = SerchModelShaderVS(pri);
	CPixelShader&  ps = SerchModelShaderPS(pri);
	CVertexDeclaration&  decl = SerchModelShaderDC(pri);

	{
		Color.x = pri.Color.GetR();
		Color.y = pri.Color.GetG();
		Color.z = pri.Color.GetB();

		if( Alpha==0xFF )	{ Color.w = pri.Alpha; }
		else
		{
			const float tmp = float((int)Alpha) / 255.0f;
			Color.w = pri.Alpha * tmp;
		}
	}

	if( !pri.ColorUV.GetID().empty() )
	{
		SetTexture( pri.ColorTex, 0 );
		SetVertex( pri.ColorUV, 2 );
	}


	vs.SetConstantF(0,mat.GetTranspose());
	vs.SetConstantF(4, Color );

	SetVertexShader( vs );
	SetPixelShader( ps );
	SetVertexDeclaration( decl );
	DrawIndexedPrimitive( PRIMITIVE_TRIANGLELIST, 0, 0, VertexCount, 0, count );
}


CVertexShader& CGraphic::SerchModelShaderVS  ( const CModelFile::LAYERINFO::PRIMITIVE& pri )
{
	const bool UseTex = !pri.ColorTex.GetID().empty();

	if( UseTex ) { return m_VertexShaderModel[1]; }

	return m_VertexShaderModel[0];
}

CPixelShader&  CGraphic::SerchModelShaderPS  ( const CModelFile::LAYERINFO::PRIMITIVE& pri )
{
	const bool UseTex = !pri.ColorTex.GetID().empty();

	if( UseTex ) { return m_PixelShaderModel[1]; }

	return m_PixelShaderModel[0];
}

CVertexDeclaration&  CGraphic::SerchModelShaderDC  ( const CModelFile::LAYERINFO::PRIMITIVE& pri )
{
	const bool UseTex = !pri.ColorTex.GetID().empty();

	if( UseTex ) { return m_DeclModel[1]; }

	return m_DeclModel[0];
}


}