#include "Mix/Private/Graphics/Utility/Common/CanvasRenderer.h"

#include "Mix/Graphics/IDevice.h"
#include "Mix/Graphics/IVertexShader.h"
#include "Mix/Graphics/IPixelShader.h"
#include "Mix/Graphics/IVertexLayout.h"
#include "Mix/Graphics/IVertexBuffer.h"
#include "Mix/Graphics/IIndexBuffer.h"
#include "Mix/Graphics/ITexture.h"
#include "Mix/Graphics/Utility/IFont.h"

#include "Mix/Private/Graphics/Common/Manager.h"
#include "Mix/Private/Graphics/Utility/Common/TextPrinter.h"

namespace Mix{ namespace Graphics{ namespace Utility{ namespace Common{

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CanvasRenderer
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

CanvasRenderer* CanvasRenderer::CreateInstance( const wchar_t* pName )
{
	return MIX_LIB_NEW_T( Mix::Memory::SECTION_GRAPHICS, CanvasRenderer, pName );
}

CanvasRenderer::CanvasRenderer( const wchar_t* pName ) :
m_Name( pName ),
m_pDevice( NULL ),
m_pFont( NULL ),
m_Color( 1.0f, 1.0f, 1.0f, 1.0f ),
m_BlendType( Mix::Graphics::BLEND_NORMAL ),
m_bIdentityMatrix( True ),
m_bClipEnabled( True ),
m_TransformVertexStart( 0 ),
m_TransformVertexCount( 0 ),
m_pVertexLayout( NULL ),
m_pVertexShader( NULL ),
m_pVertexBuffer( NULL ),
m_pIndexBuffer( NULL )
{
#ifdef _DEBUG

	Mix::StringW tempStr;

	tempStr.Sprintf( L"CanvasRenderer\\%s\\ClipStack", m_Name.GetConstPtr() );
	m_ClipStack.Initialize( CanvasRenderer::CLIPSTACK_DEFSIZE, CanvasRenderer::CLIPSTACK_RESIZESTEP, tempStr.GetConstPtr() );

	tempStr.Sprintf( L"CanvasRenderer\\%s\\MatrixStack", m_Name.GetConstPtr() );
	m_MatrixStack.Initialize( CanvasRenderer::MATRIXSTACK_DEFSIZE, CanvasRenderer::MATRIXSTACK_RESIZESTEP, tempStr.GetConstPtr() );

	tempStr.Sprintf( L"CanvasRenderer\\%s\\EntryList", m_Name.GetConstPtr() );
	m_EntryList.Initialize( CanvasRenderer::ENTRYLIST_DEFSIZE, CanvasRenderer::ENTRYLIST_RESIZESTEP, tempStr.GetConstPtr() );

	tempStr.Sprintf( L"CanvasRenderer\\%s\\ObjectList", m_Name.GetConstPtr() );
	m_ObjectList.Initialize( CanvasRenderer::OBJECTLIST_DEFSIZE, CanvasRenderer::OBJECTLIST_RESIZESTEP, tempStr.GetConstPtr() );

	tempStr.Sprintf( L"CanvasRenderer\\%s\\VertexList", m_Name.GetConstPtr() );
	m_VertexList.Initialize( CanvasRenderer::VERTEXLIST_DEFSIZE, CanvasRenderer::VERTEXLIST_RESIZESTEP, tempStr.GetConstPtr() );

#else //_DEBUG

	m_ClipStack.Initialize( CanvasRenderer::CLIPSTACK_DEFSIZE, CanvasRenderer::CLIPSTACK_RESIZESTEP );
	m_MatrixStack.Initialize( CanvasRenderer::MATRIXSTACK_DEFSIZE, CanvasRenderer::MATRIXSTACK_RESIZESTEP );
	m_EntryList.Initialize( CanvasRenderer::ENTRYLIST_DEFSIZE, CanvasRenderer::ENTRYLIST_RESIZESTEP );
	m_ObjectList.Initialize( CanvasRenderer::OBJECTLIST_DEFSIZE, CanvasRenderer::OBJECTLIST_RESIZESTEP );
	m_VertexList.Initialize( CanvasRenderer::VERTEXLIST_DEFSIZE, CanvasRenderer::VERTEXLIST_RESIZESTEP );

#endif //_DEBUG

	m_pPixelShader[0] = NULL;
	m_pPixelShader[1] = NULL;
}

CanvasRenderer::~CanvasRenderer( void )
{
	for( UInt32 i = 0; i < 2; i++ )
	{
		CanvasRenderer::ENTRY* pEntry = m_EntryList.GetBeginPtr();
		CanvasRenderer::ENTRY* pEntryEnd = m_EntryList.GetEndPtr();

		while( pEntry != pEntryEnd )
		{
			MIX_RELEASE( pEntry->tex );
			pEntry++;
		}
	}

	MIX_RELEASE( m_pTextPrinter );
	MIX_RELEASE( m_pFont );
	MIX_RELEASE( m_pIndexBuffer );
	MIX_RELEASE( m_pVertexBuffer );
	MIX_RELEASE( m_pVertexLayout );
	MIX_RELEASE( m_pPixelShader[1] );
	MIX_RELEASE( m_pPixelShader[0] );
	MIX_RELEASE( m_pVertexShader );
	MIX_RELEASE( m_pDevice );
}

Boolean CanvasRenderer::Initialize( void )
{
	Mix::Graphics::Common::Manager* pGraphicsMgr = Mix::Graphics::GetInternalManagerPtr();

	Mix::Point screenSize;

	Mix::Graphics::Common::Manager::VERTEX_EFFECT* pVertexEffect;
	Mix::Graphics::Common::Manager::PIXEL_EFFECT* pPixelEffect;

	Mix::StringW tempStr;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// グライフィックス
	////////////////////////////////////////////////////////////////////////////////////////////////////

	MIX_ASSERT( pGraphicsMgr != NULL );

	// デバイス
	pGraphicsMgr->GetDevice( &m_pDevice );

	// テキストプリンター
	pGraphicsMgr->GetTextPrinter( &m_pTextPrinter );

	// スクリーンサイズ
	screenSize = m_pDevice->GetScreenSize();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// エフェクト
	////////////////////////////////////////////////////////////////////////////////////////////////////

	pVertexEffect = pGraphicsMgr->GetVertexEffectPtr( Mix::Graphics::Common::Manager::ER_CANVAS );
	pPixelEffect = pGraphicsMgr->GetPixelEffectPtr( Mix::Graphics::Common::Manager::ER_CANVAS );

	MIX_ASSERT( pVertexEffect != NULL );
	MIX_ASSERT( pPixelEffect != NULL );

	MIX_ADD_REF( pVertexEffect->pLayout );
	m_pVertexLayout = pVertexEffect->pLayout;

	MIX_ADD_REF( pVertexEffect->pShader[Mix::Graphics::Common::Manager::VES_DEFAULT] );
	m_pVertexShader = pVertexEffect->pShader[Mix::Graphics::Common::Manager::VES_DEFAULT];

	MIX_ADD_REF( pPixelEffect->pShader[Mix::Graphics::Common::Manager::PES_CANVAS_COLOR] );
	m_pPixelShader[0] = pPixelEffect->pShader[Mix::Graphics::Common::Manager::PES_CANVAS_COLOR];

	MIX_ADD_REF( pPixelEffect->pShader[Mix::Graphics::Common::Manager::PES_CANVAS_COLOR_TEX] );
	m_pPixelShader[1] = pPixelEffect->pShader[Mix::Graphics::Common::Manager::PES_CANVAS_COLOR_TEX];

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クリップサイズ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_Clip.x = 0;
	m_Clip.y = 0;
	m_Clip.width = screenSize.x;
	m_Clip.height = screenSize.y;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 射影変換行列
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_ProjMat = Mix::Matrix4x4::Identity();

//	m_ProjMat.m00 = MIX_FLOAT_DIV( +2.0f, static_cast<Float32>( screenSize.x ) );
//	m_ProjMat.m11 = MIX_FLOAT_DIV( -2.0f, static_cast<Float32>( screenSize.y ) );
//	m_ProjMat.m30 = -1.0f;
//	m_ProjMat.m31 = +1.0f;

	m_ProjMat.m00 = +2.0f / static_cast<Float32>( screenSize.x );
	m_ProjMat.m11 = -2.0f / static_cast<Float32>( screenSize.y );
	m_ProjMat.m22 = 0.0f;
	m_ProjMat.m30 = -1.0f;
	m_ProjMat.m31 = +1.0f;

	if( m_pDevice->GetShaderModel() != Mix::Graphics::SHADER_MODEL_3 )
	{
		m_ProjMat.m30 += +1.0f / screenSize.x;
		m_ProjMat.m31 += -1.0f / screenSize.y;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// バーテックスバッファ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	tempStr.Sprintf( L"CanvasRenderer\\%s", m_Name.GetConstPtr() );

	if( m_pDevice->CreateVertexBuffer(	VERTEXBUFFER_DEFSIZE, sizeof( CanvasRenderer::VERTEX ),
										True, VERTEXBUFFER_RESIZESTEP,
										NULL,
										&m_pVertexBuffer,
										tempStr.GetConstPtr() ) == False )
	{
		return False;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// インデックスバッファ
	////////////////////////////////////////////////////////////////////////////////////////////////////

	tempStr.Sprintf( L"CanvasRenderer\\%s", m_Name.GetConstPtr() );

	if( m_pDevice->CreateIndexBuffer(	Mix::Graphics::INDEX_USHORT, INDEXBUFFER_DEFSIZE,
										True, INDEXBUFFER_RESIZESTEP,
										NULL,
										&m_pIndexBuffer,
										tempStr.GetConstPtr() ) == False )
	{
		return False;
	}

	return True;
}

void CanvasRenderer::PushEntry( Mix::Graphics::PRIMITIVE_TYPE type, Mix::Graphics::ITexture* pTexture )
{
	CanvasRenderer::ENTRY* pEntry;

	if( m_EntryList.IsEmpty() == True )
	{
		MIX_ADD_REF( pTexture );

		pEntry = m_EntryList.Add();
		pEntry->clip = m_Clip;
		pEntry->bt = m_BlendType;
		pEntry->tex = pTexture;
		pEntry->pt = type;
		pEntry->startVertex = 0;
		pEntry->startIndex = 0;
		pEntry->numVertex = 0;
		pEntry->numIndex = 0;
	}
	else
	{
		pEntry = m_EntryList.GetCurrentPtr();

		if(	( pEntry->bt != m_BlendType ) ||
			( pEntry->tex != pTexture ) ||
			( pEntry->pt != type ) ||
			( pEntry->clip.x != m_Clip.x ) ||
			( pEntry->clip.y != m_Clip.y ) ||
			( pEntry->clip.width != m_Clip.width ) ||
			( pEntry->clip.height != m_Clip.height ) )
		{
			CanvasRenderer::ENTRY* pPreEntry;

			MIX_ADD_REF( pTexture );

			pEntry = m_EntryList.Add();
			pPreEntry = &( m_EntryList[m_EntryList.GetCount() - 2] );

			pEntry->clip = m_Clip;
			pEntry->bt = m_BlendType;
			pEntry->tex = pTexture;
			pEntry->pt = type;
			pEntry->startVertex = ( pPreEntry->startVertex + pPreEntry->numVertex );
			pEntry->startIndex = ( pPreEntry->startIndex + pPreEntry->numIndex );
			pEntry->numVertex = 0;
			pEntry->numIndex = 0;
		}
	}
}

CanvasRenderer::VERTEX* CanvasRenderer::PushVertex( UInt16 numVertex, UInt16 count )
{
	MIX_ASSERT( m_EntryList.IsEmpty() == False );

	UInt32 totalVertex = numVertex * count;

	CanvasRenderer::ENTRY* pEntry;
	CanvasRenderer::VERTEX* pVertex;
	CanvasRenderer::OBJECT* pObject;

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	pEntry = m_EntryList.GetCurrentPtr();
	pEntry->numVertex += totalVertex;

	switch( pEntry->pt )
	{
	case Mix::Graphics::PRIMITIVE_TRIANGLELIST:
		pEntry->numIndex += ( ( ( numVertex - 2 ) * 3 ) * count );
		break;
	case Mix::Graphics::PRIMITIVE_LINELIST:
		pEntry->numIndex += ( ( numVertex - 1 ) << 1 );
		break;
	}

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	pVertex = m_VertexList.Add( totalVertex );

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	pObject = m_ObjectList.Add();
	pObject->type = pEntry->pt;
	pObject->numVertex = numVertex;
	pObject->count = count;

	///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

	m_TransformVertexCount += totalVertex;

	return pVertex;
}

void CanvasRenderer::TransformVertex( void )
{
	if( ( m_bIdentityMatrix == False ) &&
		( m_TransformVertexCount > 0 ) )
	{
		Float32 x;
		Float32 y;
		Float32* pm = &( m_Matrix.m[0][0] );
		VERTEX* pVertex = &( m_VertexList[m_TransformVertexStart] );
		VERTEX* pVertexEnd = ( pVertex + m_TransformVertexCount );

		while( pVertex != pVertexEnd )
		{
			x = pVertex->pos.x;
			y = pVertex->pos.y;

			pVertex->pos.x = ( ( pm[0] * x ) + ( pm[3] * y ) + pm[6] );
			pVertex->pos.y = ( ( pm[1] * x ) + ( pm[4] * y ) + pm[7] );

			pVertex++;
		}
	}

	m_TransformVertexStart += m_TransformVertexCount;
	m_TransformVertexCount = 0;
}

void CanvasRenderer::UpdateVertexBuffer( void )
{
	CanvasRenderer::VERTEX* pVertex = m_VertexList.GetBeginPtr();
	CanvasRenderer::VERTEX* pVertexEnd = pVertex + m_VertexList.GetCount();

#ifdef _MIX_USE_SSE2

	Float32 m00 = m_ProjMat.m00;
	Float32 m01 = m_ProjMat.m01;
	Float32 m02 = m_ProjMat.m02;
	Float32 m03 = m_ProjMat.m03;
	Float32 m10 = m_ProjMat.m10;
	Float32 m11 = m_ProjMat.m11;
	Float32 m12 = m_ProjMat.m12;
	Float32 m13 = m_ProjMat.m13;
	Float32 m20 = m_ProjMat.m20;
	Float32 m21 = m_ProjMat.m21;
	Float32 m22 = m_ProjMat.m22;
	Float32 m23 = m_ProjMat.m23;
	Float32 m30 = m_ProjMat.m30;
	Float32 m31 = m_ProjMat.m31;
	Float32 m32 = m_ProjMat.m32;
	Float32 m33 = m_ProjMat.m33;

	MIX_ALIGN_16 Float32 data[4];

	__m128 mt;
	__m128 mr;
	__m128 mv;

	while( pVertex != pVertexEnd )
	{
		Mix::Vector4* pos = &( pVertex->pos );

		mr = _mm_setzero_ps();

		mt = _mm_set_ps( m02, m01, m00, m03 );
		mv = _mm_set1_ps( pos->x );
		mr = _mm_mul_ps( mt, mv );

		mt = _mm_set_ps( m12, m11, m10, m13 );
		mv = _mm_set1_ps( pos->y );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		mt = _mm_set_ps( m22, m21, m20, m23 );
		mv = _mm_set1_ps( pos->z );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		mt = _mm_set_ps( m32, m31, m30, m33 );
		mv = _mm_set1_ps( pos->w );
		mt = _mm_mul_ps( mt, mv );
		mr = _mm_add_ps( mr, mt );

		_mm_store_ps( data, mr );

		pos->x = data[1];
		pos->y = data[2];
		pos->z = data[3];

		pVertex++;
	}

#else //_MIX_USE_SSE2

	while( pVertex != pVertexEnd )
	{
		pVertex->pos = m_ProjMat * pVertex->pos;
		pVertex++;
	}

#endif //_MIX_USE_SSE2

	if( m_pVertexBuffer->Lock() == True )
	{
		m_pVertexBuffer->Push( m_VertexList.GetConstBeginPtr(), m_VertexList.GetCount() );
		m_pVertexBuffer->Unlock();
	}

	m_VertexList.Clear();
}

void CanvasRenderer::UpdateIndexBuffer( void )
{
	CanvasRenderer::OBJECT* pObj;
	CanvasRenderer::OBJECT* pObjEnd;
	UInt16 indexOffset;
	UInt32 localPrimNum;
	UInt32 totalPrimNum;
	UInt16 localLastIndex;
	UInt16 i;
	UInt16 j;
	UInt16* pIndex;

	if( m_pIndexBuffer->Lock() == True )
	{
		pObj = m_ObjectList.GetBeginPtr();
		pObjEnd = ( pObj + m_ObjectList.GetCount() );

		indexOffset = 0;

		while( pObj != pObjEnd )
		{
			if( pObj->type == Mix::Graphics::PRIMITIVE_TRIANGLELIST )
			{
				localPrimNum = ( pObj->numVertex - 2 );
				totalPrimNum = ( localPrimNum * pObj->count );
				localLastIndex = ( pObj->numVertex - 1 );

				pIndex = static_cast<UInt16*>( m_pIndexBuffer->Push( totalPrimNum * 3 ) );
				if( pIndex != NULL )
				{
					for( i = 0; i < pObj->count; i++ )
					{
						for( j = 0; j < localPrimNum; j++ )
						{
							*pIndex++ = ( indexOffset + j );
							*pIndex++ = ( indexOffset + j + 1 );
							*pIndex++ = ( indexOffset + localLastIndex );
						}
					
						indexOffset += pObj->numVertex;
					}
				}
				else
				{
					break;
				}
			}
			else
			{
				localPrimNum = ( pObj->numVertex - 1 );
				totalPrimNum = ( localPrimNum * pObj->count );

				pIndex = static_cast<UInt16*>( m_pIndexBuffer->Push( totalPrimNum * 2 ) );
				if( pIndex != NULL )
				{
					for( i = 0; i < pObj->count; i++ )
					{
						for( j = 0; j < localPrimNum; j++ )
						{
							*pIndex++ = ( indexOffset + j );
							*pIndex++ = ( indexOffset + j + 1 );
						}

						indexOffset += pObj->numVertex;
					}
				}
				else
				{
					break;
				}
			}

			pObj++;
		}

		m_pIndexBuffer->Unlock();
	}

	m_ObjectList.Clear();
}

Boolean CanvasRenderer::GetFont( Mix::Graphics::Utility::IFont** ppFont ) const
{
	if( ( ppFont == NULL ) ||
		( m_pFont == NULL ) )
	{
		return False;
	}

	MIX_ADD_REF( m_pFont );
	( *ppFont ) = m_pFont;

	return True;
}

void CanvasRenderer::SetFont( Mix::Graphics::Utility::IFont* pFont )
{
	MIX_RELEASE( m_pFont );
	MIX_ADD_REF( pFont );
	m_pFont = pFont;
}

const Mix::Vector4& CanvasRenderer::GetColor( void ) const
{
	return m_Color;
}

void CanvasRenderer::SetColor( const Mix::Vector4& color )
{
	m_Color = color;
}

Mix::Graphics::BLEND_TYPE CanvasRenderer::GetBlendType( void ) const
{
	return m_BlendType;
}

void CanvasRenderer::SetBlendType( Mix::Graphics::BLEND_TYPE type )
{
	m_BlendType = type;
}

const Mix::Matrix3x3& CanvasRenderer::GetMatrix( void ) const
{
	return m_Matrix;
}

void CanvasRenderer::SetMatrix( const Mix::Matrix3x3& mat )
{
	if( m_MatrixStack.GetCount() > 0 )
	{
		m_Matrix = mat * m_MatrixStack.GetCurrent();
	}
	else
	{
		m_Matrix = mat;
	}

	m_bIdentityMatrix = ( m_Matrix == Mix::Matrix3x3::Identity() );
}

UInt32 CanvasRenderer::PushMatrix( void )
{
	UInt32 count = m_MatrixStack.GetCount();

	m_MatrixStack.Push( m_Matrix );

	return count;
}

UInt32 CanvasRenderer::PopMatrix( void )
{
	UInt32 count = m_MatrixStack.GetCount();

	if( count == 0 )
	{
		MIX_LOG_ERROR( L"Mix::Graphics::Utility::ICanvasRenderer::PopMatrix : これ以上破棄できません : Name[%s]", m_Name.GetConstPtr() );
		return count;
	}

	m_Matrix = m_MatrixStack.GetCurrent();
	m_bIdentityMatrix = ( m_Matrix == Mix::Matrix3x3::Identity() );

	m_MatrixStack.Pop();

	return count;
}

UInt32 CanvasRenderer::DrainMatrix( void )
{
	UInt32 ret = m_MatrixStack.GetCount();

	m_MatrixStack.Drain();

	return ret;
}

const Mix::Rectangle& CanvasRenderer::GetClip( void ) const
{
	return m_Clip;
}

void CanvasRenderer::SetClip( Int32 x, Int32 y, Int32 width, Int32 height )
{
	SetClip( Mix::Rectangle( x, y, width, height ) );
}

void CanvasRenderer::SetClip( const Mix::Rectangle& rect )
{
	const Mix::Rectangle& currentClip = ( m_ClipStack.GetCount() > 0 )? m_ClipStack.GetCurrent() : m_pDevice->GetScissorBounds();

	Mix::Rectangle nextClip;

	if( currentClip.Contains( rect, &nextClip ) == True )
	{
		m_bClipEnabled = True;
		m_Clip = nextClip;
	}
	else
	{
		m_bClipEnabled = False;
		m_Clip = Mix::Rectangle( 0, 0, 0, 0 );
	}
}

UInt32 CanvasRenderer::PushClip( void )
{
	UInt32 count = m_ClipStack.GetCount();

	m_ClipStack.Push( m_Clip );

	return count;
}

UInt32 CanvasRenderer::PopClip( void )
{
	UInt32 count = m_ClipStack.GetCount();

	if( count == 0 )
	{
		MIX_LOG_ERROR( L"Mix::Graphics::Utility::ICanvasRenderer::PopClip : これ以上破棄できません : Name[%s]", m_Name.GetConstPtr() );
		return count;
	}

	m_Clip = m_ClipStack.GetCurrent();
	m_bClipEnabled = ( ( m_Clip.width > 0 ) && ( m_Clip.height > 0 ) );

	m_ClipStack.Pop();

	return count;
}

UInt32 CanvasRenderer::DrainClip( void )
{
	UInt32 ret = m_ClipStack.GetCount();

	m_ClipStack.Drain();

	return ret;
}

void CanvasRenderer::AddLine( const Mix::Vector2& p1, const Mix::Vector2& p2 )
{
	if( m_bClipEnabled == False )
	{
		return;
	}

	CanvasRenderer::VERTEX* pv;

	PushEntry( Mix::Graphics::PRIMITIVE_LINELIST, NULL );

	pv = PushVertex( 2, 1 );
	MIX_ASSERT( pv != NULL );

	pv->pos.Set( p1.x, p1.y, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( 0.0f, 0.0f );
	pv++;

	pv->pos.Set( p2.x, p2.y, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( 0.0f, 0.0f );
	pv++;

	TransformVertex();
}

void CanvasRenderer::AddLines( const Mix::Vector2 points[], UInt16 count )
{
	if( ( m_bClipEnabled == False ) ||
		( count == 0 ) )
	{
		return;
	}

	CanvasRenderer::VERTEX* pv;
	UInt32 i;

	PushEntry( Mix::Graphics::PRIMITIVE_LINELIST, NULL );

	pv = PushVertex( count, 1 );
	MIX_ASSERT( pv != NULL );

	for( i = 0; i < count; i++ )
	{
		const Mix::Vector2& p = points[i];

		pv->pos.Set( p.x, p.y, 0.0f, 1.0f );
		pv->color = m_Color;
		pv->tex.Set( 0.0f, 0.0f );

		pv++;
	}

	TransformVertex();
}

void CanvasRenderer::AddRectangle( const Mix::RectangleF& rect )
{
	if( m_bClipEnabled == False )
	{
		return;
	}

	Mix::Vector2 points[5] =
	{
		Mix::Vector2( rect.x,          rect.y ),
		Mix::Vector2( rect.GetRight(), rect.y ),
		Mix::Vector2( rect.GetRight(), rect.GetBottom() ),
		Mix::Vector2( rect.x,          rect.GetBottom() ),
		Mix::Vector2( rect.x,          rect.y ),
	};

	CanvasRenderer::VERTEX* pv;
	UInt32 i;

	PushEntry( Mix::Graphics::PRIMITIVE_LINELIST, NULL );

	pv = PushVertex( 8, 1 );
	MIX_ASSERT( pv != NULL );

	for( i = 0; i < 4; i++ )
	{
		const Mix::Vector2& p0 = points[i];
		const Mix::Vector2& p1 = points[i + 1];

		pv->pos.Set( p0.x, p0.y, 0.0f, 1.0f );
		pv->color = m_Color;
		pv->tex.Set( 0.0f, 0.0f );
		pv++;

		pv->pos.Set( p1.x, p1.y, 0.0f, 1.0f );
		pv->color = m_Color;
		pv->tex.Set( 0.0f, 0.0f );
		pv++;
	}

	TransformVertex();
}

void CanvasRenderer::AddPolygon( const Mix::Vector2 points[], UInt16 count )
{
	if( ( m_bClipEnabled == False ) ||
		( count == 0 ) )
	{
		return;
	}

	CanvasRenderer::VERTEX* pv;
	UInt32 last;
	UInt32 i;

	PushEntry( Mix::Graphics::PRIMITIVE_LINELIST, NULL );

	pv = PushVertex( count * 2, 1 );
	MIX_ASSERT( pv != NULL );

	last = count - 1;

	for( i = 0; i < count; i++ )
	{
		UInt32 i0 = i;
		UInt32 i1 = ( i < last )? ( i + 1 ) : 0;

		const Mix::Vector2& p0 = points[i0];
		const Mix::Vector2& p1 = points[i1];

		pv->pos.Set( p0.x, p0.y, 0.0f, 1.0f );
		pv->color = m_Color;
		pv->tex.Set( 0.0f, 0.0f );
		pv++;

		pv->pos.Set( p1.x, p1.y, 0.0f, 1.0f );
		pv->color = m_Color;
		pv->tex.Set( 0.0f, 0.0f );
		pv++;

	}

	TransformVertex();
}

void CanvasRenderer::AddFillRectangle( const Mix::RectangleF& rect )
{
	if( m_bClipEnabled == False )
	{
		return;
	}

	CanvasRenderer::VERTEX* pv;

	PushEntry( Mix::Graphics::PRIMITIVE_TRIANGLELIST, NULL );

	pv = PushVertex( 4, 1 );
	MIX_ASSERT( pv != NULL );

	pv->pos.Set( rect.x, rect.y, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( 0.0f, 0.0f );
	pv++;

	pv->pos.Set( rect.GetRight() + 1.0f, rect.y, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( 0.0f, 0.0f );
	pv++;

	pv->pos.Set( rect.GetRight() + 1.0f, rect.GetBottom() + 1.0f, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( 0.0f, 0.0f );
	pv++;

	pv->pos.Set( rect.x, rect.GetBottom() + 1.0f, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( 0.0f, 0.0f );
	pv++;

	TransformVertex();
}

void CanvasRenderer::AddFillPolygon( const Mix::Vector2 points[], UInt16 count )
{
	if( ( m_bClipEnabled == False ) ||
		( count == 0 ) )
	{
		return;
	}

	CanvasRenderer::VERTEX* pv;
	UInt32 i;

	PushEntry( Mix::Graphics::PRIMITIVE_TRIANGLELIST, NULL );

	pv = PushVertex( count, 1 );
	MIX_ASSERT( pv != NULL );

	for( i = 0; i < count; i++ )
	{
		const Mix::Vector2& p = points[i];

		pv->pos.Set( p.x, p.y, 0.0f, 1.0f );
		pv->color = m_Color;
		pv->tex.Set( 0.0f, 0.0f );
		pv++;
	}

	TransformVertex();
}

void CanvasRenderer::AddImage( Mix::Graphics::ITexture* pTexture, Float32 dx, Float32 dy, Float32 width, Float32 height, Float32 sx, Float32 sy )
{
	AddImage( pTexture, dx, dy, width, height, sx, sy, width, height );
}

void CanvasRenderer::AddImage( Mix::Graphics::ITexture* pTexture, const Mix::RectangleF& dst, const Mix::Vector2& src )
{
	AddImage( pTexture, dst.x, dst.y, dst.width, dst.height, src.x, src.y, dst.width, dst.height );
}

void CanvasRenderer::AddImage( Mix::Graphics::ITexture* pTexture, Float32 dx, Float32 dy, Float32 dw, Float32 dh, Float32 sx, Float32 sy, Float32 sw, Float32 sh )
{
	if( ( m_bClipEnabled == False ) || ( pTexture == NULL ) )
	{
		return;
	}

	Float32 tw = MIX_FLOAT_RECIPROCAL( static_cast<Float32>( pTexture->GetWidth() ) );
	Float32 th = MIX_FLOAT_RECIPROCAL( static_cast<Float32>( pTexture->GetHeight() ) );
	Float32 tx = sx * tw;
	Float32 ty = sy * th;
	Float32 txx = ( sx + sw ) * tw;
	Float32 tyy = ( sy + sh ) * th;

	CanvasRenderer::VERTEX* pv;

	PushEntry( Mix::Graphics::PRIMITIVE_TRIANGLELIST, pTexture );

	pv = PushVertex( 4, 1 );
	MIX_ASSERT( pv != NULL );

	pv->pos.Set( dx, dy, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( tx, ty );
	pv++;

	pv->pos.Set( dx + dw, dy, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( txx, ty );
	pv++;

	pv->pos.Set( dx + dw, dy + dh, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( txx, tyy );
	pv++;

	pv->pos.Set( dx, dy + dh, 0.0f, 1.0f );
	pv->color = m_Color;
	pv->tex.Set( tx, tyy );
	pv++;

	TransformVertex();
}

void CanvasRenderer::AddImage( Mix::Graphics::ITexture* pTexture, const Mix::RectangleF& dst, const Mix::RectangleF& src )
{
	AddImage( pTexture, dst.x, dst.y, dst.width, dst.height, src.x, src.y, src.width, src.height );
}

void CanvasRenderer::AddString( Float32 x, Float32 y, const wchar_t* str )
{
	AddString( Mix::Vector2( x, y ), str );
}

void CanvasRenderer::AddString( const Mix::Vector2& pos, const wchar_t* pStr )
{
	if( ( m_bClipEnabled == False ) || ( pStr == NULL ) || ( ::wcslen( pStr ) == 0 ) )
	{
		return;
	}

	if( m_pTextPrinter->Append( m_pFont, pos, pStr ) == True )
	{
		const Mix::ContainerT<TextPrinter::QUAD_GROUP, Mix::Memory::SECTION_GRAPHICS>& quadGroups = m_pTextPrinter->GetQuadGroups();
		const Mix::ContainerT<TextPrinter::QUAD, Mix::Memory::SECTION_GRAPHICS>& quads = m_pTextPrinter->GetQuads();

		const TextPrinter::QUAD_GROUP* pQuadGroup = quadGroups.GetConstBeginPtr();
		const TextPrinter::QUAD_GROUP* pQuadGroupEnd = pQuadGroup + quadGroups.GetCount();

		while( pQuadGroup != pQuadGroupEnd )
		{
			const TextPrinter::QUAD* pQuad = &( quads[pQuadGroup->start] );
			const TextPrinter::QUAD* pQuadEnd = pQuad + pQuadGroup->count;

			CanvasRenderer::VERTEX* pv;
			UInt32 i;

			const Mix::Vector2* points;
			const Mix::Vector2* texCoords;

			PushEntry( Mix::Graphics::PRIMITIVE_TRIANGLELIST, pQuadGroup->pTexture );

			pv = PushVertex( 4, pQuadGroup->count );
			MIX_ASSERT( pv != NULL );

			while( pQuad != pQuadEnd )
			{
				points = pQuad->points;
				texCoords = pQuad->texCoords;

				for( i = 0; i < 4; i++ )
				{
					const Mix::Vector2& p = points[i];

					pv->pos.Set( p.x, p.y, 0.0f, 1.0f );
					pv->color = m_Color;
					pv->tex = texCoords[i];
					pv++;
				}

				pQuad++;
			}

			pQuadGroup++;
		}

		//頂点を変換
		TransformVertex();
	}
}

void CanvasRenderer::AddString( const Mix::RectangleF& rect, const wchar_t* pStr, UInt32 flags )
{
	if( ( m_bClipEnabled == False ) || ( pStr == NULL ) || ( ::wcslen( pStr ) == 0 ) )
	{
		return;
	}

	if( m_pTextPrinter->Append( m_pFont, rect, pStr, flags ) == True )
	{
		const Mix::ContainerT<TextPrinter::QUAD_GROUP, Mix::Memory::SECTION_GRAPHICS>& quadGroups = m_pTextPrinter->GetQuadGroups();
		const Mix::ContainerT<TextPrinter::QUAD, Mix::Memory::SECTION_GRAPHICS>& quads = m_pTextPrinter->GetQuads();

		const TextPrinter::QUAD_GROUP* pQuadGroup = quadGroups.GetConstBeginPtr();
		const TextPrinter::QUAD_GROUP* pQuadGroupEnd = pQuadGroup + quadGroups.GetCount();

		while( pQuadGroup != pQuadGroupEnd )
		{
			const TextPrinter::QUAD* pQuad = &( quads[pQuadGroup->start] );
			const TextPrinter::QUAD* pQuadEnd = pQuad + pQuadGroup->count;

			CanvasRenderer::VERTEX* pv;
			UInt32 i;

			const Mix::Vector2* points;
			const Mix::Vector2* texCoords;

			PushEntry( Mix::Graphics::PRIMITIVE_TRIANGLELIST, pQuadGroup->pTexture );

			pv = PushVertex( 4, pQuadGroup->count );
			MIX_ASSERT( pv != NULL );

			while( pQuad != pQuadEnd )
			{
				points = pQuad->points;
				texCoords = pQuad->texCoords;

				for( i = 0; i < 4; i++ )
				{
					const Mix::Vector2& p = points[i];

					pv->pos.Set( p.x, p.y, 0.0f, 1.0f );
					pv->color = m_Color;
					pv->tex = texCoords[i];
					pv++;
				}

				pQuad++;
			}

			pQuadGroup++;
		}

		//頂点を変換
		TransformVertex();
	}
}

void CanvasRenderer::Update( void )
{
	const Mix::Point& screenSize = m_pDevice->GetScreenSize();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// クリア
	////////////////////////////////////////////////////////////////////////////////////////////////////

	// トランスフォーム

	MIX_ASSERT( m_TransformVertexCount == 0 );

	m_TransformVertexStart = 0;
	m_TransformVertexCount = 0;

	// クリップ

	if( m_ClipStack.GetCount() > 0 )
	{
		MIX_LOG_WARNING( L"Mix::Graphics::Utility::ICanvasRenderer::Update : クリップスタックが空になっていません : 強制排出します : Name[%s] StackCount[%d]",
			m_Name.GetConstPtr(),
			m_ClipStack.GetCount() );

		m_ClipStack.Drain();
	}

	m_Clip.x = 0;
	m_Clip.y = 0;
	m_Clip.width = screenSize.x;
	m_Clip.height = screenSize.y;
	m_bClipEnabled = ( ( m_Clip.width > 0 ) && ( m_Clip.height > 0 ) );

	// 行列

	if( m_MatrixStack.GetCount() > 0 )
	{
		MIX_LOG_WARNING( L"Mix::Graphics::Utility::ICanvasRenderer::Update : 行列スタックが空になっていません : 強制排出します : Name[%s] StackCount[%d]",
			m_Name.GetConstPtr(),
			m_MatrixStack.GetCount() );

		m_MatrixStack.Drain();
	}

	m_Matrix = Mix::Matrix3x3::Identity();
	m_bIdentityMatrix = True;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// エントリー
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_EntryList.IsEmpty() == True )
	{
		return;
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// バーテックスバッファを更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_VertexList.GetCount() > 0 )
	{
		UpdateVertexBuffer();
	}

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// インデックスバッファを更新
	////////////////////////////////////////////////////////////////////////////////////////////////////

	if( m_ObjectList.GetCount() > 0 )
	{
		UpdateIndexBuffer();
	}
}

void CanvasRenderer::Draw( void )
{
	if( m_EntryList.IsEmpty() == True )
	{
		return;
	}

	CanvasRenderer::ENTRY* pEntry = m_EntryList.GetBeginPtr();
	CanvasRenderer::ENTRY* pEntryEnd = m_EntryList.GetEndPtr();

	Mix::Graphics::RASTERIZER_DESC oldRasterizeState;
	Mix::Graphics::DEPTH_DESC oldDepthState;
	Mix::Graphics::BLEND_DESC oldBlendState;
	Mix::Rectangle oldScissor;

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// デバイスの設定を取得
	////////////////////////////////////////////////////////////////////////////////////////////////////

	oldRasterizeState = m_pDevice->GetRasterizerState();
	oldDepthState = m_pDevice->GetDepthState();
	oldBlendState = m_pDevice->GetBlendState();
	oldScissor = m_pDevice->GetScissorBounds();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// デバイスの設定
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pDevice->SetRasterizerState( Mix::Graphics::FILL_SOLID, Mix::Graphics::CULL_NONE, True );
	m_pDevice->SetDepthState( False, False );
	
	m_pDevice->SetVertexLayout( m_pVertexLayout );
	m_pDevice->SetVertexShader( m_pVertexShader );
	m_pDevice->SetVertexBuffer( m_pVertexBuffer );
	m_pDevice->SetIndexBuffer( m_pIndexBuffer );

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// 描画
	////////////////////////////////////////////////////////////////////////////////////////////////////

	// テキストを焼き付ける

	m_pTextPrinter->Execute();

	// エントリーの処理

	while( pEntry != pEntryEnd )
	{
		m_pDevice->SetScissorBounds( pEntry->clip );
		m_pDevice->SetBlendState( pEntry->bt );
		m_pDevice->SetTexture( 0, Mix::Graphics::TEXTURE_FILTER_POINT, Mix::Graphics::TEXTURE_ADDRESS_WRAP, pEntry->tex );
		m_pDevice->SetPixelShader( m_pPixelShader[( pEntry->tex == NULL )? 0 : 1] );
		m_pDevice->DrawIndexed( pEntry->pt, pEntry->startVertex, pEntry->numVertex, pEntry->startIndex, pEntry->numIndex );

		MIX_RELEASE( pEntry->tex );

		pEntry++;
	}

	m_EntryList.Clear();

	////////////////////////////////////////////////////////////////////////////////////////////////////
	// デバイスの設定を直前の状態に戻す
	////////////////////////////////////////////////////////////////////////////////////////////////////

	m_pDevice->SetBlendState( oldBlendState );
	m_pDevice->SetDepthState( oldDepthState );
	m_pDevice->SetRasterizerState( oldRasterizeState );
	m_pDevice->SetScissorBounds( oldScissor );
}

}}}}
