//////////////////////////////////////////////////////////////////////////////
//
// FILE : ToolsAVP_Entity_Sentrygun.cpp
//
// Inherits from Tools_Entity_Actor
//
// AUTHORS : Chris Wallace
//
// Copyright (C) 2006 Rebellion, All Rights Reserved.
//
//////////////////////////////////////////////////////////////////////////////

// I N C L U D E S ///////////////////////////////////////////////////////////

// core
#include "Core/Asura.h"

// header
#include "Entity/PhysicalObject/Actor/Weapons/Sentrygun/ToolsAVP_Entity_Sentrygun.h"

// asura
#include "Mesh/Asura_Mesh_System.h"
#include "Rendering/Asura_Render.h"

// tools
#include "Blueprint/Tools_Mode_Blueprint.h"
#include "Entity/Container/Tools_Container.h"
#include "Entity/Container/Tools_Container_System.h"
#include "Entity/Tools_Entity_Data.h"
#include "Load&Save/Tools_SaveAsura.h"
#include "Misc/Tools_Timed_Messages.h"

// avp
#include "Blueprint/AVP_Blueprint_HashIDs.h"
#include "Entity/PhysicalObject/Actor/Weapons/Sentrygun/AVP_ServerWeapon_Sentrygun.h"

//////////////////////////////////////////////////////////////////////////////
//
// ToolsAVP_Entity_Sentrygun
//
//////////////////////////////////////////////////////////////////////////////

DEBUGVAR float dbg_fMuzHeight = -0.6f;

static bool s_bPreviewFireArcSelected		= false;
static bool s_bPreviewFireArcAll			= false;
static bool s_bPreviewLineOfFireSelected	= false;
static bool s_bPreviewLineOfFireAll			= false;

static Asura_Vector_3 s_pxRenderVerts[ Asura_Frustum::MAX_VERTICES ];	// used for drawing debug verts, global to save time as its an array and needs to be passed as argument. 

TOOLS_DECLARE_SHARED_PARAM(float,	0x235ba490,	FOVRange)
TOOLS_DECLARE_SHARED_PARAM(float,	0xb7c990a2,	HorFOV)
TOOLS_DECLARE_SHARED_PARAM(float,	0xB15024B6,	VertTopHalfFOV)
TOOLS_DECLARE_SHARED_PARAM(float,	0x03E1359E,	VertBottomHalfFOV)
TOOLS_DECLARE_SHARED_PARAM(float,	0xCD5E505C,	FireArc)
TOOLS_DECLARE_SHARED_PARAM(float,	0x5DEDA1A5,	LethalRange)
TOOLS_DECLARE_SHARED_PARAM(float,	0x06890047,	Speed)

ToolsAVP_Entity_Sentrygun* ToolsAVP_Entity_Sentrygun::s_pxThis = NULL;

ToolsAVP_Entity_Sentrygun::ToolsAVP_Entity_Sentrygun(AVP_ServerWeapon_Sentrygun* pxActor)
: Tools_Entity_PhysicalObject(pxActor)
, PARENT( pxActor )
, m_pxSentrygun( pxActor )
{
	Type = TOT_Entity_Sentrygun;
	SetMesh("ToolsShape_Sentry");
}

void ToolsAVP_Entity_Sentrygun::Project_Create()
{
	ToolsAVP_Entity_Sentrygun::Create( true );
}

Tools_Object* ToolsAVP_Entity_Sentrygun::Create( Asura_Entity* pxEntity )
{
	return new ToolsAVP_Entity_Sentrygun( AVP_ServerWeapon_Sentrygun::FindEntity(pxEntity->GetGuid()) );
}

Tools_Object* ToolsAVP_Entity_Sentrygun::Create( const bool bFullInit )
{
	// Get the user to pick a blueprint to initialise from.
	Asura_Hash_ID uBlueprintTypeHashID = uAVP_BLUEPRINT_TYPE_ACTORS;
	Asura_Hash_ID uBlueprintHashID     = 0xfd5d8ead;
	if ( bFullInit )
	{
		BlueprintSelect_Overlay xBPOverlay( "Choose A Blueprint", &uBlueprintHashID, &uBlueprintTypeHashID );
		if ( !xBPOverlay.DoModal() ) { return NULL; }
	}

	const Asura_Guid uGuid = Asura_Entity_System::GetCreatedByToolsGuid();

	// Set up tools data and auto-create a unique name (prompt for new name if there is a clash).
	Tools_Entity_Data* pxToolsData = CreateToolsDataWithDefaultName("Sentrygun", "Sentrygun", uGuid);
	if ( !pxToolsData ) { return NULL; }

	AVP_ServerWeapon_Sentrygun* pxServerObject = new AVP_ServerWeapon_Sentrygun(uGuid);
	if ( !pxServerObject )
	{
		delete pxToolsData;
		return NULL;
	}

	// Set the tools data before we create the tools object - otherwise it will have already been created!
	pxServerObject->ToolsData = pxToolsData;
	if ( bFullInit )
	{
		pxServerObject->SetPosition( pxToolsData->Position );
		pxServerObject->SetBlueprintTypeHashID( uBlueprintTypeHashID );
		pxServerObject->SetBlueprintHashID( uBlueprintHashID );
		pxServerObject->MakeAI();
		pxServerObject->CreateAndInitialiseBrain();
		pxServerObject->InitFromBlueprint();
	}

	ToolsAVP_Entity_Sentrygun* pxToolsObject = new ToolsAVP_Entity_Sentrygun( pxServerObject );
	if ( !pxToolsObject )
	{
		delete pxToolsObject;
		delete pxServerObject;
		return NULL;
	}
	Tools_Object_System::SelectObject(pxToolsObject);

	pxServerObject->SetBlueprintHashID( pxToolsObject->GetDefaultBlueprintHashID() );

	Tools_Timed_Message_System::AddMessage( Tools_Timed_Message_System::COLOUR_DEFAULT, "Created new Sentrygun." );
	Tools_SaveAsura::SetEntityModified();

	return pxToolsObject;
}

void ToolsAVP_Entity_Sentrygun::Copy( const Tools_Object* pxObject )
{
	PARENT::Copy( pxObject );

	AVP_ServerWeapon_Sentrygun* pxFrom = AVP_ServerWeapon_Sentrygun::FindEntity( pxObject->GetGuid() );
	if ( pxFrom )
	{
		m_pxSentrygun->m_bStartsEnabled			= pxFrom->m_bStartsEnabled;
		m_pxSentrygun->m_fVisionRange			= pxFrom->m_fVisionRange;
		m_pxSentrygun->m_fLethalRange			= pxFrom->m_fLethalRange;
		m_pxSentrygun->m_fTanHorHalfFOV			= pxFrom->m_fTanHorHalfFOV;
		m_pxSentrygun->m_fTanVertBottomHalfFOV	= pxFrom->m_fTanVertBottomHalfFOV;
		m_pxSentrygun->m_fTanVertTopHalfFOV		= pxFrom->m_fTanVertTopHalfFOV;
		m_pxSentrygun->m_fTanHalfFireArc		= pxFrom->m_fTanHalfFireArc;
		m_pxSentrygun->m_fSpeed					= pxFrom->m_fSpeed;
	}
}

void ToolsAVP_Entity_Sentrygun::AddOverlayControls( Asura_Overlay* pxOverlay, Asura_Vector_2& xOffset )
{
	PARENT::AddOverlayControls( pxOverlay, xOffset );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	Asura_Dialog* pxDialog = new Asura_FlagTickbox_Dialog( "Starts Enabled", xOffset, &m_pxSentrygun->m_uFlags, 0x00000001, &Changed );
	pxDialog->SetHelpText( "Sets whether the sentry gun will start in the enabled state (otherwise it must be enabled with a message before it will wake up)" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog( "Sweep Speed", xOffset, &g_xParam_Speed, 0.05f, 1.0f, 0.05f, "%0.2f" );
	pxDialog->SetHelpText( "Sets the speed at which the weapon sweeps from side to side (0.05 to 1.0)" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog( "Vision Range", xOffset, &g_xParam_FOVRange, 0.0f, 1000.0f, 1.0f, "%0.0f" );
	pxDialog->SetHelpText( "Sets the range for the field of view ( in meters )" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog( "Horizontal Field of View", xOffset, &g_xParam_HorFOV, 0.0f, 178.0f, 1.0f, "%0.0f" );
	pxDialog->SetHelpText( "Sets the horizontal field of view ( in degrees )" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog( "Vertical Field of View Top Half", xOffset, &g_xParam_VertTopHalfFOV, 0.0f, 30.0f, 1.0f, "%0.0f" );
	pxDialog->SetHelpText( "Sets the Vertical field of view From The Guns Forward UP( in degrees )" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog( "Vertical Field of View Bottom Half", xOffset, &g_xParam_VertBottomHalfFOV, 0.0f, 30.0f, 1.0f, "%0.0f" );
	pxDialog->SetHelpText( "Sets the Vertical field of view From The Gund Forward DOWN ( in degrees )" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog( "Preview FOV For Selected", xOffset, &s_bPreviewLineOfFireSelected );
	pxDialog->SetHelpText( "Preview the L.O.F. for the selected sentrygun" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog( "Preview FOV For All", xOffset, &s_bPreviewLineOfFireAll );
	pxDialog->SetHelpText( "Preview the L.O.F. for all sentryguns" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::LargeSpacing();

	pxDialog = new Asura_Numerical_Dialog( "Firing Arc", xOffset, &g_xParam_FireArc, 0.0f, 180.0f, 1.0f, "%0.0f" );
	pxDialog->SetHelpText( "Sets the horizontal angle that the gun will sweep for enemies ( in degrees )" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Numerical_Dialog( "Lethal Range", xOffset, &g_xParam_LethalRange, 0.0f, 1000.0f, 0.25f, "%0.2f" );
	pxDialog->SetHelpText( "Sets the range of lethal kills from the gun - where enemies will die with a single hit ( in meters )" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog( "Preview Fire Arc For Selected", xOffset, &s_bPreviewFireArcSelected );
	pxDialog->SetHelpText( "Preview the Fire Arc for the selected sentrygun" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::DefaultSpacing();

	pxDialog = new Asura_Tickbox_Dialog( "Preview Fire Arc For All", xOffset, &s_bPreviewFireArcAll );
	pxDialog->SetHelpText( "Preview the Fire Arc for all sentryguns" );
	pxOverlay->AddDialog( pxDialog );
	xOffset.y += Asura_Dialog::LargeSpacing();
}

void ToolsAVP_Entity_Sentrygun::AddFilesToExportList( List<Asura_String>& xNameList ) const
{
	// Call the base-function...
	PARENT::AddFilesToExportList( xNameList );

	Asura_Hash_ID uBPHash = m_pxSentrygun->GetBlueprintHashID();
	if ( uBPHash != ASURA_HASH_ID_UNSET )
	{
		const Asura_Blueprint* pxBlueprint = Asura_Blueprint_System::GetBlueprintByHashID( uAVP_BLUEPRINT_TYPE_ACTORS, uBPHash );
		if( pxBlueprint )
		{
			Asura_Hash_ID uContainerHash = ASURA_HASH_ID_UNSET;
			Asura_Value	xValue;

			if( pxBlueprint->GetParameterValueByHashID( 0x24D7901F /* "SentryGun.Beam.Red" */, xValue ) )	
			{
				//if we found the blueprint variable for the container get the hash value of it
				uContainerHash	= xValue.GetHashIDValue();
			
				Tools_Container* pxContainer = Tools_Container_System::FindContainerByHash(uContainerHash);
				if (pxContainer)
				{
					pxContainer->AddFilesToExportList(xNameList);
				}
			}	
		}

		Tools_Mode_Blueprint::AddBlueprintFilesToExportList( xNameList, uAVP_BLUEPRINT_TYPE_ACTORS, uBPHash, false );
	}
}

void ToolsAVP_Entity_Sentrygun::Render()
{
	PARENT::Render();

	Asura_Vector_3 xPos = m_pxSentrygun->GetPosition() + Asura_Vector_3( 0.0f, dbg_fMuzHeight, 0.0f );

	if ( s_bPreviewLineOfFireAll || ( s_bPreviewLineOfFireSelected && s_pxThis == this ) )
	{
		// work out verts of frustrum and add to global vector array. s_pxRenderVerts
		GetFrutumVertsWithTwoHorFovAngles( m_pxSentrygun->m_fVisionRange, m_pxSentrygun->m_fTanHorHalfFOV );

		bool bPrev = Asura_Render::GetEnableBatchedLineRendering();
		Asura_Render::SetEnableBatchedLineRendering(false);

		for (int iPass=0; iPass<2; iPass++)
		{
			// Pass 0 - Translucent bits - behind scenery
			// Pass 1 - Opaque visible bits
			if (iPass == 0)
			{
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled(false);
				Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_GREATER);
			}
			else
			{
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);
				Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);
			}		

			for(int i=0;i<4;i++)
			{
				uint32 uAlpha = (iPass==0)?0x20000000:0xff000000;				
				Asura_Render::RenderLine( xPos,					s_pxRenderVerts[i],				uAlpha|0x00666666);
				Asura_Render::RenderLine( s_pxRenderVerts[i],   s_pxRenderVerts[4+i],			uAlpha|0x00ff0000);
				Asura_Render::RenderLine( s_pxRenderVerts[i],   s_pxRenderVerts[(1+i)&3],		uAlpha|0x00ff0000);
				Asura_Render::RenderLine( s_pxRenderVerts[i+4],	s_pxRenderVerts[((1+i)&3)+4],	uAlpha|0x00ff0000);
			}
		}

		Asura_Render::SetEnableBatchedLineRendering(bPrev);
	}

	if ( s_bPreviewFireArcAll || ( s_bPreviewFireArcSelected && s_pxThis == this ) )
	{
		// work out verts of frustrum and add to global vector array. s_pxRenderVerts
		GetFrutumVertsWithTwoHorFovAngles( m_pxSentrygun->m_fVisionRange, m_pxSentrygun->m_fTanHalfFireArc );

		bool bPrev = Asura_Render::GetEnableBatchedLineRendering();
		Asura_Render::SetEnableBatchedLineRendering(false);

		for (int iPass=0; iPass<2; iPass++)
		{
			// Pass 0 - Translucent bits - behind scenery
			// Pass 1 - Opaque visible bits
			if (iPass == 0)
			{
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled(false);
				Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_GREATER);
			}
			else
			{
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);
				Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);
			}		

			for(int i=0;i<4;i++)
			{
				uint32 uAlpha = (iPass==0)?0x20000000:0xff000000;				
				Asura_Render::RenderLine( xPos,					s_pxRenderVerts[i],				uAlpha|0x00666666);
				Asura_Render::RenderLine( s_pxRenderVerts[i],   s_pxRenderVerts[4+i],			uAlpha|0x000000ff);	//blue
				Asura_Render::RenderLine( s_pxRenderVerts[i],   s_pxRenderVerts[(1+i)&3],		uAlpha|0x000000ff);
				Asura_Render::RenderLine( s_pxRenderVerts[i+4],	s_pxRenderVerts[((1+i)&3)+4],	uAlpha|0x000000ff);
			}
		}

		// work out verts of frustrum and add to global vector array. s_pxRenderVerts
		GetFrutumVertsWithTwoHorFovAngles( m_pxSentrygun->m_fLethalRange, m_pxSentrygun->m_fTanHalfFireArc );

		for (int iPass=0; iPass<2; iPass++)
		{
			// Pass 0 - Translucent bits - behind scenery
			// Pass 1 - Opaque visible bits
			if (iPass == 0)
			{
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled(false);
				Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_GREATER);
			}
			else
			{
				Asura_Render::CurrentStates.RequestZBufferWriteEnabled(true);
				Asura_Render::CurrentStates.RequestZBufferCompareMode(ASURA_ZBUFFERCMP_LESSEQUAL);
			}		

			for(int i=0;i<4;i++)
			{
				uint32 uAlpha = (iPass==0)?0x20000000:0xff000000;				
				Asura_Render::RenderLine( xPos,					s_pxRenderVerts[i],				uAlpha|0x00666666);
				Asura_Render::RenderLine( s_pxRenderVerts[i],   s_pxRenderVerts[4+i],			uAlpha|0x005500ff);	//purple
				Asura_Render::RenderLine( s_pxRenderVerts[i],   s_pxRenderVerts[(1+i)&3],		uAlpha|0x005500ff);
				Asura_Render::RenderLine( s_pxRenderVerts[i+4],	s_pxRenderVerts[((1+i)&3)+4],	uAlpha|0x005500ff);
			}
		}

		Asura_Render::SetEnableBatchedLineRendering(bPrev);
	}
}

bool ToolsAVP_Entity_Sentrygun::GetParameter( Asura_Hash_ID uParamID,class Tools_Parameter* pxParam ) const
{
	switch(uParamID)
	{
		case g_uHash_FOVRange:
		{
			pxParam->SetFloat( m_pxSentrygun->m_fVisionRange );
		}
		break;

		case g_uHash_LethalRange:
		{
			pxParam->SetFloat( m_pxSentrygun->m_fLethalRange );
		}
		break;

		case g_uHash_Speed:
		{
			pxParam->SetFloat( m_pxSentrygun->m_fSpeed );
		}
		break;

		case g_uHash_HorFOV:
		{
			pxParam->SetFloat( 2.0f * Asura_Maths::RadToDeg( Asura_Maths::ArcTangent( m_pxSentrygun->m_fTanHorHalfFOV, 1.0f ) ) );
		}
		break;

		case g_uHash_VertTopHalfFOV:
		{
			pxParam->SetFloat( Asura_Maths::RadToDeg( Asura_Maths::ArcTangent( m_pxSentrygun->m_fTanVertTopHalfFOV, 1.0f ) ) );
		}
		break;

		case g_uHash_VertBottomHalfFOV:
		{
			pxParam->SetFloat( Asura_Maths::RadToDeg( Asura_Maths::ArcTangent( m_pxSentrygun->m_fTanVertBottomHalfFOV, 1.0f ) ) );
		}
		break;

		case g_uHash_FireArc:
		{
			pxParam->SetFloat( 2.0f * Asura_Maths::RadToDeg( Asura_Maths::ArcTangent( m_pxSentrygun->m_fTanHalfFireArc, 1.0f ) ) );
		}
		break;

		default :
		{
			return PARENT::GetParameter(uParamID, pxParam);
		}
	}
	return true;
}

bool ToolsAVP_Entity_Sentrygun::SetParameter( Asura_Hash_ID uParamID,const class Tools_Parameter* pxParam )
{
	switch(uParamID)
	{
		case g_uHash_FOVRange:
		{
			m_pxSentrygun->m_fVisionRange = pxParam->GetFloat();

			if( m_pxSentrygun->m_fVisionRange < m_pxSentrygun->m_fLethalRange )
			{
				// if the vision range is smaller than the lethal range then lower the lethal as well. 
				m_pxSentrygun->m_fLethalRange = m_pxSentrygun->m_fVisionRange;
			}
		}
		break;

		case g_uHash_LethalRange:
		{
			m_pxSentrygun->m_fLethalRange = pxParam->GetFloat();

			if( m_pxSentrygun->m_fLethalRange > m_pxSentrygun->m_fVisionRange )
			{
				// if the lethal range is larger than the vision range clip it back to the vision range. 
				m_pxSentrygun->m_fLethalRange = m_pxSentrygun->m_fVisionRange;
			}
		}
		break;

		case g_uHash_Speed:
		{
			m_pxSentrygun->m_fSpeed = pxParam->GetFloat();
		}
		break;

		case g_uHash_HorFOV:
		{
			m_pxSentrygun->m_fTanHorHalfFOV = Asura_Maths::Tangent( Asura_Maths::DegToRad( 0.5f * pxParam->GetFloat() ) );

			if( m_pxSentrygun->m_fTanHorHalfFOV > m_pxSentrygun->m_fTanHalfFireArc )
			{
				// make sure the FOV is always the same or smaller than the fire arc
				m_pxSentrygun->m_fTanHalfFireArc = m_pxSentrygun->m_fTanHorHalfFOV;
			}
		}
		break;

		case g_uHash_VertTopHalfFOV:
		{
			m_pxSentrygun->m_fTanVertTopHalfFOV = Asura_Maths::Tangent( Asura_Maths::DegToRad( pxParam->GetFloat() ) );
		}
		break;

		case g_uHash_VertBottomHalfFOV:
		{
			m_pxSentrygun->m_fTanVertBottomHalfFOV = Asura_Maths::Tangent( Asura_Maths::DegToRad( pxParam->GetFloat() ) );
		}
		break;

		case g_uHash_FireArc:
		{
			m_pxSentrygun->m_fTanHalfFireArc = Asura_Maths::Tangent( Asura_Maths::DegToRad( 0.5f * pxParam->GetFloat() ) );

			if( m_pxSentrygun->m_fTanHalfFireArc < m_pxSentrygun->m_fTanHorHalfFOV )
			{
				//make sure the fire arc is always the same or larger than the FOV
				m_pxSentrygun->m_fTanHorHalfFOV = m_pxSentrygun->m_fTanHalfFireArc;
			}
		}
		break;

		default :
		{
			return PARENT::SetParameter(uParamID, pxParam);
		}
	}
	
	SetEntityModified();
	return true;
}

bool ToolsAVP_Entity_Sentrygun::HandlesThisMessage( int iMessageID )
{ 
	switch( iMessageID )
	{
		////////////////////
		case AVP_MSGID_SENTRYGUN_ENABLE:
		case AVP_MSGID_SENTRYGUN_DISABLE:
		case AVP_MSGID_SENTRYGUN_DESTROY:
		case AVP_MSGID_SET_SENTRYGUN_SWEEP_SPEED:
		case AVP_MSGID_SET_SENTRYGUN_VISION_RANGE:
		case AVP_MSGID_SET_SENTRYGUN_HOR_FOV:
		case AVP_MSGID_SET_SENTRYGUN_VER_FOV:
		case AVP_MSGID_SET_SENTRYGUN_FIRING_ARC:
		case AVP_MSGID_SET_SENTRYGUN_LETHAL_RANGE:
		case AVP_MSGID_SENTRYGUN_DRYFIRE_TOGGLE:
		////////////////////
		{
			return true;
		}
		////////////////////
		default:
		////////////////////
		{
			return PARENT::HandlesThisMessage( iMessageID );
		}
	}
}

void ToolsAVP_Entity_Sentrygun::GetFrutumVertsWithTwoHorFovAngles( float fVisionRange, float fTanHorHalfFOV )
{
	Asura_Vector_3 xPos = m_pxSentrygun->GetPosition() + Asura_Vector_3( 0.0f, dbg_fMuzHeight, 0.0f );
	const Asura_Matrix_3x3& xOri = m_pxSentrygun->GetOrientation();

	Asura_Frustum xFrustum;
	Asura_Vector_3 pxTopVerts[ Asura_Frustum::MAX_VERTICES ];
	Asura_Vector_3 pxBottomVerts[ Asura_Frustum::MAX_VERTICES ];

	// get the vert for a frustrum with the top half Vert FOV angle
	xFrustum.SetForFOV( 0.0f, fVisionRange, fTanHorHalfFOV, m_pxSentrygun->m_fTanVertTopHalfFOV );
	xFrustum.GenerateVertices( pxTopVerts, xPos, xOri );

	// get the vert for a frustrum with the bottom half Vert FOV angle
	xFrustum.SetForFOV( 0.0f, fVisionRange, fTanHorHalfFOV, m_pxSentrygun->m_fTanVertBottomHalfFOV );
	xFrustum.GenerateVertices( pxBottomVerts, xPos, xOri );

	// now set the verts into the render verts array. 
	s_pxRenderVerts[0] = pxTopVerts[0];
	s_pxRenderVerts[1] = pxTopVerts[1];
	s_pxRenderVerts[2] = pxTopVerts[2];
	s_pxRenderVerts[3] = pxTopVerts[3];

	s_pxRenderVerts[4] = pxBottomVerts[4];
	s_pxRenderVerts[5] = pxBottomVerts[5];
	s_pxRenderVerts[6] = pxTopVerts[6];
	s_pxRenderVerts[7] = pxTopVerts[7];
}

