//*******************************************************************
//
// File: Asura_Direct3D_Botanicals_Game_Render_Manager_SM11.h
//
// Created: 20 Oct 2006
//
// Description: 
//
//*******************************************************************

template< class Tgeometry, class TgeometryCache>
void Asura_Direct3D_BGR_Manager::DrawCacheSM11_DrawGeometryCache( const Asura_Botanical_Array< Tgeometry>& xArrayGeometry, const u_int uIndexGeometry, const TgeometryCache& xCacheGeometrys, ptrDrawTreeRenderStates pfnRenderStates, ptrDrawTreeInstances pfnDraw, const void* pxDataPointer)
{
	const Asura_Direct3D_BGR_GeometryVertexInstanceCache &xCacheGeometryInstances = xCacheGeometrys[ uIndexGeometry];
	uint32 uCountInstances = xCacheGeometryInstances.Size();
	
	if( 0 == uCountInstances)
	{
		return;
	}

	SCOPEDPIXEVENT((0xff00ff00, L"Botanical DrawGeometry Cache"));

	const Tgeometry &tGeometry = xArrayGeometry[ uIndexGeometry];
	if( false == (this->*(pfnRenderStates))( tGeometry, pxDataPointer))
	{
		return;
	}
	
	const struct Asura_Direct3D_BGR_GeometryInstanceConstants *xCacheConstants = &(xCacheGeometryInstances[ 0]);
	while( 0 < uCountInstances)
	{
		const uint32 uCountDrawnInstances = (this->*(pfnDraw))( tGeometry, xCacheConstants, uCountInstances, pxDataPointer);
		
		if( 0 == uCountDrawnInstances)
		{
			break;
		}
		
		Asura_Assert( xCacheConstants <= (&(xCacheGeometryInstances[ xCacheGeometryInstances.Size() - uCountDrawnInstances])), "Too many instances");
		Asura_Assert( uCountDrawnInstances <= uCountInstances, "Too many instances to draw");
		
		xCacheConstants += uCountDrawnInstances;
		uCountInstances -= uCountDrawnInstances;
		
		// DLH - Cannot use as it will ask for element Size
		//Asura_Assert( (&(cacheGeometryInstances[ cacheGeometryInstances.Size() - countInstances])) == cacheConstants);
	}
}

template< class Tgeometry, class TgeometryCache>
void Asura_Direct3D_BGR_Manager::DrawCacheSM11_FillGeometryCache( const Asura_Botanical_Array< Tgeometry>& xArrayGeometry, Asura_Direct3D_BGR_Cache& xCacheInstances, TgeometryCache& xCacheGeometrys)
{
	// DLH - Fill Each LOD with new constants
	const uint32 uCountInstances = xCacheInstances.Size();
	const uint32 uCountGeometrys = xArrayGeometry.Size();
	for( uint32 uIndexInstance = 0; uIndexInstance < uCountInstances; uIndexInstance += 1)
	{
		const Asura_Direct3D_BGR_InstanceCache &xCacheInstance = xCacheInstances[ uIndexInstance];
		//const uint32 indexLOD = 0;
		if( 1.0f < xCacheInstance.m_fDistance)
		{
			continue;
		}
		
		for( uint32 uIndexLOD = 0; uIndexLOD < uCountGeometrys; uIndexLOD += 1)
		{
			const Tgeometry &tGeometry = xArrayGeometry[ uIndexLOD];

			if( 0 == tGeometry.m_uPrimitiveCount)
			{
				continue;
			}
			
			if( false == tGeometry.m_xLodRange.IsInRange( xCacheInstance.m_fDistance))
			{
				continue;
			}

			Asura_Direct3D_BGR_GeometryVertexInstanceCache &xCacheGeometryInstances = xCacheGeometrys[ uIndexLOD];
			Asura_Direct3D_BGR_GeometryInstanceConstants &xCacheConstants = xCacheGeometryInstances.GetNext();

			xCacheConstants = xCacheInstance.m_xConstants;
			//cacheConstants.m_constants[1][3] = geometry.m_alphaCutValue + (1- geometry.m_lodRange.CalcStrength( cacheInstance.m_distance));
			
			const float fAlphaCutValue = tGeometry.m_fAlphaCutValue;
			const float fAlphaCutScale = 1.0f - fAlphaCutValue;
			const float fAlpha = fAlphaCutValue + (fAlphaCutScale * (1 - tGeometry.m_xLodRange.CalcStrength( xCacheInstance.m_fDistance)));

			xCacheConstants.m_xData.m_fAlphaCut = fAlpha;
		}
	}
}

template< class Tgeometry, class TgeometryCache>
void Asura_Direct3D_BGR_Manager::DrawCacheSM11_ClearGeometryCache( const Asura_Botanical_Array< Tgeometry>& xArrayGeometry, Asura_Direct3D_BGR_Cache& xCacheInstances, TgeometryCache& xCacheGeometrys)
{
	if( xCacheGeometrys.Size() < xArrayGeometry.Size())
	{
		xCacheGeometrys.SetSize( xArrayGeometry.Size());
	}
	
	{
		const uint32 uCountInstances = xCacheInstances.Size();
		const uint32 uCountGeometrys = xCacheGeometrys.Capacity();
		
		for( uint32 uIndexGeometry = 0; uIndexGeometry < uCountGeometrys; uIndexGeometry += 1)
		{
			Asura_Direct3D_BGR_GeometryVertexInstanceCache &xCacheGeometryInstances = xCacheGeometrys[ uIndexGeometry];
			
			if( xCacheGeometryInstances.Capacity() < uCountInstances)
			{
				xCacheGeometryInstances.SetCapacity( uCountInstances);
			}
			
			xCacheGeometryInstances.Clear();
		}
	}
}

template< class Tgeometry, const bool bUsePhotonSources>
void Asura_Direct3D_BGR_Manager::DrawCacheSM11( const Asura_Botanical_Array< Tgeometry> &xArrayGeometry, Asura_Direct3D_BGR_RenderCache& xRenderCache, ptrDrawTreeRenderStates pfnRenderStates, ptrDrawTreeInstances pfnDraw)
{
	if( xArrayGeometry.Size() == 0)
	{
		return;
	}

	SCOPEDPIXEVENT((0xff00ff00, L"Botanical DrawCache Instances Type"));

	// DLH - Cache all the different LOD levels that need to be drawn
	this->DrawCacheSM11_ClearGeometryCache( xArrayGeometry, xRenderCache.m_xCacheInstances, xRenderCache.m_xCacheVertexGeometrys);
	this->DrawCacheSM11_FillGeometryCache( xArrayGeometry, xRenderCache.m_xCacheInstances, xRenderCache.m_xCacheVertexGeometrys);
	
	if( true == bUsePhotonSources)
	{
		Asura_Botanical_Array< Asura_Direct3D_BGR_DynamicLightCache>& xArray_xDynamicLightCache = xRenderCache.m_xArray_xDynamicLightCache;
		const u_int uDynamicLightCacheCount = xArray_xDynamicLightCache.Size();
		for( u_int uDynamicLightCacheIndex = 0; uDynamicLightCacheIndex < uDynamicLightCacheCount; uDynamicLightCacheIndex += 1)
		{
			Asura_Direct3D_BGR_DynamicLightCache& xDynamicLightCache = xArray_xDynamicLightCache[ uDynamicLightCacheIndex];
			const Asura_Photon* pxPhoton = xDynamicLightCache.m_pxPhoton;

			if( NULL == pxPhoton)
			{
				// DLH - 30 June 2006 14:39:56 - Photons should be stored in a linear maner, so there should not be any more
				break;
			}
			
			this->DrawCacheSM11_ClearGeometryCache( xArrayGeometry, xDynamicLightCache.m_xCacheInstances, xDynamicLightCache.m_xCacheVertexGeometrys);
			this->DrawCacheSM11_FillGeometryCache( xArrayGeometry, xDynamicLightCache.m_xCacheInstances, xDynamicLightCache.m_xCacheVertexGeometrys);
		}
	}
	
	{
		// DLH - Must use the xArrayGeometry as the static and dynamic arrays can have different sizes due to being setup as and when they are needed
		const uint32 uCountGeometrys = xArrayGeometry.Size();

		// DLH - Draw Each LOD level in turn. For each LOD: Opaque part first the add each Dynhamic Light, Then Next LOD Opaque parts
		for( uint32 uIndexGeometry = 0; uIndexGeometry < uCountGeometrys; uIndexGeometry += 1)
		{
			this->DrawCacheSM11_DrawGeometryCache( xArrayGeometry, uIndexGeometry, xRenderCache.m_xCacheVertexGeometrys, pfnRenderStates, pfnDraw, NULL);
			if( true == bUsePhotonSources)
			{
				Asura_Botanical_Array< Asura_Direct3D_BGR_DynamicLightCache>& xArray_xDynamicLightCache = xRenderCache.m_xArray_xDynamicLightCache;
				const u_int uDynamicLightCacheCount = xArray_xDynamicLightCache.Size();
				for( u_int uDynamicLightCacheIndex = 0; uDynamicLightCacheIndex < uDynamicLightCacheCount; uDynamicLightCacheIndex += 1)
				{
					Asura_Direct3D_BGR_DynamicLightCache& xDynamicLightCache = xArray_xDynamicLightCache[ uDynamicLightCacheIndex];
					const Asura_Photon* pxPhoton = xDynamicLightCache.m_pxPhoton;

					if( NULL == pxPhoton)
					{
						// DLH - 30 June 2006 14:39:56 - Photons should be stored in a linear maner, so there should not be any more
						break;
					}
		
					const void* pxDataPointer = reinterpret_cast< const void*>( pxPhoton);
			
					Asura_Assert( xRenderCache.m_xCacheVertexGeometrys.Size() == xDynamicLightCache.m_xCacheVertexGeometrys.Size(), "Static and Dynamic Geomerty LOD caching has a different size!");			
					this->DrawCacheSM11_DrawGeometryCache( xArrayGeometry, uIndexGeometry, xDynamicLightCache.m_xCacheVertexGeometrys, pfnRenderStates, pfnDraw, pxDataPointer);
				}
			}
		}
	}
}

template< const bool bUsePhotonSources> void Asura_Direct3D_BGR_Manager::DrawCache( const Asura_Direct3D_BGR_Type* pxTreeDescription, Asura_Direct3D_BGR_RenderCache &xRenderCache)
{
	SCOPEDPIXEVENT((0xff00ff00, L"Botanical DrawCache Instances"));
	
	const Asura_Direct3D_BGR_Section& xSection = pxTreeDescription->m_xArray_xSections[0];
	const Asura_Direct3D_BGR_Section_Version & xSectionVersion = xSection.m_xArray_xVersions[0];
	const Asura_Direct3D_BGR_Geometry& xGeometry = xSectionVersion.m_xGeometry;

	#if defined( ASURA_DIRECT3D_BGR_SUPPORT_GEOMETRY3D)
		this->DrawCacheSM11< Asura_Direct3D_BGR_Type_Geometry3D, bUsePhotonSources>( xGeometry.m_xArrayBranchs, xRenderCache, &Asura_Direct3D_BGR_Manager::DrawTree_SM11_3D1SidedRenderStates, &Asura_Direct3D_BGR_Manager::DrawTree_SM11_3D1SidedInstances);
		this->DrawCacheSM11< Asura_Direct3D_BGR_Type_Geometry3D, bUsePhotonSources>( xGeometry.m_xArrayFronds, xRenderCache, &Asura_Direct3D_BGR_Manager::DrawTree_SM11_3D2SidedRenderStates, &Asura_Direct3D_BGR_Manager::DrawTree_SM11_3D2SidedInstances);
	#endif
	
	#if defined( ASURA_DIRECT3D_BGR_SUPPORT_LEAVES)
		this->DrawCacheSM11< Asura_Direct3D_BGR_Type_GeometryLeaves, bUsePhotonSources>( xGeometry.m_xArrayLeaves, xRenderCache, &Asura_Direct3D_BGR_Manager::DrawTree_SM11_LeafRenderStates, &Asura_Direct3D_BGR_Manager::DrawTree_SM11_LeafInstances);
	#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.
//
//*******************************************************************
