//*******************************************************************
//
// File: Asura_Direct3D_IndexBuffer_Dynamic.cpp
//
// Created: 24 Oct 2006
//
// Description: 
//
//*******************************************************************

// system libraries
#include "Core/Asura.h"

// main header
#include "Asura_Direct3D_IndexBuffer_Dynamic.h"

// other libraries

// internal dependencies

//*******************************************************************
// Constants
//*******************************************************************


//*******************************************************************
// Local Classes
//*******************************************************************


//*******************************************************************
// Function Definitions
//*******************************************************************
Asura_Direct3D_IndexBuffer_Dynamic::Asura_Direct3D_IndexBuffer_Dynamic()
{
	this->Init();
}

Asura_Direct3D_IndexBuffer_Dynamic::~Asura_Direct3D_IndexBuffer_Dynamic()
{
	this->Clear();
}

void Asura_Direct3D_IndexBuffer_Dynamic::Init()
{
	this->m_eIndexFormat = D3DFMT_INDEX16;
	
	this->m_uIndexBufferSizeBytes = 0;
	this->m_pxD3DIndexBuffer = NULL;

	this->m_uIndexBufferUsedSizeBytes = 0;
	this->m_uIndexBufferLockedSizeBytes = 0;
	this->m_pIndexBufferLockedStart = NULL;
#if defined( ASURA_ASSERT)
	this->m_pIndexBufferLockedEnd = NULL;
#endif
}
	
void Asura_Direct3D_IndexBuffer_Dynamic::Clear()
{
	Asura_Assert( NULL == this->m_pIndexBufferLockedStart, "The Index Buffer is locked. Unlock() before calling this method.");
	
	SAFE_RELEASE( this->m_pxD3DIndexBuffer);
	
	this->Init();
}

bool Asura_Direct3D_IndexBuffer_Dynamic::ClearDirect3DData()
{
	Asura_Assert( NULL == this->m_pIndexBufferLockedStart, "The Index Buffer is locked. Unlock() before calling this method.");
	
	SAFE_RELEASE( this->m_pxD3DIndexBuffer);
	
	this->m_pxD3DIndexBuffer = NULL;

	this->m_uIndexBufferUsedSizeBytes = 0;
	this->m_uIndexBufferLockedSizeBytes = 0;
	this->m_pIndexBufferLockedStart = NULL;
#if defined( ASURA_ASSERT)
	this->m_pIndexBufferLockedEnd = NULL;
#endif
	
	return( true);
}

bool Asura_Direct3D_IndexBuffer_Dynamic::CreateDirect3DData()
{
	Asura_Assert( NULL == this->m_pIndexBufferLockedStart, "The Index Buffer is locked. Unlock() before calling this method.");

	if(m_uIndexBufferSizeBytes == 0)
	{
		return(false);
	}
	else
	{
		return( this->SetSize( this->m_uIndexBufferSizeBytes));	
	}
}

bool Asura_Direct3D_IndexBuffer_Dynamic::SetFormat( const D3DFORMAT eIndexFormat)
{
	Asura_Assert( NULL == this->m_pxD3DIndexBuffer, "Index Buffer Must be cleared before setting the format");
	
	this->m_eIndexFormat = eIndexFormat;
	
	return( true);
}

bool Asura_Direct3D_IndexBuffer_Dynamic::SetSize( const u_int uSizeBytes)
{
	HRESULT xResult;
	Asura_Assert( NULL == this->m_pIndexBufferLockedStart, "The Index Buffer is locked. Unlock() before calling this method.");
	
	this->Clear();
	
	Direct3D_Device* pxD3DDevice = Asura_Direct3D::D3DDevice;
	
	Asura_Assert( NULL != pxD3DDevice, "D3D needs to be setup");
	
	const u_int uUsageFlags = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
	const D3DPOOL ePool = D3DPOOL_DEFAULT;
	Direct3D_IndexBuffer* pxD3DIndexBuffer = NULL;
	xResult = pxD3DDevice->CreateIndexBuffer( uSizeBytes, uUsageFlags, this->m_eIndexFormat, ePool, &pxD3DIndexBuffer, NULL);
	if( ASURA_D3D_FAILED( xResult))
	{
		return( false);
	}
	
	this->m_pxD3DIndexBuffer = pxD3DIndexBuffer;
	this->m_uIndexBufferSizeBytes = uSizeBytes;
	
	return( true);
}

bool Asura_Direct3D_IndexBuffer_Dynamic::Lock( const u_int uSizeBytesRequired, u_int& uLockedIndexBufferOffsetBytes, void*& pLockedMemory)
{
	HRESULT xResult;
	
	const u_int uAlignment = 4;
	u_int uAlignedSizeBytesRequired = uSizeBytesRequired & (~(uAlignment-1));
	if( uAlignedSizeBytesRequired != uSizeBytesRequired)
	{
		uAlignedSizeBytesRequired += uAlignment;
	}

	Asura_Assert( 0 == (uAlignedSizeBytesRequired & (uAlignment-1)), "Not aligned!");
	
	Asura_Assert( NULL != this->m_pxD3DIndexBuffer, "No vertex buffer has been allocated yet.");
	Asura_Assert( NULL == this->m_pIndexBufferLockedStart, "The Index Buffer is locked. Unlock() before calling this method.");
	Asura_Assert( uAlignedSizeBytesRequired <= this->m_uIndexBufferSizeBytes, "The Vertdex Buffer does not have this many bytes in it" );
	u_int uLockFlags = D3DLOCK_NOOVERWRITE;
	
	// DLH - 24 October 2006 15:35:20 - There is not enough room left in the VB so ask for a clean one 
	if( this->m_uIndexBufferSizeBytes < (this->m_uIndexBufferUsedSizeBytes + uAlignedSizeBytesRequired))
	{
		uLockFlags = D3DLOCK_DISCARD;
		this->m_uIndexBufferUsedSizeBytes = 0;
	}
	
	void* pLockedMemoryParam = NULL;
	xResult = this->m_pxD3DIndexBuffer->Lock( this->m_uIndexBufferUsedSizeBytes, uAlignedSizeBytesRequired, &pLockedMemoryParam, uLockFlags);
	if( ASURA_D3D_FAILED( xResult))
	{
		return( false);
	}
	
	this->m_pIndexBufferLockedStart = pLockedMemoryParam;
	this->m_uIndexBufferLockedSizeBytes = uAlignedSizeBytesRequired;	
#if defined( ASURA_ASSERT)
	this->m_pIndexBufferLockedEnd = (static_cast< uint8*>( pLockedMemoryParam)) + uAlignedSizeBytesRequired;
#endif
	
	pLockedMemory = pLockedMemoryParam;
	uLockedIndexBufferOffsetBytes = this->m_uIndexBufferUsedSizeBytes;
	
	return( true);
}

void Asura_Direct3D_IndexBuffer_Dynamic::Unlock( const u_int uSizeBytesUsed)
{
	HRESULT xResult;

	Asura_Assert( NULL != this->m_pxD3DIndexBuffer, "No vertex buffer has been allocated yet.");
	Asura_Assert( NULL != this->m_pIndexBufferLockedStart, "The Index Buffer is NOT locked. Lock() before calling this method.");
	
	Asura_Assert( (this->m_uIndexBufferUsedSizeBytes + uSizeBytesUsed) <= this->m_uIndexBufferSizeBytes, "More data has been used than is in the Index Buffer");
	Asura_Assert( uSizeBytesUsed <= m_uIndexBufferLockedSizeBytes, "More data has been used than was locked");
	
	xResult = this->m_pxD3DIndexBuffer->Unlock();
	ASURA_D3D_OK( xResult);
	
	this->m_uIndexBufferUsedSizeBytes += uSizeBytesUsed;
	
	this->m_pIndexBufferLockedStart = NULL;
	this->m_uIndexBufferLockedSizeBytes = 0;
#if defined( ASURA_ASSERT)
	this->m_pIndexBufferLockedEnd = NULL;
#endif
}


//*******************************************************************
//
// (c) 2006 Rebellion Derby
//
// Warning: This computer program is protected by copyright law and 
// international treaties. Unauthorized reproduction or distribution
// of this program, or any portion of it, may result in severe civil and
// criminal penalties, and will be prosecuted to the maximum extent 
// possible under the law.
//
//*******************************************************************

