#pragma once

#include "Mix/Graphics/Utility/ICanvasRenderer.h"
#include "Mix/Private/Container.h"
#include "Mix/Private/Stack.h"

namespace Mix{ namespace Graphics{ namespace Common{
	class Manager;
}}}

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

	class TextPrinter;

	class CanvasRenderer : public Mix::Graphics::Utility::ICanvasRenderer
	{
	private:
		enum VALUE
		{
			TEXTTEX_SIZE				= 512,							//テキストテクスチャのサイズ
			TEXTTEX_DEFCOUNT			= 2,							//テキストテクスチャのデフォルト数

			CLIPSTACK_DEFSIZE			= 16,							//クリップスタックのデフォルトサイズ
			CLIPSTACK_RESIZESTEP		= 4,							//クリップスタックのリサイズステップ

			MATRIXSTACK_DEFSIZE			= 16,							//行列スタックのデフォルトサイズ
			MATRIXSTACK_RESIZESTEP		= 4,							//行列スタックのリサイズステップ

			QUAD_DEF_SIZE				= 512,							//クワッドのデフォルトサイズ
			QUAD_DEF_RESIZESTEP			= 32,							//クワッドのリサイズステップ

			ENTRYLIST_DEFSIZE			= 128,							//エントリーリストのデフォルトサイズ
			ENTRYLIST_RESIZESTEP		= 8,							//エントリーリストのリサイズステップ

			OBJECTLIST_DEFSIZE			= ( QUAD_DEF_SIZE ),			//オブジェクトリストのデフォルトサイズ
			OBJECTLIST_RESIZESTEP		= ( QUAD_DEF_RESIZESTEP ),		//オブジェクトリストのリサイズステップ

			VERTEXLIST_DEFSIZE			= ( QUAD_DEF_SIZE * 4 ),		//頂点リストのデフォルトサイズ
			VERTEXLIST_RESIZESTEP		= ( QUAD_DEF_RESIZESTEP * 4 ),	//頂点リストのリサイズステップ

			VERTEXBUFFER_DEFSIZE		= ( QUAD_DEF_SIZE * 4 ),		//頂点バッファのデフォルトサイズ
			VERTEXBUFFER_RESIZESTEP		= ( QUAD_DEF_RESIZESTEP * 4 ),	//頂点バッファのリサイズステップ

			INDEXBUFFER_DEFSIZE			= ( QUAD_DEF_SIZE * 6 ),		//インデックスバッファのデフォルトサイズ
			INDEXBUFFER_RESIZESTEP		= ( QUAD_DEF_RESIZESTEP * 6 ),	//インデックスバッファのリサイズステップ
		};

		//エントリー構造体
		struct ENTRY
		{
			Mix::Rectangle clip;

			Mix::Graphics::BLEND_TYPE bt;
			Mix::Graphics::ITexture* tex;

			Mix::Graphics::PRIMITIVE_TYPE pt;
			UInt32 startVertex;
			UInt32 numVertex;
			UInt32 startIndex;
			UInt32 numIndex;
			UInt32 reserve;

			MIX_DECLARE_ALLOCATOR();
		};

		//オブジェクト構造体
		struct OBJECT
		{
			Mix::Graphics::PRIMITIVE_TYPE type;
			UInt16 numVertex;
			UInt16 count;

			MIX_DECLARE_ALLOCATOR();
		};

		//頂点構造体
		struct VERTEX
		{
			Mix::Vector4 pos;
			Mix::Vector4 color;
			Mix::Vector2 tex;

			MIX_DECLARE_ALLOCATOR();
		};

	public:
		static CanvasRenderer* CreateInstance( const wchar_t* pName );

	private:
		Mix::StringW m_Name;

		Mix::Graphics::IDevice* m_pDevice;

		Mix::Graphics::Utility::IFont* m_pFont;
		Mix::Vector4 m_Color;
		Mix::Graphics::BLEND_TYPE m_BlendType;

		Boolean m_bIdentityMatrix;
		Mix::Matrix3x3 m_Matrix;
		Mix::StackT<Mix::Memory::SECTION_GRAPHICS, Mix::Matrix3x3> m_MatrixStack;

		Boolean m_bClipEnabled;
		Mix::Rectangle m_Clip;
		Mix::StackT<Mix::Memory::SECTION_GRAPHICS, Mix::Rectangle> m_ClipStack;

		Mix::Graphics::Utility::Common::TextPrinter* m_pTextPrinter;

		Mix::ContainerT<CanvasRenderer::ENTRY, Mix::Memory::SECTION_GRAPHICS> m_EntryList;
		Mix::ContainerT<CanvasRenderer::OBJECT, Mix::Memory::SECTION_GRAPHICS> m_ObjectList;
		Mix::ContainerT<CanvasRenderer::VERTEX, Mix::Memory::SECTION_GRAPHICS> m_VertexList;

		UInt32 m_TransformVertexStart;
		UInt32 m_TransformVertexCount;

		Mix::Matrix4x4 m_ProjMat;

		Mix::Graphics::IVertexLayout* m_pVertexLayout;
		Mix::Graphics::IVertexShader* m_pVertexShader;
		Mix::Graphics::IPixelShader* m_pPixelShader[2];
		Mix::Graphics::IVertexBuffer* m_pVertexBuffer;
		Mix::Graphics::IIndexBuffer* m_pIndexBuffer;

	private:
		CanvasRenderer( const wchar_t* pDebugName );
		virtual ~CanvasRenderer( void );

		void PushEntry( Mix::Graphics::PRIMITIVE_TYPE type, Mix::Graphics::ITexture* pTexture );
		VERTEX* PushVertex( UInt16 numVertex, UInt16 numUnit );
		void TransformVertex( void );

		void UpdateVertexBuffer( void );
		void UpdateIndexBuffer( void );

	public:
		Boolean Initialize( void );

	public:
		virtual Boolean GetFont( Mix::Graphics::Utility::IFont** ppFont ) const;
		virtual void SetFont( Mix::Graphics::Utility::IFont* pFont );

		virtual const Mix::Vector4& GetColor( void ) const;
		virtual void SetColor( const Mix::Vector4& color );

		virtual Mix::Graphics::BLEND_TYPE GetBlendType( void ) const;
		virtual void SetBlendType( Mix::Graphics::BLEND_TYPE type );

		virtual const Mix::Matrix3x3& GetMatrix( void ) const;
		virtual void SetMatrix( const Mix::Matrix3x3& mat );
		virtual UInt32 PushMatrix( void );
		virtual UInt32 PopMatrix( void );
		virtual UInt32 DrainMatrix( void );

		virtual const Mix::Rectangle& GetClip( void ) const;
		virtual void SetClip( Int32 x, Int32 y, Int32 width, Int32 height );
		virtual void SetClip( const Mix::Rectangle& rect );
		virtual UInt32 PushClip( void );
		virtual UInt32 PopClip( void );
		virtual UInt32 DrainClip( void );

		virtual void AddLine( const Mix::Vector2& p1, const Mix::Vector2& p2 );
		virtual void AddLines( const Mix::Vector2 points[], UInt16 numPoints );

		virtual void AddRectangle( const Mix::RectangleF& rect );
		virtual void AddPolygon( const Mix::Vector2 points[], UInt16 numPoints );

		virtual void AddFillRectangle( const Mix::RectangleF& rect );
		virtual void AddFillPolygon( const Mix::Vector2 points[], UInt16 numPoints );

		virtual void AddImage( Mix::Graphics::ITexture* pTexture, Float32 dx, Float32 dy, Float32 width, Float32 height, Float32 sx, Float32 sy );
		virtual void AddImage( Mix::Graphics::ITexture* pTexture, const Mix::RectangleF& dst, const Mix::Vector2& src );
		virtual void AddImage( Mix::Graphics::ITexture* pTexture, Float32 dx, Float32 dy, Float32 dw, Float32 dh, Float32 sx, Float32 sy, Float32 sw, Float32 sh );
		virtual void AddImage( Mix::Graphics::ITexture* pTexture, const Mix::RectangleF& dst, const Mix::RectangleF& src );

		virtual void AddString( Float32 x, Float32 y, const wchar_t* str );
		virtual void AddString( const Mix::Vector2& pos, const wchar_t* str );
		virtual void AddString( const Mix::RectangleF& rect, const wchar_t* pStr, UInt32 flags );

		virtual void Update( void );
		virtual void Draw( void );
	};

}}}}
