Files
GTASource/game/pathserver/NavEdit.cpp
expvintl 419f2e4752 init
2025-02-23 17:40:52 +08:00

1682 lines
56 KiB
C++

#include "navedit.h"
#if __NAVEDITORS
#include "bank/bank.h"
#include "bank/bkmgr.h"
#include "bank/combo.h"
#include "bank/slider.h"
#include "ai/navmesh/navmeshoptimisations.h"
#include "camera/CamInterface.h"
#include "camera/debug/DebugDirector.h"
#include "camera/helpers/Frame.h"
#include "camera/viewports/Viewport.h"
#include "Debug/DebugScene.h"
#include "pathserver/PathServer.h"
#include "Peds/Ped.h"
#include "Peds/PlayerInfo.h"
#include "task/Combat/Cover/cover.h"
NAVMESH_OPTIMISATIONS()
namespace rage
{
bool CNavResAreaEditor::m_bEditorInitialised = false;
bool CNavResAreaEditor::m_bActive = false;
CNavResAreaEditor::EditorState CNavResAreaEditor::m_iState = CNavResAreaEditor::STATE_NONE;
int CNavResAreaEditor::m_iCurrentArea = -1;
int CNavResAreaEditor::m_iCurrentResMultCombo = 1;
bool CNavResAreaEditor::m_bCurrentAreaFlag_DoNotOptimise = false;
bool CNavResAreaEditor::m_bCurrentAreaFlag_NoCover = false;
bool CNavResAreaEditor::m_bCurrentAreaFlag_NoDrops = false;
bool CNavResAreaEditor::m_bCurrentAreaFlag_NoClimbs = false;
bool CNavResAreaEditor::m_bCurrentAreaFlag_NoCullSmallAreas = false;
CNavResArea CNavResAreaEditor::m_CurrentArea;
atArray<CNavResArea*> CNavResAreaEditor::m_ResAreas;
float CNavResAreaEditor::m_fSizeStep = 1.0f;
bool CNavResAreaEditor::m_bSizeFromCenter = false;
int CNavResAreaEditor::m_iWarpNavMeshX = 0;
int CNavResAreaEditor::m_iWarpNavMeshY = 0;
bkSlider * CNavResAreaEditor::m_pCurrentAreaSlider = NULL;
const Vector3 CNavResAreaEditor::ms_vDefaultAreaSize(4.0f, 4.0f, 2.0f);
const float CNavResAreaEditor::ms_fDefaultResolution = 1.0f;
const int CNavResAreaEditor::ms_iXmlVersion = 1;
// CNavDataCoverpointEditor statics:
// -- public --
const int CNavDataCoverpointEditor::ms_iXmlVersion = 1;
// -- private --
bool CNavDataCoverpointEditor::ms_bEditorInitialized = false;
bool CNavDataCoverpointEditor::ms_bActive = false;
bool CNavDataCoverpointEditor::ms_bDisplayExistingMapPointProximity = false;
int CNavDataCoverpointEditor::ms_iSelectedDataCoverpointIndex = -1;
atArray<CNavDataCoverpoint*> CNavDataCoverpointEditor::ms_aDataCoverpoints;
u8 CNavDataCoverpointEditor::ms_uCurrentCoverpointDirection = 0;
u8 CNavDataCoverpointEditor::ms_uCurrentCoverpointType = 0;
bkSlider* CNavDataCoverpointEditor::ms_pCurrentCoverpointIndexSlider = NULL;
bkSlider* CNavDataCoverpointEditor::ms_pCurrentCoverpointDirectionSlider = NULL;
int CNavDataCoverpointEditor::ms_iStatusCheckDataCoverpointIndex = -1;
s32 CNavDataCoverpointEditor::ms_iTempCoverPointIndex = -1;
CCoverPointStatusHelper CNavDataCoverpointEditor::ms_CoverPointStatusHelper;
// --
CNavResAreaEditor::CNavResAreaEditor()
{
}
CNavResAreaEditor::~CNavResAreaEditor()
{
}
void CNavResAreaEditor::Init()
{
bkBank * pBank = BANKMGR.FindBank("Navigation");
if(!pBank)
{
Assertf(false, "Couldn't locate \"Navigation\" bank.");
return;
}
pBank->AddButton("Initialise Nav Res Editor", OnInitEditor);
}
void CNavResAreaEditor::InitWidgets()
{
bkBank * pBank = BANKMGR.FindBank("Navigation");
if(!pBank)
{
Assertf(false, "Couldn't locate \"Navigation\" bank.");
return;
}
static const char * pResMultipliers[] = { "1x", "2x", "4x", "8x" };
pBank->PushGroup("ResArea Editor");
pBank->AddToggle("Editor Active", &m_bActive);
pBank->AddSeparator();
pBank->AddButton("New Area", OnNewArea);
pBank->AddButton("New Area (doorway default)", OnNewAreaDoorway);
pBank->AddButton("Delete Area", OnDeleteArea);
pBank->AddButton("Duplicate Area", OnDuplicateArea);
m_pCurrentAreaSlider = pBank->AddSlider("Current Area", &m_iCurrentArea, -1, m_ResAreas.GetCount()-1, 1, OnSelectArea);
pBank->AddButton("Warp Here", OnWarpToArea);
pBank->AddSeparator("Area Details..");
pBank->AddCombo("Resolution Multiplier:", &m_iCurrentResMultCombo, 4, pResMultipliers, OnSelectResolutionMultiplier, "Selects resolution multiplier for current selected area");
pBank->PushGroup("Flags", false);
pBank->AddToggle("DO NOT OPTIMISE", &m_bCurrentAreaFlag_DoNotOptimise, OnToggleFlag_DoNotOptimise);
pBank->AddToggle("NO COVER", &m_bCurrentAreaFlag_NoCover, OnToggleFlag_NoCover);
pBank->AddToggle("NO DROPS", &m_bCurrentAreaFlag_NoDrops, OnToggleFlag_NoDrops);
pBank->AddToggle("NO CLIMBS", &m_bCurrentAreaFlag_NoClimbs, OnToggleFlag_NoClimbs);
pBank->AddToggle("NO CULL SMALL AREAS", &m_bCurrentAreaFlag_NoCullSmallAreas, OnToggleFlag_NoCullSmallAreas);
pBank->PopGroup();
pBank->AddSeparator("");
pBank->PushGroup("Position");
pBank->AddButton("Nudge +X", OnNudgeAreaPosX);
pBank->AddButton("Nudge -X", OnNudgeAreaNegX);
pBank->AddButton("Nudge +Y", OnNudgeAreaPosY);
pBank->AddButton("Nudge -Y", OnNudgeAreaNegY);
pBank->AddButton("Nudge +Z", OnNudgeAreaPosZ);
pBank->AddButton("Nudge -Z", OnNudgeAreaNegZ);
pBank->PopGroup();
pBank->PushGroup("Size");
//pBank->AddSlider("Size Step", &m_fSizeStep, 1.0f, 10.0f, 1.0f);
pBank->AddToggle("Size from center", &m_bSizeFromCenter);
pBank->AddButton("Increase Size X (Width)", OnIncreaseWidth);
pBank->AddButton("Increase Size Y (Depth)", OnIncreaseDepth);
pBank->AddButton("Increase Size Z (Height)", OnIncreaseHeight);
pBank->AddButton("Decrease Size X (Width)", OnDecreaseWidth);
pBank->AddButton("Decrease Size Y (Depth)", OnDecreaseDepth);
pBank->AddButton("Decrease Size Z (Height)", OnDecreaseHeight);
pBank->PopGroup();
pBank->PushGroup("Save/Load");
pBank->AddButton("Save..", OnSave);
pBank->AddButton("Load..", OnLoad);
pBank->PopGroup();
pBank->PushGroup("Warp to navmesh coords");
pBank->AddSlider("X: ", &m_iWarpNavMeshX, 0, CPathServerExtents::GetWorldWidthInSectors(), CPathServerExtents::m_iNumSectorsPerNavMesh);
pBank->AddSlider("Y: ", &m_iWarpNavMeshY, 0, CPathServerExtents::GetWorldDepthInSectors(), CPathServerExtents::m_iNumSectorsPerNavMesh);
pBank->AddButton("Warp", OnWarpToNavmeshCoords);
pBank->PopGroup();
}
void CNavResAreaEditor::Update()
{
if(!m_bEditorInitialised || !m_bActive)
return;
ProcessInput();
}
void CNavResAreaEditor::Render()
{
if(!m_bEditorInitialised || !m_bActive)
return;
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
Matrix34 matAxis;
matAxis.Identity();
char text[16];
const float fMaxRange = 200.0f;
const float fGridRange = 50.0f;
for(int r=0; r<m_ResAreas.GetCount(); r++)
{
CNavResArea * pArea = m_ResAreas[r];
const Vector3 vMid = (pArea->m_vMin + pArea->m_vMax) * 0.5f;
const float fDistSqr = (vMid - vOrigin).Mag2();
if(fDistSqr < fMaxRange*fMaxRange)
{
const float fDist = sqrtf(fDistSqr);
const float fBoxAlpha = Clamp(1.0f - (fDist / fMaxRange), 0.0f, 1.0f);
const float fGridAlpha = Clamp(1.0f - (fDist / fGridRange), 0.0f, 1.0f);
Color32 iBoxCol = (r == m_iCurrentArea) ? Color_green : Color_DimGray;
Color32 iGridCol = (r == m_iCurrentArea) ? Color_cyan3 : Color_grey49;
Color32 iTextCol = Color_red;
iBoxCol.SetAlpha((int)(fBoxAlpha*255.0f));
iGridCol.SetAlpha((int)(fGridAlpha*255.0f));
iTextCol.SetAlpha((int)(fGridAlpha*255.0f));
grcDebugDraw::BoxAxisAligned(RCC_VEC3V(pArea->m_vMin), RCC_VEC3V(pArea->m_vMax), iBoxCol, false);
if(fGridAlpha > 0.0f)
{
DrawSamplingGrid(pArea, iGridCol);
matAxis.d = vMid;
grcDebugDraw::Axis(matAxis, 1.0f, true);
sprintf(text, "(%i) x%i", r, 1<<(pArea->m_iResMult+1) );
grcDebugDraw::Text(vMid, iTextCol, 0, 0, text);
int iY = grcDebugDraw::GetScreenSpaceTextHeight();
if((pArea->m_iFlags & CNavResArea::FLAG_DO_NOT_OPTIMISE)!=0)
grcDebugDraw::Text(vMid, iTextCol, 0, iY+=grcDebugDraw::GetScreenSpaceTextHeight(), "DO NOT OPTIMISE");
if((pArea->m_iFlags & CNavResArea::FLAG_NO_COVER)!=0)
grcDebugDraw::Text(vMid, iTextCol, 0, iY+=grcDebugDraw::GetScreenSpaceTextHeight(), "NO COVER");
if((pArea->m_iFlags & CNavResArea::FLAG_NO_DROPS)!=0)
grcDebugDraw::Text(vMid, iTextCol, 0, iY+=grcDebugDraw::GetScreenSpaceTextHeight(), "NO DROPS");
if((pArea->m_iFlags & CNavResArea::FLAG_NO_CLIMBS)!=0)
grcDebugDraw::Text(vMid, iTextCol, 0, iY+=grcDebugDraw::GetScreenSpaceTextHeight(), "NO CLIMBS");
if((pArea->m_iFlags & CNavResArea::FLAG_NO_CULL_SMALL_AREAS)!=0)
grcDebugDraw::Text(vMid, iTextCol, 0, iY+=grcDebugDraw::GetScreenSpaceTextHeight(), "NO CULL SMALL AREAS");
}
}
}
}
void CNavResAreaEditor::DrawSamplingGrid(CNavResArea * pArea, const Color32 iCol)
{
if(pArea->m_iResMult==-1)
return;
const float fStep = pArea->GetStep();
for(float y=pArea->m_vMin.y; y<=pArea->m_vMax.y; y+=fStep)
{
for(float x=pArea->m_vMin.x; x<=pArea->m_vMax.x; x+=fStep)
{
Vector3 vStart(x, y, pArea->m_vMin.z);
Vector3 vEnd(x, y, pArea->m_vMax.z);
grcDebugDraw::Line(vStart, vEnd, iCol);
}
}
}
void CNavResAreaEditor::LoadMetadata()
{
// switch to debug allocator
// switch back to game allocator
}
void CNavResAreaEditor::ProcessInput()
{
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
bool bLeftButtonDown = (ioMouse::GetPressedButtons() & ioMouse::MOUSE_LEFT)? true : false;
bool bRightButtonDown = (ioMouse::GetPressedButtons() & ioMouse::MOUSE_RIGHT)? true : false;
switch(m_iState)
{
case STATE_NONE:
{
if(bLeftButtonDown)
{
Vector3 vPickPos;
if(CDebugScene::GetWorldPositionUnderMouse(vPickPos))
{
int iArea = FindResAreaClosestToPos(vPickPos, 200.0f);
if(iArea != -1)
{
m_iCurrentArea = iArea;
OnSelectArea();
}
}
}
else if(bRightButtonDown)
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
Vector3 vPickPos;
if(CDebugScene::GetWorldPositionUnderMouse(vPickPos))
{
RoundToNearest(vPickPos);
// TODO: we should really also ensure vPickPos components are multiples of ms_fDefaultResolution
Vector3 vMid = (m_CurrentArea.m_vMin + m_CurrentArea.m_vMax) * 0.5f;
Vector3 vDelta = vPickPos - vMid;
m_CurrentArea.m_vMin += vDelta;
m_CurrentArea.m_vMax += vDelta;
RoundToNearest(m_CurrentArea.m_vMin);
RoundToNearest(m_CurrentArea.m_vMax);
if(m_CurrentArea.m_vMax.x == m_CurrentArea.m_vMin.x) m_CurrentArea.m_vMax.x += 1.0f;
if(m_CurrentArea.m_vMax.y == m_CurrentArea.m_vMin.y) m_CurrentArea.m_vMax.y += 1.0f;
if(m_CurrentArea.m_vMax.z == m_CurrentArea.m_vMin.z) m_CurrentArea.m_vMax.z += 1.0f;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
m_iCurrentResMultCombo = m_CurrentArea.m_iResMult+1;
}
}
}
break;
}
default:
break;
}
}
int CNavResAreaEditor::FindResAreaClosestToPos(const Vector3 & vPos, const float fMaxDist)
{
float fClosestDistSqr = FLT_MAX;
int iClosest = -1;
for(int r=0; r<m_ResAreas.GetCount(); r++)
{
CNavResArea * pArea = m_ResAreas[r];
Vector3 vCenter = (pArea->m_vMin + pArea->m_vMax) * 0.5f;
const float fDistSqr = (vPos - vCenter).Mag2();
if(fDistSqr < fMaxDist && fDistSqr < fClosestDistSqr)
{
fClosestDistSqr = fDistSqr;
iClosest = r;
}
}
return iClosest;
}
//---------------------------------------------------------------------------------
void CNavResAreaEditor::OnInitEditor()
{
if(!m_bEditorInitialised || !m_bActive)
{
InitWidgets();
m_bEditorInitialised = true;
m_bActive = true;
}
}
void CNavResAreaEditor::OnSelectArea()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea = *m_ResAreas[m_iCurrentArea];
m_iCurrentResMultCombo = m_CurrentArea.m_iResMult+1;
m_bCurrentAreaFlag_DoNotOptimise = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_DO_NOT_OPTIMISE)) !=0);
m_bCurrentAreaFlag_NoCover = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_COVER)) !=0);
m_bCurrentAreaFlag_NoDrops = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_DROPS)) !=0);
m_bCurrentAreaFlag_NoClimbs = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_CLIMBS)) !=0);
m_bCurrentAreaFlag_NoCullSmallAreas = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_CULL_SMALL_AREAS)) !=0);
}
}
void CNavResAreaEditor::OnNewArea()
{
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
AddNewArea(vOrigin, ms_vDefaultAreaSize.x, ms_vDefaultAreaSize.y, ms_vDefaultAreaSize.z);
}
void CNavResAreaEditor::OnNewAreaDoorway()
{
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
AddNewArea(vOrigin, 1.0f, 1.0f, 1.0f);
}
void CNavResAreaEditor::AddNewArea(const Vector3 & vOriginIn, const float fWidth, const float fDepth, const float fHeight)
{
USE_DEBUG_MEMORY(); // Ensure that we alloc from any free memory devkit may have
CNavResArea * pNewArea = rage_new CNavResArea();
Vector3 vOrigin = vOriginIn;
RoundToNearest(vOrigin);
pNewArea->m_vMin = vOrigin - (Vector3(fWidth, fDepth, fHeight) * 0.5f);
pNewArea->m_vMax = vOrigin + (Vector3(fWidth, fDepth, fHeight) * 0.5f);
pNewArea->m_iResMult = 0;
m_ResAreas.PushAndGrow(pNewArea);
m_iCurrentArea = m_ResAreas.GetCount()-1;
m_pCurrentAreaSlider->SetRange((float)-1, (float)m_ResAreas.GetCount()-1);
m_CurrentArea = *pNewArea;
m_iCurrentResMultCombo = m_CurrentArea.m_iResMult+1;
m_bCurrentAreaFlag_DoNotOptimise = false;
m_bCurrentAreaFlag_NoCover = false;
m_bCurrentAreaFlag_NoDrops = false;
m_bCurrentAreaFlag_NoClimbs = false;
m_bCurrentAreaFlag_NoCullSmallAreas = false;
}
void CNavResAreaEditor::OnDeleteArea()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
CNavResArea * pArea = m_ResAreas[m_iCurrentArea];
delete pArea;
m_ResAreas.Delete(m_iCurrentArea);
m_pCurrentAreaSlider->SetRange((float)-1, (float)m_ResAreas.GetCount()-1);
if(m_iCurrentArea >= m_ResAreas.GetCount())
m_iCurrentArea--;
if(m_iCurrentArea >= 0)
{
m_CurrentArea = *m_ResAreas[m_iCurrentArea];
m_iCurrentResMultCombo = m_CurrentArea.m_iResMult+1;
m_bCurrentAreaFlag_DoNotOptimise = (m_CurrentArea.m_iFlags & (CNavResArea::FLAG_DO_NOT_OPTIMISE));
m_bCurrentAreaFlag_NoCover = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_COVER)) !=0);
m_bCurrentAreaFlag_NoDrops = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_DROPS)) !=0);
m_bCurrentAreaFlag_NoClimbs = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_CLIMBS)) !=0);
m_bCurrentAreaFlag_NoCullSmallAreas = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_CULL_SMALL_AREAS)) !=0);
}
else
{
m_CurrentArea.Clear();
}
}
}
void CNavResAreaEditor::OnDuplicateArea()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
const int iOriginalArea = m_iCurrentArea;
const Vector3 vSize = m_CurrentArea.m_vMax - m_CurrentArea.m_vMin;
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
AddNewArea(vOrigin, vSize.x, vSize.y, vSize.z);
m_ResAreas[m_iCurrentArea]->m_iResMult = m_ResAreas[iOriginalArea]->m_iResMult;
m_ResAreas[m_iCurrentArea]->m_iFlags = m_ResAreas[iOriginalArea]->m_iFlags;
m_CurrentArea = *m_ResAreas[m_iCurrentArea];
m_iCurrentResMultCombo = m_CurrentArea.m_iResMult+1;
m_bCurrentAreaFlag_DoNotOptimise = (m_CurrentArea.m_iFlags & (CNavResArea::FLAG_DO_NOT_OPTIMISE));
m_bCurrentAreaFlag_NoCover = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_COVER)) !=0);
m_bCurrentAreaFlag_NoDrops = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_DROPS)) !=0);
m_bCurrentAreaFlag_NoClimbs = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_CLIMBS)) !=0);
m_bCurrentAreaFlag_NoCullSmallAreas = ((m_CurrentArea.m_iFlags & (CNavResArea::FLAG_NO_CULL_SMALL_AREAS)) !=0);
}
}
void CNavResAreaEditor::OnWarpToArea()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
Vector3 vMid = (m_CurrentArea.m_vMin + m_CurrentArea.m_vMax) * 0.5f;
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
pPlayer->Teleport(vMid, pPlayer->GetCurrentHeading(), false);
}
}
}
void CNavResAreaEditor::OnWarpToNavmeshCoords()
{
TNavMeshIndex iNavMesh = CPathServerGta::GetNavMeshIndexFromSector(m_iWarpNavMeshX, m_iWarpNavMeshY, kNavDomainRegular);
if(iNavMesh != NAVMESH_NAVMESH_INDEX_NONE)
{
Vector2 vMin,vMax;
CPathServerGta::GetNavMeshExtentsFromIndex(iNavMesh, vMin, vMax, kNavDomainRegular);
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
Vector3 vPos((vMin.x + vMax.x)*0.5f, (vMin.y + vMax.y)*0.5f, pPlayer->GetTransform().GetPosition().GetZf());
pPlayer->Teleport(vPos, pPlayer->GetCurrentHeading(), false);
}
}
}
void CNavResAreaEditor::OnSelectResolutionMultiplier()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_iResMult = m_iCurrentResMultCombo-1;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnToggleFlag_DoNotOptimise()
{
if(m_bCurrentAreaFlag_DoNotOptimise)
m_CurrentArea.m_iFlags |= CNavResArea::FLAG_DO_NOT_OPTIMISE;
else
m_CurrentArea.m_iFlags &= ~CNavResArea::FLAG_DO_NOT_OPTIMISE;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
void CNavResAreaEditor::OnToggleFlag_NoCover()
{
if(m_bCurrentAreaFlag_NoCover)
m_CurrentArea.m_iFlags |= CNavResArea::FLAG_NO_COVER;
else
m_CurrentArea.m_iFlags &= ~CNavResArea::FLAG_NO_COVER;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
void CNavResAreaEditor::OnToggleFlag_NoDrops()
{
if(m_bCurrentAreaFlag_NoDrops)
m_CurrentArea.m_iFlags |= CNavResArea::FLAG_NO_DROPS;
else
m_CurrentArea.m_iFlags &= ~CNavResArea::FLAG_NO_DROPS;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
void CNavResAreaEditor::OnToggleFlag_NoClimbs()
{
if(m_bCurrentAreaFlag_NoClimbs)
m_CurrentArea.m_iFlags |= CNavResArea::FLAG_NO_CLIMBS;
else
m_CurrentArea.m_iFlags &= ~CNavResArea::FLAG_NO_CLIMBS;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
void CNavResAreaEditor::OnToggleFlag_NoCullSmallAreas()
{
if(m_bCurrentAreaFlag_NoCullSmallAreas)
m_CurrentArea.m_iFlags |= CNavResArea::FLAG_NO_CULL_SMALL_AREAS;
else
m_CurrentArea.m_iFlags &= ~CNavResArea::FLAG_NO_CULL_SMALL_AREAS;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
void CNavResAreaEditor::OnNudgeAreaPosX()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMin.x += ms_fDefaultResolution;
m_CurrentArea.m_vMax.x += ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnNudgeAreaNegX()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMin.x -= ms_fDefaultResolution;
m_CurrentArea.m_vMax.x -= ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnNudgeAreaPosY()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMin.y += ms_fDefaultResolution;
m_CurrentArea.m_vMax.y += ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnNudgeAreaNegY()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMin.y -= ms_fDefaultResolution;
m_CurrentArea.m_vMax.y -= ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnNudgeAreaPosZ()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMin.z += ms_fDefaultResolution;
m_CurrentArea.m_vMax.z += ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnNudgeAreaNegZ()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMin.z -= ms_fDefaultResolution;
m_CurrentArea.m_vMax.z -= ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnIncreaseWidth()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMax.x += m_fSizeStep;
if(m_bSizeFromCenter)
m_CurrentArea.m_vMin.x -= m_fSizeStep;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnDecreaseWidth()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMax.x -= m_fSizeStep;
if(m_bSizeFromCenter)
m_CurrentArea.m_vMin.x += m_fSizeStep;
if(m_CurrentArea.m_vMax.x - m_CurrentArea.m_vMin.x < ms_fDefaultResolution)
m_CurrentArea.m_vMax.x = m_CurrentArea.m_vMin.x + ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnIncreaseDepth()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMax.y += m_fSizeStep;
if(m_bSizeFromCenter)
m_CurrentArea.m_vMin.y -= m_fSizeStep;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnDecreaseDepth()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMax.y -= m_fSizeStep;
if(m_bSizeFromCenter)
m_CurrentArea.m_vMin.y += m_fSizeStep;
if(m_CurrentArea.m_vMax.y - m_CurrentArea.m_vMin.y < ms_fDefaultResolution)
m_CurrentArea.m_vMax.y = m_CurrentArea.m_vMin.y + ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnIncreaseHeight()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMax.z += m_fSizeStep;
if(m_bSizeFromCenter)
m_CurrentArea.m_vMin.z -= m_fSizeStep;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::OnDecreaseHeight()
{
if(m_iCurrentArea >= 0 && m_iCurrentArea < m_ResAreas.GetCount())
{
m_CurrentArea.m_vMax.z -= m_fSizeStep;
if(m_bSizeFromCenter)
m_CurrentArea.m_vMin.z += m_fSizeStep;
if(m_CurrentArea.m_vMax.z - m_CurrentArea.m_vMin.z < ms_fDefaultResolution)
m_CurrentArea.m_vMax.z = m_CurrentArea.m_vMin.z + ms_fDefaultResolution;
*m_ResAreas[m_iCurrentArea] = m_CurrentArea;
}
}
void CNavResAreaEditor::RemoveAllAreas()
{
for(int r=0; r<m_ResAreas.GetCount(); r++)
{
CNavResArea * pArea = m_ResAreas[r];
delete pArea;
}
m_ResAreas.clear();
m_iCurrentResMultCombo = 0;
m_iCurrentArea = -1;
m_CurrentArea.Clear();
m_bCurrentAreaFlag_DoNotOptimise = false;
m_bCurrentAreaFlag_NoCover = false;
m_bCurrentAreaFlag_NoDrops = false;
m_bCurrentAreaFlag_NoClimbs = false;
m_bCurrentAreaFlag_NoCullSmallAreas = false;
}
void CNavResAreaEditor::OnSave()
{
USE_DEBUG_MEMORY();
char filename[512] = { 0 };
bool bOk = BANKMGR.OpenFile(filename, 512, "*.xml", true, "Navmesh Resolution Areas XML");
if(!bOk)
return;
parTree *pTree = rage_new parTree();
Assert(pTree);
parTreeNode* pRootNode = pTree->CreateRoot();
Assert(pRootNode);
parElement& rootElm = pRootNode->GetElement();
rootElm.SetName("NavResAreas");
rootElm.AddAttribute("Version", ms_iXmlVersion, false);
pTree->SetRoot(pRootNode);
parTreeNode * pAreasListXmlNode = rage_new parTreeNode();
Assert(pAreasListXmlNode);
pAreasListXmlNode->GetElement().SetName("Areas");
pAreasListXmlNode->AppendAsChildOf(pRootNode);
for(int r=0; r<m_ResAreas.GetCount(); r++)
{
CNavResArea * pResArea = m_ResAreas[r];
parTreeNode * pAreaXmlNode = rage_new parTreeNode();
Assert(pAreaXmlNode);
pAreaXmlNode->GetElement().SetName("Area");
pAreaXmlNode->GetElement().AddAttribute("MinX", pResArea->m_vMin.x, false);
pAreaXmlNode->GetElement().AddAttribute("MinY", pResArea->m_vMin.y, false);
pAreaXmlNode->GetElement().AddAttribute("MinZ", pResArea->m_vMin.z, false);
pAreaXmlNode->GetElement().AddAttribute("MaxX", pResArea->m_vMax.x, false);
pAreaXmlNode->GetElement().AddAttribute("MaxY", pResArea->m_vMax.y, false);
pAreaXmlNode->GetElement().AddAttribute("MaxZ", pResArea->m_vMax.z, false);
pAreaXmlNode->GetElement().AddAttribute("ResMult", pResArea->m_iResMult, false);
pAreaXmlNode->GetElement().AddAttribute("Flags", pResArea->m_iFlags, false);
pAreaXmlNode->AppendAsChildOf(pAreasListXmlNode);
}
const bool bSaveRes = PARSER.SaveTree(filename, "", pTree, parManager::XML);
if(!bSaveRes)
{
Assertf(false, "Failed to save Navmesh Resolution Areas XML '%s'.", filename);
delete pTree;
return;
}
delete pTree;
}
void CNavResAreaEditor::OnLoad()
{
USE_DEBUG_MEMORY();
char filename[512] = { 0 };
bool bOk = BANKMGR.OpenFile(filename, 512, "*.xml", false, "Navmesh Resolution Areas XML");
if(!bOk)
return;
RemoveAllAreas();
parTree * pTree = PARSER.LoadTree(filename, "");
Assert(pTree);
const parTreeNode* pRootNode = pTree->GetRoot();
Assert(pRootNode);
Assert(stricmp(pRootNode->GetElement().GetName(), "NavResAreas") == 0);
// Make sure we have the correct version.
ASSERT_ONLY(int version = pRootNode->GetElement().FindAttributeIntValue("Version", 0));
Assert(version >= ms_iXmlVersion);
//ASSERT_ONLY(int iNumAreas = pRootNode->GetElement().FindAttributeIntValue("NumAreas", 0));
parTreeNode::ChildNodeIterator i = pRootNode->BeginChildren();
for(; i != pRootNode->EndChildren(); ++i)
{
if(stricmp((*i)->GetElement().GetName(), "Areas") == 0)
{
// Go over any and all the child DOM trees and DOM nodes off of the list.
int areaIndex = 0;
parTreeNode::ChildNodeIterator j = (*i)->BeginChildren();
for(; j != (*i)->EndChildren(); ++j)
{
Assert(stricmp((*j)->GetElement().GetName(), "Area") == 0);
//Assertf(areaIndex < iNumAreas, "More areas than expected encountered.");
CNavResArea * pArea = rage_new CNavResArea();
m_ResAreas.PushAndGrow(pArea);
pArea->m_vMin.x = (*j)->GetElement().FindAttributeFloatValue("MinX", 0.0f);
pArea->m_vMin.y = (*j)->GetElement().FindAttributeFloatValue("MinY", 0.0f);
pArea->m_vMin.z = (*j)->GetElement().FindAttributeFloatValue("MinZ", 0.0f);
pArea->m_vMax.x = (*j)->GetElement().FindAttributeFloatValue("MaxX", 0.0f);
pArea->m_vMax.y = (*j)->GetElement().FindAttributeFloatValue("MaxY", 0.0f);
pArea->m_vMax.z = (*j)->GetElement().FindAttributeFloatValue("MaxZ", 0.0f);
pArea->m_iResMult = (*j)->GetElement().FindAttributeIntValue("ResMult", 0);
pArea->m_iFlags = (*j)->GetElement().FindAttributeIntValue("Flags", 0);
Vector3 vMinRounded = pArea->m_vMin;
RoundToNearest(vMinRounded);
Vector3 vMaxRounded = pArea->m_vMax;
RoundToNearest(vMaxRounded);
if(vMinRounded.x > pArea->m_vMin.x)
vMinRounded.x -= 1.0f;
if(vMinRounded.y > pArea->m_vMin.y)
vMinRounded.y -= 1.0f;
if(vMinRounded.z > pArea->m_vMin.z)
vMinRounded.z -= 1.0f;
pArea->m_vMin = vMinRounded;
if(vMaxRounded.x < pArea->m_vMax.x)
vMaxRounded.x += 1.0f;
if(vMaxRounded.y < pArea->m_vMax.y)
vMaxRounded.y += 1.0f;
if(vMaxRounded.z < pArea->m_vMax.z)
vMaxRounded.z += 1.0f;
if(vMaxRounded.x <= pArea->m_vMin.x)
vMaxRounded.x += 1.0f;
if(vMaxRounded.y <= pArea->m_vMin.y)
vMaxRounded.y += 1.0f;
if(vMaxRounded.z <= pArea->m_vMin.z)
vMaxRounded.z += 1.0f;
pArea->m_vMax = vMaxRounded;
areaIndex++;
}
}
}
delete pTree;
m_iCurrentArea = Min(0, m_ResAreas.GetCount()-1);
m_pCurrentAreaSlider->SetRange((float)-1, (float)m_ResAreas.GetCount()-1);
OnSelectArea();
}
//------------------------------------------------------------------
void CNavResAreaEditor::RoundToNearest(float & f)
{
f = (float) round(f);
//f = (float)((int)(f+0.5f));
}
void CNavResAreaEditor::RoundToNearest(Vector3 & v)
{
RoundToNearest(v.x);
RoundToNearest(v.y);
RoundToNearest(v.z);
}
//------------------------------------------------------------------
CNavDataCoverpointEditor::CNavDataCoverpointEditor()
{
}
CNavDataCoverpointEditor::~CNavDataCoverpointEditor()
{
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::Init()
{
bkBank * pBank = BANKMGR.FindBank("Navigation");
if(!pBank)
{
Assertf(false, "Couldn't locate \"Navigation\" bank.");
return;
}
pBank->AddButton("Initialise Nav Coverpoint Editor", OnInitEditor);
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::Update()
{
if(!ms_bEditorInitialized || !ms_bActive)
return;
ProcessInput();
ProcessAIObstructionChecks();
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::Render()
{
if(!ms_bEditorInitialized || !ms_bActive)
return;
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
const float fMaxRange = 200.0f;
for(int r=0; r<ms_aDataCoverpoints.GetCount(); r++)
{
CNavDataCoverpoint* pDataCoverpoint = ms_aDataCoverpoints[r];
const Vector3 vCoverpointPos = Vector3(pDataCoverpoint->m_CoordsX, pDataCoverpoint->m_CoordsY, pDataCoverpoint->m_CoordsZ);
const float fDistSqr = (vCoverpointPos - vOrigin).Mag2();
if(fDistSqr < fMaxRange*fMaxRange)
{
const float fDist = sqrtf(fDistSqr);
const float fAlpha = Clamp(1.0f - (fDist / fMaxRange), 0.0f, 1.0f);
if( fAlpha <= 0.0f )
{
continue;
}
float fDrawHeight = 1.3f;// default for tall cover
if( pDataCoverpoint->m_Type == NAVMESH_COVERPOINT_LOW_WALL || pDataCoverpoint->m_Type == NAVMESH_COVERPOINT_LOW_WALL_TO_LEFT || pDataCoverpoint->m_Type == NAVMESH_COVERPOINT_LOW_WALL_TO_RIGHT )
{
fDrawHeight = 0.8f;// height for low cover
}
Color32 renderColor = Color_blue;
renderColor.SetAlpha((int)(fAlpha*255));
// Draw vertical line at cover position
grcDebugDraw::Line(vCoverpointPos, vCoverpointPos + Vector3(0.0f,0.0f,fDrawHeight), renderColor, renderColor);
Vector3 vCoverDir;
Vector3FromCoverDir(vCoverDir, pDataCoverpoint->m_Direction);
// Draw horizontal line in cover direction
renderColor = Color_white;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Line(vCoverpointPos + Vector3(0.0f,0.0f,fDrawHeight), vCoverpointPos + Vector3(0.0f,0.0f,fDrawHeight) + vCoverDir, renderColor, renderColor);
// If coverpoint is wall to left
if( pDataCoverpoint->m_Type == NAVMESH_COVERPOINT_LOW_WALL_TO_LEFT || pDataCoverpoint->m_Type == NAVMESH_COVERPOINT_WALL_TO_LEFT )
{
Vector3 vRight;
vRight.Cross( vCoverDir, Vector3( 0.0f, 0.0f, 1.0f ) );
vRight.NormalizeFast();
renderColor = Color_green;
renderColor.SetAlpha((int)(fAlpha*255));
// Draw horizontal line indicating vantage side
Vector3 vVantageStart = vCoverpointPos + Vector3(0.0f,0.0f,fDrawHeight);
Vector3 vVantageEnd = vVantageStart + vRight;
grcDebugDraw::Line(vVantageStart, vVantageEnd, renderColor);
}
// If coverpoint is wall to right
else if( pDataCoverpoint->m_Type == NAVMESH_COVERPOINT_LOW_WALL_TO_RIGHT || pDataCoverpoint->m_Type == NAVMESH_COVERPOINT_WALL_TO_RIGHT )
{
Vector3 vRight;
vRight.Cross( vCoverDir, Vector3( 0.0f, 0.0f, 1.0f ) );
vRight.NormalizeFast();
renderColor = Color_green;
renderColor.SetAlpha((int)(fAlpha*255));
// Draw horizontal line indicating vantage side
Vector3 vVantageStart = vCoverpointPos + Vector3(0.0f,0.0f,fDrawHeight);
Vector3 vVantageEnd = vVantageStart - vRight;
grcDebugDraw::Line(vVantageStart, vVantageEnd, renderColor);
}
// Indicate selected coverpoint
if( ms_iSelectedDataCoverpointIndex == r )
{
renderColor = Color_white;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Sphere(vCoverpointPos + Vector3(0.0f,0.0f, fDrawHeight+0.1f), 0.1f, renderColor);
}
Vector3 vDrawPosition = vCoverpointPos + Vector3(0.0f,0.0f,0.5f);
int iNumTexts = 0;
// Render ID
char idString[256];
formatf(idString, "%u", pDataCoverpoint->m_ID );
grcDebugDraw::Text(vDrawPosition, Color_grey, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), idString);
// Render type text
renderColor = Color_green;
renderColor.SetAlpha((int)(fAlpha*255));
switch(pDataCoverpoint->m_Type)
{
case NAVMESH_COVERPOINT_LOW_WALL:
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "LOW_WALL_TO_NEITHER");
break;
case NAVMESH_COVERPOINT_LOW_WALL_TO_LEFT:
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "LOW_WALL_TO_LEFT");
break;
case NAVMESH_COVERPOINT_LOW_WALL_TO_RIGHT:
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "LOW_WALL_TO_RIGHT");
break;
case NAVMESH_COVERPOINT_WALL_TO_LEFT:
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "HIGH_WALL_TO_LEFT");
break;
case NAVMESH_COVERPOINT_WALL_TO_RIGHT:
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "HIGH_WALL_TO_RIGHT");
break;
case NAVMESH_COVERPOINT_WALL_TO_NEITHER:
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "HIGH_WALL_TO_NEITHER");
break;
default:
grcDebugDraw::Text(vDrawPosition, Color_red, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "UNKNOWN!");
}
// Render AI obstruction status text
switch(pDataCoverpoint->m_iObstructionCheckStatus)
{
case CNavDataCoverpoint::AISTATUS_VALID:
renderColor = Color_green;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "AI Clear");
break;
case CNavDataCoverpoint::AISTATUS_INVALID:
renderColor = Color_red;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "AI Obstructed");
break;
case CNavDataCoverpoint::AISTATUS_PENDING:
renderColor = Color_yellow;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "AI Pending");
break;
case CNavDataCoverpoint::AISTATUS_EXISTING:
renderColor = Color_orange;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "Existing Point");
break;
case CNavDataCoverpoint::AISTATUS_UNCHECKED:
renderColor = Color_white;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "AI UNCHECKED");
break;
default:
grcDebugDraw::Text(vDrawPosition, Color_red, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "Error, unhandled status!");
}
// Render too close to other data coverpoint
if( pDataCoverpoint->m_bTooCloseToOtherDataPoint )
{
renderColor = Color_red;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "Too close to data coverpoint");
}
// Render too close to existing map coverpoint
if( ms_bDisplayExistingMapPointProximity && pDataCoverpoint->m_bTooCloseToExistingMapCoverPoint )
{
renderColor = Color_red;
renderColor.SetAlpha((int)(fAlpha*255));
grcDebugDraw::Text(vDrawPosition, renderColor, 0, iNumTexts++*grcDebugDraw::GetScreenSpaceTextHeight(), "Too close to existing map coverpoint");
}
}
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnInitEditor()
{
if(!ms_bEditorInitialized || !ms_bActive)
{
InitWidgets();
ms_bEditorInitialized = true;
ms_bActive = true;
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::InitWidgets()
{
bkBank * pBank = BANKMGR.FindBank("Navigation");
if(!pBank)
{
Assertf(false, "Couldn't locate \"Navigation\" bank.");
return;
}
static const char * pTypeStrings[] = { "LOW_WALL_TO_NEITHER", "LOW_WALL_TO_LEFT", "LOW_WALL_TO_RIGHT", "HIGH_WALL_TO_LEFT", "HIGH_WALL_TO_RIGHT", "HIGH_WALL_TO_NEITHER" };
pBank->PushGroup("Coverpoint Editor");
pBank->AddToggle("Editor Active", &ms_bActive);
pBank->AddToggle("Show Existing Map Cover Proximity (requires data re-Load and player in range)", &ms_bDisplayExistingMapPointProximity);
pBank->AddSeparator();
pBank->AddButton("New Coverpoint", OnNewCoverpoint);
pBank->AddButton("Delete Coverpoint", OnDeleteCoverpoint);
pBank->AddButton("Select None", OnSelectNone);
ms_pCurrentCoverpointIndexSlider = pBank->AddSlider("Current Coverpoint Index", &ms_iSelectedDataCoverpointIndex, -1, ms_aDataCoverpoints.GetCount()-1, 1, OnSelectCoverpoint);
ms_pCurrentCoverpointDirectionSlider = pBank->AddSlider("Direction", &ms_uCurrentCoverpointDirection, 0, 255, 1, OnModifyDirection);
pBank->AddCombo("Type:", &ms_uCurrentCoverpointType, 6, pTypeStrings, OnModifyType);
pBank->AddSeparator("");
pBank->PushGroup("Save/Load");
pBank->AddButton("Save..", OnSave);
pBank->AddButton("Load..", OnLoad);
pBank->PopGroup();
pBank->PopGroup(); // "Coverpoint Editor"
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::ProcessInput()
{
bool bLeftButtonDown = (ioMouse::GetPressedButtons() & ioMouse::MOUSE_LEFT)? true : false;
bool bRightButtonDown = (ioMouse::GetPressedButtons() & ioMouse::MOUSE_RIGHT)? true : false;
// Left mouse click
if(bLeftButtonDown)
{
// select closest
Vector3 vPickPos;
if(CDebugScene::GetWorldPositionUnderMouse(vPickPos))
{
int iCoverpointIndex = FindDataCoverpointIndexClosestToPos(vPickPos, 200.0f);
if(iCoverpointIndex != -1)
{
ms_iSelectedDataCoverpointIndex = iCoverpointIndex;
OnSelectCoverpoint();
}
}
}
// right mouse click
else if(bRightButtonDown)
{
// reposition currently selected unless it is being checked
if(ms_iSelectedDataCoverpointIndex >= 0 && ms_iSelectedDataCoverpointIndex < ms_aDataCoverpoints.GetCount())
{
Vector3 vPickPos;
if(CDebugScene::GetWorldPositionUnderMouse(vPickPos))
{
// update position
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_CoordsX = vPickPos.x;
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_CoordsY = vPickPos.y;
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_CoordsZ = vPickPos.z;
// mark for obstruction check needed
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_UNCHECKED;
// check updated position for proximity to other data points
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_bTooCloseToOtherDataPoint = IsViolatingMinDistToOtherDataPoint(ms_iSelectedDataCoverpointIndex);
// check position for proximity to existing cover points
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_bTooCloseToExistingMapCoverPoint = IsViolatingMinDistToExistingCoverPoint(ms_iSelectedDataCoverpointIndex);
}
}
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::ProcessAIObstructionChecks()
{
ProcessStatusHelperStart();
ms_CoverPointStatusHelper.Update();
ProcessStatusHelperFinished();
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnSelectCoverpoint()
{
if(ms_iSelectedDataCoverpointIndex >= 0 && ms_iSelectedDataCoverpointIndex < ms_aDataCoverpoints.GetCount())
{
ms_uCurrentCoverpointDirection = ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_Direction;
ms_uCurrentCoverpointType = ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_Type;
}
else
{
ms_uCurrentCoverpointDirection = 0;
ms_uCurrentCoverpointType = 0;
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnModifyDirection()
{
if(ms_iSelectedDataCoverpointIndex >= 0 && ms_iSelectedDataCoverpointIndex < ms_aDataCoverpoints.GetCount())
{
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_Direction = ms_uCurrentCoverpointDirection;
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_UNCHECKED;
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnModifyType()
{
if(ms_iSelectedDataCoverpointIndex >= 0 && ms_iSelectedDataCoverpointIndex < ms_aDataCoverpoints.GetCount())
{
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_Type = ms_uCurrentCoverpointType;
ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex]->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_UNCHECKED;
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnNewCoverpoint()
{
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vSpawnPosition = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
vSpawnPosition += camInterface::GetFront();
AddNewCoverpoint(vSpawnPosition);
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnDeleteCoverpoint()
{
if(ms_iSelectedDataCoverpointIndex >= 0 && ms_iSelectedDataCoverpointIndex < ms_aDataCoverpoints.GetCount())
{
// First check if the point being deleted is being checked
if( ms_iStatusCheckDataCoverpointIndex == ms_iSelectedDataCoverpointIndex )
{
ms_CoverPointStatusHelper.Reset();
ms_iStatusCheckDataCoverpointIndex = -1;
}
// Delete the coverpoint from the list
CNavDataCoverpoint * pCoverpoint = ms_aDataCoverpoints[ms_iSelectedDataCoverpointIndex];
delete pCoverpoint;
ms_aDataCoverpoints.Delete(ms_iSelectedDataCoverpointIndex);
// Update the index slider range
ms_pCurrentCoverpointIndexSlider->SetRange((float)-1, (float)ms_aDataCoverpoints.GetCount()-1);
// If index is out of range
if( ms_iSelectedDataCoverpointIndex >= ms_aDataCoverpoints.GetCount() )
{
// decrement it, possibly resulting in -1 index intentionally
ms_iSelectedDataCoverpointIndex = ms_aDataCoverpoints.GetCount() - 1;
}
// Select current index point
OnSelectCoverpoint();
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnSelectNone()
{
ms_iSelectedDataCoverpointIndex = -1;
OnSelectCoverpoint();
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnSave()
{
USE_DEBUG_MEMORY();
char filename[512] = { 0 };
bool bOk = BANKMGR.OpenFile(filename, 512, "*.xml", true, "Custom Coverpoints XML");
if(!bOk)
return;
parTree *pTree = rage_new parTree();
Assert(pTree);
parTreeNode* pRootNode = pTree->CreateRoot();
Assert(pRootNode);
parElement& rootElm = pRootNode->GetElement();
rootElm.SetName("NavCustomCoverpoints");
rootElm.AddAttribute("Version", ms_iXmlVersion, false);
pTree->SetRoot(pRootNode);
parTreeNode * pCoverpointsListXmlNode = rage_new parTreeNode();
Assert(pCoverpointsListXmlNode);
pCoverpointsListXmlNode->GetElement().SetName("CustomCoverpoints");
pCoverpointsListXmlNode->AppendAsChildOf(pRootNode);
for(int r=0; r<ms_aDataCoverpoints.GetCount(); r++)
{
CNavDataCoverpoint * pDataCoverpoint = ms_aDataCoverpoints[r];
parTreeNode * pCoverpointXmlNode = rage_new parTreeNode();
Assert(pCoverpointXmlNode);
pCoverpointXmlNode->GetElement().SetName("Coverpoint");
pCoverpointXmlNode->GetElement().AddAttribute("ID", r, false); // ensure no possibility of duplicate IDs
pCoverpointXmlNode->GetElement().AddAttribute("Type", (int)pDataCoverpoint->m_Type, false);
pCoverpointXmlNode->GetElement().AddAttribute("Direction", (int)pDataCoverpoint->m_Direction, false);
pCoverpointXmlNode->GetElement().AddAttribute("CoordsX", pDataCoverpoint->m_CoordsX, false);
pCoverpointXmlNode->GetElement().AddAttribute("CoordsY", pDataCoverpoint->m_CoordsY, false);
pCoverpointXmlNode->GetElement().AddAttribute("CoordsZ", pDataCoverpoint->m_CoordsZ, false);
pCoverpointXmlNode->AppendAsChildOf(pCoverpointsListXmlNode);
}
const bool bSaveRes = PARSER.SaveTree(filename, "", pTree, parManager::XML);
if(!bSaveRes)
{
Assertf(false, "Failed to save Custom Coverpoints XML '%s'.", filename);
delete pTree;
return;
}
delete pTree;
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::OnLoad()
{
USE_DEBUG_MEMORY();
char filename[512] = { 0 };
bool bOk = BANKMGR.OpenFile(filename, 512, "*.xml", false, "Custom Coverpoints XML");
if(!bOk)
return;
Reset();
parTree * pTree = PARSER.LoadTree(filename, "");
Assert(pTree);
const parTreeNode* pRootNode = pTree->GetRoot();
Assert(pRootNode);
Assert(stricmp(pRootNode->GetElement().GetName(), "NavCustomCoverpoints") == 0);
// Make sure we have the correct version.
ASSERT_ONLY(int version = pRootNode->GetElement().FindAttributeIntValue("Version", 0));
Assert(version >= ms_iXmlVersion);
parTreeNode::ChildNodeIterator i = pRootNode->BeginChildren();
for(; i != pRootNode->EndChildren(); ++i)
{
if(stricmp((*i)->GetElement().GetName(), "CustomCoverpoints") == 0)
{
int loadIndex = 0;
// Go over any and all the child DOM trees and DOM nodes off of the list.
parTreeNode::ChildNodeIterator j = (*i)->BeginChildren();
for(; j != (*i)->EndChildren(); ++j)
{
Assert(stricmp((*j)->GetElement().GetName(), "Coverpoint") == 0);
CNavDataCoverpoint * pDataCoverpoint = rage_new CNavDataCoverpoint();
ms_aDataCoverpoints.PushAndGrow(pDataCoverpoint);
pDataCoverpoint->m_ID = (u32)loadIndex; // ensure no possibility of duplicate IDs
pDataCoverpoint->m_Type = (u8)(*j)->GetElement().FindAttributeIntValue("Type", 0);
pDataCoverpoint->m_Direction = (u8)(*j)->GetElement().FindAttributeIntValue("Direction", 0);
pDataCoverpoint->m_CoordsX = (*j)->GetElement().FindAttributeFloatValue("CoordsX", 0.0f);
pDataCoverpoint->m_CoordsY = (*j)->GetElement().FindAttributeFloatValue("CoordsY", 0.0f);
pDataCoverpoint->m_CoordsZ = (*j)->GetElement().FindAttributeFloatValue("CoordsZ", 0.0f);
++loadIndex;
}
}
}
delete pTree;
ms_pCurrentCoverpointIndexSlider->SetRange((float)-1, (float)ms_aDataCoverpoints.GetCount()-1);
CheckAllPointsForViolatingMinDist();
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::Reset()
{
for(int r=0; r<ms_aDataCoverpoints.GetCount(); r++)
{
CNavDataCoverpoint * pDataCoverpoint = ms_aDataCoverpoints[r];
delete pDataCoverpoint;
}
ms_aDataCoverpoints.clear();
ms_iSelectedDataCoverpointIndex = -1;
OnSelectCoverpoint();
}
//------------------------------------------------------------------
int CNavDataCoverpointEditor::FindDataCoverpointIndexClosestToPos(const Vector3 & vPos, const float fMaxDist)
{
float fClosestDistSq = FLT_MAX;
int iClosestIndex = -1;
for(int r=0; r < ms_aDataCoverpoints.GetCount(); r++)
{
CNavDataCoverpoint* pCoverpoint = ms_aDataCoverpoints[r];
Vector3 vCoverpointPos(pCoverpoint->m_CoordsX, pCoverpoint->m_CoordsY, pCoverpoint->m_CoordsZ);
float fDistSq = vPos.Dist2(vCoverpointPos);
if(fDistSq < fClosestDistSq && fDistSq <= fMaxDist)
{
fClosestDistSq = fDistSq;
iClosestIndex = r;
}
}
return iClosestIndex;
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::AddNewCoverpoint(const Vector3& vSpawnPosition)
{
USE_DEBUG_MEMORY(); // Ensure that we alloc from any free memory devkit may have
// Setup the new coverpoint at position with default values
CNavDataCoverpoint* pNewCoverpoint = rage_new CNavDataCoverpoint();
pNewCoverpoint->m_CoordsX = vSpawnPosition.x;
pNewCoverpoint->m_CoordsY = vSpawnPosition.y;
pNewCoverpoint->m_CoordsZ = vSpawnPosition.z;
// Append to the list
ms_aDataCoverpoints.PushAndGrow(pNewCoverpoint);
pNewCoverpoint->m_ID = ms_aDataCoverpoints.GetCount()-1;
// Update the slider range of indices
ms_pCurrentCoverpointIndexSlider->SetRange((float)-1, (float)(ms_aDataCoverpoints.GetCount()-1));
// Select the new coverpoint
ms_iSelectedDataCoverpointIndex = ms_aDataCoverpoints.GetCount()-1;
OnSelectCoverpoint();
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::ProcessStatusHelperStart()
{
// if status check index is negative
if( ms_iStatusCheckDataCoverpointIndex < 0 )
{
// Find the next index corresponding to a data coverpoint in camera range
const float fMaxRange = 200.0f;
camDebugDirector & debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
for(int r=0; r<ms_aDataCoverpoints.GetCount(); r++)
{
CNavDataCoverpoint* pDataCoverpoint = ms_aDataCoverpoints[r];
// skip unless unchecked status
if( pDataCoverpoint->m_iObstructionCheckStatus != CNavDataCoverpoint::AISTATUS_UNCHECKED )
{
continue;
}
// check if within range
const Vector3 vCoverpointPos = Vector3(pDataCoverpoint->m_CoordsX, pDataCoverpoint->m_CoordsY, pDataCoverpoint->m_CoordsZ);
const float fDistSqr = (vCoverpointPos - vOrigin).Mag2();
if(fDistSqr < fMaxRange*fMaxRange)
{
// set next index to check!
ms_iStatusCheckDataCoverpointIndex = r;
break;
}
}
// If a qualifying coverpoint was found
if( ms_iStatusCheckDataCoverpointIndex >= 0 )
{
// Get the qualifying data coverpoint
CNavDataCoverpoint* pDataCoverpointToCheck = ms_aDataCoverpoints[ms_iStatusCheckDataCoverpointIndex];
Vector3 vDataCoverpointPos(pDataCoverpointToCheck->m_CoordsX,pDataCoverpointToCheck->m_CoordsY,pDataCoverpointToCheck->m_CoordsZ);
// Add a temporary coverpoint to test the status
CCoverPoint::eCoverUsage coverUsage = CCoverPoint::COVUSE_WALLTOBOTH;
CCoverPoint::eCoverHeight coverHeight = CCoverPoint::COVHEIGHT_LOW;
// Convert the older style cover usage type into the new cover usage and cover height
if(pDataCoverpointToCheck->m_Type == NAVMESH_COVERPOINT_LOW_WALL)
{
coverUsage = CCoverPoint::COVUSE_WALLTOBOTH;
coverHeight = CCoverPoint::COVHEIGHT_LOW;
}
else if(pDataCoverpointToCheck->m_Type == NAVMESH_COVERPOINT_LOW_WALL_TO_LEFT)
{
coverUsage = CCoverPoint::COVUSE_WALLTOLEFT;
coverHeight = CCoverPoint::COVHEIGHT_LOW;
}
else if(pDataCoverpointToCheck->m_Type == NAVMESH_COVERPOINT_LOW_WALL_TO_RIGHT)
{
coverUsage = CCoverPoint::COVUSE_WALLTORIGHT;
coverHeight = CCoverPoint::COVHEIGHT_LOW;
}
else if(pDataCoverpointToCheck->m_Type == NAVMESH_COVERPOINT_WALL_TO_LEFT)
{
coverUsage = CCoverPoint::COVUSE_WALLTOLEFT;
coverHeight = CCoverPoint::COVHEIGHT_TOOHIGH;
}
else if(pDataCoverpointToCheck->m_Type == NAVMESH_COVERPOINT_WALL_TO_RIGHT)
{
coverUsage = CCoverPoint::COVUSE_WALLTORIGHT;
coverHeight = CCoverPoint::COVHEIGHT_TOOHIGH;
}
else if(pDataCoverpointToCheck->m_Type == NAVMESH_COVERPOINT_WALL_TO_NEITHER)
{
coverUsage = CCoverPoint::COVUSE_WALLTONEITHER;
coverHeight = CCoverPoint::COVHEIGHT_TOOHIGH;
}
else
{
Assert(0);
}
// In case there is an existing coverpoint here
s16 iExistingCoverPointIndex = INVALID_COVER_POINT_INDEX;
// Try to add coverpoint the same way we load from map data
ms_iTempCoverPointIndex = CCover::AddCoverPoint(
CCover::CP_NavmeshAndDynamicPoints,
CCoverPoint::COVTYPE_POINTONMAP,
NULL,
&vDataCoverpointPos,
coverHeight,
coverUsage,
pDataCoverpointToCheck->m_Direction,
CCoverPoint::COVARC_90,
false,
VEH_INVALID_ID,
&iExistingCoverPointIndex
);
// If we are trying to add a coverpoint to test, and there is an existing one
if( ms_iTempCoverPointIndex == INVALID_COVER_POINT_INDEX && iExistingCoverPointIndex != INVALID_COVER_POINT_INDEX )
{
// mark the status as existing
pDataCoverpointToCheck->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_EXISTING;
// reset the status index to try again
ms_iStatusCheckDataCoverpointIndex = -1;
return;
}
// If we tried to add but just couldn't for some other reason
else if( ms_iTempCoverPointIndex == INVALID_COVER_POINT_INDEX )
{
// reset the status index to try again
ms_iStatusCheckDataCoverpointIndex = -1;
return;
}
// we added a point for test successfully
else // ms_iTempCoverPointIndex != INVALID_COVER_POINT_INDEX
{
CCoverPoint* pCoverPointToCheck = CCover::FindCoverPointWithIndex(ms_iTempCoverPointIndex);
if(pCoverPointToCheck)
{
// Start the helper checks
ms_CoverPointStatusHelper.Start(pCoverPointToCheck);
// Get the qualifying data coverpoint and mark status pending
ms_aDataCoverpoints[ms_iStatusCheckDataCoverpointIndex]->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_PENDING;
return;
}
// something went wrong along the way here
// reset the status index to try again
ms_iStatusCheckDataCoverpointIndex = -1;
}
}
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::ProcessStatusHelperFinished()
{
if( ms_CoverPointStatusHelper.IsFinished() )
{
// Get the data coverpoint being checked
CNavDataCoverpoint* pDataCoverpointToCheck = ms_aDataCoverpoints[ms_iStatusCheckDataCoverpointIndex];
// Check that nothing has been modified while the check was pending
// NOTE: Otherwise it will be changed back to AISTATUS_UNCHECKED and we'll check it again
if( pDataCoverpointToCheck->m_iObstructionCheckStatus == CNavDataCoverpoint::AISTATUS_PENDING )
{
// mark the data coverpoint status according to the result
u8 statusResult = ms_CoverPointStatusHelper.GetStatus();
if( statusResult == CCoverPoint::COVSTATUS_Clear )
{
pDataCoverpointToCheck->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_VALID;
}
else if( statusResult == CCoverPoint::COVSTATUS_DirectionBlocked || statusResult == CCoverPoint::COVSTATUS_PositionBlocked )
{
pDataCoverpointToCheck->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_INVALID;
}
// not sure why but sometimes status helper finishes on statusResult invalid, which means unchecked
else if( statusResult == CCoverPoint::COVSTATUS_Invalid )
{
pDataCoverpointToCheck->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_UNCHECKED;
}
else // unhandled coverpoint status!
{
Assertf(0, "unhandled coverpoint status!");
pDataCoverpointToCheck->m_iObstructionCheckStatus = CNavDataCoverpoint::AISTATUS_UNCHECKED;
}
}
// reset the helper
ms_CoverPointStatusHelper.Reset();
// remove the coverpoint from the real cover pool
CCover::RemoveCoverPointWithIndex(ms_iTempCoverPointIndex);
ms_iTempCoverPointIndex = INVALID_COVER_POINT_INDEX;
// set the status check index back to -1 to repeat the process
ms_iStatusCheckDataCoverpointIndex = -1;
}
}
//------------------------------------------------------------------
void CNavDataCoverpointEditor::CheckAllPointsForViolatingMinDist()
{
for(int r=0; r < ms_aDataCoverpoints.GetCount(); r++)
{
ms_aDataCoverpoints[r]->m_bTooCloseToOtherDataPoint = IsViolatingMinDistToOtherDataPoint(r);
ms_aDataCoverpoints[r]->m_bTooCloseToExistingMapCoverPoint = IsViolatingMinDistToExistingCoverPoint(r);
}
}
//------------------------------------------------------------------
bool CNavDataCoverpointEditor::IsViolatingMinDistToOtherDataPoint(int queryDataCoverpointIndex)
{
if( queryDataCoverpointIndex >= 0 && queryDataCoverpointIndex < ms_aDataCoverpoints.GetCount() )
{
const CNavDataCoverpoint* pQueryDataCoverpoint = ms_aDataCoverpoints[queryDataCoverpointIndex];
const Vector3 vQueryPosition(pQueryDataCoverpoint->m_CoordsX,pQueryDataCoverpoint->m_CoordsY,pQueryDataCoverpoint->m_CoordsZ);
for(int r=0; r < ms_aDataCoverpoints.GetCount(); r++)
{
if(r == queryDataCoverpointIndex)
{
// skip self
continue;
}
const CNavDataCoverpoint* pOtherDataCoverpoint = ms_aDataCoverpoints[r];
const Vector3 vOtherPosition(pOtherDataCoverpoint->m_CoordsX, pOtherDataCoverpoint->m_CoordsY, pOtherDataCoverpoint->m_CoordsZ);
const float fDistSq = vOtherPosition.Dist2(vQueryPosition);
// check against cover constant limit - this is what run-time will use to reject inside AddCoverPoint
if( fDistSq <= CCover::ms_fMinDistSqrBetweenCoverPoints )
{
return true;
}
}
}
return false;
}
//------------------------------------------------------------------
bool CNavDataCoverpointEditor::IsViolatingMinDistToExistingCoverPoint(int queryDataCoverpointIndex)
{
if( queryDataCoverpointIndex >= 0 && queryDataCoverpointIndex < ms_aDataCoverpoints.GetCount() )
{
const CNavDataCoverpoint* pQueryDataCoverpoint = ms_aDataCoverpoints[queryDataCoverpointIndex];
const Vector3 vQueryPosition(pQueryDataCoverpoint->m_CoordsX,pQueryDataCoverpoint->m_CoordsY,pQueryDataCoverpoint->m_CoordsZ);
CCoverPoint* pOverlappingCoverPoint = NULL;
if( NULL == CCoverPointsContainer::CheckIfNoOverlapAndGetGridCell(vQueryPosition, CCoverPoint::COVTYPE_POINTONMAP, NULL, pOverlappingCoverPoint) )
{
return true;
}
}
return false;
}
//------------------------------------------------------------------
} // namespace rage
#endif // __NAVEDITORS