#include"CGraphic.h"


namespace Maid
{
	using namespace RenderMessage;



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

	BltModelTone( Model, Shadow, Light, Rinkaku, mat, Alpha );
}

void CGraphic::BltModelToneS ( const CModelFile& Model, const CTexture& Shadow, const LIGHT& Light, int Rinkaku, 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 );
	BltModelTone( Model, Shadow, Light, Rinkaku, mat, Alpha );
}

void CGraphic::BltModelToneR ( const CModelFile& Model, const CTexture& Shadow, const LIGHT& Light, int Rinkaku, 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 );
	BltModelTone( Model, Shadow, Light, Rinkaku, mat, Alpha );
}

void CGraphic::BltModelToneSR( const CModelFile& Model, const CTexture& Shadow, const LIGHT& Light, int Rinkaku, 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 );
	BltModelTone( Model, Shadow, Light, Rinkaku, mat, Alpha );

}

void CGraphic::BltModelTone  ( const CModelFile& Model, const CTexture& Shadow, const LIGHT& Light, int Rinkaku, const MATRIX4DF& world, unt08 Alpha )
{
	SetRenderStateZWriteEnable(true);
	SetRenderStateZTestEnable(true);
	SetCullingMode(CULLINGMODE_LEFT);
	SetSamplerStateMagFilter( 0, m_FilterType );
	SetSamplerStateMinFilter( 0, m_FilterType );
	SetSamplerStateMagFilter( 1, m_FilterType );
	SetSamplerStateMinFilter( 1, 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;}
			BltPrimitiveTone( info.Primitive[j], Shadow, Light, Rinkaku, mat, world, 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;}
			BltPrimitiveTone( info.Primitive[j], Shadow, Light, Rinkaku, mat, world, info.VertexCount, Alpha );
		}
	}
}

void CGraphic::BltPrimitiveTone( const CModelFile::LAYERINFO::PRIMITIVE& pri, const CTexture& Shadow, const LIGHT& Light, int Rinkaku, const MATRIX4DF& mat, const MATRIX4DF& world, int VertexCount, unt08 Alpha )
{
	const int count = pri.Count / 3;

	SetIndex( pri.Index );


	{
		VECTOR4DF Color;

		CVertexShader& vs = SerchModelShaderVSTone(pri);
		CPixelShader&  ps = SerchModelShaderPSTone(pri);
		CVertexDeclaration&  decl = SerchModelShaderDCTone(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 );
		}

		SetTexture( Shadow, 1 );

		//	カメラから見た平行光源の方向を求める
		VECTOR4DF light_vec;

		{
			//	求めるんだけど、vsの方で
			//	光源方向が一定で法線が回る  == 光源が反対に回って、法線が固定。
			//	とやっているので、それ用の行列をかけてしまう

			MATRIX4DF l = world * m_ViewMatrix;
			l.m41 = 0.0f;
			l.m42 = 0.0f;
			l.m43 = 0.0f;
			l.m44 = 1.0f;

			const VECTOR4DF tmp1 = Light.Direction.Convert4D() * l.GetInverse();
			const VECTOR3DF tmp2 = VECTOR3DF(tmp1.x,tmp1.y,tmp1.z).Normalize();

			light_vec = tmp2.Convert4D();

		}


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


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


	{
		//	輪郭線を引く
		const SCREENMODE& mode = m_ScreenMode;

		CVertexShader& vs = m_VertexShaderModelToneLine[0];
		CPixelShader&  ps = m_PixelShaderFill[0];

		const float bold = float(Rinkaku*2) / float(mode.Size.w);

		SetCullingMode(CULLINGMODE_RIGHT);
		vs.SetConstantF(4,mat.GetTranspose());
		vs.SetConstantF(1,VECTOR4DF(bold,0,0,0));
		vs.SetConstantF(2,VECTOR4DF(0,0,0,1));

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


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

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

	return m_VertexShaderModelTone[0];
}

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

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

	return m_PixelShaderModelTone[0];
}

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

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

	return m_DeclModelTone[0];
}


}