#include "BufferManager.h"

Buffer::Buffer(BufferManager* const pManager, const unsigned size, const POOL pool, const unsigned usage) : m_pManager(pManager)
{
	m_Pool = pool;
	m_Size = size;
	m_Usage = usage;
	m_pBuffer = NULL;
}

void Buffer::Release(void)
{
	m_pManager->Release(this);
}

VertexBuffer::VertexBuffer(BufferManager* const pManager, const unsigned nSize, const unsigned fvf, const unsigned usage, const POOL pool): Buffer(pManager, nSize, pool, usage)
{
	m_FVF = fvf;

	Restore();
}

IndexBuffer::IndexBuffer(BufferManager* const pManager, const unsigned nSize, const unsigned usage, const bool index32, const POOL pool) : Buffer(pManager, nSize, pool, usage)
{
	m_Index32 = index32;

	Restore();
}

DynamicVB::DynamicVB(BufferManager* const pManager, unsigned nSize) : Buffer(pManager, nSize, POOL_DEFAULT, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY), m_pDevice(pManager->GetDevice()->GetDevice())
{
	m_pVB = NULL;
	m_nVBUsed = -1;

	Restore();
}

/*DynamicVB::~DynamicVB(void)
{
	SAFERELEASE(m_pVB);
}*/

unsigned DynamicVB::LockVB(const unsigned nSize)
{
	void* pVBLock;

	if(nSize > m_Size - m_nVBUsed) //lock a new buffer
	{
		if(m_Size < nSize)//create a larger vb
		{
			while(m_Size < nSize) m_Size <<= 1;
			
			SAFERELEASE(m_pBuffer);
			Create();
		}

		m_pVB->Lock(0, 0, &pVBLock, D3DLOCK_DISCARD);
		m_nVBUsed = 0;
	}
	else
		m_pVB->Lock(m_nVBUsed, nSize, &pVBLock, D3DLOCK_NOOVERWRITE);

	m_nVBOffset = m_nVBUsed;
	m_nVBUsed += nSize;

	return (unsigned)pVBLock;
}

DynamicIB::DynamicIB(BufferManager* const pManager, const unsigned nSize, const bool bIndex32) : Buffer(pManager, nSize, POOL_DEFAULT, D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY), m_pDevice(pManager->GetDevice()->GetDevice())
{
	m_pIB = NULL;
	m_nIBUsed = -1;
	m_bIndex32 = bIndex32;

	Restore();
}

unsigned DynamicIB::LockIB(const unsigned nSize)
{
	void* pIBLock;

	if(nSize > m_Size - m_nIBUsed) //lock a new buffer
	{
		if(m_Size < nSize)//create a larger vb
		{
			while(m_Size < nSize) m_Size <<= 1;
			
			SAFERELEASE(m_pBuffer);
			Create();
		}

		m_pIB->Lock(0, 0, &pIBLock, D3DLOCK_DISCARD);
		m_nIBUsed = 0;
	}
	else
		m_pIB->Lock(m_nIBUsed, nSize, &pIBLock, D3DLOCK_NOOVERWRITE);

	m_nIBOffset = m_nIBUsed;
	m_nIBUsed += nSize;

	return (unsigned)pIBLock;
}

BufferManager::BufferManager(DeviceStateManager* const device) : m_Device(device)
{
}

BufferManager::~BufferManager(void)
{
	m_lBuffers.Clear();
}

VertexBuffer* BufferManager::CreateVB(const unsigned size, const unsigned fvf, const unsigned usage, const POOL pool)
{
	VertexBuffer* const vb = new VertexBuffer(this, size, fvf, usage, pool);
	m_lBuffers.AddHead(vb,(DWORD)vb);
	return vb;
}

IndexBuffer* BufferManager::CreateIB(const unsigned size, const unsigned usage, const bool index32, const POOL pool)
{
	IndexBuffer* const ib = new IndexBuffer(this, size, usage, index32, pool);
	m_lBuffers.AddHead(ib,(DWORD)ib);
	return ib;
}

DynamicVB* BufferManager::CreateDynamicVB(const unsigned size)
{
	DynamicVB* const dvb = new DynamicVB(this, size);
	m_lBuffers.AddHead(dvb,(DWORD)dvb);
	return dvb;
}

DynamicIB* BufferManager::CreateDynamicIB(const unsigned size, const bool index32)
{
	DynamicIB* const dib = new DynamicIB(this, size, index32);
	m_lBuffers.AddHead(dib,(DWORD)dib);
	return dib;
}

void BufferManager::Release(Buffer* const buffer)
{
	ListElement<Buffer> *el = m_lBuffers.GetElement((DWORD)buffer);
	if(el)
	{
		el->Delete();
		//el->Unlink();
		//delete el;
	}
}

void BufferManager::Restore(void)
{
	FOREACH(el, m_lBuffers, Buffer)
	{
		el->GetInfo()->Restore();
	}
}

void BufferManager::Invalidate(void)
{
	FOREACH(el, m_lBuffers, Buffer)
	{
		el->GetInfo()->Invalidate();
	}
}