#ifndef _INC_XRVBManager
#define _INC_XRVBManager

#include "XRVertexBuffer.h"


// -------------------------------------------------------------------
//  CXR_VBManager
// -------------------------------------------------------------------
class CXR_VBPtr
{
public:
	CXR_VertexBuffer* m_pVB;

	CXR_VBPtr()
	{
		m_pVB = NULL;
	}

	CXR_VBPtr(CXR_VertexBuffer* _pVB)
	{
		m_pVB = _pVB;
	}

	int Compare(const CXR_VBPtr& _pVB) const;
};

enum
{
	VBM_SHOWTIME = 1,

	VBM_HWALLOCALIGN = 32,
};

enum
{
	VBMSCOPE_FL_NEEDSORT	= DBit(0),
	VBMSCOPE_FL_RENDERWIRE	= DBit(1),

	VBMCONTEXT_ENGINE	= 0,
	VBMCONTEXT_RENDER	= 1,

	CXR_VBMCONTEXT_COUNT	= 2,
};

enum
{
	CXR_VBMANAGER_STATE_PREBEGIN	= 0,
	CXR_VBMANAGER_STATE_RENDERING	= 1,
	CXR_VBMANAGER_STATE_POSTBEGIN	= 2,
};


enum
{
	CXR_CLIPMAXPLANES			= 6,
	CXR_CLIP_STACK_MAX			= 8,
	CXR_CLIP_HEAP_MAX			= 32,		// NOTE: uint8 CXR_VertexBuffer::m_iClip

	CXR_VIEWPORT_STACK_MAX		= 8,
	CXR_VIEWPORT_HEAP_MAX		= 256,		// NOTE: uint8 CXR_VertexBuffer::m_iVP

	CXR_SORTSCOPES_MAX			= 32,
};

class CXR_ClipStackEntry
{
public:
	CPlane3Dfp4 m_lPlanes[CXR_CLIPMAXPLANES];
	int m_nPlanes;

	CXR_ClipStackEntry();
	void Create(const CPlane3Dfp4* _pPlanes, int _nPlanes, const CMat4Dfp4* _pTransform = NULL);
	void Copy(const CXR_ClipStackEntry& _Src, const CMat4Dfp4* _pTransform = NULL);
};

class CXR_VBMScope
{
public:
	class CVBM_SortableVector
	{
	protected:
		CXR_VBPtr*	m_lpVBP;
		uint32 m_nMax;
		uint32 m_iCurrent;
	public:
		CVBM_SortableVector() : m_lpVBP(NULL),m_nMax(0),m_iCurrent(0) {}

		void Create(uint32 _MaxVB);

		void Add(CXR_VBManager* _pVBM, CXR_VBPtr _pVBP);
		void Sort();
		CXR_VBPtr* GetBasePtr()
		{
			return m_lpVBP;
		}

		CXR_VBPtr& operator [] (int _iVB);

		int Len() const;
	};

	CXR_VBMScope() {}
	CXR_VBMScope(bool _bSort) : m_pLO(0), m_nMaxLights(0), m_nBufferSkip(0)
	{
		m_Flags	= _bSort?VBMSCOPE_FL_NEEDSORT:0;
	}
	void Create(uint32 _MaxVB);
	CVBM_SortableVector	m_lpVB;
	int	m_Flags;
	class CXR_LightOcclusionInfo* m_pLO;
	int m_nMaxLights;
	int	m_nBufferSkip;
};

class CXR_VBCallback
{
public:
	static void RenderCallback(CRenderContext* _pRC, CXR_VBManager* _pVBM, CXR_VertexBuffer* _pVB, void* _pContext, CXR_VBMScope* _pScope, int _Flags)
	{
		((CXR_VBCallback *)_pContext)->Callback(_pRC, _pVBM, _pVB, _pScope, _Flags);
	}

	virtual void Callback(CRenderContext* _pRC, CXR_VBManager* _pVBM, CXR_VertexBuffer* _pVB, CXR_VBMScope* _pScope, int _Flags) pure;
};

class CXR_VBManager : public CReferenceCount
{
	MRTC_DECLARE;


/*
	class CXR_VBMContext
	{
	public:
		TArray<uint8>	m_lHeap;

		int m_AllocPos;	// This is updated in Internal_End

		void Create(int _HeapSize)
		{
			m_lHeap.SetLen(_HeapSize);
			m_State	= CXR_VBMANAGER_STATE_PREBEGIN;
			m_AvailableEvent.Signal();
		}

		void SortScopes()
		{
			int nCount = m_lSortScopes.Len();
			for(int i = 0; i < nCount; i++)
			{
				CXR_VBMScope& Scope = m_lSortScopes[i];
				if(Scope.m_Flags & VBMSCOPE_FL_NEEDSORT)
				{
					Scope.m_lpVB.Sort();
				}
			}
		}
	};
*/
protected:
//	TArray<uint8> m_lHeap;	// This points at a context's array
	uint8 *m_pHeap;
	mint m_HeapSize;

	CXR_VBMScope* m_pActiveScope;
	TStaticArray<int, 8> m_lScopeStack;
	TStaticArray<CXR_VBMScope, 32> m_lSortScopes;

	int	m_iScopeStack;
	int	m_MaxVB;

	int	m_State;
	int m_AllocPos;
#ifdef M_Profile
	int m_AllocPosMax;
#endif
#ifdef MRTC_ENABLE_REMOTEDEBUGGER
	int m_RecordUsage;
#endif

	class CXR_VBContext* m_pVBCtx;

	// Memory potentially provided by render-context. (i.e, by VertexArrayRange)
	uint8* m_pHeapHW;
	int m_HeapSizeHW;
	int m_AllocPosHW;

	TList_Vector<uint8> m_lVertexUseMap;

	bool m_bOutOfMemory;

	int m_nBuffers;
	CMTime m_TSort;

	CRenderContext* m_pCurrentRC;		// Only valid between Begin()/End()

#ifdef PLATFORM_DOLPHIN
	int m_nToken;
#endif

#ifdef M_Profile
	int m_Stats_nVB;
	int m_Stats_nAttrib;
	int m_Stats_nLights;
	int m_Stats_nXRLights;
	int m_Stats_nM4;
	int m_Stats_nV4;
	int m_Stats_nV3;
	int m_Stats_nV2;
	int m_Stats_nInt16;
	int m_Stats_nInt32;
	int m_Stats_nFp4;
	int m_Stats_nPixel32;
	int m_Stats_nOpen;
	int m_Stats_nChains;
	int m_Stats_nChainVBs;
public:
	int m_Stats_nRenderSurface;
#endif


	// -------------------------------
	// Viewport stack
	CRC_Viewport*	m_lpVPHeap[CXR_VIEWPORT_HEAP_MAX];
	int m_nVPHeap;

	uint8 m_liVPStack[CXR_VIEWPORT_STACK_MAX];
	int m_iVPStack;

	// -------------------------------
	// Clipping stack
	CXR_ClipStackEntry*	m_lpClipHeap[CXR_CLIP_HEAP_MAX];
	int m_nClipHeap;

	uint8 m_liClipStack[CXR_CLIP_STACK_MAX];
	int m_iClipStack;

	// -------------------------------
	void* m_pOwner;

	// Internal functions, these assume locking has been done
	void Internal_Begin(CRenderContext* _pRC, const CRC_Viewport* _pVP);
	void Internal_End();
	void Internal_Render(CXR_VBMScope* _pScope, CRenderContext* _pRC, int _Flags, fp4 _StartPrio, fp4 _EndPrio);
	void Internal_Sort();

	void Internal_Viewport_Set(CRC_Viewport* _pVP, fp4 _Priority);
public:
	MRTC_SpinLock m_AddLock;
	MRTC_SpinLock m_AllocLock;

#ifdef MRTC_ENABLE_REMOTEDEBUGGER
	void RecordFrame()
	{
		gf_RDSendHeapClear(this);
		m_RecordUsage = true;
	}
#endif

	CXR_VBManager();
	~CXR_VBManager();
	dllvirtual void Create(int _HeapSize, int _MaxVB);

	dllvirtual uint8* GetVertexUseMap(int _nV);
	void GetAllocParams(int* _pAllocPos,MRTC_SpinLock* _pLock,uint8** _pHeap,mint* _pHeapSize);
	void *GetHeapPtr()
	{
		return m_pHeap;
	}
	dllvirtual int GetHeap();
	dllvirtual int GetAvail();
	dllvirtual int GetAllocPos();
#ifdef M_Profile
	dllvirtual int GetMinAvail();
#endif

	dllvirtual void* Alloc_Open();
	dllvirtual void Alloc_Close(int _Size);
	dllvirtual bool OutOfMemory();

	// HW heap alloc was a test and is not in use.
#ifdef NEVER
	dllvirtual int GetHeapHW();
	dllvirtual int GetAvailHW();
	dllvirtual void* Alloc_OpenHW();
	dllvirtual void Alloc_CloseHW(int _Size);
#endif

	// Allocation
	dllvirtual void* Alloc(int _Size);
	dllvirtual void* AllocHW(int _Size);
	dllvirtual void* AllocArray(int _Size);										// Tries to allocate in HW heap if possible.
	dllvirtual CXR_VertexBuffer* Alloc_VB();
	dllvirtual CXR_VertexBuffer* Alloc_VBAttrib();
	dllvirtual CXR_VertexBuffer* Alloc_VB(int _Contents, int _nV = 0);
	dllvirtual CXR_VBChain* Alloc_VBChain(int _Contents, int _nV = 0);
	dllvirtual CXR_VBIDChain* Alloc_VBIDChain();
	dllvirtual CXR_VBChain* Alloc_VBChain();
	dllvirtual CXR_VertexBuffer_PreRender* Alloc_PreRender(PFN_VERTEXBUFFER_PRERENDER _pFunc, void *_pContext);
	dllvirtual const CMat4Dfp4** Alloc_TextureMatrixArray();

	dllvirtual bool Alloc_VBChainCopy(CXR_VertexBuffer* _pDst, CXR_VertexBuffer* _pSrc);					// Only allocates chain. no attrib. :No geometry can be alloced with Alloc_VBChain
//	dllvirtual CXR_VertexBuffer* Alloc_VBChain(int _Contents, int _Len = 1);		// No geometry can be alloced with Alloc_VBChain
//	dllvirtual CXR_VertexBuffer* Alloc_VBChainOnly(CXR_VertexBuffer* _pSrc);					// Only allocates chain. no attrib. :No geometry can be alloced with Alloc_VBChain
//	dllvirtual CXR_VertexBuffer* Alloc_VBChainAttrib(int _Len = 1);					// Allocates chain and attrib :No geometry can be alloced with Alloc_VBChain
	dllvirtual CRC_Attributes* Alloc_Attrib();
	dllvirtual class CXR_Light* Alloc_XRLights(int _nCount);
	dllvirtual CRC_Light* Alloc_Lights(int _nLights);
	dllvirtual CMat4Dfp4* Alloc_M4();
	dllvirtual CMat4Dfp4* Alloc_M4(const CMat4Dfp4& _Mat);
	dllvirtual CMat43fp4* Alloc_M43();
	dllvirtual CMat43fp4* Alloc_M43(const CMat43fp4& _Mat);
#ifndef DEFINE_MAT43_IS_MAT4D
	dllvirtual CMat4Dfp4* Alloc_M4(const CMat43fp4& _Mat);
	dllvirtual CMat43fp4* Alloc_M43(const CMat4Dfp4& _Mat);
#endif

	dllvirtual CVec4Dfp4* Alloc_V4(int _nV);
	dllvirtual CVec3Dfp4* Alloc_V3(int _nV);
	dllvirtual CVec2Dfp4* Alloc_V2(int _nV);
	dllvirtual uint16* Alloc_Int16(int _nV);
	dllvirtual uint32* Alloc_Int32(int _nV);
	dllvirtual fp4* Alloc_fp4(int _nV);
	dllvirtual CPixel32* Alloc_CPixel32(int _nV);

	// !!! _pVB and _pAttrib must be a pointer to m_lHeap unless they're guaranteed to be valid over several frames !!!
	dllvirtual void AddVB(CXR_VertexBuffer* _pVB);
	dllvirtual void AddVB(const CXR_VertexBuffer& _VB);
	dllvirtual bool AddCallback(PFN_VERTEXBUFFER_PRERENDER _pfnCallback, void* _pContext, fp4 _Priority);

	template<typename t_CCallback>
	t_CCallback* AddCallbackClass(fp4 _Priority)
	{
		t_CCallback* pData = (t_CCallback*)Alloc(sizeof(t_CCallback));
		if (!pData)
			return NULL;

		new ((void *)pData) t_CCallback;

		if (!AddCallback(t_CCallback::RenderCallback, pData, _Priority))
			return NULL;

		return pData;

	}

	dllvirtual bool AddRenderOptions(fp4 _Priority, uint32 _Options, uint32 _Format = 0xffffffff);
	dllvirtual bool AddRenderRange(fp4 _Priority, fp4 _StartRenderPrio, fp4 _EndRenderPrio);
	dllvirtual bool AddClearRenderTarget(fp4 _Priority, int _WhatToClear, CPixel32 _ColorClearTo, fp4 _ZClearTo, int _StencilClearTo, CRct _ClearArea = CRct(-1,-1,-1,-1));
	dllvirtual bool AddCopyToTexture(fp4 _Priority, CRct _SrcRect, CPnt _Dst, uint16 _TextureID, bint _bContinueTiling, uint16 _Slice = 0);


	dllvirtual bool AddNextClearParams(fp4 _Priority, int _WhatToClear, CPixel32 _ColorClearTo, fp4 _ZClearTo, int _StencilClearTo, CRct _ClearArea = CRct(-1,-1,-1,-1));

	// These won't work properly with scopes
	int GetNextVBIndex();
	CXR_VertexBuffer* GetVB(int _iVB);

protected:

	void Sort();

public:

	dllvirtual void Begin(CRenderContext* _pRC, const CRC_Viewport* _pVP);// , int _nBuckets = 0, fp4 _BucketPriorityStart = 0.0f, fp4 _BucketPriorityEnd = 0.0f
	dllvirtual void End();
//	dllvirtual void Render(CRenderContext* _pRC, int _Flags, int _nBufferSkip = 0, class CXR_ViewClipInterface* _pViewClip = NULL);
	dllvirtual void Render(CRenderContext* _pRC, int _Flags);
	dllvirtual bool IsRendering();

	dllvirtual void Flush(CRenderContext* _pRC, int _Flags,  int _nBufferSkip = 0, class CXR_ViewClipInterface* _pViewClip = NULL);

	dllvirtual void ScopeBegin(bool _bNeedSort, int _MaxVB = 0);	// 0 means use default value
	dllvirtual void ScopeEnd();
	dllvirtual void ScopeSetLightOcclusionMask(class CXR_LightOcclusionInfo* _pLO, int _nMaxLights);
	dllvirtual void ScopeSetBufferskip(int _nBufferskip);
	dllvirtual void ScopeSetFlags(int _Flags);
	dllvirtual void ScopeClearFlags(int _Flags);

	dllvirtual CStr GetInfoString();

	dllvirtual void SetOwner(void* _pOwner);

	// Viewport
	dllvirtual CRC_Viewport* Viewport_Get();
	dllvirtual CRC_Viewport* Viewport_Get(int _Index);
	dllvirtual int Viewport_Add(const CRC_Viewport* _pVP);					// 0 == Out of VB heap
	dllvirtual bool Viewport_Push(const CRC_Viewport* _pVP);				// false == Out of VB heap, don't Viewport_Pop()
	dllvirtual void Viewport_Pop();
	dllvirtual int Viewport_GetCurrentIndex();

	// Clipping
	dllvirtual CXR_ClipStackEntry* Clip_Get(int _iClip);
	dllvirtual int Clip_Add(const CPlane3Dfp4* _pPlanes, int _nPlanes, const CMat4Dfp4* _pTransform = NULL);		// 0 == Out of VB heap
	dllvirtual bool Clip_Push(const CPlane3Dfp4* _pPlanes, int _nPlanes, const CMat4Dfp4* _pTransform = NULL);		// false == Out of VB heap, don't Clip_Pop()
	dllvirtual void Clip_Pop();

	// Debug
	dllvirtual void IncBufferSkip(int _nStep);
	dllvirtual void DecBufferSkip(int _nStep);

#ifdef PLATFORM_PS2
	void PrefetchTexture( CRenderContext* _pRC, int i, int _nBufferSkip );
#endif

	dllvirtual bint ConvertVertexBuildBuffer(CRC_VertexBuffer &_Dest, const CRC_BuildVertexBuffer&_Source);

	dllvirtual void RenderBox(const CMat4Dfp4& _Transform, const CBox3Dfp4& _Box, CPixel32 _Color);
	dllvirtual void RenderWire(const CMat4Dfp4& _Transform, const CVec3Dfp4& _p0, const CVec3Dfp4& _p1, CPixel32 _Color);
	dllvirtual void RenderBox(const CBox3Dfp4& _Box, CPixel32 _Color);
	dllvirtual void RenderWire(const CVec3Dfp4& _p0, const CVec3Dfp4& _p1, CPixel32 _Color);
	dllvirtual void RenderWires(const CMat4Dfp4& _Transform, const CVec3Dfp4* _pV, int _nVertices, CPixel32 _Color, bool bLoop);
	dllvirtual void RenderWires(const CMat4Dfp4& _Transform, const CVec3Dfp4* _pV, const uint16* _piV, int _nVertices, CPixel32 _Color, bool bLoop);
	dllvirtual void RenderWires(const CMat4Dfp4& _Transform, const CVec3Dfp4* _pV, const uint32* _piV, int _nVertices, CPixel32 _Color, bool bLoop);

	dllvirtual bool InsertTexGen(CRC_Attributes* _pA, int _nTexGen, const int* _pTexGenModes, const int* _pTexGenComp, const int* _piTexGenChannel, fp4** _pTexGenAttr);

	class CXR_VBManager_RenderRange
	{
	public:
		fp4 m_StartPrio;
		fp4 m_EndPrio;

		static void RenderCallback(CRenderContext* _pRC, CXR_VBManager* _pVBM, CXR_VertexBuffer* _pVB, void* _pContext, CXR_VBMScope* _pScope, int _Flags)
		{
			MSCOPESHORT(InitiateTexturePrecache);

			CXR_VBManager_RenderRange* pData = (CXR_VBManager_RenderRange*)_pContext;

			_pRC->Viewport_Push();
			_pVBM->Internal_Render(_pScope, _pRC, _Flags, pData->m_StartPrio, pData->m_EndPrio);
			_pRC->Viewport_Pop();
		}
	};
};

typedef TPtr<CXR_VBManager> spCXR_VBManager;

// -------------------------------------------------------------------
//  CXR_VBMContainer
// -------------------------------------------------------------------

#if 1
class CXR_VBMContainer : public CReferenceCount
{
	MRTC_DECLARE;
protected:
	class CVBM
	{
	public:
		DLinkD_Link(CVBM, m_Link);
		CXR_VBManager *m_pVBM;
		spCXR_VBManager m_spVBM;
	};

	DLinkD_List(CVBM, m_Link) m_Available;
	DLinkD_List(CVBM, m_Link) m_Dirty;
	DLinkD_List(CVBM, m_Link) m_Free;
	int m_nAvailable;
	int m_bBlockUntilFree;

	TThinArray<CVBM> m_lVBM;
	MRTC_CriticalSection m_Lock;

	NThread::CEventAutoReset m_AvailableEvent;
	NThread::CEventAutoReset m_DirtyEvent;

public:
	CXR_VBMContainer() {}

	void Create(int _nCount, int _nHeapSize, int _MaxVB)
	{
		M_LOCK(m_Lock);
		m_lVBM.SetLen(_nCount);
		m_nAvailable = _nCount;
		m_bBlockUntilFree = false;
		for(int i = 0; i < _nCount; i++)
		{
			MRTC_SAFECREATEOBJECT(spVBM, "CXR_VBManager", CXR_VBManager);
			m_lVBM[i].m_spVBM = spVBM;
			m_lVBM[i].m_pVBM = spVBM;
			spVBM->Create(_nHeapSize, _MaxVB);
			m_Available.Insert(m_lVBM[i]);
		}

		//m_AvailableEvent.SetSignaled();
		//m_DirtyEvent.ResetSignaled();
		//m_AllDoneEvent.SetSignaled();
	}

	CXR_VBManager* GetAvailVBM(fp8 _Timeout = 0.0)
	{
		M_LOCK(m_Lock);
		while (Volatile(m_bBlockUntilFree))
		{
			M_UNLOCK(m_Lock);
			MRTC_SystemInfo::OS_Sleep(10);
		}
		m_AvailableEvent.TryWait();
		CVBM* pVBM = m_Available.Pop();
		if(!pVBM)
		{
			if(_Timeout == 0.0) 
				return NULL;
			{
				M_UNLOCK(m_Lock);
				m_AvailableEvent.WaitTimeout(_Timeout);
			}

			pVBM = m_Available.Pop();
			if (!pVBM)
				return NULL;
		}

		--m_nAvailable;
		m_Free.Insert(pVBM);
		return pVBM->m_pVBM;
	}

	void BlockUntilAllVBMFree()
	{
		Volatile(m_bBlockUntilFree) = 1;
		while (1)
		{
			{
				M_LOCK(m_Lock);
				if (m_nAvailable == m_lVBM.Len())
					break;
			}
			MRTC_SystemInfo::OS_Sleep(10);
		}
		Volatile(m_bBlockUntilFree) = 0;
	}


	bool WaitForVBMAdd(fp8 _Timeout)
	{
		M_LOCK(m_Lock);
		while (Volatile(m_bBlockUntilFree))
		{
			M_UNLOCK(m_Lock);
			MRTC_SystemInfo::OS_Sleep(10);
		}
		m_AvailableEvent.TryWait();
		{
			M_UNLOCK(m_Lock);
			return !m_AvailableEvent.WaitTimeout(_Timeout);
		}
	}

	
	int GetNumAvailVBM() const
	{
		return m_nAvailable;
	}


	bool BlockUntilSingleVBMFree(fp8 _Timeout = 0.0)
	{
		M_LOCK(m_Lock);
		while (Volatile(m_bBlockUntilFree))
		{
			M_UNLOCK(m_Lock);
			MRTC_SystemInfo::OS_Sleep(10);
		}
		m_AvailableEvent.TryWait();
		if( !m_Available.IsEmpty() ) return true;
		
		if(_Timeout == 0.0) return false;

		{
			M_UNLOCK(m_Lock);
			m_AvailableEvent.WaitTimeout(_Timeout);
		}

		return !m_Available.IsEmpty();
	}

	CXR_VBManager* GetDirtyVBM(fp8 _Timeout = 0.0)
	{
		M_LOCK(m_Lock);
		m_DirtyEvent.TryWait();
		CVBM* pVBM = m_Dirty.Pop();
		if(!pVBM)
		{
			if(_Timeout == 0.0) 
				return NULL;
			{
				M_UNLOCK(m_Lock);
				m_DirtyEvent.WaitTimeout(_Timeout);
			}

			pVBM = m_Dirty.Pop();
			if (!pVBM)
				return NULL;
		}
		m_Free.Insert(pVBM);
		return pVBM->m_pVBM;
	}

	void Clean()
	{
		M_LOCK(m_Lock);
		CXR_VBManager* pVBM = 0;
		while((pVBM = GetDirtyVBM()))
		{
			pVBM->SetOwner(MRTC_SystemInfo::OS_GetThreadID());
			pVBM->End();
			AddAvailVBM(pVBM);
		}
	}

	void AddDirtyVBM(CXR_VBManager* _pVBM)
	{
		M_LOCK(m_Lock);
		CVBM *pFree = m_Free.Pop();
		M_ASSERT(pFree, "");
		pFree->m_pVBM = _pVBM;
		m_Dirty.Insert(pFree);
		m_DirtyEvent.Signal();
	}

	void AddAvailVBM(CXR_VBManager* _pVBM)
	{
		M_LOCK(m_Lock);
		CVBM *pFree = m_Free.Pop();
		M_ASSERT(pFree, "");
		pFree->m_pVBM = _pVBM;
		m_Available.Insert(pFree);
		++m_nAvailable;
		m_AvailableEvent.Signal();
	}
};

typedef TPtr<CXR_VBMContainer> spCXR_VBMContainer;
#else
class CXR_VBMContainer : public CReferenceCount
{
	MRTC_DECLARE;
protected:
	TArray<spCXR_VBManager> m_lspVBM;
	TArray<CXR_VBManager*> m_lpDirtyVBM;
	TArray<CXR_VBManager*> m_lpAvailVBM;
	MRTC_CriticalSection m_Lock;

	NThread::CEvent m_AllDoneEvent;
	NThread::CEvent m_AvailableEvent;
	NThread::CEvent m_DirtyEvent;
public:
	CXR_VBMContainer() {}

	void Create(int _nCount, int _nHeapSize, int _MaxVB)
	{
		M_LOCK(m_Lock);
		m_lspVBM.SetLen(_nCount);
		for(int i = 0; i < _nCount; i++)
		{
			MRTC_SAFECREATEOBJECT(spVBM, "CXR_VBManager", CXR_VBManager);
			m_lspVBM[i] = spVBM;
			m_lspVBM[i]->Create(_nHeapSize, _MaxVB);
			m_lpAvailVBM.Add(m_lspVBM[i]);
		}

		m_AvailableEvent.SetSignaled();
		m_DirtyEvent.ResetSignaled();
		m_AllDoneEvent.SetSignaled();
	}

	CXR_VBManager* GetAvailVBM(fp8 _Timeout = 0.0)
	{
		M_LOCK(m_Lock);
		if(!m_AvailableEvent.TryWait())
		{
			if(_Timeout == 0.0) return NULL;

			M_UNLOCK(m_Lock);
			if(!m_AvailableEvent.WaitTimeout(_Timeout))
				return NULL;
		}

		m_AllDoneEvent.ResetSignaled();

		CXR_VBManager* pVBM = m_lpAvailVBM[0];
		m_lpAvailVBM.Del(0);
		if(m_lpAvailVBM.Len() == 0)
			m_AvailableEvent.ResetSignaled();

		return pVBM;
	}

	void BlockUntilAllVBMFree()
	{
		m_AllDoneEvent.Wait();
	}

	CXR_VBManager* GetDirtyVBM(fp8 _Timeout = 0.0)
	{
		M_LOCK(m_Lock);
		if(!m_DirtyEvent.TryWait())
		{
			if(_Timeout == 0.0) return NULL;

			M_UNLOCK(m_Lock);
			if(!m_DirtyEvent.WaitTimeout(_Timeout))
				return NULL;
		}

		CXR_VBManager* pVBM = m_lpDirtyVBM[0];
		m_lpDirtyVBM.Del(0);
		if(m_lpDirtyVBM.Len() == 0)
			m_DirtyEvent.ResetSignaled();

		return pVBM;
	}

	void Clean()
	{
		M_LOCK(m_Lock);
		CXR_VBManager* pVBM = 0;
		while((pVBM = GetDirtyVBM()))
		{
			pVBM->SetOwner(MRTC_SystemInfo::OS_GetThreadID());
			pVBM->End();
			AddAvailVBM(pVBM);
		}
	}

	void AddDirtyVBM(CXR_VBManager* _pVBM)
	{
		M_LOCK(m_Lock);
		m_lpDirtyVBM.Add(_pVBM);
		if(!m_DirtyEvent.TryWait())
			m_DirtyEvent.SetSignaled();
	}

	void AddAvailVBM(CXR_VBManager* _pVBM)
	{
		M_LOCK(m_Lock);
		m_lpAvailVBM.Add(_pVBM);
		if(!m_AvailableEvent.TryWait())
			m_AvailableEvent.SetSignaled();

		if(m_lpAvailVBM.Len() == m_lspVBM.Len())
			m_AllDoneEvent.SetSignaled();
	}
};

typedef TPtr<CXR_VBMContainer> spCXR_VBMContainer;

#endif


#endif //_INC_XRVBManager
