///////////////////////////////////////////////////////////////////////////////
//
// File   : Asura_PSP_BotanicalsSystem.cpp
// Author : Catalin Arsenescu
// Date   : 09-March-2007
//
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////
#include "Core\Asura.h"

#ifdef ASURA_USE_BOTANICALS

// This file's header
#include "Botanicals/Asura_PSP_BotanicalsTemplate.h"

// Asura independent headers
#include "Camera/Asura_Camera.h"
#include "Debugging\Asura_Assert.h"
#include "Core/Asura_Material_System.h"
#include "Core/Asura_TextureManagement.h"
#include "Rendering/Asura_Render.h"

// Sony libraries

// PSP headers
#include "Rendering/Asura_PSP_Graphics.h"
#include "Rendering/Asura_PSP_TextureManagement.h"

#include "Botanicals/Asura_PSP_BotanicalsSystem.h"
#include "Botanicals/Asura_PSP_BotanicalsShape.h"
#include "Botanicals/Asura_PSP_BotanicalsElement.h"

DEBUGVAR float dbg_fMaxBotanicalRangeSquared = 10000.0f;

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PSP_BotanicalsInstance::Render
// Author       : Catalin Arsenescu
// Date         : 09-March-2007
////////////////////////////////////////////////////////////////////////////////
void Asura_PSP_BotanicalsInstance::Render(Asura_PSP_BotanicalsTemplate* pxTemplate,Asura_PSP_BotanicalsShape* pxShape, int iInstanceID)
{
	bool bSomethingToRender = true;

	const Asura_Vector_3* pxCameraPosition = Asura_Camera::GetPosition(); 

	// If all elements are out of the frustum, we can skip the preparation and save some display list space.
	for(unsigned int uElements = 0; uElements < pxShape->m_uNumElements && (bSomethingToRender == true); ++uElements)
	{		
		Asura_PSP_BotanicalsElement* pxCurrentElement = &pxShape->m_pxElements[uElements];
			
		if (!Asura_Camera::IsSphereInFrustum(afCull, pxCurrentElement->m_fRadius))
		{
			bSomethingToRender = false;
		}
 
		// We should also do the same with range; in BF at least, it's quite possible you'll be above the surface of the planet
		// looking straight down, at which point there will be a large number of (small) botanicals being rendered at once and not
		// frustum culled.
		if(pxCameraPosition && bSomethingToRender)
		{
			// Calculate camera distance to this object 
			Asura_Vector_3 xCameraInstanceVector( afCull ); 
			xCameraInstanceVector -= *(pxCameraPosition); 
			float fDistanceSquared = xCameraInstanceVector.MagnitudeSquared(); 

			if(fDistanceSquared > dbg_fMaxBotanicalRangeSquared)
			{
				bSomethingToRender = false;
			}
		}
	}

	if (!bSomethingToRender)
	{
		return;
	}


	if( pxLightingSolution->IsStaticValid() )
	{
		pxLightingSolution->SetPosition( Asura_Vector_3(afCull) );
	}
	pxLightingSolution->RecalculateLighting( true, false );
	Asura_PSP_Graphics::SetupEntityLights(1.0f, true);

	GUM_UpdateMatrix();
	GU_CallList( &uStart ); 

	if(eType == ASURA_PSP_BOTANICALS_TEMPLATE_BOTANICALSHAPE)
	{
		RenderBotanicalShape(pxTemplate, pxShape, afCull, iInstanceID);
	}
	else
	{
		RenderShape(pxShape, afCull);
	}
}
/// End of function 'Asura_PSP_BotanicalsInstance::Render'. ///

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PSP_BotanicalsInstance::RenderBotanicalShape
// Author       : Catalin Arsenescu
// Date         : 09-March-2007
////////////////////////////////////////////////////////////////////////////////
void Asura_PSP_BotanicalsInstance::RenderBotanicalShape(Asura_PSP_BotanicalsTemplate* pxTemplate,Asura_PSP_BotanicalsShape* pxShape, Asura_Vector_3 xInstancePosition, int iInstanceID)
{
	const Asura_Vector_3* pxCameraPosition = Asura_Camera::GetPosition(); 

	// Calculate camera distance to this object 
	Asura_Vector_3 xCameraInstanceVector( afCull ); 
	xCameraInstanceVector -= *(pxCameraPosition); 
	float fDistance = xCameraInstanceVector.Magnitude(); 


#if defined( ASURA_BOTANICAL_SUPPORT_DYNAMIC_DATA) && 1 == ASURA_BOTANICAL_SUPPORT_DYNAMIC_DATA
	Asura_BGR_DynamicInstance* pxDynamicInstanceData = pxTemplate->GetDynamicInstanceData( iInstanceID );
#endif

	for(unsigned int uElements = 0; uElements < pxShape->m_uNumElements; ++uElements)
	{
		pxShape->m_pxElements[uElements].Render(  pxTemplate
												, pxShape
												, xInstancePosition
												, iInstanceID
												, fDistance
												, fScale
#if defined( ASURA_BOTANICAL_SUPPORT_DYNAMIC_DATA) && 1 == ASURA_BOTANICAL_SUPPORT_DYNAMIC_DATA
												, pxDynamicInstanceData
#endif
												);
	}
}
/// End of function 'Asura_PSP_BotanicalsInstance::RenderBotanicalShape'. ///

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PSP_BotanicalsInstance::RenderShape
// Author       : Catalin Arsenescu
// Date         : 09-March-2007
////////////////////////////////////////////////////////////////////////////////
void Asura_PSP_BotanicalsInstance::RenderShape(Asura_PSP_BotanicalsShape* pxShape, Asura_Vector_3 xInstancePosition)
{
	for(unsigned int uElements = 0; uElements < pxShape->m_uNumElements; ++uElements)
	{
		Asura_PSP_BotanicalsElement* pxCurrentElement = &pxShape->m_pxElements[uElements];

		xInstancePosition.y += pxCurrentElement->m_fCentre; 		
		if (!Asura_Camera::IsSphereInFrustum(xInstancePosition, pxCurrentElement->m_fRadius)) continue;

		Asura_PSP_Botanicals_LOD_Geometry* pxGeometry = (pxCurrentElement->m_pxLODData->m_pxGeometryLODs);

		// Draw this botanical
		GU_CallList( pxGeometry->m_uDrawArrayDisplayList ); 

		#if defined ASURA_RENDER_TTYPES
			Asura_Render::AddToTrianglesRendered(pxGeometry->m_uNumTriangles,1,
				ASURA_RENDER_TTYPE_OBJ);
		#else
			Asura_Render::AddToTrianglesRendered(pxGeometry->m_uNumTriangles);
		#endif
	}
}
/// End of function 'Asura_PSP_BotanicalsInstance::RenderShape'. ///

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PSP_BotanicalsTemplate::Asura_PSP_BotanicalsTemplate
// Author       : Catalin Arsenescu
// Date         : 09-March-2007
////////////////////////////////////////////////////////////////////////////////
Asura_PSP_BotanicalsTemplate::Asura_PSP_BotanicalsTemplate()
: m_pxShape(NULL)
, m_pxInstances(NULL)
, m_iUID(0)
, m_iNumInstances(0)
, m_iOffsetToNextBase(0)
{
}
/// End of function 'Asura_PSP_BotanicalsTemplate::Asura_PSP_BotanicalsTemplate'. ///

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PSP_BotanicalsTemplate::~Asura_PSP_BotanicalsTemplate
// Author       : Catalin Arsenescu
// Date         : 09-March-2007
////////////////////////////////////////////////////////////////////////////////
Asura_PSP_BotanicalsTemplate::~Asura_PSP_BotanicalsTemplate()
{
	delete[] m_pxInstances;
	m_iNumInstances = 0;
	m_pxInstances = NULL;
}
/// End of function 'Asura_PSP_BotanicalsTemplate::~Asura_PSP_BotanicalsTemplate'. ///

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PSP_BotanicalsTemplate::GetInstanceCount
// Author       : Catalin Arsenescu
// Date         : 09-March-2007
////////////////////////////////////////////////////////////////////////////////
u_int Asura_PSP_BotanicalsTemplate::GetInstanceCount() const
{
	return( this->m_iNumInstances);
}
/// End of function 'Asura_PSP_BotanicalsTemplate::GetInstanceCount'. ///

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PSP_BotanicalsTemplate::GetInstance
// Author       : Catalin Arsenescu
// Date         : 09-March-2007
////////////////////////////////////////////////////////////////////////////////
const Asura_BGR_Instance* const Asura_PSP_BotanicalsTemplate::GetInstance( const u_int uInstanceIndex ) const
{
#ifdef ASURA_ASSERT
	Asura_Assertf( uInstanceIndex < static_cast< u_int>( this->m_iNumInstances), ("Asura_PSP_BotanicalsTemplate::GetInstance -> Instance %d is out of %d range.", uInstanceIndex, this->m_iNumInstances));
#endif
	const Asura_BGR_Instance* const pxInstance = this->m_pxInstances + uInstanceIndex;
	
	return( pxInstance);
}
/// End of function 'Asura_PSP_BotanicalsTemplate::GetInstance'. ///

////////////////////////////////////////////////////////////////////////////////
// Function     : Asura_PSP_BotanicalsTemplate::Render
// Author       : Catalin Arsenescu
// Date         : 13-March-2007
////////////////////////////////////////////////////////////////////////////////
void Asura_PSP_BotanicalsTemplate::Render(void)
{
	if(m_iNumInstances == 0 || m_pxShape->m_uNumElements == 0) return;

	Asura_Render::CurrentStates.RequestTranslucencyMode( ASURA_TRANSLUCENCY_OFF );
	GU_BlendFunc( SCEGU_ADD, SCEGU_FIX_VALUE, SCEGU_FIX_VALUE, 0xffffffff, 0 );
	
	for(int iInstance = 0; iInstance < m_iNumInstances; ++iInstance)
	{
		m_pxInstances[iInstance].Render(this, m_pxShape, iInstance);
	}
}
/// End of function 'Asura_PSP_BotanicalsTemplate::Render'. ///

#endif //#ifdef ASURA_USE_BOTANICALS
