//*******************************************************************
//
// File: Asura_Direct3D_Carpet_Game_Render_Resource.cpp
//
// Created: 3 Feb 2006
//
// Description: 
//
//*******************************************************************

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

#if defined( ASURA_USE_CARPET)

// main header
#include "Asura_Direct3D_Carpet_Game_Render.h"

// other libraries
#include "Rendering/Asura_Render.h"
#include "Rendering/Asura_Direct3d.h"

// internal dependencies

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


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


//*******************************************************************
// Static Data
//*******************************************************************


//*******************************************************************
// Function Definitions
//*******************************************************************

bool Asura_Direct3D_Carpet_Game_Render::CreateVertexFormat()
{
	HRESULT xResult;
	
	xResult = Asura_Direct3D::D3DDevice->CreateVertexDeclaration( s_paxVSD_Carpet_Simple, &(s_pxVertexDeclarationSimple) );
	ASURA_D3D_OK( xResult);
	
	return( true);
}

bool Asura_Direct3D_Carpet_Game_Render::CreateVertexBufferMesh( Asura_Direct3D_CGR_Mesh& xCGRMesh)
{
	HRESULT xResult;
	
	Asura_Assert( NULL == xCGRMesh.m_pxBatchVertexBuffer, "Vertex Buffer already setup!");

	const uint32 uiVertexDataSize = xCGRMesh.m_uBatchVertexBufferSize * sizeof( Asura_Direct3D_CGR_StreamVertexSimple);
	
	if( NULL != xCGRMesh.m_pxBatchVertexBuffer)
	{
		return( false);
	}
	
	xResult = Asura_Direct3D::D3DDevice->CreateVertexBuffer
	(
		uiVertexDataSize,
		D3DUSAGE_WRITEONLY | D3DUSAGE_DYNAMIC,
		0,
		D3DPOOL_DEFAULT,
		&xCGRMesh.m_pxBatchVertexBuffer,
		0
	);
	if( ASURA_D3D_FAILED( xResult))
	{
		return( false);
	}
	
	xCGRMesh.m_xVBRangeManager.SetMaxRange( xCGRMesh.m_uBatchVertexBufferSize);
	return( true);
}

bool Asura_Direct3D_Carpet_Game_Render::CreateVertexBuffer()
{
	for( uint32 uiMeshIndex = 0; uiMeshIndex < s_uMeshesCount; uiMeshIndex += 1)
	{
		Asura_Direct3D_CGR_Mesh& xCGRMesh = s_pxMeshes[ uiMeshIndex];
		
		CreateVertexBufferMesh( xCGRMesh);
		
	}
	return( true);
}

bool Asura_Direct3D_Carpet_Game_Render::CreateIndexBuffer()
{
	HRESULT xResult;
	
	{
		const uint32 uiIndexDataSize = s_uBatchIndexBufferSize * sizeof( uint16);
		
		if( NULL == s_pxBatchIndexBuffer)
		{
			xResult = Asura_Direct3D::D3DDevice->CreateIndexBuffer
			(
				uiIndexDataSize,
				D3DUSAGE_WRITEONLY,
				D3DFMT_INDEX16,
				D3DPOOL_MANAGED,
				&s_pxBatchIndexBuffer,
				0
			);
			if( ASURA_D3D_FAILED( xResult))
			{
				return( false);
			}
		}
		uint16* pausVertexIndexData = NULL;
		xResult = s_pxBatchIndexBuffer->Lock( 0, uiIndexDataSize, (void**)&pausVertexIndexData, 0);
		if( ASURA_D3D_FAILED( xResult))
		{
			return( false);
		}
	
		// DLH - 12 January 2006 16:07:27 - This should really be in an index buffer
		// DLH - 12 January 2006 16:07:13 - If this array has not been initialise then fill it with indices
		const uint32 uQuadCount = s_uBatchIndexBufferSize / 6;
		Asura_Assert( (6 * uQuadCount) == s_uBatchIndexBufferSize, "CGR Number of Indices is not a multiple of 6");
		for( uint32 uIndexQuad = 0; uIndexQuad < uQuadCount; uIndexQuad += 1)
		{
			const uint32 uIndexVertex = 4 * uIndexQuad;
			const uint16 usIndexVertex = static_cast<uint16>( uIndexVertex );
			const uint32 uIndexIndex = 6 * uIndexQuad;
			
			Asura_Assert( usIndexVertex == uIndexVertex, "Index Too big for uint16!");
			
			//uint16* paxIndex = &s_axDrawCacheIndexArray[ uiIndexIndex];
			uint16* paxIndex = &pausVertexIndexData[ uIndexIndex];
			
			paxIndex[ 0] = usIndexVertex + 0;
			paxIndex[ 1] = usIndexVertex + 1;
			paxIndex[ 2] = usIndexVertex + 3;
			paxIndex[ 3] = usIndexVertex + 1;
			paxIndex[ 4] = usIndexVertex + 3;
			paxIndex[ 5] = usIndexVertex + 2;
		}
	
		xResult = s_pxBatchIndexBuffer->Unlock();
		ASURA_D3D_OK( xResult);
	}
	return( true);
}

bool Asura_Direct3D_Carpet_Game_Render::CreateDirect3DData()
{
	if( NULL == Asura_Direct3D::D3DDevice)
	{
		return( false);
	}

	ClearDirect3DData();
	
	CreateVertexFormat();
	CreateIndexBuffer();
	CreateVertexBuffer();

	return( true);
}

bool Asura_Direct3D_Carpet_Game_Render::ClearDirect3DData_AllBuffers()
{
	for( uint32 uiMeshIndex = 0; uiMeshIndex < s_uMeshesCount; uiMeshIndex += 1)
	{
		Asura_Direct3D_CGR_Mesh& xCGRMesh = s_pxMeshes[ uiMeshIndex];
		
		const uint32 uBatchCount = xCGRMesh.m_uPolygonBatchCount;
		for( uint32 uBatchIndex = 0; uBatchIndex < uBatchCount; uBatchIndex += 1)
		{
			Asura_Direct3D_CGR_PolygonBatch& xBatch = xCGRMesh.m_pxPolygonBatches[ uBatchIndex];
			
			BatchRemoveFromBuffers( xCGRMesh, xBatch);
		}
		
		Asura_Assert( 0 == xCGRMesh.m_xVBRangeManager.m_uRangeUsedCount, "Not all the vertex Batchs where deallocated");
		Asura_Assert( 0 == xCGRMesh.m_xVBRangeManager.m_uBlockUsedCount, "Not all the Batchs where deallocated");
	}

	return( true);	
}

bool Asura_Direct3D_Carpet_Game_Render::ClearDirect3DData()
{
	ClearDirect3DData_AllBuffers();
	
	for( uint32 uiMeshIndex = 0; uiMeshIndex < s_uMeshesCount; uiMeshIndex += 1)
	{
		Asura_Direct3D_CGR_Mesh& xCGRMesh = s_pxMeshes[ uiMeshIndex];
		
		SAFE_RELEASE( xCGRMesh.m_pxBatchVertexBuffer);
	}
	
	SAFE_RELEASE( s_pxBatchIndexBuffer);
	
	SAFE_RELEASE( s_pxVertexDeclarationSimple);
	
	s_iAttenuationMap = ASURA_TEXTURE_INVALID;
	
	return( true);
}

bool Asura_Direct3D_Carpet_Game_Render::Initialise()
{
	Asura_Direct3D::AddPreResetCallback( Asura_Direct3D_Carpet_Game_Render::PreD3DReset, NULL);
	Asura_Direct3D::AddPostResetCallback( Asura_Direct3D_Carpet_Game_Render::PostD3DReset, NULL);
	
	CreateDirect3DData();
	return( true);
}

void Asura_Direct3D_Carpet_Game_Render::ShutDown()
{
	ClearDirect3DData();
	ClearDataSet();
	
	Asura_Direct3D::RemovePostResetCallback( Asura_Direct3D_Carpet_Game_Render::PostD3DReset, NULL);
	Asura_Direct3D::RemovePreResetCallback( Asura_Direct3D_Carpet_Game_Render::PreD3DReset, NULL);
}

bool Asura_Direct3D_Carpet_Game_Render::PreD3DReset( void*)
{
	ClearDirect3DData();
	return( true);
}

bool Asura_Direct3D_Carpet_Game_Render::PostD3DReset( void*)
{
	CreateDirect3DData();
	BatchCopyAllToBuffers();
	return( true);
}

bool Asura_Direct3D_Carpet_Game_Render::ClearDataSet()
{
	delete[] s_pxMeshes;
	s_pxMeshes = NULL;
	s_uMeshesCount = 0;
	
	return( true);
}


#endif //defined( ASURA_USE_CARPET)

//*******************************************************************
//
// (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.
//
//*******************************************************************

