
///////////////////////////////////////////////////////////////////////////////
//
// File   : AVP_LOS.cpp
// Author : Andy Tate
// Date   : 12-Mar-2007
//
// Copyright (C) 2007 Rebellion, All Rights Reserved.
//
///////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////
// Include files...
////////////////////////////////////////////////////////////////////////////////

#include "Core/Asura.h"

// This file's header...
#include "Core/AVP_LOS.h"

// Asura independent header-files...
#include "Core/Asura_HashedList.h"
#include "Core/Asura_LOS.h"

// Game independent header-files...
#include "Entity/PhysicalObject/PhysicsObject/AVP_ClientEntity_PhysicsObject.h"
#include "Entity/PhysicalObject/Lift/AVP_ClientEntity_Lift.h"

////////////////////////////////////////////////////////////////////////////////
// Static declarations...
////////////////////////////////////////////////////////////////////////////////

Asura_LOS_OutputData AVP_LOS::s_xOutData;
unsigned int AVP_LOS::s_uLOSTestCount = 0;

////////////////////////////////////////////////////////////////////////////////
// functions...
////////////////////////////////////////////////////////////////////////////////

bool AVP_LOS::TestAgainstPhysics( const Asura_LOS_InputData* pxInputData )
{
	const Asura_Guid uIgnore = pxInputData->m_uEntityToIgnore;
	bool bHit = false;

	for( Asura_Hashed_List_It<AVP_ClientEntity_PhysicsObject> xIt(AVP_ClientEntity_PhysicsObject::GetList()); !xIt.Done(); xIt.Next() )
	{
		Asura_Entity_Renderable* pxPO = xIt.GetCurrent();

		if( pxPO->IsDestroyed() ) { continue; }

		if ( !pxPO->IsEntityActive() ) { continue; }

		if( ASURA_GUID_UNREGISTERED != uIgnore && pxPO->GetGuid() == uIgnore ) { continue; }

		bHit |= pxPO->LOSTest( pxInputData, &s_xOutData );
	}

	return bHit;
}

bool AVP_LOS::TestAgainstLifts( const Asura_LOS_InputData* pxInputData )
{
	const Asura_Guid uIgnore = pxInputData->m_uEntityToIgnore;
	bool bHit = false;

	for( Asura_Hashed_List_It<AVP_ClientEntity_Lift> xIt(AVP_ClientEntity_Lift::GetList()); !xIt.Done(); xIt.Next() )
	{
		Asura_Entity_Renderable* pxPO = xIt.GetCurrent();

		if( pxPO->IsDestroyed() ) { continue; }

		if ( !pxPO->IsEntityActive() ) { continue; }

		if( ASURA_GUID_UNREGISTERED != uIgnore && pxPO->GetGuid() == uIgnore ) { continue; }

		bHit |= pxPO->LOSTest( pxInputData, &s_xOutData );
	}

	return bHit;
}

const Asura_LOS_OutputData* AVP_LOS::TestAgainstEnvironmentAndMoveableObjects( const Asura_LOS_InputData* pxInputData )
{
	++s_uLOSTestCount;
	const Asura_LOS_OutputData* pxEvnOutputData = Asura_LOS::TestAgainstEnvironment(pxInputData);

	if (pxEvnOutputData->m_bHitEnvironment)
	{
		s_xOutData.Reset(pxEvnOutputData->m_fDistanceToIntersection);
	}
	else
	{
		s_xOutData.Reset(pxInputData->m_fInitialMaximumRange);
	}

	bool bHitMOB = false;

	bHitMOB |= TestAgainstLifts(pxInputData);

	bHitMOB |= TestAgainstPhysics(pxInputData);

	if (bHitMOB)
	{
		return &s_xOutData;
	}
	else
	{
		return pxEvnOutputData;
	}
}

const Asura_LOS_OutputData* AVP_LOS::TestAgainstAlmostEverything( const Asura_LOS_InputData* pxInputData, const u_int uNumClassificationExceptions /*= 0*/, const u_short* ausClassification /*= NULL*/, const u_int uNumGuidExceptions /*= 0*/, const Asura_Guid* auGuid /*= NULL*/ )
{
	++s_uLOSTestCount;
	s_xOutData = *Asura_LOS::TestAgainstEnvironment(pxInputData);

	ExceptionFunctor xFunctor( s_xOutData, uNumClassificationExceptions, ausClassification, uNumGuidExceptions, auGuid );
	Asura_Entity_System::TestEntitiesWithLOSFunctor( pxInputData, xFunctor );
	if (s_xOutData.m_uHitEntity)
	{
		s_xOutData.m_bHitEnvironment = false;
	}

	return &s_xOutData;
}

AVP_LOS::ExceptionFunctor::ExceptionFunctor( Asura_LOS_OutputData& xOutputData, const u_int uNumClassificationExceptions, const u_short* ausClassification, const u_int uNumGuidExceptions, const Asura_Guid* auGuid )
: m_rxOutData( xOutputData )
, m_uNumClassificationExceptions( uNumClassificationExceptions )
, m_ausClassification( ausClassification )
, m_uNumGuidExceptions( uNumGuidExceptions )
, m_auGuid( auGuid )
{
	Asura_Assert( uNumClassificationExceptions == 0 || ausClassification != NULL, "Improper usage" );
	Asura_Assert( uNumGuidExceptions == 0 || auGuid != NULL, "Improper usage" );
}

bool AVP_LOS::ExceptionFunctor::CheckEntity( Asura_Entity_Renderable* pxEntity, const Asura_LOS_InputData& xInputData )
{
	Asura_Assert( pxEntity, "Null leaf object pointer" );
	if ( pxEntity )
	{
		bool bDoTest = true;
		if ( m_ausClassification )
		{
			for ( u_int uClassificationItr = 0; uClassificationItr < m_uNumClassificationExceptions && bDoTest; ++uClassificationItr )
			{
				if ( pxEntity->GetClassification() == m_ausClassification[ uClassificationItr ] )
				{
					bDoTest = false;
				}
			}
		}

		if ( m_auGuid && bDoTest )
		{
			for ( u_int uGuidItr = 0; uGuidItr < m_uNumGuidExceptions && bDoTest; ++uGuidItr )
			{
				if ( pxEntity->GetGuid() == m_auGuid[ uGuidItr ] )
				{
					bDoTest = false;
				}
			}
		}

		if ( bDoTest )
		{
			return pxEntity->LOSTest( &xInputData, &m_rxOutData );
		}
	}
	return false;
}

/// End of file. ///
