#pragma once

#include "Mix/Graphics/Utility/IPerspectiveRenderer.h"
#include "Mix/Private/Container.h"

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

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

	class PerspectiveRenderer : public Mix::Graphics::Utility::IPerspectiveRenderer
	{
	private:
		enum VALUE
		{
			DEF_VERTEXBUFFER_SIZE = 4096,
			VERTEXBUFFER_RESIZESTEP = 2048,
		};

		struct VERTEX
		{
			Mix::Vector4 pos;
			Mix::Vector4 color;

			MIX_DECLARE_ALLOCATOR();
		};

		static const UInt32 BOX_VERTEX_NUM;
		static const UInt32 BOX_INDEX_TABLE[24];

		static const UInt32 OBB_VERTEX_NUM;
		static const UInt32 OBB_INDEX_TABLE[24];

		static const UInt32 AABB_VERTEX_NUM;
		static const UInt32 AABB_INDEX_TABLE[24];

		static const UInt32 AXIS_DIR_NUM;
		static const Mix::Vector3 AXIS_DIR_TABLE[3];

		static const UInt32 FRUSTUM_POINT_NUM;
		static const UInt32 FRUSTUM_INDEX_NUM;
		static const Mix::Vector3 FRUSTUM_POINT_TABLE[8];
		static const UInt32 FRUSTUM_INDEX_TABLE[28];

	public:
		static PerspectiveRenderer* CreateInstance(	const wchar_t* pDebugName );
		static PerspectiveRenderer* CreateInstance(	UInt32 defSize, UInt32 resizeStep, const wchar_t* pDebugName );

	private:
		Mix::Graphics::IDevice* m_pDevice;
		Mix::Graphics::IShaderConstant* m_pShaderConstant;
		Mix::Graphics::IVertexShader* m_pVertexShader;
		Mix::Graphics::IPixelShader* m_pPixelShader;
		Mix::Graphics::IVertexLayout* m_pVertexLayout;
		Mix::Graphics::IVertexBuffer* m_pVertexBuffer;
		Mix::Vector4 m_Color;
		Mix::Matrix4x4 m_Mat;
		Mix::ContainerT<PerspectiveRenderer::VERTEX, Mix::Memory::SECTION_GRAPHICS> m_VertexTable;
		UInt32 m_CacheSize;
		UInt32 m_TransformVertexEntry;

		Mix::STL::Vector<Mix::Memory::SECTION_GRAPHICS, Mix::Vector3> m_SphereLineTable;
		Mix::STL::Vector<Mix::Memory::SECTION_GRAPHICS, Mix::Vector3> m_HemisphereLineTable;
		Mix::STL::Vector<Mix::Memory::SECTION_GRAPHICS, Mix::Vector3> m_CylinderLineTable;

	private:
		PerspectiveRenderer( const wchar_t* pDebugName );
		PerspectiveRenderer( UInt32 defSize, UInt32 resizeStep, const wchar_t* pDebugName );
		virtual ~PerspectiveRenderer( void );

		void TransformVertex( void );

	public:
		Boolean Initialize( Mix::Graphics::Common::Manager* pManager, const wchar_t* pName );

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

		virtual void SetMatrix( const Mix::Matrix4x4& mat );
		virtual const Mix::Matrix4x4& GetMatrix( void ) const;

		virtual void AddLine( const Mix::Vector3& p0, const Mix::Vector3& p1 );
		virtual void AddLines( const Mix::Vector3* pPointTable, UInt32 pointCount );

		virtual void AddAxis( Float32 scale );

		virtual void AddBox( const Mix::Vector3& halfExtents );
		virtual void AddBox( const Mix::Geometry::OBB& obb );
		virtual void AddBox( const Mix::Geometry::AABB& aabb );

		virtual void AddCylinder( UInt32 axis, Float32 length, Float32 radius );

		virtual void AddCapsule( UInt32 axis, Float32 length, Float32 radius );

		virtual void AddFrustum( const Mix::Geometry::Frustum& frustum );

		virtual void AddSphere( Float32 radius );
		virtual void AddSphere( const Mix::Vector3& radius );
		virtual void AddSphere( const Mix::Vector3& center, Float32 radius );
		virtual void AddSphere( const Mix::Geometry::Sphere& sphere );
		virtual void AddSphere( const Mix::Vector3& center, const Mix::Vector3& radius );

		virtual void AddCone( const Mix::Vector3& pos, const Mix::Vector3& vec, Float32 angle, UInt32 divCount );

		virtual void AddDisc( const Mix::Vector3& axis, Float32 radius );

		virtual void AddPolygon( const Mix::Vector3* points, UInt32 pointNum );

		virtual void Update( void );

		virtual void Draw( const Mix::Matrix4x4& viewProjMat );
	};

}}}}
