#ifndef _RURENDERERD3D_H_
#define _RURENDERERD3D_H_

#include "../../Engine/Animation/RuAnimBase.h"

// Aurora system core
#include "../../Engine/Base/RuCore.h"

// Aurora base renderer core
#include "../../Engine/Base/RuShaderBase.h"
#include "../../Engine/Base/RuMaterialBase.h"
#include "../../Engine/Base/RuInstanceManagerBase.h"

#include "../../Engine/Geometry/RuMeshBase.h"

#include "../../Direct3D/Engine/RuEngineD3D.h"

#pragma unmanaged

// ************************************************************************************************************************************************************

class CRuInstancedMeshD3D : public IRuInstancedMesh
{
private:
	CRuEngineD3D*					m_engine;							//!< Engine core

	IRuVertexBuffer**				m_vbArray;							//!< Array of vertex buffers containing one or more morph targets
	IRuIndexBuffer*					m_ib;								//!< Index buffer

	INT32							m_numVBs;							//!< Number of vertex buffers in the array
	UINT32							m_stride;							//!< Vertex stride
	UINT32							m_numVertices;						//!< Number of vertices per vertex buffer
	UINT32							m_numPrimitives;					//!< Number of primitives
	RuPrimitiveType					m_primitiveType;					//!< Primitive type

public:
									CRuInstancedMeshD3D();
	virtual							~CRuInstancedMeshD3D();

	void							SetEngine(CRuEngineD3D *engine) { m_engine = engine; }

	void							SetBuffers(IRuVertexBuffer **vbArray, IRuIndexBuffer *ib, INT32 numVBs, UINT32 stride, UINT32 numVertices, UINT32 numPrimitives, RuPrimitiveType primitiveType);

	virtual UINT32					Render();
	virtual UINT32					Render(UINT32 primitiveOffset, UINT32 numPrimitives, INT32 vb0Index = -1, INT32 vb1Index = -1);
};

// ************************************************************************************************************************************************************

class CRuInstanceManagerD3D : public IRuInstanceManager
{
private:
	struct VBInfo
	{
		INT32											m_iterationNumber;					//!< Iteration of the instanced mesh

		INT32											m_numVBs;							//!< Number of child VBs
		IRuVertexBuffer*								m_masterVB;							//!< Master VB from which child VBs are derived
		IRuVertexBuffer**								m_vbArray;							//!< Child VB array containing individual morph targets

		void											DiscardResources();
	};

	struct IBInfo
	{
		INT32											m_iterationNumber;
		IRuIndexBuffer*									m_ib;
	};

	// Dynamic buffers
	const static UINT32									s_dynamicVBSizesCount;
	const static UINT32									s_dynamicVBSizes[];
	const static UINT32									s_dynamicIBSizesCount;
	const static UINT32									s_dynamicIBSizes[];

	// Device buffer manager states
	CRuLRUQueueEx<DWORD, CRuGUID, VBInfo>*				m_vbQueue;							//!< Vertex buffer LRU queue
	CRuLRUQueue<CRuGUID, IBInfo>*						m_ibQueue;							//!< Index buffer LRU queue
	CRuEngineD3D*										m_engine;							//!< Engine core

	// Dynamic buffers
	IRuVertexBuffer**									m_dynamicVertexBuffers;
	IRuIndexBuffer**									m_dynamicIndexBuffers;

	// Temporaries
	INT32												m_lastDynamicVBArraySize;
	IRuVertexBuffer**									m_lastDynamicVBArray;				//!< Last allocated dynamic VB array
	CRuInstancedMeshD3D									m_lastInstancedMesh;				//!< Last instanced mesh

	// Metrics
	char												m_metric_String[1024];
	INT32												m_metric_NumIBAllocations;
	INT32												m_metric_NumVBAllocations;
	INT32												m_metric_NumIBInstanceOps;
	INT32												m_metric_NumVBInstanceOps;

public:
														CRuInstanceManagerD3D();
	virtual												~CRuInstanceManagerD3D();

	virtual UINT32										GetCacheSize();

	BOOL												SetEngine(CRuEngineD3D *engine);
	virtual IRuEngine*									GetEngine();

	virtual IRuInstancedMesh*							GetInstance(IRuMesh *mesh, IRuShader *shader);

	virtual BOOL										ClearCache();

	// Metrics
	virtual INT32										GetNumMetricStrings();
	virtual const char*									GetMetricString(INT32 stringIndex);

private:
	static BOOL											VBClearCacheCallback(const void *key, const void *data, void *userData);
	static BOOL											IBClearCacheCallback(const void *key, const void *data, void *userData);
};

// ************************************************************************************************************************************************************

#pragma managed

#endif
