#include"CGraphic.h"

#include"CRenderMessageImpl1.h"
#include"CRenderMessageImpl2.h"

//	ここのソースには 描画メッセージを書く


namespace Maid
{
	using namespace RenderMessage;


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! レンダーターゲットを単色で塗りつぶす
/*!
	@param	Color	[i ]	塗りつぶす色
 */
void CGraphic::ClearRenderTargetColor( const COLOR_R08G08B08I& Color )
{
	RenderMessage::ClearColor* p = new RenderMessage::ClearColor;
	p->Color = Color;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}

void CGraphic::ClearRenderTargetZ( float val )
{
	RenderMessage::ClearZ* p = new RenderMessage::ClearZ;
	p->val = val;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! テクスチャの設定
/*!
	@param	tex	[i ]	設定するテクスチャ
	@param	pos	[i ]	設定する位置(デフォルトで0)
 */
void CGraphic::SetTexture( const CTexture& tex, int pos )
{
	RenderMessage::SetTexture* p = new RenderMessage::SetTexture;
	p->ID = tex.GetID();
	p->Stage = pos;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
	m_pTextureCache[pos] = &tex;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! テクスチャの解除
/*!
	@param	pos	[i ]	解除する位置(デフォルトで0)
 */
void CGraphic::UnsetTexture( int pos )
{
	if( m_pTextureCache[pos]==NULL ) { return ; }

	RenderMessage::UnsetTexture* p = new RenderMessage::UnsetTexture;
	p->Stage = pos;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );

	m_pTextureCache[pos] = NULL;
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! テクスチャの全解除
/*!
 */
void CGraphic::UnsetAllTexture()
{
	for( int i=0; i<NUMELEMENTS(m_pTextureCache); ++i )
	{
		UnsetTexture(i);
	}
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 頂点の設定
/*!
	@param	vertex	[i ]	設定するシェーダー
 */
void CGraphic::SetVertex( const CVertex& vertex, int pos )
{
	RenderMessage::SetVertex* p = new RenderMessage::SetVertex;
	p->ID = vertex.GetID();
	p->pos = pos;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 頂点インデックスの設定
/*!
	@param	index	[i ]	設定する頂点インデックス
 */
void CGraphic::SetIndex( const CIndex& index )
{
	RenderMessage::SetIndex* p = new RenderMessage::SetIndex;
	p->ID = index.GetID();
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}


void CGraphic::SetVertexDeclaration( const CVertexDeclaration& decl )
{
	RenderMessage::SetVertexDeclaration* p = new RenderMessage::SetVertexDeclaration;
	p->ID = decl.GetID();
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! バーテックスシェーダーの設定
/*!
	@param	shader	[i ]	設定するシェーダー
 */
void CGraphic::SetVertexShader( const CVertexShader& shader )
{
	const MySTL::map<int,VECTOR4DF>& c = shader.m_ConstF;

	for( MySTL::map<int,VECTOR4DF>::const_iterator ite=c.begin(); ite!=c.end(); ++ite )
	{
		RenderMessage::SetVertexShaderConstF* p = new RenderMessage::SetVertexShaderConstF;
		p->pos = ite->first;
		p->vec = ite->second;
		
		PostRenderMessage( SPRENDERMESSAGE(p) );
	}


	RenderMessage::SetVertexShader* p = new RenderMessage::SetVertexShader;
	p->ID = shader.GetID();
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! ピクセルシェーダーの設定
/*!
	@param	shader	[i ]	設定するシェーダー
 */
void CGraphic::SetPixelShader( const CPixelShader& shader )
{
	RenderMessage::SetPixelShader* p = new RenderMessage::SetPixelShader;
	p->ID = shader.GetID();
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! レンダリング先の設定
/*!
	@param	target	[i ]	設定するバッファ
 */
void CGraphic::SetRenderTarget( const CSurface& target )
{
	boost::shared_ptr<RenderMessage::SetRenderTarget> pMess( new RenderMessage::SetRenderTarget );

	pMess->ID = target.GetID();
	pMess->Type   = SetRenderTarget::TYPE_SURFACE;
	pMess->Target = SetRenderTarget::TARGET_COLOR;

	PostRenderMessage( pMess );

	VIEWPORT view;

	view.Screen = RECT2DI(POINT2DI(0,0),target.GetSize());
	view.MinZ = 0.0f;
	view.MaxZ = 1.0f;

	SetViewPort( view );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! レンダリング先の設定
/*!
	@param	target	[i ]	設定するテスクチャ
 */
void CGraphic::SetRenderTarget( const CTexture& target )
{
	boost::shared_ptr<RenderMessage::SetRenderTarget> pMess( new RenderMessage::SetRenderTarget );

	pMess->ID = target.GetID();
	pMess->Type   = SetRenderTarget::TYPE_TEXTURE;
	pMess->Target = SetRenderTarget::TARGET_COLOR;

	PostRenderMessage( pMess );

	VIEWPORT view;

	view.Screen = RECT2DI(POINT2DI(0,0),target.GetSize());
	view.MinZ = 0.0f;
	view.MaxZ = 1.0f;

	SetViewPort( view );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 深度バッファの設定
/*!
	@param	target	[i ]	設定するバッファ(深度フォーマットになってること)
 */
void CGraphic::SetDepthStencil( const CSurface& target )
{
	boost::shared_ptr<RenderMessage::SetRenderTarget> pMess( new RenderMessage::SetRenderTarget );

	pMess->ID = target.GetID();
	pMess->Type   = SetRenderTarget::TYPE_SURFACE;
	pMess->Target = SetRenderTarget::TARGET_DEPTHSTENCIL;

	PostRenderMessage( pMess );
}


void CGraphic::ResetRenderTarget()
{
	boost::shared_ptr<RenderMessage::ResetRenderTarget> pMess( new RenderMessage::ResetRenderTarget );

	pMess->Target   = ResetRenderTarget::TARGET_COLOR;
	PostRenderMessage( pMess );
}

void CGraphic::ResetDepthStencil()
{
	boost::shared_ptr<RenderMessage::ResetRenderTarget> pMess( new RenderMessage::ResetRenderTarget );

	pMess->Target   = ResetRenderTarget::TARGET_DEPTHSTENCIL;
	PostRenderMessage( pMess );
}

void CGraphic::SetCamera( const CCamera& camera )
{
	m_ViewMatrix = camera.GetViewMatrix();
	m_ProjectionMatrix = camera.GetProjectionMatrix();

	m_CameraMatrix = m_ViewMatrix * m_ProjectionMatrix;
}

MATRIX4DF	CGraphic::GetViewMatrix() { return m_ViewMatrix; }
MATRIX4DF	CGraphic::GetProjectionMatrix() { return m_ProjectionMatrix; }
MATRIX4DF	CGraphic::GetCameraMatrix() { return m_CameraMatrix; }


void CGraphic::SetViewPort( const VIEWPORT& view )
{
	boost::shared_ptr<RenderMessage::SetViewPort> pMess( new RenderMessage::SetViewPort );

	pMess->Screen = view.Screen;
	pMess->MinZ   = view.MinZ;
	pMess->MaxZ   = view.MaxZ;
	PostRenderMessage( pMess );
}


void CGraphic::SetCullingMode( CULLINGMODE mode )
{
	boost::shared_ptr<RenderMessage::SetRenderState> p( new RenderMessage::SetRenderState );
	p->state		= IVideoCardDriver::RENDERSTATE_CULLINGMODE;

	switch( mode )
	{
	case CULLINGMODE_NONE: { p->Value = IVideoCardDriver::CULLINGMODE_NONE; }break;
	case CULLINGMODE_LEFT: { p->Value = IVideoCardDriver::CULLINGMODE_LEFT; }break;
	case CULLINGMODE_RIGHT:{ p->Value = IVideoCardDriver::CULLINGMODE_RIGHT;}break;
	}

	PostRenderMessage( p );
}

void CGraphic::SetRenderStateZWriteEnable( bool Enable )
{
	boost::shared_ptr<RenderMessage::SetRenderState> p( new RenderMessage::SetRenderState );
	p->state		= IVideoCardDriver::RENDERSTATE_ZWRITEENABLE;

	if( Enable )	{ p->Value = IVideoCardDriver::STATE_TRUE; }
	else			{ p->Value = IVideoCardDriver::STATE_FALSE;}

	PostRenderMessage( p );
}

void CGraphic::SetRenderStateZWriteFunc( CMPTYPE Type )
{
	boost::shared_ptr<RenderMessage::SetRenderState> p( new RenderMessage::SetRenderState );
	p->state		= IVideoCardDriver::RENDERSTATE_ZWRITEFUNC;

	switch( Type )
	{
	case CMPTYPE_NEVER:		{ p->Value = IVideoCardDriver::CMPTYPE_NEVER; }break;
	case CMPTYPE_LESS:		{ p->Value = IVideoCardDriver::CMPTYPE_LESS; }break;
	case CMPTYPE_EQUAL:		{ p->Value = IVideoCardDriver::CMPTYPE_EQUAL;}break;
	case CMPTYPE_LESSEQUAL:		{ p->Value = IVideoCardDriver::CMPTYPE_LESSEQUAL; }break;
	case CMPTYPE_GREATER:		{ p->Value = IVideoCardDriver::CMPTYPE_GREATER; }break;
	case CMPTYPE_NOTEQUAL:		{ p->Value = IVideoCardDriver::CMPTYPE_NOTEQUAL;}break;
	case CMPTYPE_GREATEREQUAL:	{ p->Value = IVideoCardDriver::CMPTYPE_GREATEREQUAL; }break;
	case CMPTYPE_ALWAYS:		{ p->Value = IVideoCardDriver::CMPTYPE_ALWAYS; }break;
	}

	PostRenderMessage( p );


}

void CGraphic::SetRenderStateZTestEnable( bool Enable )
{
	boost::shared_ptr<RenderMessage::SetRenderState> p( new RenderMessage::SetRenderState );
	p->state		= IVideoCardDriver::RENDERSTATE_ZTESTENABLE;

	if( Enable )	{ p->Value = IVideoCardDriver::STATE_TRUE; }
	else			{ p->Value = IVideoCardDriver::STATE_FALSE;}
	PostRenderMessage( p );
}

void CGraphic::SetSamplerStateMagFilter( int Stage, FILTERTYPE type )
{
	boost::shared_ptr<RenderMessage::SetSamplerState> p( new RenderMessage::SetSamplerState );
	p->Stage		= Stage;
	p->State		= IVideoCardDriver::SAMPLERSTATE_MAGFILTER;

	switch( type )
	{
	case FILTERTYPE_POINT:		{ p->Value = IVideoCardDriver::FILTERTYPE_POINT; }break;
	case FILTERTYPE_LINEAR:		{ p->Value = IVideoCardDriver::FILTERTYPE_LINEAR; }break;
	case FILTERTYPE_ANISOTROPIC:{ p->Value = IVideoCardDriver::FILTERTYPE_ANISOTROPIC; }break;
	}

	PostRenderMessage( p );
}

void CGraphic::SetSamplerStateMinFilter( int Stage, FILTERTYPE type )
{
	boost::shared_ptr<RenderMessage::SetSamplerState> p( new RenderMessage::SetSamplerState );
	p->Stage		= Stage;
	p->State		= IVideoCardDriver::SAMPLERSTATE_MINFILTER;

	switch( type )
	{
	case FILTERTYPE_POINT:		{ p->Value = IVideoCardDriver::FILTERTYPE_POINT; }break;
	case FILTERTYPE_LINEAR:		{ p->Value = IVideoCardDriver::FILTERTYPE_LINEAR; }break;
	case FILTERTYPE_ANISOTROPIC:{ p->Value = IVideoCardDriver::FILTERTYPE_ANISOTROPIC; }break;
	}

	PostRenderMessage( p );
}

void CGraphic::SetSamplerStateAddressU( int Stage, TEXTUREADDRESS address )
{
	boost::shared_ptr<RenderMessage::SetSamplerState> p( new RenderMessage::SetSamplerState );
	p->Stage		= Stage;
	p->State		= IVideoCardDriver::SAMPLERSTATE_TADDRESSU;

	switch( address )
	{
	case TEXTUREADDRESS_WRAP:	{ p->Value = IVideoCardDriver::TEXTUREADDRESS_WRAP; }break;
	case TEXTUREADDRESS_MIRROR:	{ p->Value = IVideoCardDriver::TEXTUREADDRESS_MIRROR; }break;
	case TEXTUREADDRESS_CLAMP:	{ p->Value = IVideoCardDriver::TEXTUREADDRESS_CLAMP; }break;
	}

	PostRenderMessage( p );
}

void CGraphic::SetSamplerStateAddressV( int Stage, TEXTUREADDRESS address )
{
	boost::shared_ptr<RenderMessage::SetSamplerState> p( new RenderMessage::SetSamplerState );
	p->Stage		= Stage;
	p->State		= IVideoCardDriver::SAMPLERSTATE_TADDRESSV;

	switch( address )
	{
	case TEXTUREADDRESS_WRAP:	{ p->Value = IVideoCardDriver::TEXTUREADDRESS_WRAP; }break;
	case TEXTUREADDRESS_MIRROR:	{ p->Value = IVideoCardDriver::TEXTUREADDRESS_MIRROR; }break;
	case TEXTUREADDRESS_CLAMP:	{ p->Value = IVideoCardDriver::TEXTUREADDRESS_CLAMP; }break;
	}

	PostRenderMessage( p );
}


/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 設定されている頂点でポリゴンの描画
/*!
	@param	prim			[i ]	描画の形
	@param	StartVertex		[i ]	描画を開始する頂点番号
	@param	PrimitiveCount	[i ]	描画する数
 */
void CGraphic::DrawPrimitive( PRIMITIVE prim, unt StartVertex, unt PrimitiveCount )
{
	RenderMessage::DrawPrimitive* p = new RenderMessage::DrawPrimitive;
	p->type				= (RenderMessage::DrawPrimitive::TYPE)prim;
	p->StartVertex		= StartVertex;
	p->PrimitiveCount	= PrimitiveCount;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}

/*-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
//! 指定した頂点でポリゴンの描画
/*!
	@param	prim			[i ]	描画の形
	@param	pStartVertex	[i ]	頂点データの先頭
	@param	Stride			[i ]	１頂点あたりの大きさ
	@param	PrimitiveCount	[i ]	描画する数
 */
void CGraphic::DrawPrimitiveUP( PRIMITIVE prim, const void* pStartVertex, unt Stride, unt PrimitiveCount )
{
	RenderMessage::DrawPrimitiveUP* p = new RenderMessage::DrawPrimitiveUP;
	p->type				= (RenderMessage::DrawPrimitiveUP::TYPE)prim;

	unt vertexcount = 0;
	switch( prim )
	{
	case PRIMITIVE_POINTLIST:		{ vertexcount = PrimitiveCount;		}break;
	case PRIMITIVE_LINELIST:		{ vertexcount = PrimitiveCount*2;	}break;
	case PRIMITIVE_LINESTRIP:		{ vertexcount = PrimitiveCount+1;	}break;
	case PRIMITIVE_TRIANGLELIST:	{ vertexcount = PrimitiveCount*3;	}break;
	case PRIMITIVE_TRIANGLESTRIP:	{ vertexcount = PrimitiveCount+2;	}break;
	case PRIMITIVE_TRIANGLEFAN:		{ vertexcount = PrimitiveCount+2;	}break;
	}

	{
		const unt08* pStart = (unt08*)pStartVertex;
		const unt size = Stride*vertexcount;
		p->Vertex = MySTL::vector<unt08>( pStart, pStart+size );
	}

	p->Stride			= Stride;
	p->PrimitiveCount	= PrimitiveCount;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}

void CGraphic::DrawIndexedPrimitive( PRIMITIVE prim, int BaseVertexOffset, unt MinIndex, unt NumVertices, unt StartIndex, unt PrimitiveCount )
{
	RenderMessage::DrawIndexedPrimitive* p = new RenderMessage::DrawIndexedPrimitive;
	p->type				= (RenderMessage::DrawIndexedPrimitive::TYPE)prim;
	p->VertexOffset		= BaseVertexOffset;
	p->MinIndex			= MinIndex;
	p->NumVertex		= NumVertices;
	p->StartIndex		= StartIndex;
	p->PrimitiveCount	= PrimitiveCount;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}


void CGraphic::DrawIndexPrimitiveUP( PRIMITIVE prim, int MinIndex, int NumVertices, const void* pVertex, int VertexSize,
														int PrimitiveCount, const void* pIndex, int IndexSize  )
{
	RenderMessage::DrawIndexedPrimitiveUP* p = new RenderMessage::DrawIndexedPrimitiveUP;
	p->type				= (RenderMessage::DrawIndexedPrimitiveUP::TYPE)prim;

	unt vertexcount = 0;
	switch( prim )
	{
	case PRIMITIVE_POINTLIST:		{ vertexcount = PrimitiveCount;		}break;
	case PRIMITIVE_LINELIST:		{ vertexcount = PrimitiveCount*2;	}break;
	case PRIMITIVE_LINESTRIP:		{ vertexcount = PrimitiveCount+1;	}break;
	case PRIMITIVE_TRIANGLELIST:	{ vertexcount = PrimitiveCount*3;	}break;
	case PRIMITIVE_TRIANGLESTRIP:	{ vertexcount = PrimitiveCount+2;	}break;
	case PRIMITIVE_TRIANGLEFAN:		{ vertexcount = PrimitiveCount+2;	}break;
	}

	{
		const unt08* pStart = (unt08*)pVertex;
		const unt size = VertexSize*NumVertices;
		p->Vertex = MySTL::vector<unt08>( pStart, pStart+size );
	}

	{
		const unt08* pStart = (unt08*)pIndex;
		const unt size = IndexSize*vertexcount;
		p->Index = MySTL::vector<unt08>( pStart, pStart+size );
	}

	p->VertexSize		= VertexSize;
	p->PrimitiveCount	= PrimitiveCount;
	p->MinIndex		= MinIndex;
	p->NumVertices	= NumVertices;
	p->IndexSize	= IndexSize;
	
	PostRenderMessage( SPRENDERMESSAGE(p) );
}


}