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

5094 lines
176 KiB
C++

#if !__FINAL
//******************************************************************************************************
// Filename : PathServer_Debug.cpp
// Author : James Broad
// Description : Somewhere to place the navmesh & pathserver debugging code, outside of the main file.
//******************************************************************************************************
#include "PathServer\PathServer.h"
#include "PathServer\NavMeshGta.h"
#include "PathServer\NavGenParam.h"
#if defined(GTA_ENGINE) && defined(DEBUG_DRAW) && DEBUG_DRAW
// Rage headers
#include "bank/bank.h"
#include "bank/bkmgr.h"
#include "bank/combo.h"
#include "file/stream.h"
#include "file/asset.h"
#include "grcore/debugdraw.h"
#include "grcore/device.h"
#include "string/string.h"
#include "system/xtl.h"
#include "system/criticalsection.h"
#include "vector/colors.h"
#include "vector/geometry.h"
#include "spatialdata/sphere.h"
// Framework headers
#include "ai/navmesh/navmeshextents.h"
#include "ai/navmesh/tessellation.h"
#include "fwmaths/Random.h"
#include "fwscene/world/WorldLimits.h"
#ifdef GTA_ENGINE
// Game headers
// These includes for using within the GTA engine
#include "camera/CamInterface.h"
#include "camera/debug/DebugDirector.h"
#include "camera/helpers/Frame.h"
#include "camera/viewports/Viewport.h"
#include "Debug/DebugScene.h"
#include "Objects/Object.h"
#include "Peds/PedDebugVisualiser.h"
#include "Peds/PedGeometryAnalyser.h"
#include "Peds/PedIntelligence.h"
#include "Peds/PedPopulation.h"
#include "peds/Ped.h"
#include "Physics/Physics.h"
#include "physics/WorldProbe/worldprobe.h"
#include "Scene/Physical.h"
#include "scene/world/GameWorld.h"
#include "Task/Movement/TaskNavMesh.h"
#include "vehicles/vehicle.h"
#include "camera/viewports/ViewportManager.h"
#include "Text/Text.h"
#include "Text/TextConversion.h"
#else // GTA_ENGINE
// This include for when developing the system outside of GTA
#include "GTATypes.h"
#endif
NAVMESH_OPTIMISATIONS()
// Define __CATCH_BAD_NAVMESH_VERTS to check vertices when debug-drawing the navmesh
#define __CATCH_BAD_NAVMESH_VERTS 0
bool g_bTestBlockingObjectEnabled = false;
Vector3 g_vTestBlockingObjectPos(0.0f,0.0f,0.0f);
Vector3 g_vTestBlockingObjectSize(2.0f,2.0f,1.0f);
float g_fTestBlockingObjectRot = 0.0f;
bool PathTest_bPreferPavements = false;
bool PathTest_bNeverLeaveWater = false;
bool PathTest_bGoAsFarAsPossible = false;
bool PathTest_bNeverLeavePavements = false;
bool PathTest_bNeverClimbOverStuff = false;
bool PathTest_bNeverDropFromHeight = false;
bool PathTest_bNeverUseLadders = false;
bool PathTest_bFleeTarget = false;
bool PathTest_bWander = false;
bool PathTest_bNeverEnterWater = false;
bool PathTest_bDontAvoidDynamicObjects = false;
bool PathTest_bPreferDownhill = false;
bool PathTest_bReduceObjectBBoxes = false;
bool PathTest_bUseLargerSearchExtents = false;
bool PathTest_bMayUseFatalDrops = false;
bool PathTest_bIgnoreObjectsWithNoUprootLimit = false;
bool PathTest_bAllowToTravelUnderwater = false;
bool PathTest_bUseDirectionalCover = false;
bool PathTest_bCutSharpCorners = false;
bool PathTest_bAllowToNavigateUpSteepPolygons = false;
bool PathTest_bScriptedRoute = false;
bool PathTest_bPreserveZ = false;
bool PathTest_bRandomisePoints = false;
bool PathTest_bGetPointsFromMeasuringTool = false;
float PathTest_fPathTestMaxSlopeNavigable = 0.0f;
void PathSever_VerifyAdjacencies();
#if !__FINAL
// Offset from top-left of screen
// This is here so we can tweak the positioning in game on crap monitors which have no adjustment controls
Vector2 g_vPathserverDebugTopLeft(0.0, 0.0);
Vector2 ScreenPos(const Vector2 & vPos) { return Vector2( (float)vPos.x / (float)SCREEN_WIDTH, (float)vPos.y / (float)SCREEN_HEIGHT); }
Vector2 ScreenPos(const float ix, const float iy) { return Vector2( ((float)ix) / (float)SCREEN_WIDTH, ((float)iy) / (float)SCREEN_HEIGHT); }
const char * CPathServer::ms_pNavMeshVisModeTxt[NavMeshVis_NumModes] =
{
"Off",
"Wireframe",
"Transparent",
"Solid",
"Pavements",
"Roads",
"Train Tracks",
"Ped Density",
"Disabled",
"Shelter",
"Special Links",
"Too Steep",
"Water Surface",
"Audio Properties",
"Cover Directions",
"Car Nodes",
"Interior",
"Isolated",
"Network Spawn Candidates",
"No Wander",
"Pavement-Checking Mode"
};
void
CPathServer::DrawPolyDebug(CNavMesh * pNavMesh, u32 iPolyIndex, Color32 iCol, float fAddHeight, bool bOutline, int filledAlpha, bool bDrawCentroidQuick)
{
#ifdef GTA_ENGINE
TNavMeshPoly * pPoly = pNavMesh->GetPoly(iPolyIndex);
if(bOutline)
{
Vector3 vec, lastvec;
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, pPoly->GetNumVertices()-1), lastvec );
lastvec.z += fAddHeight;
for(u32 v=0; v<pPoly->GetNumVertices(); v++)
{
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, v), vec );
#if __CATCH_BAD_NAVMESH_VERTS
Assert(rage::FPIsFinite(vec.x));
Assert(rage::FPIsFinite(vec.y));
Assert(rage::FPIsFinite(vec.z));
if(pNavMesh->m_pQuadTree)
{
Assert(vec.x >= pNavMesh->m_pQuadTree->m_Mins.x && vec.x <= pNavMesh->m_pQuadTree->m_Maxs.x);
Assert(vec.y >= pNavMesh->m_pQuadTree->m_Mins.y && vec.y <= pNavMesh->m_pQuadTree->m_Maxs.y);
Assert(vec.z >= pNavMesh->m_pQuadTree->m_Mins.z && vec.z <= pNavMesh->m_pQuadTree->m_Maxs.z);
}
#endif
vec.z += fAddHeight;
grcDebugDraw::Line(lastvec, vec, iCol);
lastvec = vec;
}
}
else
{
u32 r = iCol.GetRed();
u32 g = iCol.GetGreen();
u32 b = iCol.GetBlue();
Vector3 v0,v1,v2;
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, 0), v0 );
v0.z += fAddHeight;
for(u32 v=1; v<pPoly->GetNumVertices()-1; v++)
{
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, v), v1 );
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, v+1), v2 );
v1.z += fAddHeight;
v2.z += fAddHeight;
Color32 polyCol;
polyCol.Set(r,g,b,filledAlpha);
grcDebugDraw::Poly(RCC_VEC3V(v0),RCC_VEC3V(v1),RCC_VEC3V(v2),polyCol);
}
}
if(bDrawCentroidQuick && pNavMesh->GetIndexOfMesh() != NAVMESH_INDEX_TESSELLATION)
{
Vector3 vCentroid;
pNavMesh->GetPolyCentroidQuick(pPoly, vCentroid);
grcDebugDraw::Line(vCentroid, vCentroid + ZAXIS*2.0f, Color_beige, Color_white);
}
#else // GTA_ENGINE
pNavMesh;
iPolyIndex;
iCol;
fAddHeight;
bOutline;
#endif // GTA_ENGINE
}
void CPathServer::DrawPolyVolumeDebug(CNavMesh * pNavMesh, int iPolyIndex, Color32 iCol1, Color32 iCol2, float fSpaceAboveTopZ)
{
#ifndef GTA_ENGINE
pNavMesh; iPolyIndex; iCol1; iCol2; fSpaceAboveTopZ;
return;
#else
DrawPolyDebug(pNavMesh, iPolyIndex, iCol1, m_fVisNavMeshVertexShiftAmount, true);
TNavMeshPoly * pPoly = pNavMesh->GetPoly(iPolyIndex);
static Vector3 vPolyVerts[NAVMESHPOLY_MAX_NUM_VERTICES];
u32 p;
for(p=0; p<pPoly->GetNumVertices(); p++)
{
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, p), vPolyVerts[p] );
}
for(p=0; p<pPoly->GetNumVertices(); p++)
{
grcDebugDraw::Line(vPolyVerts[p], Vector3(vPolyVerts[p].x, vPolyVerts[p].y, fSpaceAboveTopZ), iCol1, iCol2);
}
Vector3 v0 = Vector3(vPolyVerts[0].x, vPolyVerts[0].y, fSpaceAboveTopZ);
for(p=1; p<pPoly->GetNumVertices()-1; p++)
{
Vector3 v1 = Vector3(vPolyVerts[p].x, vPolyVerts[p].y, fSpaceAboveTopZ);
Vector3 v2 = Vector3(vPolyVerts[p+1].x, vPolyVerts[p+1].y, fSpaceAboveTopZ);
grcDebugDraw::Poly(RCC_VEC3V(v2),RCC_VEC3V(v1),RCC_VEC3V(v0),iCol2);
}
#endif
}
void
#if __WIN32PC
CPathServer::DebugPolyText(CNavMesh * pNavMesh, u32 iPolyIndex)
#else
CPathServer::DebugPolyText(CNavMesh * UNUSED_PARAM(pNavMesh), u32 UNUSED_PARAM(iPolyIndex))
#endif
{
#if __WIN32PC
TNavMeshPoly * pPoly = pNavMesh->GetPoly(iPolyIndex);
Assert(pPoly->GetNavMeshIndex() == pNavMesh->GetIndexOfMesh());
char tmp[256];
sprintf(tmp, "NavMesh %i Poly %i (addr:0x%p)\n", pNavMesh->GetIndexOfMesh(), iPolyIndex, pPoly);
OutputDebugString(tmp);
sprintf(tmp, "NumVertices %i, PedDensity %i, Flags %i\n", pPoly->GetNumVertices(), pPoly->GetPedDensity(), pPoly->GetFlags());
OutputDebugString(tmp);
sprintf(tmp, "Area %.2f\n", pNavMesh->GetPolyArea(iPolyIndex));
OutputDebugString(tmp);
Vector3 vPolyNormal;
pNavMesh->GetPolyNormal(vPolyNormal, pPoly);
const float fDotUp = DotProduct(ZAXIS, vPolyNormal);
sprintf(tmp, "PolyNormal (%.2f, %.2f, %.2f), DotUp=%.2f\n", vPolyNormal.x, vPolyNormal.y, vPolyNormal.z, fDotUp);
OutputDebugString(tmp);
u32 testFlags = NAVMESHPOLY_SMALL | NAVMESHPOLY_LARGE | NAVMESHPOLY_OPEN | NAVMESHPOLY_CLOSED | NAVMESHPOLY_TESSELLATED_FRAGMENT | NAVMESHPOLY_REPLACED_BY_TESSELLATION;
if(pPoly->GetIsSmall()) OutputDebugString("(small)");
if(pPoly->GetIsLarge()) OutputDebugString("(large)");
if(pPoly->GetIsOpen()) OutputDebugString("(open)");
if(pPoly->GetIsClosed()) OutputDebugString("(closed)");
if(pPoly->GetIsTessellatedFragment()) OutputDebugString("(frag)");
if(pPoly->GetReplacedByTessellation()) OutputDebugString("(replaced)");
if(pPoly->TestFlags(testFlags)) OutputDebugString("\n");
Vector3 vert, nextVert, vDiff, vNormal;
int nextv, vi1, vi2;
u32 v;
Vector3 vMins(FLT_MAX, FLT_MAX, FLT_MAX);
Vector3 vMaxs(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for(v=0; v<pPoly->GetNumVertices(); v++)
{
nextv = (v+1) % pPoly->GetNumVertices();
vi1 = pNavMesh->GetPolyVertexIndex(pPoly, v);
vi2 = pNavMesh->GetPolyVertexIndex(pPoly, nextv);
pNavMesh->GetVertex(vi1, vert);
pNavMesh->GetVertex(vi2, nextVert);
if(vert.x < vMins.x) vMins.x = vert.x;
if(vert.y < vMins.y) vMins.y = vert.y;
if(vert.z < vMins.z) vMins.z = vert.z;
if(vert.x > vMaxs.x) vMaxs.x = vert.x;
if(vert.y > vMaxs.y) vMaxs.y = vert.y;
if(vert.z > vMaxs.z) vMaxs.z = vert.z;
vDiff = nextVert - vert;
const TAdjPoly & adjPoly = pNavMesh->GetAdjacentPoly(pPoly->GetFirstVertexIndex() + v);
pNavMesh->GetPolyEdgeNormal(vNormal, pPoly, v);
sprintf(tmp, "%i) [%i] (%.2f, %.2f, %.2f) \t adjType:%i (adjNav:%i, adjPoly:%i, origAdjNav:%i, origAdjPoly:%i) length : %.2f normal : (%.2f, %.2f, %.2f)\n",
v,
vi1,
vert.x, vert.y, vert.z,
adjPoly.GetAdjacencyType(),
adjPoly.GetNavMeshIndex(pNavMesh->GetAdjacentMeshes()), adjPoly.GetPolyIndex(),
adjPoly.GetOriginalNavMeshIndex(pNavMesh->GetAdjacentMeshes()), adjPoly.GetOriginalPolyIndex(),
vDiff.Mag(),
vNormal.x, vNormal.y, vNormal.z
);
OutputDebugString(tmp);
}
Vector3 vSize = vMaxs - vMins;
sprintf(tmp, "Mins (%.1f, %.1f, %.1f) Maxs (%.1f, %.1f, %.1f) Size (%.1f, %.1f, %.1f)\n",
vMins.x, vMins.y, vMins.z, vMaxs.x, vMaxs.y, vMaxs.z, vSize.x, vSize.y, vSize.z
);
OutputDebugString(tmp);
#endif
}
#ifdef GTA_ENGINE
void
CPathServer::ClearAllPathHistory()
{
for(int p=0; p<MAX_NUM_PATH_REQUESTS; p++)
{
m_PathRequests[p].Clear();
CPathServer::m_PathRequests[p].m_bSlotEmpty = true;
}
}
void CPathServer::ClearAllOpenClosedFlags()
{
LOCK_STORE_LOADED_MESHES;
for(int n=0; n<m_pNavMeshStores[kNavDomainRegular]->GetLoadedMeshes().GetCount(); n++)
{
u32 iMesh = m_pNavMeshStores[kNavDomainRegular]->GetLoadedMeshes()[n];
CNavMesh * pMesh = m_pNavMeshStores[kNavDomainRegular]->GetMeshByIndex(iMesh);
if(pMesh)
{
for(int p=0; p<pMesh->GetNumPolys(); p++)
{
TNavMeshPoly * pPoly = pMesh->GetPoly(p);
pPoly->SetIsOpen(false);
pPoly->SetIsClosed(false);
}
}
}
for(int p=0; p<GetTessellationNavMesh()->GetNumPolys(); p++)
{
TNavMeshPoly * pPoly = GetTessellationNavMesh()->GetPoly(p);
pPoly->SetIsOpen(false);
pPoly->SetIsClosed(false);
}
#ifndef GTA_ENGINE
UNLOCK_STORE_LOADED_MESHES;
#endif
}
void CPathServer::DebugDrawPedGenBlockingAreas()
{
Color32 cols[4] = { Color_red, Color_red1, Color_red2, Color_red3 };
s32 a;
for(a=0; a<MAX_PEDGEN_BLOCKED_AREAS; a++)
{
if(m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_bActive)
{
if(m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_iType==CPedGenBlockedArea::ESphere)
{
grcDebugDraw::Sphere(m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Sphere.GetOrigin(), m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Sphere.m_fActiveRadius, cols[0], false);
}
else if(m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_iType==CPedGenBlockedArea::EAngledArea)
{
int lastp = 3;
for(int p=0; p<4; p++)
{
Vector3 vTop(
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_CornerPts[p][0],
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_CornerPts[p][1],
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_fTopZ);
Vector3 vLastTop(
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_CornerPts[lastp][0],
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_CornerPts[lastp][1],
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_fTopZ);
Vector3 vBottom(
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_CornerPts[p][0],
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_CornerPts[p][1],
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_fBottomZ);
Vector3 vLastBottom(
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_CornerPts[lastp][0],
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_CornerPts[lastp][1],
m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.m_fBottomZ);
const Color32 col = cols[p];
const Color32 lastcol = cols[lastp];
// Draw the edges of the area
grcDebugDraw::Line(vLastTop, vTop, lastcol, col);
grcDebugDraw::Line(vLastBottom, vBottom, lastcol, col);
grcDebugDraw::Line(vTop, vBottom, col);
// Draw the normal of this face, from the centre of the face
const Vector3 vFaceCentre = (vLastTop + vTop + vLastBottom + vBottom) * 0.25f;
const Vector3 vNormal = m_AmbientPedGeneration.m_PedGenBlockedAreas[a].m_Area.GetNormal3(p);
grcDebugDraw::Line(vFaceCentre, vFaceCentre + vNormal, col, Color_white);
lastp = p;
}
}
}
}
}
void
CPathServer::DebugDrawPedSwitchAreas()
{
s32 a;
for(a=0; a<m_iNumPathRegionSwitches; a++)
{
if(m_PathRegionSwitches[a].m_iScriptUID != 0)
{
Vector3 vMid = (m_PathRegionSwitches[a].m_vMin + m_PathRegionSwitches[a].m_vMax) * 0.5f;
if(m_PathRegionSwitches[a].m_Switch & SWITCH_NAVMESH_DISABLE_AMBIENT_PEDS)
{
grcDebugDraw::BoxAxisAligned(RCC_VEC3V(m_PathRegionSwitches[a].m_vMin), RCC_VEC3V(m_PathRegionSwitches[a].m_vMax), Color_red, false);
grcDebugDraw::Text(vMid, Color_red, 0, 0, "NAVMESH NO WANDERING");
}
else if(m_PathRegionSwitches[a].m_Switch & SWITCH_NAVMESH_DISABLE_POLYGONS)
{
grcDebugDraw::BoxAxisAligned(RCC_VEC3V(m_PathRegionSwitches[a].m_vMin), RCC_VEC3V(m_PathRegionSwitches[a].m_vMax), Color_black, false);
grcDebugDraw::Text(vMid, Color_black, 0, 0, "NAVMESH DISABLED!!!");
}
else
{
grcDebugDraw::BoxAxisAligned(RCC_VEC3V(m_PathRegionSwitches[a].m_vMin), RCC_VEC3V(m_PathRegionSwitches[a].m_vMax), Color_green, false);
}
}
}
}
#endif
#endif // !__FINAL
#if !__FINAL
bool gOnlyVisualiseDynamicNavmeshes=false;
// This function displays the meshes for debugging purposes
float g_fClosestHierNodeDist2 = FLT_MAX;
CHierarchicalNavNode * g_pClosestHierNode = NULL;
#ifdef GTA_ENGINE
bool CPathServer::TransformWorldPosToScreenPos( const Vector3 & vWorldPos, Vector2 & vScreenPos )
{
CViewport* pVP = gVpMan.GetGameViewport();;
if(!pVP)
{
return false;
}
// look at rage code for clipping with grcViewport, and ???? private??? maybe just clip against near?
bool isVisible = true;
float fOutZ;
if(pVP->GetGrcViewport().IsSphereVisible(vWorldPos.x, vWorldPos.y, vWorldPos.z, 0.1f, &fOutZ)==cullOutside)
{
isVisible = false;
}
pVP->GetGrcViewport().Transform(VECTOR3_TO_VEC3V(vWorldPos), vScreenPos.x, vScreenPos.y );
// convert screen position to 0-1 space:
vScreenPos.x /= SCREEN_WIDTH;
vScreenPos.y /= SCREEN_HEIGHT;
vScreenPos.x = rage::Clamp(vScreenPos.x, 0.0f, 1.0f);
vScreenPos.y = rage::Clamp(vScreenPos.y, 0.0f, 1.0f);
return isVisible;
}
#endif
bool g_VisPolyUnderCamera = false;
void
CPathServer::Visualise()
{
#ifdef GTA_ENGINE
aiNavDomain domain = (aiNavDomain)m_iVisualiseDataSet;
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
float fHeightAboveMesh = debugDirector.IsFreeCamActive() ? 30.0f : 3.0f;
aiNavMeshStore* pStore = m_pNavMeshStores[domain];
if(m_bVerifyAdjacencies)
{
if(fwTimer::GetFrameCount() & 0x5)
{
PathSever_VerifyAdjacencies();
}
}
if(m_iVisualiseNavMeshes)
{
LOCK_NAVMESH_DATA;
//********************************************
// Display NavMesh
//********************************************
if(!gOnlyVisualiseDynamicNavmeshes)
{
u32 iNavMeshIndices[10];
static const float fSizeOfBlockX = CPathServerExtents::GetWorldWidthOfSector() * pStore->GetNumSectorsPerMesh();
static const float fSizeOfBlockY = CPathServerExtents::GetWorldWidthOfSector() * pStore->GetNumSectorsPerMesh();
iNavMeshIndices[0] = GetNavMeshIndexFromPosition(vOrigin + Vector3(-fSizeOfBlockX,-fSizeOfBlockY,0), domain);
iNavMeshIndices[1] = GetNavMeshIndexFromPosition(vOrigin + Vector3(0,-fSizeOfBlockY,0), domain);
iNavMeshIndices[2] = GetNavMeshIndexFromPosition(vOrigin + Vector3(fSizeOfBlockX,-fSizeOfBlockY,0), domain);
iNavMeshIndices[3] = GetNavMeshIndexFromPosition(vOrigin + Vector3(-fSizeOfBlockX,0,0), domain);
iNavMeshIndices[4] = GetNavMeshIndexFromPosition(vOrigin, domain);
iNavMeshIndices[5] = GetNavMeshIndexFromPosition(vOrigin + Vector3(fSizeOfBlockX,0,0), domain);
iNavMeshIndices[6] = GetNavMeshIndexFromPosition(vOrigin + Vector3(-fSizeOfBlockX,fSizeOfBlockY,0), domain);
iNavMeshIndices[7] = GetNavMeshIndexFromPosition(vOrigin + Vector3(0,fSizeOfBlockY,0), domain);
iNavMeshIndices[8] = GetNavMeshIndexFromPosition(vOrigin + Vector3(fSizeOfBlockY,fSizeOfBlockY,0), domain);
iNavMeshIndices[9] = NAVMESH_INDEX_TESSELLATION; // This is special navmesh used to store tessellated polys
for(int i=0; i<10; i++)
{
u32 index = iNavMeshIndices[i];
if(index == NAVMESH_NAVMESH_INDEX_NONE || (index != NAVMESH_INDEX_TESSELLATION && index >= pStore->GetMaxMeshIndex()))
continue;
if(index != NAVMESH_NAVMESH_INDEX_NONE)
{
CNavMesh * pMesh = GetNavMeshFromIndex(index, domain);
VisualiseNavMesh(pMesh, vOrigin, fHeightAboveMesh, (i==4), domain);
}
}
}
if(CPathServer::m_iNumDynamicNavMeshesInExistence)
{
for(int n=0; n<CVehicle::GetPool()->GetSize(); n++)
{
CVehicle * pVehicle = CVehicle::GetPool()->GetSlot(n);
if(pVehicle)
{
const CModelInfoNavMeshRef * pRef = CPathServer::m_DynamicNavMeshStore.GetByModelIndex(pVehicle->GetModelIndex());
if(pRef && pRef->m_pBackUpNavmeshCopy)
{
pRef->m_pBackUpNavmeshCopy->SetMatrix( MAT34V_TO_MATRIX34(pVehicle->GetMatrix()) );
VisualiseNavMesh(pRef->m_pBackUpNavmeshCopy, vOrigin, fHeightAboveMesh, false, domain);
}
}
}
}
//******************************************************
// Draw the dynamic objects as well.
//******************************************************
Color32 objColNormal(0x80,0x80,0xff,0xff);
Color32 objColHasUprootLimit(0xf0,0x00,0xa0,0xff);
Color32 objColNoObstacle(0xb0,0x40,0x60,0xff);
Color32 objColIsDoor(0x90,0xa0,0x20,0xff);
Color32 objColIsUserObstable(0x50,0x10,0xaa,0xff);
// Wait until dynamic objects are available
LOCK_DYNAMIC_OBJECTS_DATA;
Vector3 vTopPts[4];
Vector3 vBottomPts[4];
TDynamicObject * pCurr = m_PathServerThread.m_pFirstDynamicObject;
while(pCurr)
{
if(pCurr->m_pEntity)
{
Vector3 vCenter(0.0f,0.0f,0.0f);
for(s32 t=0; t<4; t++)
{
vTopPts[t] = Vector3(pCurr->m_vVertices[t].x, pCurr->m_vVertices[t].y, pCurr->m_NewBounds.GetTopZ());
vBottomPts[t] = Vector3(pCurr->m_vVertices[t].x, pCurr->m_vVertices[t].y, pCurr->m_NewBounds.GetBottomZ());
vCenter += vTopPts[t];
vCenter += vBottomPts[t];
}
vCenter *= 0.125f;
const Vector3 vDiff = vOrigin - vCenter;
if(vDiff.Mag2() < CPathServer::ms_fDebugVisPolysMaxDist*CPathServer::ms_fDebugVisPolysMaxDist)
{
const float fRadius = (pCurr->m_vVertices[0] - Vector2(pCurr->m_Bounds.GetOrigin().x, pCurr->m_Bounds.GetOrigin().y)).Mag();
if(camInterface::IsSphereVisibleInGameViewport(vCenter, fRadius))
{
const bool bIgnorable = pCurr->m_bInactiveDueToVelocity || (pCurr->m_bIsCurrentlyAnObstacle==false);
Color32 objCol;
if(pCurr->m_bIsUserAddedBlockingObject)
objCol = bIgnorable ? objColNoObstacle : objColIsUserObstable;
else if(pCurr->m_bIsOpenable)
objCol = bIgnorable ? objColNoObstacle : objColIsDoor;
else if(pCurr->m_bHasUprootLimit)
objCol = bIgnorable ? objColNoObstacle : objColHasUprootLimit;
else
objCol = bIgnorable ? objColNoObstacle : objColNormal;
grcDebugDraw::Line(vTopPts[0], vTopPts[1], objCol);
grcDebugDraw::Line(vTopPts[1], vTopPts[2], objCol);
grcDebugDraw::Line(vTopPts[2], vTopPts[3], objCol);
grcDebugDraw::Line(vTopPts[3], vTopPts[0], objCol);
grcDebugDraw::Line(vBottomPts[0], vBottomPts[1], objCol);
grcDebugDraw::Line(vBottomPts[1], vBottomPts[2], objCol);
grcDebugDraw::Line(vBottomPts[2], vBottomPts[3], objCol);
grcDebugDraw::Line(vBottomPts[3], vBottomPts[0], objCol);
grcDebugDraw::Line(vTopPts[0], vBottomPts[0], objCol);
grcDebugDraw::Line(vTopPts[1], vBottomPts[1], objCol);
grcDebugDraw::Line(vTopPts[2], vBottomPts[2], objCol);
grcDebugDraw::Line(vTopPts[3], vBottomPts[3], objCol);
if(ms_bDrawDynamicObjectGrids)
{
char tmp[64];
sprintf(tmp, "obj %" PTRDIFFTFMT "i (0x%p)", pCurr - m_PathServerThread.m_DynamicObjectsStore, pCurr);
grcDebugDraw::Text(vCenter, objCol, 0, 0, tmp);
}
/*
if(ms_bDrawDynamicObjectAxes)
{
Matrix34 mat;
mat.Identity();
mat.a = pCurr->m_Bounds.m_vRight;
mat.b = pCurr->m_Bounds.m_vForwards;
mat.c = CrossProduct(mat.a, mat.b);
mat.d = pCurr->m_Bounds.m_vOrigin;
grcDebugDraw::Axis(mat, 1.0f, false);
}
*/
}
if(CPathServer::ms_bDrawDynamicObjectMinMaxs)
{
Vector3 vMin, vMax;
pCurr->m_MinMax.GetAsFloats(vMin, vMax);
Vector3 vCorners[8] = {
Vector3(vMin.x, vMin.y, vMin.z), Vector3(vMax.x, vMin.y, vMin.z), Vector3(vMax.x, vMax.y, vMin.z), Vector3(vMin.x, vMax.y, vMin.z),
Vector3(vMin.x, vMin.y, vMax.z), Vector3(vMax.x, vMin.y, vMax.z), Vector3(vMax.x, vMax.y, vMax.z), Vector3(vMin.x, vMax.y, vMax.z)
};
Color32 color(192,32,48,255);
for(s32 v=0; v<4; v++)
{
grcDebugDraw::Line(vCorners[v], vCorners[(v+1)%4], color);
grcDebugDraw::Line(vCorners[v+4], vCorners[((v+1)%4)+4], color);
grcDebugDraw::Line(vCorners[v], vCorners[v+4], color);
}
}
}
}
pCurr = pCurr->m_pNext;
}
if(ms_bDrawDynamicObjectGrids)
{
Color32 gridCol(0x80,0xa0,0xff,0xff);
Color32 dynObjCol(0x90,0xa0,0x8f,0xff);
int g,h;
for(g=0; g<CDynamicObjectsContainer::GetNumGrids(); g++)
{
CDynamicObjectsGridCell * pGrid = CDynamicObjectsContainer::ms_DynamicObjectGrids[g];
Vector3 vCellMin, vCellMax, vObjMin, vObjMax;
pGrid->m_MinMaxOfGrid.GetAsFloats(vCellMin, vCellMax);
pGrid->m_MinMaxOfObjectsInGrid.GetAsFloats(vObjMin, vObjMax);
Vector3 vCellCorners[8] = {
Vector3(vCellMin.x, vCellMin.y, vCellMin.z), Vector3(vCellMax.x, vCellMin.y, vCellMin.z), Vector3(vCellMax.x, vCellMax.y, vCellMin.z), Vector3(vCellMin.x, vCellMax.y, vCellMin.z),
Vector3(vCellMin.x, vCellMin.y, vCellMax.z), Vector3(vCellMax.x, vCellMin.y, vCellMax.z), Vector3(vCellMax.x, vCellMax.y, vCellMax.z), Vector3(vCellMin.x, vCellMax.y, vCellMax.z)
};
Vector3 vObjCorners[8] = {
Vector3(vObjMin.x, vObjMin.y, vObjMin.z), Vector3(vObjMax.x, vObjMin.y, vObjMin.z), Vector3(vObjMax.x, vObjMax.y, vObjMin.z), Vector3(vObjMin.x, vObjMax.y, vObjMin.z),
Vector3(vObjMin.x, vObjMin.y, vObjMax.z), Vector3(vObjMax.x, vObjMin.y, vObjMax.z), Vector3(vObjMax.x, vObjMax.y, vObjMax.z), Vector3(vObjMin.x, vObjMax.y, vObjMax.z)
};
for(h=0; h<4; h++)
{
grcDebugDraw::Line(vCellCorners[h], vCellCorners[(h+1)%4], gridCol);
grcDebugDraw::Line(vCellCorners[h+4], vCellCorners[((h+1)%4)+4], gridCol);
grcDebugDraw::Line(vCellCorners[h], vCellCorners[h+4], gridCol);
}
for(h=0; h<4; h++)
{
grcDebugDraw::Line(vObjCorners[h], vObjCorners[(h+1)%4], dynObjCol);
grcDebugDraw::Line(vObjCorners[h+4], vObjCorners[((h+1)%4)+4], dynObjCol);
grcDebugDraw::Line(vObjCorners[h], vObjCorners[h+4], dynObjCol);
}
char tmp[64];
sprintf(tmp, "gridcell %i (0x%p)", g, pGrid);
grcDebugDraw::Text((vCellMin+vCellMax)*0.5f, gridCol, 0, 0, tmp);
}
}
}
#if __HIERARCHICAL_NODES_ENABLED
if(m_bVisualiseHierarchicalNodes)
{
g_fClosestHierNodeDist2 = FLT_MAX;
g_pClosestHierNode = NULL;
const float fHierVisDist = ms_fDebugVisNodesMaxDist;
const u32 iOriginNodes = m_pNavNodesStore->GetMeshIndexFromPosition(vOrigin);
s32 iNodesX, iNodesY;
m_pNavNodesStore->MeshIndexToMeshCoords(iOriginNodes, iNodesX, iNodesY);
for(int iHY=-1; iHY<=1; iHY++)
{
for(int iHX=-1; iHX<=1; iHX++)
{
const TNavMeshIndex iHierIndex = m_pNavNodesStore->MeshCoordsToMeshIndex(iNodesX+iHX, iNodesY+iHY);
if(iHierIndex != NAVMESH_NODE_INDEX_NONE)
{
CHierarchicalNavData * pNodes = m_pNavNodesStore->GetMeshByIndex(iHierIndex);
if(pNodes)
{
VisualiseHierarchicalNavData(pNodes, vOrigin, fHierVisDist);
}
}
}
}
if(g_pClosestHierNode)
{
Vector3 vWldNodePos;
Vector2 vScreenNodePos;
const u32 iHierNavMesh = g_pClosestHierNode->GetNavMeshIndex();
if(iHierNavMesh != NAVMESH_NAVMESH_INDEX_NONE && CPathServer::GetHierarchicalNavFromNavMeshIndex(iHierNavMesh))
{
const Vector3 & vMins = CPathServer::GetHierarchicalNavFromNavMeshIndex(iHierNavMesh)->GetMin();
const Vector3 & vSize = CPathServer::GetHierarchicalNavFromNavMeshIndex(iHierNavMesh)->GetSize();
g_pClosestHierNode->GetNodePosition(vWldNodePos, vMins, vSize);
if(CPathServer::TransformWorldPosToScreenPos(vWldNodePos, vScreenNodePos))
{
char TempString[256];
Color32 dbgCol = Color32(255, 255, 64, 255);
const float fLineHeight = ((float)grcDebugDraw::GetScreenSpaceTextHeight()) / ((float)SCREEN_HEIGHT);
sprintf(TempString, "%p", g_pClosestHierNode);
grcDebugDraw::Text(ScreenPos(vScreenNodePos), dbgCol, TempString);
vScreenNodePos.y += fLineHeight;
sprintf(TempString, "PedDensity : %i", g_pClosestHierNode->GetPedDensity());
grcDebugDraw::Text(vScreenNodePos, dbgCol, TempString);
vScreenNodePos.y += fLineHeight;
sprintf(TempString, "NodeRadius : %i", g_pClosestHierNode->GetNodeRadius());
grcDebugDraw::Text(vScreenNodePos, dbgCol, TempString);
vScreenNodePos.y += fLineHeight;
sprintf(TempString, "NodeArea : %i", g_pClosestHierNode->GetAreaRepresented());
grcDebugDraw::Text(vScreenNodePos, dbgCol, TempString);
vScreenNodePos.y += fLineHeight;
sprintf(TempString, "Flags : %u", g_pClosestHierNode->GetFlags());
grcDebugDraw::Text(vScreenNodePos, dbgCol, TempString);
}
}
}
}
#endif // __HIERARCHICAL_NODES_ENABLED
if(g_VisPolyUnderCamera)
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
if(debugDirector.IsFreeCamActive())
{
const Vector3& vPos = debugDirector.GetFreeCamFrame().GetPosition();
CNavMesh * pNavMeshUnderfoot = CPathServer::GetNavMeshFromIndex( CPathServer::GetNavMeshIndexFromPosition(vPos, domain), domain );
if(pNavMeshUnderfoot)
{
Vector3 vIsect;
u32 iPolyIndexUnderfoot = pNavMeshUnderfoot->GetPolyBelowPoint(vPos, vIsect, 10.0f);
if(iPolyIndexUnderfoot != NAVMESH_POLY_INDEX_NONE)
{
ASSERT_ONLY(TNavMeshPoly * pPolyUnderfoot = pNavMeshUnderfoot->GetPoly(iPolyIndexUnderfoot));
Assert(pPolyUnderfoot->GetNavMeshIndex() == pNavMeshUnderfoot->GetIndexOfMesh());
DrawPolyDebug(pNavMeshUnderfoot, iPolyIndexUnderfoot, Color_wheat, 0.15f, true);
}
bool bDbgTxt = false;
if(bDbgTxt)
DebugPolyText(pNavMeshUnderfoot, iPolyIndexUnderfoot);
}
}
}
//***************************************************************
//
// Finally, let's draw all the paths which have been found
// and are still remaining in the store..
//
//***************************************************************
if((m_iVisualiseNavMeshes != NavMeshVis_Off && m_iVisualiseNavMeshes != NavMeshVis_NavMeshTransparent)|| m_bVisualisePaths)
{
u32 iTotalNumReqs = MAX_NUM_PATH_REQUESTS + MAX_NUM_GRID_REQUESTS + MAX_NUM_LOS_REQUESTS;
int c;
s32 p;
u32 iAlpha;
float fAlpha, fAlphaMul;
float fMinAlpha = 1.0f / ((float)iTotalNumReqs);
struct TCtrlPts
{
Vector3 m_vCtrlPt2;
Vector3 m_vCtrlPt3;
};
static TCtrlPts vSplineCtrlPts[MAX_NUM_PATH_POINTS];
const Vector3 vRaiseAmt(0.0f, 0.0f, m_fVisNavMeshVertexShiftAmount+0.2f);
for(c=0; c<MAX_NUM_PATH_REQUESTS; c++)
{
if(m_PathRequests[c].m_hHandleThisWas == 0)
continue;
if(ms_bOnlyDisplaySelectedRoute && CPathServer::m_iSelectedPathRequest != c)
continue;
fAlpha = 1.0f;
iAlpha = (u32)(fAlpha * 255.0f);
Color32 iCol1, iCol2;
Color32 alphaMagenta = Color_magenta;
alphaMagenta.SetAlpha(64);
if(m_PathRequests[c].m_iNumPoints > 1)
{
// Record the spline ctrl points
// Just so we can nicely visualise the paths
for(p=0; p<m_PathRequests[c].m_iNumPoints; p++)
{
const int iSplineEnum = m_PathRequests[c].m_PathResultInfo.m_iPathSplineDistances[p];
if(iSplineEnum >= 0)
{
const Vector3 & vLast = m_PathRequests[c].m_PathPoints[p-1];
const Vector3 & vNext = m_PathRequests[c].m_PathPoints[p+1];
const Vector3 & vCurrent = m_PathRequests[c].m_PathPoints[p];
const Vector3 vLastToCurrent = vCurrent - vLast;
const Vector3 vCurrentToNext = vNext - vCurrent;
Vector3 vCtrlPt1, vCtrlPt4;
CalcPathSplineCtrlPts(iSplineEnum, m_PathRequests[c].m_PathResultInfo.m_fPathCtrlPt2TVals[p], vLast, vNext, vLastToCurrent, vCurrentToNext, vCtrlPt1, vSplineCtrlPts[p].m_vCtrlPt2, vSplineCtrlPts[p].m_vCtrlPt3, vCtrlPt4);
}
else
{
vSplineCtrlPts[p].m_vCtrlPt2 = m_PathRequests[c].m_PathPoints[p];
vSplineCtrlPts[p].m_vCtrlPt3 = m_PathRequests[c].m_PathPoints[p];
}
}
// Draw node markers
for(p=0; p<m_PathRequests[c].m_iNumPoints; p++)
{
Color32 iNodeCol = Color_MediumOrchid;
if(m_PathRequests[c].m_WaypointFlags[p].m_iSpecialActionFlags)
iNodeCol = Color_maroon;
grcDebugDraw::Line(m_PathRequests[c].m_PathPoints[p], m_PathRequests[c].m_PathPoints[p] + Vector3(0,0,0.6f), iNodeCol, iNodeCol);
}
// Draw the straight line segment of each path. We will do the spline curves (if any) in a sec..
for(p=0; p<m_PathRequests[c].m_iNumPoints-1; p++)
{
grcDebugDraw::Line(vSplineCtrlPts[p].m_vCtrlPt3 + vRaiseAmt, vSplineCtrlPts[p+1].m_vCtrlPt2 + vRaiseAmt, Color_magenta, Color_magenta);
}
for(p=0; p<m_PathRequests[c].m_iNumPoints-1; p++)
{
// If we have a spline at this corner, then draw this as well
const int iSplineEnum = m_PathRequests[c].m_PathResultInfo.m_iPathSplineDistances[p];
if(iSplineEnum >= 0)
{
const Vector3 & vLast = m_PathRequests[c].m_PathPoints[p-1];
const Vector3 & vNext = m_PathRequests[c].m_PathPoints[p+1];
const Vector3 & vCurrent = m_PathRequests[c].m_PathPoints[p];
const Vector3 vLastToCurrent = vCurrent - vLast;
const Vector3 vCurrentToNext = vNext - vCurrent;
Vector3 vCtrlPt1, vCtrlPt2, vCtrlPt3, vCtrlPt4;
CalcPathSplineCtrlPts(iSplineEnum, m_PathRequests[c].m_PathResultInfo.m_fPathCtrlPt2TVals[p], vLast, vNext, vLastToCurrent, vCurrentToNext, vCtrlPt1, vCtrlPt2, vCtrlPt3, vCtrlPt4);
// Draw the sharp un-splined corner in faint alpha col
grcDebugDraw::Line(vCtrlPt2 + vRaiseAmt, vCurrent + vRaiseAmt, alphaMagenta, alphaMagenta);
grcDebugDraw::Line(vCtrlPt3 + vRaiseAmt, vCurrent + vRaiseAmt, alphaMagenta, alphaMagenta);
// Now draw the spline
Vector3 vSplinePtA = vCtrlPt2;
static const float fSplineStep = 1.0f / ((float)PATHSPLINE_NUM_TEST_SUBDIVISIONS);
for(float u=fSplineStep; u<=1.0f; u+=fSplineStep)
{
const Vector3 vSplinePtB = PathSpline(vCtrlPt1, vCtrlPt2, vCtrlPt3, vCtrlPt4, u);
grcDebugDraw::Line(vSplinePtA + vRaiseAmt, vSplinePtB + vRaiseAmt, Color_magenta, Color_magenta);
vSplinePtA = vSplinePtB;
}
}
}
}
for(int s=0; s<m_PathRequests[c].m_iNumInfluenceSpheres; s++)
{
Color32 iCol = (CPathServer::m_iSelectedPathRequest == c) ? Color_orange2 : Color_orange4;
grcDebugDraw::Sphere(m_PathRequests[c].m_InfluenceSpheres[s].GetOrigin(), m_PathRequests[c].m_InfluenceSpheres[s].GetRadius(), iCol, false);
}
if(ms_bShowSearchExtents)
{
TShortMinMax minMax;
Vector3 vSearchMin, vSearchMax;
m_PathServerThread.CalculateSearchExtents(&m_PathRequests[c], minMax, vSearchMin, vSearchMax);
grcDebugDraw::BoxAxisAligned(RCC_VEC3V(vSearchMin), RCC_VEC3V(vSearchMax), Color_yellow3, false, 1);
}
}
for(c=0; c<MAX_NUM_LOS_REQUESTS; c++)
{
if(m_LineOfSightRequests[c].m_hHandleThisWas == 0)
continue;
u32 iHandleDiff = m_iNextHandle - m_LineOfSightRequests[c].m_hHandleThisWas;
if(iHandleDiff < iTotalNumReqs)
{
fAlphaMul = ((float)iHandleDiff) / ((float)iTotalNumReqs);
fAlpha = 1.0f - fAlphaMul;
}
else
{
fAlpha = fMinAlpha;
}
if(fAlpha < fMinAlpha) fAlpha = fMinAlpha;
else if(fAlpha > 1.0f) fAlpha = 1.0f;
iAlpha = (u32)(fAlpha * 255.0f);
if(m_LineOfSightRequests[c].m_iNumPts > 1)
{
for(int l=0; l<m_LineOfSightRequests[c].m_iNumPts-1; l++)
{
Color32 col = m_LineOfSightRequests[c].m_bLosResults[l] ? Color_green : Color_red;
col.SetAlpha(iAlpha);
grcDebugDraw::Line(
m_LineOfSightRequests[c].m_vPoints[l] + vRaiseAmt,
m_LineOfSightRequests[c].m_vPoints[l+1] + vRaiseAmt,
col
);
}
}
}
for(c=0; c<MAX_NUM_GRID_REQUESTS; c++)
{
if(m_GridRequests[c].m_hHandleThisWas == 0)
continue;
u32 iHandleDiff = m_iNextHandle - m_GridRequests[c].m_hHandleThisWas;
if(iHandleDiff < iTotalNumReqs)
{
fAlphaMul = ((float)iHandleDiff) / ((float)iTotalNumReqs);
fAlpha = 1.0f - fAlphaMul;
}
else
{
fAlpha = fMinAlpha;
}
if(fAlpha < fMinAlpha) fAlpha = fMinAlpha;
else if(fAlpha > 1.0f) fAlpha = 1.0f;
iAlpha = (u32)(fAlpha * 128.0f);
float fHalfSize = ((float)m_GridRequests[c].m_WalkRndObjGrid.m_iCentreCell) - 1.0f;
Vector3 vGridOrigin = m_GridRequests[c].m_WalkRndObjGrid.m_vOrigin;
// Don't display if it is too far away
float fDistSqr = (vGridOrigin - vOrigin).Mag2();
if(fDistSqr < 100.0f * 100.0f)
{
float fResolution = m_GridRequests[c].m_WalkRndObjGrid.m_fResolution;
// Get the min/max bounds of the grid area to be sampled
Vector3 vGridMin = vGridOrigin;
vGridMin.x -= (fResolution * fHalfSize);
vGridMin.y -= (fResolution * fHalfSize);
Vector3 vGridMax = vGridOrigin;
vGridMax.x += (fResolution * fHalfSize);
vGridMax.y += (fResolution * fHalfSize);
float x,y;
Color32 iFlagCol;
for(y=vGridMin.y; y<=vGridMax.y; y+=fResolution)
{
for(x=vGridMin.x; x<=vGridMax.x; x+=fResolution)
{
int ix = (int) ((x - vGridOrigin.x) / fResolution);
int iy = (int) ((y - vGridOrigin.y) / fResolution);
if(m_GridRequests[c].m_WalkRndObjGrid.IsWalkable(ix, iy))
{
iFlagCol.Set(0,0xff,0,iAlpha);
}
else
{
iFlagCol.Set(0xff,0,0,iAlpha);
}
grcDebugDraw::Line(
Vector3(x,y,vGridOrigin.z),
Vector3(x,y,vGridOrigin.z + 0.25f),
iFlagCol);
}
}
}
}
VisualiseTestPathEndPoints();
}
RenderMiscThings();
if(g_bTestBlockingObjectEnabled)
{
Matrix34 mat;
mat.Identity();
mat.RotateZ(g_fTestBlockingObjectRot * DtoR);
mat.d = g_vTestBlockingObjectPos;
Vector3 vMin = g_vTestBlockingObjectSize * -0.5f;
Vector3 vMax = g_vTestBlockingObjectSize * 0.5f;
static bool bFlash = false;
grcDebugDraw::BoxOriented(VECTOR3_TO_VEC3V(vMin), VECTOR3_TO_VEC3V(vMax), RCC_MAT34V(mat), bFlash ? Color_yellow : Color_navy, false);
}
//******************************************************************************
// Ok, also render the path start & end positions for all paths, plus the
// adjusted positions outside any dynamic objects.
//******************************************************************************
if(m_iVisualiseNavMeshes != NavMeshVis_Off && m_iVisualiseNavMeshes != NavMeshVis_NavMeshTransparent)
{
Color32 iUnadjustedPosCol, iAdjustedPosCol, iLinkCol, iFontCol;
iUnadjustedPosCol.Set(0xa0,0xa0,0xa0,0xff);
iAdjustedPosCol.Set(0xff,0xff,0xff,0xff);
iLinkCol.Set(0xff,0xff,0xff,0x80);
iFontCol.Set(0xff,0,0xff,0xff);
s32 i;
char szPathTxt[64];
for(i=0; i<MAX_NUM_PATH_REQUESTS; i++)
{
CPathRequest * pPathReq = &m_PathRequests[i];
if(pPathReq->m_hHandleThisWas != 0)
{
if(ms_bOnlyDisplaySelectedRoute && CPathServer::m_iSelectedPathRequest != i)
continue;
Vector3 vUnadjustedPathStart = pPathReq->m_vUnadjustedStartPoint;
Vector3 vUnadjustedPathEnd = pPathReq->m_vUnadjustedEndPoint;
Vector3 vPathStart = pPathReq->m_vPathStart;
Vector3 vPathEnd = pPathReq->m_vPathEnd;
// The UNADJUSTED positions (ie. those initially passed into the pathfinder)
grcDebugDraw::Line(vUnadjustedPathStart - Vector3(1.0f, 0, 0), vUnadjustedPathStart + Vector3(1.0f, 0, 0), iUnadjustedPosCol);
grcDebugDraw::Line(vUnadjustedPathStart - Vector3(0, 1.0f, 0), vUnadjustedPathStart + Vector3(0, 1.0f, 0), iUnadjustedPosCol);
grcDebugDraw::Line(vUnadjustedPathEnd - Vector3(1.0f, 0, 0), vUnadjustedPathEnd + Vector3(1.0f, 0, 0), iUnadjustedPosCol);
grcDebugDraw::Line(vUnadjustedPathEnd - Vector3(0, 1.0f, 0), vUnadjustedPathEnd + Vector3(0, 1.0f, 0), iUnadjustedPosCol);
// The ADJUSTED positions (ie. those which were used to try to find the path)
grcDebugDraw::Line(vPathStart - Vector3(1.0f, 0, 0), vPathStart + Vector3(1.0f, 0, 0), iAdjustedPosCol);
grcDebugDraw::Line(vPathStart - Vector3(0, 1.0f, 0), vPathStart + Vector3(0, 1.0f, 0), iAdjustedPosCol);
grcDebugDraw::Line(vPathEnd - Vector3(1.0f, 0, 0), vPathEnd + Vector3(1.0f, 0, 0), iAdjustedPosCol);
grcDebugDraw::Line(vPathEnd - Vector3(0, 1.0f, 0), vPathEnd + Vector3(0, 1.0f, 0), iAdjustedPosCol);
// Lines between the unadjusted & adjusted positions
grcDebugDraw::Line(vPathStart, vUnadjustedPathStart, iAdjustedPosCol, iUnadjustedPosCol);
grcDebugDraw::Line(vPathEnd, vUnadjustedPathEnd, iAdjustedPosCol, iUnadjustedPosCol);
// The reference vector
if(pPathReq->m_vReferenceVector.Mag2() > SMALL_FLOAT)
{
grcDebugDraw::Arrow(VECTOR3_TO_VEC3V(vPathStart + Vector3(0,0,0.5f)), VECTOR3_TO_VEC3V(vPathStart + Vector3(0,0,0.5f) + pPathReq->m_vReferenceVector), 0.2f, Color_grey32);
}
Vector2 vScreenStart, vScreenEnd;
if(CPathServer::TransformWorldPosToScreenPos(vPathStart, vScreenStart))
{
sprintf(szPathTxt, "start (0x%x)", pPathReq->m_hHandleThisWas);
grcDebugDraw::Text(vScreenStart, Color_white, szPathTxt);
}
if(CPathServer::TransformWorldPosToScreenPos(vPathEnd, vScreenEnd))
{
sprintf(szPathTxt, "end (0x%x)", pPathReq->m_hHandleThisWas);
grcDebugDraw::Text(vScreenEnd, Color_white, szPathTxt);
}
// Draw a faint link between the adjusted start & endpoints
grcDebugDraw::Line(vPathStart, vPathEnd, iLinkCol);
}
}
}
#endif // GTA_ENGINE
//*******************************************
//
// Visualise PathServer info ?
//
//*******************************************
if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_PathRequests)
{
int ypos = VisualisePathServerCommon(domain, (s32)(s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
VisualisePathRequests(ypos, domain);
}
if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_LineOfSightRequests)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
VisualiseLineOfSightRequests(ypos, domain);
}
if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_AudioRequests)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
VisualiseAudioPropertiesRequests(ypos, domain);
}
if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_FloodFillRequests)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
VisualiseFloodFillRequests(ypos, domain);
}
if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_ClearAreaRequests)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
VisualiseClearAreaRequests(ypos, domain);
}
if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_ClosestPositionRequests)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
VisualiseClosestPositionRequests(ypos, domain);
}
if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_Text)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
VisualiseText(ypos, domain);
}
else if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_MemoryUsage)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
VisualiseMemoryUsage(ypos, domain);
}
else if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_CurrentNavMesh)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
s32 iCurrentMesh = pStore->GetMeshIndexFromPosition(vOrigin);
CNavMesh * pCurrentNavMesh = pStore->GetMeshByIndex(iCurrentMesh);
if(pCurrentNavMesh)
{
ypos = VisualiseCurrentNavMeshDetails(ypos, pCurrentNavMesh);
}
ypos += grcDebugDraw::GetScreenSpaceTextHeight() * 2;
char tmp[256];
const atArray<s32> & loadedMeshes = pStore->GetLoadedMeshes();
for(s32 s=0; s<loadedMeshes.GetCount(); s++)
{
s32 iMesh = loadedMeshes[s];
CNavMesh * pNavMesh = pStore->GetMeshByIndex(iMesh);
if(pNavMesh)
{
int iMeshX, iMeshY;
pStore->MeshIndexToMeshCoords(pNavMesh->GetIndexOfMesh(), iMeshX, iMeshY);
iMeshX *= CPathServerExtents::m_iNumSectorsPerNavMesh;
iMeshY *= CPathServerExtents::m_iNumSectorsPerNavMesh;
sprintf(tmp, "[%i][%i] - polys=%i", iMeshX, iMeshY, pNavMesh->GetNumPolys());
grcDebugDraw::Text( ScreenPos(g_vPathserverDebugTopLeft.x+40,(float)ypos), Color_white, tmp);
ypos += grcDebugDraw::GetScreenSpaceTextHeight();
}
}
}
else if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_PolygonInfo)
{
int ypos = VisualisePathServerCommon(domain, (s32)g_vPathserverDebugTopLeft.y);
ypos = Max(ypos, 64);
s32 iCurrentMesh = pStore->GetMeshIndexFromPosition(vOrigin);
CNavMesh * pCurrentNavMesh = pStore->GetMeshByIndex(iCurrentMesh);
if(pCurrentNavMesh)
{
VisualisePolygonInfo(ypos, pCurrentNavMesh, vOrigin, domain);
}
}
//*************************************************************************************
// Allow the toggling of navmesh display modes via the "I" key. Also print up a
// little message to say which display mode is currently active.
#ifdef GTA_ENGINE
static u32 iLastTimeNavMeshModeToggled = 0x7FFFFFFF;
// We don't want the I key to toggle between ALL the modes, there are too many of them
const int iNumQuickModes = 8;
static const int iVisModes[iNumQuickModes+1] =
{
NavMeshVis_Off,
NavMeshVis_NavMeshTransparent,
NavMeshVis_NavMeshWireframe,
NavMeshVis_NavMeshSolid,
NavMeshVis_Pavements,
NavMeshVis_PedDensity,
NavMeshVis_AudioProperties,
NavMeshVis_PavementCheckingMode,
-1
};
static int iVisModeIndex = 0;
if(CControlMgr::GetKeyboard().GetKeyJustDown(KEY_I, KEYBOARD_MODE_DEBUG, "Increment navmesh display"))
{
iVisModeIndex++;
if(iVisModes[iVisModeIndex] == -1)
iVisModeIndex = 0;
iLastTimeNavMeshModeToggled = fwTimer::GetTimeInMilliseconds();
m_iVisualiseNavMeshes = iVisModes[iVisModeIndex];
}
else if(CControlMgr::GetKeyboard().GetKeyJustDown(KEY_I, KEYBOARD_MODE_DEBUG_SHIFT, "Decrement navmesh display"))
{
iVisModeIndex--;
if(iVisModeIndex < 0)
iVisModeIndex += iNumQuickModes;
iLastTimeNavMeshModeToggled = fwTimer::GetTimeInMilliseconds();
m_iVisualiseNavMeshes = iVisModes[iVisModeIndex];
}
else if(CControlMgr::GetKeyboard().GetKeyJustDown(KEY_I, KEYBOARD_MODE_DEBUG_CTRL, "Toggle navmesh display off"))
{
iVisModeIndex = 0;
iLastTimeNavMeshModeToggled = fwTimer::GetTimeInMilliseconds();
m_iVisualiseNavMeshes = iVisModes[iVisModeIndex];
}
if(fwTimer::GetTimeInMilliseconds() - iLastTimeNavMeshModeToggled < 4000)
{
//if(grcViewport::GetCurrent())
{
char text[256];
sprintf(text, "NavMesh Display : %s", ms_pNavMeshVisModeTxt[CPathServer::m_iVisualiseNavMeshes]);
Vector2 vTextRenderPos(0.0f, (float)(SCREEN_HEIGHT - 32));
grcDebugDraw::Text(ScreenPos(vTextRenderPos), Color_white, text);
}
}
m_iNumImmediateModeLosCallsThisFrame = 0;
m_iNumImmediateModeWanderPathsThisFrame = 0;
m_iNumImmediateModeFleePathsThisFrame = 0;
m_iNumImmediateModeSeekPathsThisFrame = 0;
m_fTimeSpentOnImmediateModeCallsThisFrame = 0.0f;
#endif // GTA_ENGINE
}
#endif
#if !__FINAL
#ifdef GTA_ENGINE
void
CPathServer::VisualiseNavMesh(CNavMesh * pNavMesh, const Vector3 & vOrigin, const float fHeightAboveMesh, bool bIsMainNavMeshUnderFoot, aiNavDomain domain)
{
u32 t;
u32 v;
Vector3 v1, v2, v3, vCenter;
static Color32 polyCol(0x80,0x80,0xff,0);
static Color32 pavementCol(0xb0,0x10,0xb0,0x80);
static Color32 roadCol(0xa0,0x30,0x30,0x80);
static Color32 trainTracksCol(0xa0,0xa0,0x30,0x80);
static Color32 polyColMarked(0xff,0,0xff,0xff);
static Color32 selCol(0xff,0,0,0xff);
static Color32 adjCol(0xff,0xff,0xff,0xff);
static Color32 openCol(0,0xff,0,0xff);
static Color32 closedCol(0xff,0,0,0xff);
static Color32 coverEdgeCol(0xff,0xff,0,0);
static Color32 coverPointBaseCol(0xff,0,0,0);
static Color32 coverPointTopCol(0xff,0xff,0xff,0);
static Color32 shelterCol(0x4f, 0x78, 0x20, 0);
static Color32 specialLinksCol(0xaf, 0x98, 0x60, 0);
static Color32 tooSteepCol(0xff, 0x18, 0x18, 0);
static Color32 waterCol(0x20, 0x20, 0xff, 0);
static Color32 waterColShallow(0xa0, 0xa0, 0xff, 0);
static Color32 spaceAboveCol1(0x30, 0x30, 0x90, 0xff);
static Color32 spaceAboveCol2(0x50, 0x50, 0xf0, 0xff);
static Color32 carNodeCol(0x90, 0x90, 0x30, 0);
static Color32 interiorCol(0xa0, 0xa0, 0, 0);
static Color32 isolatedCol(0x60, 0, 0, 0);
static Color32 networkSpawnCandidateCol(0, 0x60, 0xa0, 0xff);
static Color32 noWanderCol(0x90, 0x10, 0x0, 0);
float fMaxDist = ms_fDebugVisPolysMaxDist;
float fNormalHeight = m_fVisNavMeshVertexShiftAmount;
float fCoverHeight = fNormalHeight + 0.08f;
float fHeightExtra = fNormalHeight; //0.1f;
if(pNavMesh)
{
if(m_bVisualiseQuadTrees)
{
reinterpret_cast<CNavMeshGTA*>(pNavMesh)->VisualiseQuadTree(m_bVisualiseAllCoverPoints);
}
if(m_bDebugShowSpecialLinks)
{
VisualiseSpecialLinks(pNavMesh, domain);
}
if(m_iVisualiseNavMeshes != NavMeshVis_Off)
{
// Use a colour based upon the NavMesh's address.
// It'll be important to be able to distinguish clearly between adjacent meshes.
// u32 iRandVal = static_cast<u32>(reinterpret_cast<size_t>(pNavMesh));
// iRandVal ^= (pNavMesh->GetIndexOfMesh() * pNavMesh->GetIndexOfMesh());
Color32 meshCol = ((pNavMesh->GetFlags()&NAVMESH_DLC)==0) ? Color_SlateGray1 : Color_LimeGreen;
// meshCol.SetRed((iRandVal & 0xFF000000)>>24);
// meshCol.SetGreen((iRandVal & 0x00FF0000)>>16);
// meshCol.SetBlue((iRandVal & 0x0000FF00)>>8);
// meshCol.SetAlpha(iRandVal & 0x000000FF);
Color32 col;
for(t=0; t<pNavMesh->GetNumPolys(); t++)
{
TNavMeshPoly * pPoly = pNavMesh->GetPoly(t);
if(pPoly->GetReplacedByTessellation())
continue;
if(pPoly->GetNavMeshIndex() == NAVMESH_INDEX_TESSELLATION)
{
if(!pPoly->GetIsTessellatedFragment())
continue;
}
float fRecip = 1.0f / ((float)pPoly->GetNumVertices() );
vCenter = Vector3(0,0,0);
for(v=0; v<pPoly->GetNumVertices(); v++)
{
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, v), v1 );
vCenter += v1;
}
vCenter *= fRecip;
float fDistSqr = (vCenter - vOrigin).Mag2();
if(fDistSqr < CPathServer::ms_fDebugVisPolysMaxDist*CPathServer::ms_fDebugVisPolysMaxDist)
{
float fRadius = 10.0f;
if((m_bDebugShowPolyVolumesAbove || m_bDebugShowPolyVolumesBelow)
&& pNavMesh->GetPoly(t)->GetIsWater())
fRadius += 100.0f;
if(!camInterface::IsSphereVisibleInGameViewport(vCenter, fRadius))
continue;
col = meshCol;
if(m_iVisualiseNavMeshes != NavMeshVis_NavMeshTransparent) // Skip the OPEN/CLOSED draw in Transparent mode, to keep it as a clean view of the static data.
{
if(pNavMesh->GetPoly(t)->TestFlags(NAVMESHPOLY_OPEN))
{
col = openCol;
}
else if(pNavMesh->GetPoly(t)->TestFlags(NAVMESHPOLY_CLOSED))
{
col = closedCol;
}
if(pPoly->GetNavMeshIndex()==NAVMESH_INDEX_TESSELLATION)
col = Lerp(0.75f, col, Color_black);
}
else
{
if(m_iVisualisePathServerInfo == CPathServer::PathServerVis_PolygonInfo)
{
if(pPoly->GetLiesAlongEdgeOfMesh())
{
col = Lerp(0.5f, col, Color_black);
}
}
}
col.SetAlpha(0);
float fAlpha;
if(m_iVisualiseNavMeshes == NavMeshVis_NavMeshTransparent)
{
// Not much use in fading the lines in this mode, at least not unless we also fade the polygons.
fAlpha = 1.0f;
}
else
{
// Fade out nicely..
float fDist = rage::Sqrtf(fDistSqr);
fAlpha = fDist / fMaxDist;
if(fAlpha < 0.0f) fAlpha = 0.0f;
else if(fAlpha > 0.999f) fAlpha = 0.999f;
fAlpha = 1.0f - (fAlpha*fAlpha); // inv sqr falloff
}
u32 iAlpha = (u32)(fAlpha * 255.0f);
col.SetAlpha(iAlpha);
if(ms_bMarkVisitedPolys && pPoly->GetDebugMarked())
{
polyColMarked.SetAlpha(iAlpha);
DrawPolyDebug(pNavMesh, t, polyColMarked, fNormalHeight, false);
}
if(m_iVisualiseNavMeshes==NavMeshVis_PavementCheckingMode)
{
static u32 iLastFlashTime = 0;
static bool bFlashToggle = false;
if(iLastFlashTime + 250 < fwTimer::GetTimeInMilliseconds())
{
iLastFlashTime = fwTimer::GetTimeInMilliseconds();
bFlashToggle = !bFlashToggle;
}
// Mark in flashing red if there is ped-density here, but NO pavement.
// This can cause peds to wander freely around the map & into the road.
// This is generally ok only for parks, wasteground, etc.
if(pPoly->GetPedDensity()>0 && !pPoly->GetIsPavement())
{
if(bFlashToggle)
{
DrawPolyDebug(pNavMesh, t, Color_red, fNormalHeight + 0.1f, false);
}
}
else
{
// Mark areas of pavement
if(pPoly->GetIsPavement())
{
DrawPolyDebug(pNavMesh, t, Color_magenta1, fNormalHeight + 0.1f, false);
}
}
continue;
}
const bool bDrawAllPolys = true;
//m_iVisualiseNavMeshes != NavMeshVis_WaterSurface;
if(bDrawAllPolys)
{
if(m_iVisualiseNavMeshes!=NavMeshVis_NavMeshSolid && m_iVisualiseNavMeshes!=NavMeshVis_NavMeshTransparent)
{
DrawPolyDebug(pNavMesh, t, col, fNormalHeight, true);
}
else
{
Color32 outlineCol(0,0,0,(s32)iAlpha);
DrawPolyDebug(pNavMesh, t, outlineCol, fNormalHeight, true);
DrawPolyDebug(pNavMesh, t, col, fNormalHeight, false, m_iVisualiseNavMeshes == NavMeshVis_NavMeshTransparent ? 128 : 255);
}
}
int lastv = pPoly->GetNumVertices()-1;
for(v=0; v<pPoly->GetNumVertices(); v++)
{
const TAdjPoly & adjPoly = pNavMesh->GetAdjacentPoly( (u32)pPoly->GetFirstVertexIndex() + lastv );
Vector3 vEdgeVec, vLastEdgeVec;
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, lastv), vLastEdgeVec );
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, v), vEdgeVec );
vLastEdgeVec.z += fCoverHeight;
vEdgeVec.z += fCoverHeight;
// If this poly has an edge which provides cover, then highlight it
if(adjPoly.GetEdgeProvidesCover())
{
Color32 iTmpCol = coverEdgeCol;
iTmpCol.SetAlpha(iAlpha);
grcDebugDraw::Line(vLastEdgeVec, vEdgeVec, iTmpCol);
}
// If this poly has a non-standard adjacency to the next one,
// then draw a visual indication of it..
if(adjPoly.GetAdjacencyType() == ADJACENCY_TYPE_NORMAL)
{
lastv = v;
continue;
}
CNavMesh * pAdjNavMesh = GetNavMeshFromIndex(adjPoly.GetNavMeshIndex(pNavMesh->GetAdjacentMeshes()), domain);
if(!pAdjNavMesh)
{
lastv = v;
continue;
}
Vector3 vHalfWayAlongThisEdge = (vLastEdgeVec + vEdgeVec) * 0.5f;
Vector3 vEdge = vEdgeVec - vLastEdgeVec;
vEdge.z = 0;
vEdge.Normalize();
Vector3 vEdgeNormal = CrossProduct(vEdge, Vector3(0,0,1.0f));
vEdgeNormal.Normalize();
Vector3 vAdjPolyCentroid;
pAdjNavMesh->GetPolyCentroid(adjPoly.GetPolyIndex(), vAdjPolyCentroid);
// Visualise the adjacency link into the next poly, if a special type
VisualiseAdjacency(vHalfWayAlongThisEdge, vAdjPolyCentroid, (eNavMeshPolyAdjacencyType)adjPoly.GetAdjacencyType(), adjPoly.GetHighDropOverEdge(), adjPoly.GetAdjacencyDisabled(), iAlpha);
lastv = v;
}
if(m_iVisualiseNavMeshes == NavMeshVis_Pavements)
{
if(pPoly->TestFlags(NAVMESHPOLY_IS_PAVEMENT))
{
DrawPolyDebug(pNavMesh, t, pavementCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_Roads)
{
if(pPoly->GetIsRoad())
{
DrawPolyDebug(pNavMesh, t, pavementCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_TrainTracks)
{
if(pPoly->GetIsTrainTrack())
{
DrawPolyDebug(pNavMesh, t, trainTracksCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_PedDensity)
{
float fDensity = (float)pPoly->GetPedDensity();
if(fDensity != 0.0f && CPedPopulation::GetAdjustPedSpawnDensity()!=0)
{
if( vCenter.IsGreaterOrEqualThan(CPedPopulation::GetAdjustPedSpawnDensityMin()) &&
CPedPopulation::GetAdjustPedSpawnDensityMax().IsGreaterThan(vCenter) )
{
fDensity += CPedPopulation::GetAdjustPedSpawnDensity();
fDensity = Clamp(fDensity, 0.0f, (float)MAX_PED_DENSITY);
}
}
Color32 iDensityCol;
float s = fDensity / (float)MAX_PED_DENSITY;
int c = (int) (s * 255.0f);
iDensityCol = Color32(c, 0, 0, 255);
iDensityCol.SetAlpha(iAlpha);
DrawPolyDebug(pNavMesh, t, iDensityCol, fHeightExtra, false);
static const bool bPrintDensity=true;
if(bPrintDensity)
{
// Draw the enumeration value
static char txt[8];
Vector2 vScreenPos;
if(CPathServer::TransformWorldPosToScreenPos(vCenter, vScreenPos))
{
s32 iDensity = (s32)fDensity;
if(CPedPopulation::GetAdjustPedSpawnDensity() > 0)
sprintf(txt, "%u (%u +%i)", iDensity, pPoly->GetPedDensity(), CPedPopulation::GetAdjustPedSpawnDensity());
else if(CPedPopulation::GetAdjustPedSpawnDensity() < 0)
sprintf(txt, "%u (%u %i)", iDensity, pPoly->GetPedDensity(), CPedPopulation::GetAdjustPedSpawnDensity());
else
sprintf(txt, "%u", pPoly->GetPedDensity());
grcDebugDraw::Text(vScreenPos, Color_white, txt);
}
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_Disabled)
{
if(pPoly->GetIsDisabled())
{
DrawPolyDebug(pNavMesh, t, Color_black, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_Shelter)
{
if(pPoly->TestFlags(NAVMESHPOLY_IN_SHELTER))
{
DrawPolyDebug(pNavMesh, t, shelterCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_HasSpecialLinks)
{
if(pPoly->GetNumSpecialLinks()!=0)
{
DrawPolyDebug(pNavMesh, t, specialLinksCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_TooSteep)
{
if(pPoly->TestFlags(NAVMESHPOLY_TOO_STEEP_TO_WALK_ON))
{
DrawPolyDebug(pNavMesh, t, tooSteepCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_WaterSurface)
{
if(pPoly->GetIsWater())
{
if(pPoly->GetIsShallow())
{
DrawPolyDebug(pNavMesh, t, waterColShallow, fHeightExtra, false);
}
else
{
DrawPolyDebug(pNavMesh, t, waterCol, fHeightExtra, false);
}
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_AudioProperties)
{
// Draw the enumeration value
u32 iAudioProperty = pPoly->GetAudioProperties();
static char txt[8];
Vector2 vScreenPos;
if(CPathServer::TransformWorldPosToScreenPos(vCenter, vScreenPos))
{
sprintf(txt, "%u", iAudioProperty);
grcDebugDraw::Text(vScreenPos, Color_white, txt);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_CoverDirections)
{
// Draw the bitfield
u32 iCoverDirections = pPoly->GetCoverDirections();
static char txt[8];
Vector2 vScreenPos;
if(CPathServer::TransformWorldPosToScreenPos(vCenter, vScreenPos))
{
sprintf(txt, "%u", iCoverDirections);
grcDebugDraw::Text(vScreenPos, Color_white, txt);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_CarNodes)
{
if(pPoly->GetIsNearCarNode())
{
DrawPolyDebug(pNavMesh, t, carNodeCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_Interior)
{
if(pPoly->GetIsInterior())
{
DrawPolyDebug(pNavMesh, t, interiorCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_Isolated)
{
if(pPoly->GetIsIsolated())
{
DrawPolyDebug(pNavMesh, t, isolatedCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_NetworkSpawnCandidates)
{
if(pPoly->GetIsNetworkSpawnCandidate())
{
DrawPolyDebug(pNavMesh, t, networkSpawnCandidateCol, fHeightExtra, false);
}
}
else if(m_iVisualiseNavMeshes == NavMeshVis_NoWander)
{
if(pPoly->GetIsSwitchedOffForPeds())
{
DrawPolyDebug(pNavMesh, t, noWanderCol, fHeightExtra, false);
}
}
/*
if(pNavMesh->GetPolyVolumeInfos())
{
if((m_bDebugShowPolyVolumesAbove && pPoly->GetIsUnderwater()) ||
(m_bDebugShowPolyVolumesBelow && (pPoly->GetIsWater()&&!pPoly->GetIsUnderwater())))
{
Assert(pNavMesh->GetFlags() & NAVMESH_HAS_POLY_VOLUME_SECTION);
Assert(pNavMesh->GetPolyVolumeInfos());
spaceAboveCol1.SetAlpha(iAlpha);
spaceAboveCol2.SetAlpha(iAlpha);
const s16 iFreeSpaceTopZ = pNavMesh->GetPolyVolumeInfos()[t].GetFreeSpaceTopZ();
if(iFreeSpaceTopZ != TPolyVolumeInfo::ms_iFreeSpaceNone)
{
DrawPolyVolumeDebug(pNavMesh, t, spaceAboveCol1, spaceAboveCol2, (float)iFreeSpaceTopZ);
}
}
}
*/
}
}
if(bIsMainNavMeshUnderFoot && m_iVisualiseNavMeshes != NavMeshVis_NavMeshTransparent)
{
CNavMesh * pNavMeshUnderfoot = pNavMesh;
TNavMeshPoly * pPoly;
// The poly under foot
Vector3 vTmp;
u32 iPoly = pNavMeshUnderfoot->GetPolyBelowPoint(vOrigin, vTmp, fHeightAboveMesh);
// Or maybe a little way above ?
if(iPoly == NAVMESH_POLY_INDEX_NONE)
{
// If we didn't find one exactly below, then try again with a volume test
Vector3 vNewPos;
TNavMeshAndPoly navMeshAndPoly;
m_PathServerThread.FindApproxNavMeshPolyForRouteEndPoints(vOrigin, 10.0f, navMeshAndPoly, false, NAVMESH_NAVMESH_INDEX_NONE, domain);
pNavMeshUnderfoot = GetNavMeshFromIndex(navMeshAndPoly.m_iNavMeshIndex, domain);
iPoly = navMeshAndPoly.m_iPolyIndex;
}
if(iPoly != NAVMESH_POLY_INDEX_NONE)
{
pPoly = pNavMeshUnderfoot->GetPoly(iPoly);
if(pPoly->GetReplacedByTessellation())
{
pNavMeshUnderfoot = m_pTessellationNavMesh;
iPoly = pNavMeshUnderfoot->GetPolyBelowPoint(vOrigin, vTmp, fHeightAboveMesh);
if(iPoly != NAVMESH_POLY_INDEX_NONE)
{
pPoly = pNavMeshUnderfoot->GetPoly(iPoly);
}
else
{
Vector3 vNewPos;
TNavMeshAndPoly navMeshAndPoly;
m_PathServerThread.FindApproxNavMeshPolyForRouteEndPoints(vOrigin, 10.0f, navMeshAndPoly, true, NAVMESH_NAVMESH_INDEX_NONE, domain);
pNavMeshUnderfoot = GetNavMeshFromIndex(navMeshAndPoly.m_iNavMeshIndex, domain);
iPoly = navMeshAndPoly.m_iPolyIndex;
}
pPoly = pNavMeshUnderfoot->GetPoly(iPoly);
}
if(pPoly)
{
if(CPathServer::m_bDebugPolyUnderfoot)
{
DebugPolyText(pNavMeshUnderfoot, iPoly);
CPathServer::m_bDebugPolyUnderfoot = false;
}
// The adjacent polys
for(u32 a=0; a<pPoly->GetNumVertices(); a++)
{
const TAdjPoly & adjPoly = pNavMeshUnderfoot->GetAdjacentPoly((u32) pPoly->GetFirstVertexIndex() + a);
CNavMesh * pAdjNavMesh = GetNavMeshFromIndex(adjPoly.GetNavMeshIndex(pNavMeshUnderfoot->GetAdjacentMeshes()), domain);
if(pAdjNavMesh)
{
DrawPolyDebug(pAdjNavMesh, adjPoly.GetPolyIndex(), adjCol, fHeightExtra + 0.1f, true);
}
}
DrawPolyDebug(pNavMeshUnderfoot, iPoly, selCol, fHeightExtra + 0.1f, true);
}
}
}
}
}
}
#if !__HIERARCHICAL_NODES_ENABLED
void CPathServer::VisualiseHierarchicalNavData(CHierarchicalNavData * UNUSED_PARAM(pHierNav), const Vector3 & UNUSED_PARAM(vOrigin), const float UNUSED_PARAM(fVisDist))
{
#else
void CPathServer::VisualiseHierarchicalNavData(CHierarchicalNavData * pHierNav, const Vector3 & vOrigin, const float fVisDist)
{
if(!pHierNav)
return;
Vector3 vNodeVec(0.0f, 0.0f, 2.0f);
Vector3 vNodeLinkA(0.0f, 0.0f, 1.0f);
Vector3 vNodeLinkB(0.0f, 0.0f, 1.15f);
const Vector3 & vMins = pHierNav->GetMin();
const Vector3 & vSize = pHierNav->GetSize();
Vector3 vNodePos, vDestNodePos;
static const float fDrawRangeSqr = fVisDist*fVisDist;
u32 n,l;
for(n=0; n<pHierNav->GetNumNodes(); n++)
{
CHierarchicalNavNode * pNode = pHierNav->GetNode(n);
pNode->GetNodePosition(vNodePos, vMins, vSize);
const float fD2 = (vNodePos - vOrigin).Mag2();
if(fD2 < fDrawRangeSqr)
{
if(fD2 < g_fClosestHierNodeDist2)
{
g_fClosestHierNodeDist2 = fD2;
g_pClosestHierNode = pNode;
}
{
if(pNode->GetIsDebugMarked())
{
grcDebugDraw::Line(vNodePos, vNodePos + (vNodeVec*2.0f), Color_yellow2, Color_red2);
}
else
{
grcDebugDraw::Line(vNodePos, vNodePos + vNodeVec, Color_grey0, Color_white);
}
const u32 iNumLinks = pNode->GetNumLinks();
for(l=0; l<iNumLinks; l++)
{
CHierarchicalNavLink * pLink = pHierNav->GetLink(pNode->GetStartOfLinkData()+l);
if(pLink->GetNavMeshIndex()!=NAVMESH_NAVMESH_INDEX_NONE)
{
const TNavMeshIndex iNavMesh = pLink->GetNavMeshIndex();
Assert(iNavMesh<=NAVMESH_MAX_MAP_INDEX);
if(iNavMesh<=NAVMESH_MAX_MAP_INDEX)
{
int iX,iY;
m_pNavMeshStore->GetSectorCoordsFromMeshIndex(iNavMesh, iX, iY);
if(iX >= 0 && iY >= 0 && iX < CPathServerExtents::GetWorldWidthInSectors() && iY < CPathServerExtents::GetWorldDepthInSectors())
{
const int iNodesIndex = m_pNavNodesStore->GetMeshIndexFromSectorCoords(iX, iY);
if(iNodesIndex != m_pNavNodesStore->GetMeshIndexNone())
{
CHierarchicalNavData * pNodes = m_pNavNodesStore->GetMeshByIndex(iNodesIndex);
if(pNodes)
{
const Vector3 & vDestMins = pNodes->GetMin();
const Vector3 & vDestSize = pNodes->GetSize();
CHierarchicalNavNode * pDestNode = pNodes->GetNode(pLink->GetNodeIndex());
pDestNode->GetNodePosition(vDestNodePos, vDestMins, vDestSize);
grcDebugDraw::Line(vNodePos + vNodeLinkA, vDestNodePos + vNodeLinkB, Color_yellow, Color_orange);
if(CPathServer::m_bVisualiseLinkWidths)
{
Vector3 vLinkVec = vDestNodePos - vNodePos;
vLinkVec.Normalize();
const Vector3 vTangent = CrossProduct(vLinkVec, ZAXIS);
if(pLink->GetWidthToLeft() != 0)
{
const float fWidthLeft = (float) pLink->GetWidthToLeft();
const Vector3 vLeft1 = vNodePos+vNodeLinkA - (vTangent*fWidthLeft);
const Vector3 vLeft2 = vDestNodePos+vNodeLinkB - (vTangent*fWidthLeft);
grcDebugDraw::Line(vNodePos + vNodeLinkA, vLeft1, Color_DarkGoldenrod4, Color_DarkGoldenrod4);
grcDebugDraw::Line(vDestNodePos + vNodeLinkB, vLeft2, Color_DarkGoldenrod4, Color_DarkGoldenrod4);
grcDebugDraw::Line(vLeft1, vLeft2, Color_yellow4, Color_orange4);
grcDebugDraw::Poly(vNodePos + vNodeLinkA, vLeft1, vLeft2, Color_DarkGoldenrod2);
}
if(pLink->GetWidthToRight() != 0)
{
const float fWidthRight = (float) pLink->GetWidthToRight();
const Vector3 vRight1 = vNodePos+vNodeLinkA + (vTangent*fWidthRight);
const Vector3 vRight2 = vDestNodePos+vNodeLinkB + (vTangent*fWidthRight);
grcDebugDraw::Line(vNodePos + vNodeLinkA, vRight1, Color_DarkGoldenrod4, Color_DarkGoldenrod4);
grcDebugDraw::Line(vDestNodePos + vNodeLinkB, vRight2, Color_DarkGoldenrod4, Color_DarkGoldenrod4);
grcDebugDraw::Line(vRight1, vRight2, Color_yellow4, Color_orange4);
grcDebugDraw::Poly(vNodePos + vNodeLinkA, vRight1, vRight2, Color_DarkGoldenrod2);
}
}
}
}
}
}
}
}
}
}
}
#endif // __HIERARCHICAL_NODES_ENABLED
}
#endif
void
CPathServer::VisualiseAdjacency(const Vector3 & vPosStart, const Vector3 & vPosEnd, eNavMeshPolyAdjacencyType adjacencyType, bool bIsHighDrop, bool bIsDisabled, s32 iAlpha)
{
#ifdef GTA_ENGINE
static Color32 climbHighCol1(0,0,0xff,0);
static Color32 climbHighCol2(0x40,0x40,0xff,0);
static Color32 climbHighCol3(0x80,0x80,0xff,0);
static Color32 climbHighCol4(0xc0,0xc0,0xff,0);
static Color32 climbLowCol1(0,0,0x40,0);
static Color32 climbLowCol2(0x40,0x40,0xa0,0);
static Color32 climbLowCol3(0x80,0x80,0xa0,0);
static Color32 climbLowCol4(0xc0,0xc0,0xa0,0);
static Color32 dropDownCol1(0,0,0xff,0);
static Color32 dropDownCol2(0,0x40,0xff,0);
static Color32 dropDownCol3(0,0x80,0xff,0);
static Color32 dropDownCol4(0,0xc0,0xff,0);
Color32 colStart, colAboveStart, colAboveEnd, colEnd;
Vector3 vPosAboveStart, vPosAboveEnd, vArrowTip1, vArrowTip2;
bool bDrawAdjacency = false;
switch(adjacencyType)
{
case ADJACENCY_TYPE_CLIMB_HIGH:
{
if(CPathServer::m_bDebugShowHighClimbOvers)
{
vPosAboveStart = vPosStart + Vector3(0,0,4.0f);
vPosAboveEnd = vPosEnd + Vector3(0,0,4.0f);
colStart = climbHighCol1;
colAboveStart = climbHighCol2;
colAboveEnd = climbHighCol2;
colEnd = climbHighCol3;
bDrawAdjacency = true;
}
break;
}
case ADJACENCY_TYPE_CLIMB_LOW:
{
if(CPathServer::m_bDebugShowLowClimbOvers)
{
vPosAboveStart = vPosStart + Vector3(0,0,2.0f);
vPosAboveEnd = vPosEnd + Vector3(0,0,2.0f);
colStart = climbLowCol1;
colAboveStart = climbLowCol2;
colAboveEnd = climbLowCol2;
colEnd = climbLowCol3;
bDrawAdjacency = true;
}
break;
}
case ADJACENCY_TYPE_DROPDOWN:
{
if(CPathServer::m_bDebugShowDropDowns)
{
vPosAboveStart = vPosStart + Vector3(0,0,2.0f);
vPosAboveEnd = vPosEnd + Vector3(0,0,2.0f);
colStart = dropDownCol1;
colAboveStart = dropDownCol2;
colAboveEnd = dropDownCol3;
colEnd = dropDownCol4;
bDrawAdjacency = true;
}
break;
}
default:
{
Assert(0);
return;
}
}
if(!bDrawAdjacency)
return;
if(bIsHighDrop)
{
colEnd = Color32(0xFF,0,0,iAlpha);
}
if(bIsDisabled)
{
colStart = colAboveStart = Color32(0x90,0,0,iAlpha);
colEnd = colAboveEnd = Color32(0x60,0,0,iAlpha);
}
colStart.SetAlpha(iAlpha);
colAboveStart.SetAlpha(iAlpha);
colAboveEnd.SetAlpha(iAlpha);
colEnd.SetAlpha(iAlpha);
float fHeighestVal = Max(vPosAboveStart.z, vPosAboveEnd.z);
vPosAboveStart.z = fHeighestVal;
vPosAboveEnd.z = fHeighestVal;
grcDebugDraw::Line(vPosStart, vPosAboveStart, colStart, colAboveStart);
grcDebugDraw::Line(vPosAboveStart, vPosAboveEnd, colAboveStart, colAboveEnd);
grcDebugDraw::Line(vPosAboveEnd, vPosEnd, colAboveEnd, colEnd);
#else // GTA_ENGINE
vPosStart; vPosEnd; adjacencyType; iAlpha; bIsHighDrop; bIsDisabled;
#endif // GTA_ENGINE
}
#endif
#ifdef GTA_ENGINE
#if !__FINAL
void
CPathServer::VisualiseSpecialLinks(CNavMesh * pNavMesh, aiNavDomain domain)
{
u32 s;
for(s=0; s<pNavMesh->GetNumSpecialLinks(); s++)
{
const CSpecialLinkInfo & specLink = pNavMesh->GetSpecialLinks()[s];
if(specLink.GetIsDisabled())
continue;
CNavMesh * pOriginalFromNavMesh = GetNavMeshFromIndex(specLink.GetOriginalLinkFromNavMesh(), domain);
CNavMesh * pOriginalToNavMesh = GetNavMeshFromIndex(specLink.GetOriginalLinkToNavMesh(), domain);
Assert(pOriginalToNavMesh->GetIndexOfMesh()==pNavMesh->GetIndexOfMesh());
Vector3 vFromPos, vToPos;
pOriginalFromNavMesh->DecompressVertex(vFromPos, specLink.GetLinkFromPosX(), specLink.GetLinkFromPosY(), specLink.GetLinkFromPosZ());
pOriginalToNavMesh->DecompressVertex(vToPos, specLink.GetLinkToPosX(), specLink.GetLinkToPosY(), specLink.GetLinkToPosZ());
vFromPos.z += 0.5f;
Vector3 vFromPolyCentroid, vToPolyCentroid;
pOriginalFromNavMesh->GetPolyCentroidQuick( pOriginalFromNavMesh->GetPoly(specLink.GetOriginalLinkFromPoly()), vFromPolyCentroid);
pOriginalToNavMesh->GetPolyCentroidQuick( pOriginalToNavMesh->GetPoly(specLink.GetOriginalLinkToPoly()), vToPolyCentroid);
switch(specLink.GetLinkType())
{
case NAVMESH_LINKTYPE_CLIMB_LADDER:
case NAVMESH_LINKTYPE_DESCEND_LADDER:
{
const bool bBlocked = m_PathServerThread.m_BlockedLadders.IsLadderBlocked( vFromPos.z < vToPos.z ? vFromPos : vToPos );
grcDebugDraw::Line( vFromPolyCentroid, vFromPos, bBlocked ? Color_red3 : Color_turquoise, bBlocked ? Color_red3 : Color_DarkTurquoise );
grcDebugDraw::Line( vFromPos, vToPos, bBlocked ? Color_red2 : Color_DarkTurquoise);
grcDebugDraw::Line( vToPos, vToPolyCentroid, bBlocked ? Color_red3 : Color_DeepSkyBlue4 );
break;
}
case NAVMESH_LINKTYPE_CLIMB_OBJECT:
{
grcDebugDraw::Line( vFromPolyCentroid, vFromPos, Color_tan, Color_tan );
grcDebugDraw::Line( vFromPos, vFromPos+(ZAXIS*2.0f), Color_tan );
grcDebugDraw::Line( vFromPos+(ZAXIS*2.0f), vToPos+(ZAXIS*2.0f), Color_tan2 );
grcDebugDraw::Line( vToPos+(ZAXIS*2.0f), vToPos, Color_tan4 );
grcDebugDraw::Line( vToPos, vToPolyCentroid, Color_tan4 );
break;
}
default:
Assert(false);
break;
}
// Draw heading
float fHeading = (((float)specLink.GetLinkFlags()) / 255.0f) * TWO_PI;
fHeading = fwAngle::LimitRadianAngle(fHeading);
Vector3 vWaypointNormal(-rage::Sinf(fHeading),rage::Cosf(fHeading),0.0f);
grcDebugDraw::Arrow( VECTOR3_TO_VEC3V(vFromPos + ZAXIS), VECTOR3_TO_VEC3V(vFromPos + ZAXIS + (vWaypointNormal * 0.5f)), 0.2f, Color_orange);
}
}
#endif
#endif
#if !__FINAL
int
CPathServer::VisualisePathServerCommon(aiNavDomain domain, int ypos)
{
#ifdef GTA_ENGINE
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
//****************************************
// Ready for text drawing
//****************************************
char TempString[256];
int iIndexPos = (s32)g_vPathserverDebugTopLeft.x + 40;
//********************************************
// Get navmesh
//********************************************
int iSectorX = CPathServerExtents::GetWorldToSectorX(vOrigin.x);
int iSectorY = CPathServerExtents::GetWorldToSectorY(vOrigin.y);
aiNavMeshStore* pStore = m_pNavMeshStores[domain];
u32 index = pStore->GetMeshIndexFromPosition(vOrigin);
CNavMesh * pNavMesh = (index == NAVMESH_NAVMESH_INDEX_NONE) ? NULL : pStore->GetMeshByIndex(index);
if(!pNavMesh)
{
int iMeshX, iMeshY;
pStore->MeshIndexToMeshCoords(index, iMeshX, iMeshY);
iMeshX *= CPathServerExtents::m_iNumSectorsPerNavMesh;
iMeshY *= CPathServerExtents::m_iNumSectorsPerNavMesh;
sprintf(
TempString,
"NavMesh[%i][%i] Index:%i - not loaded",
iMeshX, iMeshY, index
);
//Sector(%i, %i) iSectorX, iSectorY,
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
return ypos;
}
//********************************************
// Display PathServer info
//********************************************
// draw main caption
if(pNavMesh)
{
int iMeshX, iMeshY;
pStore->MeshIndexToMeshCoords(index, iMeshX, iMeshY);
iMeshX *= CPathServerExtents::m_iNumSectorsPerNavMesh;
iMeshY *= CPathServerExtents::m_iNumSectorsPerNavMesh;
s32 iSizeInKb = (s32) (((float)pNavMesh->GetTotalMemoryUsed()) / 1024.0f);
sprintf(
TempString,
"NavMesh[%i][%i] Index:%i (%iKb)",
iMeshX, iMeshY, index, iSizeInKb
);
//Sector(%i, %i) iSectorX, iSectorY,
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(
TempString,
"NumPolys: %i, NumVerts: %i, SizeOfPools: %i",
pNavMesh->GetNumPolys(), pNavMesh->GetNumVertices(), pNavMesh->GetSizeOfPools()
);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
}
else
{
sprintf(
TempString,
"PathServer - Sector(%i, %i) : no NavMesh at this location",
iSectorX, iSectorY
);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
}
#endif // GTA_ENGINE
return ypos;
}
void
CPathServer::VisualiseText(int ypos, aiNavDomain domain)
{
ypos += 16;
#ifdef GTA_ENGINE
char TempString[256];
int iIndexPos = (s32)g_vPathserverDebugTopLeft.x + 48;
sprintf(TempString, "MSecs to last extract coverpoints : %.2f", m_fLastTimeTakenToExtractCoverPointsMs);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "MSecs to add/remove/update objects : %.2f", m_fTimeTakenToAddRemoveUpdateObjects);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "MSecs to process ped-gen algorithm : %.2f", m_fTimeTakenToDoPedGenInMSecs);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "MSecs spent on requests this game turn : %.2f", m_fTimeSpentProcessingThisGameTurn);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "MSecs main game spent on thread-stalls : %.2f", m_fMainGameTimeSpendOnThreadStalls);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "ms_iBlockRequestsFlags : %i", ms_iBlockRequestsFlags);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
// Render some extra info
sprintf(
TempString,
"[ThreadStalls on NavMeshes:%i] [ThreadStalls on Objects:%i] [Couldn't update objects:%i]",
m_iNumThreadStallsForNavMeshes,
m_iNumThreadStallsForDynamicObjects,
m_iNumTimesCouldntUpdateObjectsDueToGameThreadAccess
);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
// Render some extra info
sprintf(
TempString,
"[DynObjects:%i] [ObjGrids:%i] [GaveTime:%i] [Scripted:%i]",
m_iNumDynamicObjects,
CDynamicObjectsContainer::GetNumGrids(),
m_iNumTimesGaveTime,
m_iNumScriptBlockingObjects
);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "Num tessellation polys : %i / %i (peaked at %i)", m_iCurrentNumTessellationPolys, CNavMesh::ms_iNumPolysInTesselationNavMesh, fwPathServer::ms_iPeakNumTessellationPolys);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
#if __BANK
for(s32 r=0; r<NAVMESH_MAX_REQUIRED_REGIONS; r++)
{
sprintf(TempString, "Region %i) Active=%s (%.1f, %.1f) radius=%.1f, threadId=%u, scriptName=\"%s\"",
r,
m_NavMeshRequiredRegions[r].m_bActive ? "true" : "false",
m_NavMeshRequiredRegions[r].m_vOrigin.x,
m_NavMeshRequiredRegions[r].m_vOrigin.y,
m_NavMeshRequiredRegions[r].m_fNavMeshLoadRadius,
m_NavMeshRequiredRegions[r].m_iThreadId,
m_NavMeshRequiredRegions[r].m_ScriptName
);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
}
#endif
bool bAllLoaded = AreAllNavMeshRegionsLoaded(domain);
sprintf(TempString, "All requested regions loaded : %s", bAllLoaded ? "true" : "false");
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), bAllLoaded ? Color_white : Color_red, TempString);
ypos += 16;
sprintf(TempString, "ImmediateMode calls : Time(%.2f ms) Los(%i) Wander(%i) Flee(%i) Seek(%i)",
m_fTimeSpentOnImmediateModeCallsThisFrame, m_iNumImmediateModeLosCallsThisFrame, m_iNumImmediateModeWanderPathsThisFrame, m_iNumImmediateModeFleePathsThisFrame, m_iNumImmediateModeSeekPathsThisFrame);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "Tracking (crit sec: %.2f), (track all peds: %.2f)", m_fTimeToLockDataForTracking, m_fTimeToTrackAllPeds);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "WorldMin (%.1f, %.1f, %.1f) Sector (%i, %i)",
g_WorldLimits_MapDataExtentsAABB.GetMinVector3().x, g_WorldLimits_MapDataExtentsAABB.GetMinVector3().y, g_WorldLimits_MapDataExtentsAABB.GetMinVector3().z,
CPathServerExtents::GetWorldToSectorX(g_WorldLimits_MapDataExtentsAABB.GetMinVector3().x), CPathServerExtents::GetWorldToSectorY(g_WorldLimits_MapDataExtentsAABB.GetMinVector3().y));
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "WorldMax (%.1f, %.1f, %.1f) Sector (%i, %i)",
g_WorldLimits_MapDataExtentsAABB.GetMaxVector3().x, g_WorldLimits_MapDataExtentsAABB.GetMaxVector3().y, g_WorldLimits_MapDataExtentsAABB.GetMaxVector3().z,
CPathServerExtents::GetWorldToSectorX(g_WorldLimits_MapDataExtentsAABB.GetMaxVector3().x), CPathServerExtents::GetWorldToSectorY(g_WorldLimits_MapDataExtentsAABB.GetMaxVector3().y));
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
sprintf(TempString, "PedGenCoords (ShouldUseStartupMode:%s, InUse:%s Complete:%s Consumed:%s NumCoords:%i)",
CPedPopulation::ShouldUseStartupMode()?"true":"false",
GetAmbientPedGen().m_PedGenCoords.GetInUse()?"true":"false",
GetAmbientPedGen().m_PedGenCoords.GetIsComplete()?"true":"false",
GetAmbientPedGen().m_PedGenCoords.GetIsConsumed()?"true":"false",
GetAmbientPedGen().m_PedGenCoords.GetNumCoords()
);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), Color_white, TempString);
ypos += 16;
#endif
}
void
CPathServer::VisualiseLineOfSightRequests(int ypos, aiNavDomain domain)
{
#ifdef GTA_ENGINE
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
//********************************************
// Get navmesh
//********************************************
u32 iNavMeshIndex = GetNavMeshIndexFromPosition(vOrigin, domain);
CNavMesh * pNavMesh = GetNavMeshFromIndex(iNavMeshIndex, domain);
if(!pNavMesh)
return;
//********************************************
// Display PathServer info
//********************************************
char TempString[256];
char FullString[256];
char InfoString[256];
char TimeTakenString[256];
char StatusString[256];
int iIndexPos = (s32)g_vPathserverDebugTopLeft.x + 16;
int iHandlePos = (s32)g_vPathserverDebugTopLeft.x + 32;
int iAddrPos = (s32)g_vPathserverDebugTopLeft.x + 128;
int iStatusPos = (s32)g_vPathserverDebugTopLeft.x + 200;
int ySpacing = grcDebugDraw::GetScreenSpaceTextHeight();
// draw titles for each column
grcDebugDraw::Text(ScreenPos((float)iHandlePos,(float)ypos), Color_white, "Handle");
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_white, "Status");
ypos += 16;
int i;
int index = 0;
for(i=0; i<MAX_NUM_LOS_REQUESTS; i++)
{
CLineOfSightRequest * pLosRequest = &m_LineOfSightRequests[i];
Color32 iDbgCol;
if(i==m_iSelectedLosRequest)
iDbgCol = Color32(255,255,255,255);
else
iDbgCol = Color32(128,128,128,255);
sprintf(TempString, "%i)", index++);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), iDbgCol, TempString);
sprintf(TempString, "%X", pLosRequest->m_hHandle);
grcDebugDraw::Text(ScreenPos(float(iHandlePos + 16), (float)ypos), Color_white, TempString);
// Draw the path request's 'context' - this is usually the CPed pointer
sprintf(TempString, "%p", pLosRequest->m_pContext);
grcDebugDraw::Text(ScreenPos((float)iAddrPos, (float)ypos), Color_white, TempString);
if(pLosRequest->m_bRequestPending)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_yellow, "Pending");
}
else if(pLosRequest->m_bRequestActive)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_red, "Active");
}
else if(pLosRequest->m_bComplete)
{
// Create the string for how long the request took to process
TimeTakenString[0] = 0;
InfoString[0] = 0;
StatusString[0] = 0;
FullString[0] = 0;
sprintf(
TimeTakenString, "Took %.2f ms (%.2f, %.2f)",
pLosRequest->m_fTotalProcessingTimeInMillisecs,
pLosRequest->m_fMillisecsToFindPolys,
pLosRequest->m_fMillisecsToFindLineOfSight);
switch((int)pLosRequest->m_iCompletionCode)
{
case PATH_FOUND:
{
sprintf(StatusString, "%s", "COMPLETE");
break;
}
case PATH_NO_SURFACE_AT_COORDINATES:
{
sprintf(StatusString, "%s", "PATH_NO_SURFACE_AT_COORDINATES");
break;
}
default:
sprintf(StatusString, "%s", "UNKNOWN_ERR_MSG");
break;
}
sprintf(InfoString, "LOS %s, pts:%i", pLosRequest->m_bLineOfSightExists ? "CLEAR" : "BLOCKED", pLosRequest->m_iNumPts);
sprintf(FullString, "%s, %s, %s", StatusString, InfoString, TimeTakenString);
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_green, FullString);
}
ypos += ySpacing;
}
#else // GTA_ENGINE
ypos;
#endif // GTA_ENGINE
}
void
CPathServer::VisualiseAudioPropertiesRequests(int ypos, aiNavDomain domain)
{
#ifdef GTA_ENGINE
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
//********************************************
// Get navmesh
//********************************************
u32 iNavMeshIndex = GetNavMeshIndexFromPosition(vOrigin, domain);
CNavMesh * pNavMesh = GetNavMeshFromIndex(iNavMeshIndex, domain);
if(!pNavMesh)
return;
//********************************************
// Display PathServer info
//********************************************
char TempString[256];
char FullString[256];
char InfoString[256];
char TimeTakenString[256];
char StatusString[256];
int iIndexPos = (s32)g_vPathserverDebugTopLeft.x + 16;
int iHandlePos = (s32)g_vPathserverDebugTopLeft.x + 32;
int iAddrPos = (s32)g_vPathserverDebugTopLeft.x + 128;
int iStatusPos = (s32)g_vPathserverDebugTopLeft.x + 200;
// Set render state for text
int ySpacing = grcDebugDraw::GetScreenSpaceTextHeight();
// draw titles for each column
grcDebugDraw::Text(ScreenPos((float)iHandlePos,(float)ypos), Color_white, "Handle");
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_white, "Status");
ypos += 16;
int i;
int index = 0;
for(i=0; i<MAX_NUM_AUDIO_REQUESTS; i++)
{
CAudioRequest * pAudioRequest = &m_AudioRequests[i];
sprintf(TempString, "%i)", index++);
Color32 dbgCol;
if(i==m_iSelectedLosRequest)
dbgCol = Color32(255,255,255,255);
else
dbgCol = Color32(128,128,128,255);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), dbgCol, TempString);
sprintf(TempString, "%X", pAudioRequest->m_hHandle);
grcDebugDraw::Text(ScreenPos(float(iHandlePos + 16), (float)ypos), Color_white, TempString);
// Draw the path request's 'context' - this is usually the CPed pointer
sprintf(TempString, "%p", pAudioRequest->m_pContext);
grcDebugDraw::Text(ScreenPos((float)iAddrPos, (float)ypos), Color_white, TempString);
if(pAudioRequest->m_bRequestPending)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_yellow, "Pending");
}
else if(pAudioRequest->m_bRequestActive)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_red, "Active");
}
else if(pAudioRequest->m_bComplete)
{
// Create the string for how long the request took to process
TimeTakenString[0] = 0;
InfoString[0] = 0;
StatusString[0] = 0;
FullString[0] = 0;
sprintf(TimeTakenString, "Took %.2f ms", pAudioRequest->m_fTotalProcessingTimeInMillisecs);
switch((int)pAudioRequest->m_iCompletionCode)
{
case PATH_FOUND:
{
sprintf(StatusString, "%s", "COMPLETE");
break;
}
case PATH_NOT_FOUND:
{
sprintf(StatusString, "%s", "NOT_FOUND");
break;
}
default:
sprintf(StatusString, "%s", "UNKNOWN_ERR_MSG");
break;
}
sprintf(FullString, "%s, %s, %s", StatusString, InfoString, TimeTakenString);
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_green, FullString);
}
ypos += ySpacing;
}
#else // GTA_ENGINE
ypos;
#endif // GTA_ENGINE
}
void
CPathServer::VisualiseFloodFillRequests(int ypos, aiNavDomain domain)
{
#ifdef GTA_ENGINE
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
//********************************************
// Get navmesh
//********************************************
u32 iNavMeshIndex = GetNavMeshIndexFromPosition(vOrigin, domain);
CNavMesh * pNavMesh = GetNavMeshFromIndex(iNavMeshIndex, domain);
if(!pNavMesh)
return;
//********************************************
// Display PathServer info
//********************************************
char TempString[256];
char FullString[256];
char InfoString[256];
char TimeTakenString[256];
char StatusString[256];
char ReqTypeString[256];
int iIndexPos = (s32)g_vPathserverDebugTopLeft.x + 16;
int iHandlePos = (s32)g_vPathserverDebugTopLeft.x + 32;
int iAddrPos = (s32)g_vPathserverDebugTopLeft.x + 128;
int iStatusPos = (s32)g_vPathserverDebugTopLeft.x + 200;
// Set render state for text
int ySpacing = grcDebugDraw::GetScreenSpaceTextHeight();
// draw titles for each column
grcDebugDraw::Text(ScreenPos((float)iHandlePos, (float)ypos), Color_white, "Handle");
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_white, "Status");
ypos += 16;
int i;
int index = 0;
for(i=0; i<MAX_NUM_FLOODFILL_REQUESTS; i++)
{
CFloodFillRequest * pFloodFillRequest = &m_FloodFillRequests[i];
sprintf(TempString, "%i)", index++);
grcDebugDraw::Text(ScreenPos((float)iIndexPos, (float)ypos), Color_grey, TempString);
sprintf(TempString, "%X", pFloodFillRequest->m_hHandle);
grcDebugDraw::Text(ScreenPos(float(iHandlePos + 16), (float)ypos), Color_white, TempString);
// Draw the path request's 'context' - this is usually the CPed pointer
sprintf(TempString, "%p", pFloodFillRequest->m_pContext);
grcDebugDraw::Text(ScreenPos((float)iAddrPos, (float)ypos), Color_white, TempString);
if(pFloodFillRequest->m_FloodFillType==CFloodFillRequest::EAudioPropertiesFloodFill)
{
sprintf(ReqTypeString, "Audio");
}
else if(pFloodFillRequest->m_FloodFillType==CFloodFillRequest::EFindClosestCarNodeFloodFill)
{
sprintf(ReqTypeString, "CarNode");
}
else if(pFloodFillRequest->m_FloodFillType==CFloodFillRequest::EFindClosestShelteredPolyFloodFill)
{
sprintf(ReqTypeString, "FindShelter");
}
else if(pFloodFillRequest->m_FloodFillType==CFloodFillRequest::ECalcAreaUnderfoot)
{
sprintf(ReqTypeString, "CalcArean");
}
else if(pFloodFillRequest->m_FloodFillType==CFloodFillRequest::EFindNearbyPavementFloodFill)
{
sprintf(ReqTypeString, "FindPavement");
}
else
{
sprintf(ReqTypeString, "Unknown");
}
if(pFloodFillRequest->m_bRequestPending)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_yellow, "Pending");
}
else if(pFloodFillRequest->m_bRequestActive)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_red, "Pending");
}
else if(pFloodFillRequest->m_bComplete)
{
// Create the string for how long the request took to process
TimeTakenString[0] = 0;
InfoString[0] = 0;
StatusString[0] = 0;
FullString[0] = 0;
sprintf(TimeTakenString, "Took %.2f ms", pFloodFillRequest->m_fTotalProcessingTimeInMillisecs);
switch((int)pFloodFillRequest->m_iCompletionCode)
{
case PATH_FOUND:
{
sprintf(StatusString, "%s", "COMPLETE");
break;
}
case PATH_NOT_FOUND:
{
sprintf(StatusString, "%s", "NOT_FOUND");
break;
}
default:
sprintf(StatusString, "%s", "UNKNOWN_ERR_MSG");
break;
}
sprintf(FullString, "(%s), %s, %s, %s", StatusString, InfoString, TimeTakenString, ReqTypeString);
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_green, FullString);
}
ypos += ySpacing;
}
#else // GTA_ENGINE
ypos;
#endif // GTA_ENGINE
}
void CPathServer::VisualiseClearAreaRequests(int ypos, aiNavDomain domain)
{
#ifdef GTA_ENGINE
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
//********************************************
// Get navmesh
//********************************************
u32 iNavMeshIndex = GetNavMeshIndexFromPosition(vOrigin, domain);
CNavMesh * pNavMesh = GetNavMeshFromIndex(iNavMeshIndex, domain);
if(!pNavMesh)
return;
//********************************************
// Display PathServer info
//********************************************
char TempString[256];
char FullString[256];
char InfoString[256];
char TimeTakenString[256];
char StatusString[256];
int iIndexPos = (s32)g_vPathserverDebugTopLeft.x + 16;
int iHandlePos = (s32)g_vPathserverDebugTopLeft.x + 32;
int iAddrPos = (s32)g_vPathserverDebugTopLeft.x + 128;
int iStatusPos = (s32)g_vPathserverDebugTopLeft.x + 200;
// Set render state for text
int ySpacing = grcDebugDraw::GetScreenSpaceTextHeight();
// draw titles for each column
grcDebugDraw::Text(ScreenPos((float)iHandlePos,(float)ypos), Color_white, "Handle");
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_white, "Status");
ypos += 16;
int i;
int index = 0;
for(i=0; i<MAX_NUM_CLEARAREA_REQUESTS; i++)
{
CClearAreaRequest * pClearAreaRequest = &m_ClearAreaRequests[i];
sprintf(TempString, "%i)", index++);
Color32 dbgCol;
if(i==m_iSelectedLosRequest)
dbgCol = Color32(255,255,255,255);
else
dbgCol = Color32(128,128,128,255);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), dbgCol, TempString);
sprintf(TempString, "%X", pClearAreaRequest->m_hHandleThisWas);
grcDebugDraw::Text(ScreenPos(float(iHandlePos + 16), (float)ypos), Color_white, TempString);
// Draw the path request's 'context' - this is usually the CPed pointer
sprintf(TempString, "%p", pClearAreaRequest->m_pContext);
grcDebugDraw::Text(ScreenPos((float)iAddrPos, (float)ypos), Color_white, TempString);
if(pClearAreaRequest->m_bRequestPending)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_yellow, "Pending");
}
else if(pClearAreaRequest->m_bRequestActive)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_red, "Active");
}
else if(pClearAreaRequest->m_bComplete)
{
// Create the string for how long the request took to process
TimeTakenString[0] = 0;
InfoString[0] = 0;
StatusString[0] = 0;
FullString[0] = 0;
sprintf(InfoString, "slept:%i", pClearAreaRequest->m_iNumTimesSlept);
sprintf(TimeTakenString, "Took %.2f ms", pClearAreaRequest->m_fTotalProcessingTimeInMillisecs);
switch((int)pClearAreaRequest->m_iCompletionCode)
{
case PATH_FOUND:
{
sprintf(StatusString, "%s", "COMPLETE");
break;
}
case PATH_NOT_FOUND:
{
sprintf(StatusString, "%s", "NOT_FOUND");
break;
}
default:
sprintf(StatusString, "%s", "UNKNOWN_ERR_MSG");
break;
}
sprintf(FullString, "%s, %s, %s", StatusString, InfoString, TimeTakenString);
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_green, FullString);
}
ypos += ySpacing;
}
#else // GTA_ENGINE
ypos;
#endif // GTA_ENGINE
}
void CPathServer::VisualiseClosestPositionRequests(int ypos, aiNavDomain domain)
{
#ifdef GTA_ENGINE
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
//********************************************
// Get navmesh
//********************************************
u32 iNavMeshIndex = GetNavMeshIndexFromPosition(vOrigin, domain);
CNavMesh * pNavMesh = GetNavMeshFromIndex(iNavMeshIndex, domain);
if(!pNavMesh)
return;
//********************************************
// Display PathServer info
//********************************************
char TempString[256];
char FullString[256];
char InfoString[256];
char TimeTakenString[256];
char StatusString[256];
int iIndexPos = (s32)g_vPathserverDebugTopLeft.x + 16;
int iHandlePos = (s32)g_vPathserverDebugTopLeft.x + 32;
int iAddrPos = (s32)g_vPathserverDebugTopLeft.x + 128;
int iStatusPos = (s32)g_vPathserverDebugTopLeft.x + 200;
// Set render state for text
int ySpacing = grcDebugDraw::GetScreenSpaceTextHeight();
// draw titles for each column
grcDebugDraw::Text(ScreenPos((float)iHandlePos,(float)ypos), Color_white, "Handle");
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_white, "Status");
ypos += 16;
int i;
int index = 0;
for(i=0; i<MAX_NUM_CLOSESTPOSITION_REQUESTS; i++)
{
CClosestPositionRequest * pClosestPosRequest = &m_ClosestPositionRequests[i];
sprintf(TempString, "%i)", index++);
Color32 dbgCol = Color32(255,255,255,255);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), dbgCol, TempString);
sprintf(TempString, "%X", pClosestPosRequest->m_hHandleThisWas);
grcDebugDraw::Text(ScreenPos(float(iHandlePos + 16), (float)ypos), Color_white, TempString);
// Draw the path request's 'context' - this is usually the CPed pointer
sprintf(TempString, "%p", pClosestPosRequest->m_pContext);
grcDebugDraw::Text(ScreenPos((float)iAddrPos, (float)ypos), Color_white, TempString);
if(pClosestPosRequest->m_bRequestPending)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_yellow, "Pending");
}
else if(pClosestPosRequest->m_bRequestActive)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_red, "Active");
}
else if(pClosestPosRequest->m_bComplete)
{
// Create the string for how long the request took to process
TimeTakenString[0] = 0;
InfoString[0] = 0;
StatusString[0] = 0;
FullString[0] = 0;
sprintf(InfoString, "slept:%i", pClosestPosRequest->m_iNumTimesSlept);
sprintf(TimeTakenString, "Took %.2f ms", pClosestPosRequest->m_fTotalProcessingTimeInMillisecs);
switch((int)pClosestPosRequest->m_iCompletionCode)
{
case PATH_FOUND:
{
sprintf(StatusString, "%s", "COMPLETE");
break;
}
case PATH_NOT_FOUND:
{
sprintf(StatusString, "%s", "NOT_FOUND");
break;
}
default:
sprintf(StatusString, "%s", "UNKNOWN_ERR_MSG");
break;
}
sprintf(FullString, "%s, %s, %s", StatusString, InfoString, TimeTakenString);
grcDebugDraw::Text(ScreenPos((float)iStatusPos, (float)ypos), Color_green, FullString);
}
ypos += ySpacing;
}
#else // GTA_ENGINE
ypos;
#endif // GTA_ENGINE
}
#ifdef GTA_ENGINE
void
CPathServer::VisualisePathDetails(CPathRequest * pPathReq, int ypos)
{
char TempString[256];
float fX = g_vPathserverDebugTopLeft.x + (SCREEN_WIDTH / 40.0f) + 8;
int ySpacing = grcDebugDraw::GetScreenSpaceTextHeight();
//*****************************************
// Type
if(pPathReq->m_bWander)
sprintf(TempString, "Type:Wander");
else if(pPathReq->m_bFleeTarget)
sprintf(TempString, "Type:Flee");
else
sprintf(TempString, "Type:Normal");
if(pPathReq->m_bDontAvoidDynamicObjects)
strcat(TempString, " NoAvoidance");
if(pPathReq->m_bDoPostProcessToPreserveSlopeInfo)
strcat(TempString, " PreserveZ");
if(pPathReq->m_bSmoothSharpCorners)
strcat(TempString, " Smooth");
if(pPathReq->m_bGoAsFarAsPossibleIfNavMeshNotLoaded)
strcat(TempString, " GoFarAsPoss");
if(pPathReq->m_bUseLargerSearchExtents)
strcat(TempString, " LargerSearchExtents");
if(pPathReq->m_bDontLimitSearchExtents)
strcat(TempString, " DontLimitSearchExtents");
if(pPathReq->m_iNumInfluenceSpheres)
{
char ispheres[64];
sprintf(ispheres, " iSpheres:%i", pPathReq->m_iNumInfluenceSpheres);
strcat(TempString, ispheres);
}
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
//**********************************************
// Time stats
sprintf(TempString, "Total Time : %.3f, Frame Issued: %u, Frame Started: %u, Frame Completed: %u", pPathReq->m_fMillisecsToFindPath, pPathReq->m_iFrameRequestIssued, pPathReq->m_iFrameRequestStarted, pPathReq->m_iFrameRequestCompleted);
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
sprintf(TempString, "FindEndPolys: %.3f, FindPolygonPath: %.3f, StringPullPath: %.3f, PostProcessZ: %.3f", pPathReq->m_fMillisecsToFindPolys, pPathReq->m_fMillisecsToFindPath, pPathReq->m_fMillisecsToRefinePath, pPathReq->m_fMillisecsToPostProcessZHeights);
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
sprintf(TempString, "MinimisePathLength: %.3f, PullOutFromEdges: %.3f, SmoothPath: %.3f", pPathReq->m_fMillisecsToMinimisePathLength, pPathReq->m_fMillisecsToPullOutFromEdges, pPathReq->m_fMillisecsToSmoothPath);
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
sprintf(TempString, "TimeInTessellation: %.3f, TimeInDetessellation: %.3f", pPathReq->m_fMillisecsSpentInTessellation, pPathReq->m_fMillisecsSpentInDetessellation);
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
//********************************************************
// Counter stats
sprintf(TempString, "NumVisitedPolys:%i, NumTessellations:%i, NumTestDynObjLOS:%i, NumTestNavMeshLOS:%i",
pPathReq->m_iNumVisitedPolygons,
pPathReq->m_iNumTessellations,
pPathReq->m_iNumTestDynamicObjectLOS,
pPathReq->m_iNumTestNavMeshLOS);
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
sprintf(TempString, "NumGetObjectsIntersectingRegion:%i, DynObjCacheHits:%i",
pPathReq->m_iNumGetObjectsIntersectingRegion,
pPathReq->m_iNumCacheHitsOnDynamicObjects);
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
sprintf(TempString, "Num tessellation polys used : %i / %i", pPathReq->m_iNumTessellatedPolys, CNavMesh::GetNumPolysInTesselationMesh() );
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
sprintf(TempString, "Entity radius : %f", pPathReq->m_fEntityRadius);
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, TempString);
ypos += ySpacing;
}
#endif // GTA_ENGINE
void
CPathServer::VisualisePathRequests(int ypos, aiNavDomain domain)
{
#ifdef GTA_ENGINE
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : CPlayerInfo::ms_cachedMainPlayerPos;
//********************************************
// Get navmesh
//********************************************
u32 iNavMeshIndex = GetNavMeshIndexFromPosition(vOrigin, domain);
CNavMesh * pNavMesh = GetNavMeshFromIndex(iNavMeshIndex, domain);
if(!pNavMesh)
return;
//********************************************
// Display PathServer info
//********************************************
char TempString[256];
char FullString[256];
char InfoString[256];
char TimeTakenString[256];
char StatusString[256];
int iIndexPos = (s32)g_vPathserverDebugTopLeft.x + 38;
int iHandlePos = (s32)g_vPathserverDebugTopLeft.x + 48;
int iAddrPos = (s32)g_vPathserverDebugTopLeft.x + 136;
int iFramePos = (s32)g_vPathserverDebugTopLeft.x + 240;
int iStatusPos = (s32)g_vPathserverDebugTopLeft.x + 320;
// Set render state for text
int ySpacing = grcDebugDraw::GetScreenSpaceTextHeight();
// draw titles for each column
grcDebugDraw::Text(ScreenPos((float)iHandlePos,(float)ypos), Color_white, "Handle");
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_white, "Status");
ypos += 16;
int i;
int index = 0;
for(i=0; i<MAX_NUM_PATH_REQUESTS; i++)
{
CPathRequest * pPathRequest = &m_PathRequests[i];
sprintf(TempString, "%i)", index++);
Color32 dbgCol;
if(i==m_iSelectedPathRequest)
dbgCol = Color32(255,255,255,255);
else
dbgCol = Color32(128,128,128,255);
grcDebugDraw::Text(ScreenPos((float)iIndexPos,(float)ypos), dbgCol, TempString);
if(pPathRequest->m_bFleeTarget)
{
sprintf(TempString, "%x:flee", pPathRequest->m_hHandleThisWas);
}
else if(pPathRequest->m_bWander)
{
sprintf(TempString, "%x:wdr", pPathRequest->m_hHandleThisWas);
}
else
{
sprintf(TempString, "%x", pPathRequest->m_hHandleThisWas);
}
grcDebugDraw::Text(ScreenPos(float(iHandlePos+16),(float)ypos), Color_white, TempString);
// Draw the path request's 'context' - this is usually the CPed pointer
sprintf(TempString, "%p", pPathRequest->m_pContext);
grcDebugDraw::Text(ScreenPos((float)iAddrPos,(float)ypos), Color_white, TempString);
// Draw the path request's request frame
sprintf(TempString, "%u", pPathRequest->m_iFrameRequestIssued);
grcDebugDraw::Text(ScreenPos((float)iFramePos,(float)ypos), Color_white, TempString);
if(pPathRequest->m_bWasAborted)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_tomato, "Aborted");
}
else if(pPathRequest->m_bRequestPending)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_yellow, "Pending");
}
else if(pPathRequest->m_bRequestActive)
{
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_red, "Active");
}
else if(pPathRequest->m_bComplete)
{
// Create the string for how long the request took to process
TimeTakenString[0] = 0;
InfoString[0] = 0;
StatusString[0] = 0;
FullString[0] = 0;
sprintf(
TimeTakenString, "Took %.2f ms (%.1f, %.1f, %.1f, %.1f, %.1f, %.1f)",
pPathRequest->m_fTotalProcessingTimeInMillisecs,
pPathRequest->m_fMillisecsToFindPolys,
pPathRequest->m_fMillisecsToFindPath,
pPathRequest->m_fMillisecsToRefinePath,
pPathRequest->m_fMillisecsToMinimisePathLength,
pPathRequest->m_fMillisecsToPullOutFromEdges,
pPathRequest->m_fMillisecsToPostProcessZHeights
);
switch((int)pPathRequest->m_iCompletionCode)
{
case PATH_FOUND:
{
sprintf(StatusString, "%s", "COMPLETE");
break;
}
case PATH_NOT_FOUND:
sprintf(StatusString, "%s", "PATH_NOT_FOUND");
break;
case PATH_TIMED_OUT:
sprintf(StatusString, "%s", "PATH_TIMED_OUT");
break;
case PATH_REACHED_MAX_PATH_POLYS:
sprintf(StatusString, "%s", "PATH_REACHED_MAX_PATH_POLYS");
break;
case PATH_INVALID_COORDINATES:
sprintf(StatusString, "%s", "PATH_INVALID_COORDINATES");
break;
case PATH_NAVMESH_NOT_LOADED:
sprintf(StatusString, "%s", "PATH_NAVMESH_NOT_LOADED");
break;
case PATH_ENDPOINTS_INSIDE_OBJECTS:
sprintf(StatusString, "%s", "ENDPOINTS_INSIDE_OBJECTS");
break;
case PATH_NO_SURFACE_AT_COORDINATES:
sprintf(StatusString, "%s", "PATH_NO_SURFACE");
break;
case PATH_RAN_OUT_OF_PATH_STACK_SPACE:
sprintf(StatusString, "%s", "EXCEEDED_PATH_STACK");
break;
case PATH_RAN_OUT_VISITED_POLYS_SPACE:
sprintf(StatusString, "%s", "EXCEEDED_VISITED_POLYS");
break;
case PATH_CANCELLED:
sprintf(StatusString, "%s", "PATH_CANCELLED");
break;
case PATH_ERROR_INVALID_HANDLE:
sprintf(StatusString, "%s", "PATH_ERROR_INVALID_HANDLE");
break;
case PATH_NO_POINTS:
sprintf(StatusString, "%s", "PATH_NO_POINTS");
break;
case PATH_STILL_PENDING:
sprintf(StatusString, "%s", "PATH_STILL_PENDING");
break;
case PATH_ABORTED_DUE_TO_ANOTHER_THREAD:
sprintf(StatusString, "%s", "PATH_ABORTED_DUE_TO_ANOTHER_THREAD");
break;
default:
sprintf(StatusString, "%s", "UNKNOWN_ERR_MSG");
break;
}
sprintf(InfoString, "pts:%i tess:%i slept:%i visited:%i iters(%i,%i)",
pPathRequest->m_iNumPoints,
pPathRequest->m_iNumTessellations,
pPathRequest->m_iNumTimesSlept,
pPathRequest->m_iNumVisitedPolygons,
pPathRequest->m_iNumFindPathIterations,
pPathRequest->m_iNumRefinePathIterations);
sprintf(FullString, "%s %s %s", StatusString, TimeTakenString, InfoString);
grcDebugDraw::Text(ScreenPos((float)iStatusPos,(float)ypos), Color_NavyBlue, FullString);
}
ypos += ySpacing;
}
CPathRequest * pPathReq = &m_PathRequests[m_iSelectedPathRequest];
VisualisePathDetails(pPathReq, ypos + ySpacing);
#else // GTA_ENGINE
ypos;
#endif // GTA_ENGINE
}
#endif
#if !__FINAL
void CPathServer::RenderMiscThings()
{
#ifdef GTA_ENGINE
if(ms_bDrawPedGenBlockingAreas)
{
DebugDrawPedGenBlockingAreas();
}
if(m_iVisualiseNavMeshes && ms_bDrawPedSwitchAreas)
{
DebugDrawPedSwitchAreas();
}
if(ms_bVisualiseOpponentPedGeneration)
{
CPathServerOpponentPedGen & pedGen = GetOpponentPedGen();
if(pedGen.GetState() != CPathServerOpponentPedGen::STATE_IDLE)
{
Vector3 vStart, vEnd;
vStart = vEnd = pedGen.m_vSearchOrigin;
vStart.z -= pedGen.m_fDistZ;
vEnd.z += pedGen.m_fDistZ;
grcDebugDraw::Cylinder(RCC_VEC3V(vStart), RCC_VEC3V(vEnd), pedGen.m_fSearchRadiusXY, Color_chartreuse, false, false);
s32 iNum = pedGen.m_iNumCoords;
for(s32 i=0; i<iNum; i++)
{
float s = ((float)i) / ((float)iNum);
Color32 col = Lerp(s, Color_green, Color_red);
grcDebugDraw::Arrow(RCC_VEC3V(pedGen.m_SpawnCoords[i].m_vPos), VECTOR3_TO_VEC3V(pedGen.m_SpawnCoords[i].m_vPos+(ZAXIS*2.0f)), 0.4f, col);
}
}
}
if(m_iVisualiseNavMeshes == NavMeshVis_PedDensity)
{
if(CPedPopulation::GetAdjustPedSpawnDensity())
{
grcDebugDraw::BoxAxisAligned(VECTOR3_TO_VEC3V(CPedPopulation::GetAdjustPedSpawnDensityMin()), VECTOR3_TO_VEC3V(CPedPopulation::GetAdjustPedSpawnDensityMax()), Color_red, false);
}
}
if(m_iVisualiseNavMeshes)
{
// Draw the water edges.
int iNumWaterEdges;
Vector3 vWaterEdges[SIZE_OF_WATEREDGES_BUFFER];
if(GetWaterEdgePoints(iNumWaterEdges, &vWaterEdges[0]))
{
for(int v=0; v<iNumWaterEdges; v++)
{
Vector3 vTop = vWaterEdges[v] + Vector3(0.0f,0.0f,8.0f);
grcDebugDraw::Line(vWaterEdges[v], vTop, Color_SeaGreen, Color_SeaGreen2);
vTop.z -= 1.0f;
grcDebugDraw::Line(vTop - Vector3(1.0f,0.0f,0.0f), vTop + Vector3(1.0f,0.0f,0.0f), Color_SeaGreen3);
grcDebugDraw::Line(vTop - Vector3(0.0f,1.0f,0.0f), vTop + Vector3(0.0f,1.0f,0.0f), Color_SeaGreen3);
}
}
else
{
printf("Couldn't call CPathServer::GetWaterEdgePoints() - it was busy.\n");
}
}
if(PathTest_bGetPointsFromMeasuringTool)
{
ms_vPathTestStartPos = CPhysics::g_vClickedPos[0];
ms_vPathTestEndPos = CPhysics::g_vClickedPos[1];
}
#endif
}
#endif
#if !__FINAL
void
CPathServer::VisualiseMemoryUsage(int UNUSED_PARAM(ypos), aiNavDomain domain)
{
Vector3 v = VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetPosition());
if(m_bVisualiseHierarchicalNodes)
{
#if __HIERARCHICAL_NODES_ENABLED
m_pNavNodesStore->Visualise(&v);
#endif
}
else
{
m_pNavMeshStores[domain]->Visualise(&v);
}
}
void GetQuadTreeDetails(CNavMeshQuadTree * pTree, int & iQuadTreeNumPolyIndices, int & iQuadTreeNumCoverPoints)
{
if(pTree->m_pLeafData)
{
iQuadTreeNumPolyIndices += pTree->m_pLeafData->m_iNumPolys;
iQuadTreeNumCoverPoints += pTree->m_pLeafData->m_iNumCoverPoints;
return;
}
for(int c=0; c<4; c++)
{
if(pTree->m_pChildren[c])
{
GetQuadTreeDetails(pTree->m_pChildren[c], iQuadTreeNumPolyIndices, iQuadTreeNumCoverPoints);
}
}
}
void CPathServer::VisualisePolygonInfo(int ypos, CNavMesh * pNavMesh, const Vector3 & vOrigin, aiNavDomain domain)
{
char tmp[256];
float fX = g_vPathserverDebugTopLeft.x + (SCREEN_WIDTH / 40.0f) + 8;
int ySpacing = grcDebugDraw::GetScreenSpaceTextHeight();
Vector3 vIntersect;
u32 iPoly = pNavMesh->GetPolyBelowPoint(vOrigin, vIntersect, 50.0f);
if(iPoly == NAVMESH_POLY_INDEX_NONE)
return;
TNavMeshPoly * pPoly = pNavMesh->GetPoly(iPoly);
if(pPoly->GetReplacedByTessellation())
{
pNavMesh = fwPathServer::GetTessellationNavMesh();
iPoly = pNavMesh->GetPolyBelowPoint(vOrigin, vIntersect, 50.0f);
if(iPoly == NAVMESH_POLY_INDEX_NONE)
return;
pPoly = pNavMesh->GetPoly(iPoly);
}
sprintf(tmp, "Poly underfoot: 0x%p ( %i : %i )", pPoly, pPoly->GetNavMeshIndex(), iPoly);
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, tmp);
ypos += ySpacing;
sprintf(tmp, "Num verts: %i, Flags: 0x%X", pPoly->GetNumVertices(), pPoly->GetFlags());
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, tmp);
ypos += ySpacing;
ypos += ySpacing;
Vector3 vVec;
for(int a=0; a<pPoly->GetNumVertices(); a++)
{
const TAdjPoly & adjPoly = pNavMesh->GetAdjacentPoly((u32) pPoly->GetFirstVertexIndex() + a);
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, a), vVec );
sprintf(tmp, " %i) Adjacent ( %i : %i ) Original ( %i : %i )",
a, adjPoly.GetNavMeshIndex(pNavMesh->GetAdjacentMeshes()), adjPoly.GetPolyIndex(),
adjPoly.GetOriginalNavMeshIndex(pNavMesh->GetAdjacentMeshes()), adjPoly.GetOriginalPolyIndex() );
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, tmp);
ypos += ySpacing;
if(adjPoly.GetNavMeshIndex(pNavMesh->GetAdjacentMeshes()) != NAVMESH_NAVMESH_INDEX_NONE)
{
CNavMesh * pAdjNavMesh = GetNavMeshFromIndex( adjPoly.GetNavMeshIndex(pNavMesh->GetAdjacentMeshes()), domain);
if(pAdjNavMesh)
{
TNavMeshPoly * pAdjPoly = pAdjNavMesh->GetPoly(adjPoly.GetPolyIndex());
sprintf(tmp, " 0x%p Flags: 0x%X", pAdjPoly, pAdjPoly->GetFlags());
grcDebugDraw::Text(ScreenPos((float)fX,(float)ypos), Color_white, tmp);
ypos += ySpacing;
}
}
}
DrawPolyDebug(pNavMesh, iPoly, Color_magenta, 0.1f, true, 255, true);
for(u32 p=0; p<pNavMesh->GetNumPolys(); p++)
{
pPoly = pNavMesh->GetPoly(p);
Vector3 vCentroid;
pNavMesh->GetPolyCentroid(p, vCentroid);
if((vCentroid - vOrigin).Mag2() > 50.0f*50.0f)
continue;
for(int a=0; a<pPoly->GetNumVertices(); a++)
{
const TAdjPoly & adjPoly = pNavMesh->GetAdjacentPoly((u32) pPoly->GetFirstVertexIndex()+a);
pNavMesh->GetVertex( pNavMesh->GetPolyVertexIndex(pPoly, a), vVec );
float fFreeSpace = adjPoly.GetFreeSpaceAroundVertex();
if(fFreeSpace > 0.0f)
grcDebugDraw::Sphere(vVec, fFreeSpace, Color_SeaGreen2, false);
else
grcDebugDraw::Sphere(vVec, 0.2f, Color_red, false);
}
}
}
int CPathServer::VisualiseCurrentNavMeshDetails(int ypos, CNavMesh * pNavMesh)
{
Vector3 vMin = pNavMesh->GetNonResourcedData()->m_vMinOfNavMesh;
Vector3 vMax = pNavMesh->GetNonResourcedData()->m_vMinOfNavMesh + pNavMesh->GetExtents();
Color32 iCol = Color_yellow1;
iCol.SetAlpha(128);
grcDebugDraw::BoxAxisAligned(
RCC_VEC3V(vMin),
RCC_VEC3V(vMax),
iCol, false);
const float fStep = pNavMesh->GetExtents().x / 10.0f;
float fVal=0.0f;
for(int i=1; i<10; i++)
{
grcDebugDraw::Line( Vector3(vMin.x, vMin.y+fVal, vMin.z), Vector3(vMin.x, vMin.y+fVal, vMax.z), iCol );
grcDebugDraw::Line( Vector3(vMax.x, vMin.y+fVal, vMin.z), Vector3(vMax.x, vMin.y+fVal, vMax.z), iCol );
grcDebugDraw::Line( Vector3(vMin.x+fVal, vMin.y, vMin.z), Vector3(vMin.x+fVal, vMin.y, vMax.z), iCol );
grcDebugDraw::Line( Vector3(vMin.x+fVal, vMax.y, vMin.z), Vector3(vMin.x+fVal, vMax.y, vMax.z), iCol );
fVal += fStep;
}
// compressed vertices
int iVertexMem = pNavMesh->GetNumVertices() * 6;
int iPolyMem = pNavMesh->GetNumPolys() * sizeof(TNavMeshPoly);
// u16 for each vertex index
int iVertexIndexPoolMem = pNavMesh->GetSizeOfPools() * 2;
int iAdjPolyPoolMem = pNavMesh->GetSizeOfPools() * sizeof(TAdjPoly);
int iQuadTreeNumPolyIndices = 0;
int iQuadTreeNumCoverPoints = 0;
GetQuadTreeDetails(pNavMesh->GetQuadTree(), iQuadTreeNumPolyIndices, iQuadTreeNumCoverPoints);
int iQuadTreePolyIndexMem = iQuadTreeNumPolyIndices * 2;
int iQuadTreeCoverPointsMem = iQuadTreeNumCoverPoints * sizeof(CNavMeshCoverPoint);
int iSpecialLinksMem = pNavMesh->GetNumSpecialLinks() * sizeof(CSpecialLinkInfo);
int iPolyVolumeInfoMem = pNavMesh->GetNumPolys() * sizeof(TPolyVolumeInfo);
int iTotal =
iVertexMem + iPolyMem + iVertexIndexPoolMem + iAdjPolyPoolMem +
iQuadTreePolyIndexMem + iQuadTreeCoverPointsMem +
iSpecialLinksMem + iPolyVolumeInfoMem;
char txt[256];
Vector2 vTextPos(g_vPathserverDebugTopLeft.x, (float)ypos);
int iTextInc = grcDebugDraw::GetScreenSpaceTextHeight();
sprintf(txt, "%i Vertices : %i kb", pNavMesh->GetNumVertices(), iVertexMem/1024);
grcDebugDraw::Text(ScreenPos(vTextPos.x, vTextPos.y), Color_white, txt);
vTextPos.y += iTextInc;
sprintf(txt, "%i Polys : %i kb", pNavMesh->GetNumPolys(), iPolyMem/1024);
grcDebugDraw::Text(ScreenPos(vTextPos.x, vTextPos.y), Color_white, txt);
vTextPos.y += iTextInc;
sprintf(txt, "%i VertexIndices : %i kb", pNavMesh->GetSizeOfPools(), iVertexIndexPoolMem/1024);
grcDebugDraw::Text(ScreenPos(vTextPos.x, vTextPos.y), Color_white, txt);
vTextPos.y += iTextInc;
sprintf(txt, "%i AdjPolys : %i kb", pNavMesh->GetSizeOfPools(), iAdjPolyPoolMem/1024);
grcDebugDraw::Text(ScreenPos(vTextPos.x, vTextPos.y), Color_white, txt);
vTextPos.y += iTextInc;
sprintf(txt, "%i QuadTree PolyIndeces : %i kb", iQuadTreeNumPolyIndices, iQuadTreePolyIndexMem/1024);
grcDebugDraw::Text(ScreenPos(vTextPos.x, vTextPos.y), Color_white, txt);
vTextPos.y += iTextInc;
sprintf(txt, "%i QuadTree CoverPoints : %i kb", iQuadTreeNumCoverPoints, iQuadTreeCoverPointsMem/1024);
grcDebugDraw::Text(ScreenPos(vTextPos.x, vTextPos.y), Color_white, txt);
vTextPos.y += iTextInc;
sprintf(txt, "%i SpecialLinks : %i kb", pNavMesh->GetNumSpecialLinks(), iSpecialLinksMem/1024);
grcDebugDraw::Text(ScreenPos(vTextPos.x, vTextPos.y), Color_white, txt);
vTextPos.y += iTextInc;
sprintf(txt, "Total Memory (excluding CNavMesh itself) : %i kb (%.1fmb)", iTotal/1024, ((float)(iTotal/1024))/1024.0f);
grcDebugDraw::Text(ScreenPos(vTextPos.x, vTextPos.y), Color_white, txt);
vTextPos.y += iTextInc;
return (s32)vTextPos.y;
}
#ifdef GTA_ENGINE
void
CPathServer::VisualiseTestPathEndPoints()
{
Vector3 vEndPoints[3] = { ms_vPathTestStartPos, ms_vPathTestEndPos, ms_vPathTestCoverOrigin };
const float s = 0.25f;
static int iFlashTime = 0;
static bool bFlashToggle = false;
if(fwTimer::GetTimeInMilliseconds() - iFlashTime > 150)
{
iFlashTime = fwTimer::GetTimeInMilliseconds();
bFlashToggle = !bFlashToggle;
}
Color32 iCols[3] = {
bFlashToggle ? Color_LightSeaGreen : Color_white,
bFlashToggle ? Color_OrangeRed: Color_white,
bFlashToggle ? Color_red: Color_red3
};
for(int i=0; i<3; i++)
{
if(!vEndPoints[i].IsZero())
{
grcDebugDraw::Line(vEndPoints[i]-Vector3(s, 0.0f, 0.0f), vEndPoints[i]+Vector3(s, 0.0f, 0.0f), iCols[i]);
grcDebugDraw::Line(vEndPoints[i]-Vector3(0.0f, s, 0.0f), vEndPoints[i]+Vector3(0.0f, s, 0.0f), iCols[i]);
grcDebugDraw::Line(vEndPoints[i]-Vector3(0.0f, 0.0f, s), vEndPoints[i]+Vector3(0.0f, 0.0f, s), iCols[i]);
if(i==0 || i==1)
{
Color32 iCol = iCols[i];
iCol.SetAlpha(128);
grcDebugDraw::Sphere(vEndPoints[i], ms_fPathTestEntityRadius, iCol, false);
}
}
}
Color32 iRefVecCol = bFlashToggle ? Color_yellow1 : Color_tan;
grcDebugDraw::Line(ms_vPathTestStartPos, ms_vPathTestStartPos+(ms_vPathTestReferenceVector*ms_fPathTestReferenceDist), iRefVecCol);
Color32 iSphereCol = bFlashToggle ? Color_GreenYellow : Color_LightSeaGreen;
for(int s=0; s<CPathServer::ms_iPathTestNumInfluenceSpheres; s++)
{
grcDebugDraw::Sphere(CPathServer::ms_PathTestInfluenceSpheres[s].GetOrigin(), CPathServer::ms_PathTestInfluenceSpheres[s].GetRadius(), iSphereCol, false);
}
}
#endif // GTA_ENGINE
#endif // !__FINAL
void AddUserDynamicObjectAtCameraPos()
{
if(!camInterface::GetDebugDirector().IsFreeCamActive())
return;
const Vector3 vOrigin = camInterface::GetDebugDirector().GetFreeCamFrame().GetPosition();
const Vector3 vFwd = camInterface::GetDebugDirector().GetFreeCamFrame().GetFront();
const float fHeading = fwAngle::GetRadianAngleBetweenPoints(vFwd.x, vFwd.y, 0.0f, 0.0f);
static Vector3 vSize(10.0f, 5.0f, 5.0f);
TDynamicObjectIndex iObj = CPathServerGta::AddBlockingObject(vOrigin, vSize, fHeading, TDynamicObject::BLOCKINGOBJECT_ALL_PATH_TYPES);
Displayf("TDynamicObject = 0x%x", iObj);
}
void PathServer_ToggleDrawPathNodes(void)
{
}
#if __BANK
void OnSelectObjAvoidanceCombo(void)
{
CPathServer::m_eObjectAvoidanceMode = (CPathServer::EObjectAvoidanceMode)CPathServer::m_iObjAvoidanceModeComboIndex;
}
#endif
void PathSever_VerifyAdjacencies()
{
LOCK_NAVMESH_DATA;
LOCK_STORE_LOADED_MESHES;
aiNavMeshStore * pStore = CPathServer::GetNavMeshStore(kNavDomainRegular);
const atArray<s32> & meshes = pStore->GetLoadedMeshes();
for(s32 m=0; m<meshes.GetCount(); m++)
{
s32 iMesh = meshes[m];
CNavMesh * pMesh = CPathServer::GetNavMeshFromIndex(iMesh, kNavDomainRegular);
if(pMesh)
{
for(s32 p=0; p<pMesh->GetNumPolys(); p++)
{
TNavMeshPoly * pPoly = pMesh->GetPoly(p);
for(s32 a=0; a<pPoly->GetNumVertices(); a++)
{
const TAdjPoly & adjPoly = pMesh->GetAdjacentPoly( pMesh->GetPolyVertexIndex( pPoly, a ) );
const s32 iAdjacentMesh = adjPoly.GetNavMeshIndex(pMesh->GetAdjacentMeshes());
if(iAdjacentMesh != NAVMESH_NAVMESH_INDEX_NONE)
{
Assert(iAdjacentMesh != NAVMESH_INDEX_TESSELLATION); // no tessellations, since this is outside of a pathsearch
CNavMesh * pAdjMesh = CPathServer::GetNavMeshFromIndex(iAdjacentMesh, kNavDomainRegular);
if(pAdjMesh)
{
Assert(adjPoly.GetPolyIndex() < pAdjMesh->GetNumPolys());
}
}
}
}
}
}
UNLOCK_NAVMESH_DATA
UNLOCK_STORE_LOADED_MESHES
}
/*
void PathServer_TogglePathServerThreadRunning(void)
{
#ifdef GTA_ENGINE
#if !__FINAL
#if __BANK
// Rage widgets toggle the boolean variable they're associated with before calling the associated callback.
// This isn't what we want, so we have to flip the variable again here!
CPathServer::ms_bPathServerThreadIsRunning = !CPathServer::ms_bPathServerThreadIsRunning;
if(CPathServer::ms_bPathServerThreadIsRunning)
{
CPathServer::SuspendThread();
}
else
{
CPathServer::ResumeThread();
}
#endif
#endif
#endif
}
*/
void PathServer_RepeatPathQuery(void)
{
#ifdef GTA_ENGINE
#if !__FINAL
#if __BANK
CPathRequest * pRequest = CPathServer::GetPathRequest(CPathServer::m_iSelectedPathRequest);
pRequest->m_bComplete = false;
pRequest->m_bRequestPending = true;
pRequest->m_bSlotEmpty = false;
pRequest->m_hHandle = 1;
#endif
#endif
#endif
}
void PathServer_OutputPathQuery(void)
{
#ifdef GTA_ENGINE
#if !__FINAL && __BANK
CPathServer::OutputPathRequestProblem(CPathServer::m_iSelectedPathRequest);
#endif
#endif
}
void PathServer_RequestPathButDontRetrieve(void)
{
#ifdef GTA_ENGINE
#if !__FINAL && __BANK
Vector3 vStart(0.0f,0.0f,0.0f);
Vector3 vEnd(10.0f,10.0f,0.0f);
CPathServer::RequestPath(vStart, vEnd, 0);
//#endif
#endif
#endif
}
void PathServer_TestLosStackOverflow()
{
#ifdef GTA_ENGINE
#if !__FINAL && __BANK
// Navmesh must be [62,74]
// Teleport to (152,710,11)
Vector3 vStart(169.735565f, 680.479065f, 7.24429321f);
Vector3 vEnd(168.991272f, 662.717468f, 7.14869213f);
TPathHandle h = CPathServer::RequestLineOfSight(vStart, vEnd, 0.0f);
while(CPathServer::IsRequestResultReady(h)==ERequest_NotReady)
{
sysIpcYield(0);
}
bool bRet;
CPathServer::GetLineOfSightResult(h, bRet);
//#endif
#endif
#endif
}
void PathServer_OnSelectPrevPathRequest()
{
switch(CPathServer::m_iVisualisePathServerInfo)
{
case CPathServer::PathServerVis_PathRequests:
CPathServer::m_iSelectedPathRequest--;
if(CPathServer::m_iSelectedPathRequest < 0) CPathServer::m_iSelectedPathRequest = MAX_NUM_PATH_REQUESTS-1;
break;
case CPathServer::PathServerVis_LineOfSightRequests:
CPathServer::m_iSelectedLosRequest--;
if(CPathServer::m_iSelectedLosRequest < 0) CPathServer::m_iSelectedLosRequest = MAX_NUM_LOS_REQUESTS-1;
break;
}
}
void PathServer_OnSelectNextPathRequest()
{
switch(CPathServer::m_iVisualisePathServerInfo)
{
case CPathServer::PathServerVis_PathRequests:
CPathServer::m_iSelectedPathRequest++;
if(CPathServer::m_iSelectedPathRequest >= MAX_NUM_PATH_REQUESTS) CPathServer::m_iSelectedPathRequest = 0;
break;
case CPathServer::PathServerVis_LineOfSightRequests:
CPathServer::m_iSelectedLosRequest++;
if(CPathServer::m_iSelectedLosRequest >= MAX_NUM_LOS_REQUESTS) CPathServer::m_iSelectedLosRequest = 0;
break;
}
}
void CPathServer::DebugDetessellateNow()
{
fwPathServer::DetessellateAllPolys();
}
#ifdef GTA_ENGINE
#if !__FINAL
#if __BANK
void PathServer_TestColPolyVsPaths()
{
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
Vector3 vPts[3];
vPts[0] = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
vPts[1] = vPts[0] + XAXIS;
vPts[2] = vPts[0] + YAXIS;
ThePaths.CollisionTriangleIntersectsRoad(vPts, false);
}
}
#endif
#endif
#endif
void PathServer_TestLOS()
{
#if defined(GTA_ENGINE) && !__FINAL && __BANK && __WIN32PC && (!IS_CONSOLE)
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
Vector3 vStart = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
if(!debugDirector.IsFreeCamActive()) return;
const Vector3& vEnd = debugDirector.GetFreeCamFrame().GetPosition();
TPathHandle hLosPath = CPathServer::RequestLineOfSight(vStart, vEnd, 0.0f);
while(CPathServer::IsRequestResultReady(hLosPath)==ERequest_NotReady) {
Sleep(0);
}
bool bIsLosClear = false;
EPathServerErrorCode eRet = CPathServer::GetLineOfSightResult(hLosPath, bIsLosClear);
eRet;
#endif
}
void PathServer_TestDebugPolyUnderCamera()
{
#if defined(GTA_ENGINE) && __BANK && __DEV
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
if(!debugDirector.IsFreeCamActive()) return;
const Vector3& vPos = debugDirector.GetFreeCamFrame().GetPosition();
const aiNavDomain domain = kNavDomainRegular;
CNavMesh * pNavMesh = CPathServer::GetNavMeshFromIndex( CPathServer::GetNavMeshIndexFromPosition(vPos, domain), domain );
if(!pNavMesh)
return;
int iMeshX, iMeshY;
CPathServer::GetNavMeshStore(domain)->MeshIndexToMeshCoords(pNavMesh->GetIndexOfMesh(), iMeshX, iMeshY);
iMeshX *= CPathServerExtents::m_iNumSectorsPerNavMesh;
iMeshY *= CPathServerExtents::m_iNumSectorsPerNavMesh;
char tmp[256];
sprintf(tmp, "NavMesh [%i][%i]\n", iMeshX, iMeshY);
Displayf("%s", tmp);
Vector3 vIsect;
u32 iPolyIndex = pNavMesh->GetPolyBelowPoint(vPos, vIsect, 10.0f);
if(iPolyIndex != NAVMESH_POLY_INDEX_NONE)
{
TNavMeshPoly * pPoly = pNavMesh->GetPoly(iPolyIndex);
Assert(pPoly->GetNavMeshIndex() == pNavMesh->GetIndexOfMesh());
sprintf(tmp, "NavMesh %i Poly %i (addr:0x%p)\n", pNavMesh->GetIndexOfMesh(), iPolyIndex, pPoly);
Displayf("%s", tmp);
sprintf(tmp, "NumVertices %i, PedDensity %i, Flags %i\n", pPoly->GetNumVertices(), pPoly->GetPedDensity(), pPoly->GetFlags());
Displayf("%s", tmp);
sprintf(tmp, "Area %.2f\n", pNavMesh->GetPolyArea(iPolyIndex));
Displayf("%s", tmp);
Vector3 vPolyNormal;
pNavMesh->GetPolyNormal(vPolyNormal, pPoly);
sprintf(tmp, "PolyNormal (%.2f, %.2f, %.2f)\n", vPolyNormal.x, vPolyNormal.y, vPolyNormal.z);
Displayf("%s", tmp);
u32 testFlags = NAVMESHPOLY_SMALL | NAVMESHPOLY_LARGE | NAVMESHPOLY_OPEN | NAVMESHPOLY_CLOSED | NAVMESHPOLY_TESSELLATED_FRAGMENT | NAVMESHPOLY_REPLACED_BY_TESSELLATION;
if(pPoly->GetIsSmall()) Displayf("(small)");
if(pPoly->GetIsLarge()) Displayf("(large)");
if(pPoly->GetIsOpen()) Displayf("(open)");
if(pPoly->GetIsClosed()) Displayf("(closed)");
if(pPoly->GetIsTessellatedFragment()) Displayf("(frag)");
if(pPoly->GetReplacedByTessellation()) Displayf("(replaced)");
if(pPoly->TestFlags(testFlags)) Displayf("\n");
Vector3 vert, nextVert, vDiff, vEdgeNormal;
int nextv, vi1, vi2;
u32 v;
Vector3 vMins(FLT_MAX, FLT_MAX, FLT_MAX);
Vector3 vMaxs(-FLT_MAX, -FLT_MAX, -FLT_MAX);
for(v=0; v<pPoly->GetNumVertices(); v++)
{
nextv = (v+1) % pPoly->GetNumVertices();
vi1 = pNavMesh->GetPolyVertexIndex(pPoly, v);
vi2 = pNavMesh->GetPolyVertexIndex(pPoly, nextv);
pNavMesh->GetVertex(vi1, vert);
pNavMesh->GetVertex(vi2, nextVert);
if(vert.x < vMins.x) vMins.x = vert.x;
if(vert.y < vMins.y) vMins.y = vert.y;
if(vert.z < vMins.z) vMins.z = vert.z;
if(vert.x > vMaxs.x) vMaxs.x = vert.x;
if(vert.y > vMaxs.y) vMaxs.y = vert.y;
if(vert.z > vMaxs.z) vMaxs.z = vert.z;
vDiff = nextVert - vert;
const TAdjPoly & adjPoly = pNavMesh->GetAdjacentPoly((u32) pPoly->GetFirstVertexIndex()+v);
pNavMesh->GetPolyEdgeNormal(vEdgeNormal, pPoly, v);
sprintf(tmp, "%i) [%i] (%.1f, %.1f, %.1f) \t adjType:%i (adjNav:%i, adjPoly:%i, origAdjNav:%i, origAdjPoly:%i) length : %.2f normal : (%.2f, %.2f, %.2f)\n",
v,
vi1,
vert.x, vert.y, vert.z,
adjPoly.GetAdjacencyType(),
adjPoly.GetNavMeshIndex(pNavMesh->GetAdjacentMeshes()), adjPoly.GetPolyIndex(),
adjPoly.GetOriginalNavMeshIndex(pNavMesh->GetAdjacentMeshes()), adjPoly.GetOriginalPolyIndex(),
vDiff.Mag(),
vEdgeNormal.x, vEdgeNormal.y, vEdgeNormal.z
);
Displayf("%s", tmp);
}
Vector3 vSize = vMaxs - vMins;
sprintf(tmp, "Mins (%.1f, %.1f, %.1f) Maxs (%.1f, %.1f, %.1f) Size (%.1f, %.1f, %.1f)\n",
vMins.x, vMins.y, vMins.z, vMaxs.x, vMaxs.y, vMaxs.z, vSize.x, vSize.y, vSize.z);
Displayf("%s", tmp);
}
#endif
}
void PathServer_TestAudioPropertiesRequest()
{
#if defined(GTA_ENGINE) && __BANK
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
Vector3 vPos = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
TPathHandle hAudioReq = CPathServer::RequestAudioProperties(vPos);
while(CPathServer::IsRequestResultReady(hAudioReq)==ERequest_NotReady)
{
sysIpcYield(0);
}
u32 iAudioProperties;
EPathServerErrorCode eRet = CPathServer::GetAudioPropertiesResult(hAudioReq, iAudioProperties);
if(eRet==PATH_NO_ERROR)
{
printf("AudioProperties:%i\n", iAudioProperties);
}
else
{
printf("AudioProperties couldn't be queried. No navmesh poly nearby?\n");
}
(void)eRet; // stop VS from complaining
#endif
}
void PathServer_TestClearAreaRequest()
{
#if defined(GTA_ENGINE) && __BANK
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
Vector3 vPos = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
static float fSearchRadius = 100.0f;
static float fDesiredClearRadius = 10.0f;
static float fMinimumRadius = 0.0f;
static bool bTestObjects = true;
static bool bInteriors = false;
static bool bExteriors = true;
static bool bWater = false;
static bool bSheltered = false;
u32 iFlags = 0;
if(bTestObjects) iFlags |= CNavmeshClearAreaHelper::Flag_TestForObjects;
if(bInteriors) iFlags |= CNavmeshClearAreaHelper::Flag_AllowInteriors;
if(bExteriors) iFlags |= CNavmeshClearAreaHelper::Flag_AllowExterior;
if(bWater) iFlags |= CNavmeshClearAreaHelper::Flag_AllowWater;
if(bSheltered) iFlags |= CNavmeshClearAreaHelper::Flag_AllowSheltered;
grcDebugDraw::Sphere(vPos, fSearchRadius, Color_orange3, false, 50);
CNavmeshClearAreaHelper searchHelper;
searchHelper.StartClearAreaSearch(vPos, fSearchRadius, fSearchRadius, fDesiredClearRadius, iFlags, fMinimumRadius);
Vector3 vClearPos;
SearchStatus ss;
while(!searchHelper.GetSearchResults( ss, vClearPos ))
{
sysIpcYield(0);
}
if(ss == SS_SearchSuccessful)
{
grcDebugDraw::Sphere(vClearPos, fDesiredClearRadius, Color_cyan, false, 50);
printf("Clear position at (%.1f, %.1f, %.1f)\n", vClearPos.x, vClearPos.y, vClearPos.z);
}
else
{
printf("Failed to find clear position\n");
}
#endif
}
void PathServer_TestClosestPositionRequest()
{
#if defined(GTA_ENGINE) && __BANK
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
Vector3 vPos = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
static float fSearchRadius = 100.0f;
static u32 iFlags = CClosestPositionRequest::Flag_ConsiderInterior|CClosestPositionRequest::Flag_ConsiderExterior|CClosestPositionRequest::Flag_ConsiderDynamicObjects;
static float fMinimumSpacing = 0.0f;
static float fZWeightingAbove = 1.0f;
static float fZWeightingAtOrBelow = 1.0f;
static s32 iMaxNumResults = CClosestPositionRequest::MAX_NUM_RESULTS;
static s32 iNumAvoidSpheres = 0;
spdSphere avoidSpheres[1];
static float fSphereRadius = 10.0f;
avoidSpheres[0].Set(VECTOR3_TO_VEC3V(vPos), ScalarV(fSphereRadius));
CNavmeshClosestPositionHelper helper;
helper.StartClosestPositionSearch(vPos, fSearchRadius, iFlags, fZWeightingAbove, fZWeightingAtOrBelow, fMinimumSpacing, iNumAvoidSpheres, avoidSpheres, iMaxNumResults);
s32 iNumPositions;
Vector3 vPositions[CClosestPositionRequest::MAX_NUM_RESULTS];
SearchStatus ss;
while(1)
{
sysIpcYield(0);
if(helper.GetSearchResults(ss, iNumPositions, vPositions, CClosestPositionRequest::MAX_NUM_RESULTS))
{
if(ss == SS_SearchSuccessful)
{
Vector3 vRGB(0.0f,1.0f,0.0f);
for(s32 r=0; r<iNumPositions; r++)
{
Color32 col(vRGB);
grcDebugDraw::Sphere(vPositions[r] + ZAXIS * 0.5f, 0.5f, col, false, 500, 16);
vRGB *= 0.9f;
}
}
break;
}
}
/*
TPathHandle hReq = CPathServer::RequestClosestPosition(vPos, fSearchRadius, iFlags, fZWeightingAbove, fZWeightingAtOrBelow, fMinimumSpacing, iNumAvoidSpheres, avoidSpheres, iMaxNumResults, NULL, kNavDomainRegular);
if(hReq != PATH_HANDLE_NULL)
{
while(!CPathServer::IsRequestResultReady(hReq))
{
sysIpcYield(0);
}
CClosestPositionRequest::TResults results;
EPathServerErrorCode ret = CPathServer::GetClosestPositionResultAndClear(hReq, results);
if(ret == PATH_FOUND)
{
Vector3 vRGB(0.0f,1.0f,0.0f);
for(s32 r=0; r<results.m_iNumResults; r++)
{
Color32 col(vRGB);
grcDebugDraw::Sphere(results.m_vResults[r] + ZAXIS * 0.5f, 0.5f, col, false, 500, 16);
vRGB *= 0.9f;
}
}
}
*/
#endif
}
void TestEvictDynamicObjectForScript()
{
s32 iObjectIndex = CPathServer::EvictDynamicObjectForScript();
if(iObjectIndex != -1)
{
const TDynamicObject & obj = CPathServer::GetPathServerThread()->GetDynamicObject((TDynamicObjectIndex)iObjectIndex);
Vector3 vObjPos = obj.m_Bounds.GetOrigin();
grcDebugDraw::Sphere(vObjPos, 4.0, Color_green, false, 4000, 12);
grcDebugDraw::Arrow(FindPlayerPed()->GetTransform().GetPosition(), VECTOR3_TO_VEC3V(vObjPos), 0.5f, Color_green, 4000);
}
}
void PathServer_TestDisablePolysAroundCamera()
{
static float fSize = 8.0f;
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
if(!debugDirector.IsFreeCamActive()) return;
const Vector3& vPos = debugDirector.GetFreeCamFrame().GetPosition();
Vector3 vMin = vPos - Vector3(fSize,fSize,fSize);
Vector3 vMax = vPos + Vector3(fSize,fSize,fSize);
CPathServer::DisableNavMeshInArea(vMin, vMax, THREAD_INVALID);
}
void PathServer_TestTurnOffPolysForPedsAroundCamera()
{
static float fSize = 8.0f;
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
if(!debugDirector.IsFreeCamActive()) return;
const Vector3& vPos = debugDirector.GetFreeCamFrame().GetPosition();
Vector3 vMin = vPos - Vector3(fSize,fSize,fSize);
Vector3 vMax = vPos + Vector3(fSize,fSize,fSize);
CPathServer::SwitchPedsOffInArea(vMin, vMax, THREAD_INVALID);
}
void PathServer_TestFindClosestPos(
#if __BANK && !__FINAL && defined(GTA_ENGINE)
bool bOnPavement, bool bClearOfObjects, bool bExtraThorough, bool bUseFloodFill
#else
bool, bool, bool, bool
#endif
)
{
#if __BANK && !__FINAL && defined(GTA_ENGINE)
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
Vector3 vPos = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
u32 iFlags = 0;
if(bOnPavement) iFlags |= GetClosestPos_OnlyPavement;
if(bClearOfObjects) iFlags |= GetClosestPos_ClearOfObjects;
if(bExtraThorough) iFlags |= GetClosestPos_ExtraThorough;
if(bUseFloodFill) iFlags |= GetClosestPos_UseFloodFill;
sysPerformanceTimer timer("GetClosestPosForPed");
timer.Start();
Vector3 vOut;
static const float fFindPolyRadius = 30.0f;
EGetClosestPosRet eRet = CPathServer::GetClosestPositionForPed(vPos, vOut, fFindPolyRadius, iFlags);
timer.Stop();
const float fTimeTaken = timer.GetTimeMS();
Printf("CPathServer::GetClosestPositionForPed with radius %.1fm took : %.4f ms\n", fFindPolyRadius, fTimeTaken);
if(eRet!=ENoPositionFound)
{
grcDebugDraw::Line(vOut - Vector3(1.0f, 0.0f, 0.0f), vOut + Vector3(1.0f, 0.0f, 0.0f), Color_red3);
grcDebugDraw::Line(vOut - Vector3(0.0f, 1.0f, 0.0f), vOut + Vector3(0.0f, 1.0f, 0.0f), Color_red3);
grcDebugDraw::Line(vOut, vOut + Vector3(0.0f, 0.0f, 3.0f), Color_red3, Color_red2);
}
#endif
}
void PathServer_TestFindClosestPosOnPavement() { PathServer_TestFindClosestPos(true, false, false, false); }
void PathServer_TestFindClosestPosOnAnySurface() { PathServer_TestFindClosestPos(false, false, false, false); }
void PathServer_TestFindClosestPosOnPavementClearOfObjects() { PathServer_TestFindClosestPos(true, true, false, false); }
void PathServer_TestFindClosestPosOnAnySurfaceClearOfObjects() { PathServer_TestFindClosestPos(false, true, false, false); }
void PathServer_TestFindClosestPosOnAnySurfaceClearOfObjectsExtraThorough() { PathServer_TestFindClosestPos(false, true, true, true); }
#if __BANK && defined(GTA_ENGINE)
void PathServer_AddRequiredRegion()
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
if(!debugDirector.IsFreeCamActive()) return;
const Vector3& vPos = debugDirector.GetFreeCamFrame().GetPosition();
CPathServer::AddNavMeshRegion( NMR_Script, static_cast<scrThreadId>(0xABCD), vPos.x, vPos.y, 250.0f );
}
void PathServer_RemoveRequiredRegion()
{
CPathServer::RemoveNavMeshRegion( NMR_Script, static_cast<scrThreadId>(0xABCD) );
}
#endif
void PathServer_TestFloodFillToClosestCarNode()
{
#ifdef GTA_ENGINE
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
Vector3 vPos = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
Vector3 vOut;
static const float fMaxRadius = 50.0f;
TPathHandle hHandle = CPathServer::RequestClosestCarNodeSearch(vPos, fMaxRadius, pPlayer);
if(hHandle != PATH_HANDLE_NULL)
{
while(CPathServer::IsRequestResultReady(hHandle)==ERequest_NotReady)
{
sysIpcSleep(0);
}
Vector3 vClosestCarNode;
EPathServerErrorCode errCode = CPathServer::GetClosestCarNodeSearchResultAndClear(hHandle, vClosestCarNode);
if(errCode==PATH_NO_ERROR)
{
grcDebugDraw::Line(vClosestCarNode - Vector3(1.0f, 0.0f, 0.0f), vClosestCarNode + Vector3(1.0f, 0.0f, 0.0f), Color_red3);
grcDebugDraw::Line(vClosestCarNode - Vector3(0.0f, 1.0f, 0.0f), vClosestCarNode + Vector3(0.0f, 1.0f, 0.0f), Color_red3);
grcDebugDraw::Line(vClosestCarNode, vClosestCarNode + Vector3(0.0f, 0.0f, 3.0f), Color_red3, Color_red2);
}
}
#endif
}
void PathServer_TestTurnOffWandering()
{
#ifdef GTA_ENGINE
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
const Vector3 vPos = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
const float fSize = 20.0f;
const Vector3 vMin = vPos - Vector3(fSize,fSize,fSize);
const Vector3 vMax = vPos + Vector3(fSize,fSize,fSize);
CPathServer::SwitchPedsOffInArea(vMin, vMax, THREAD_INVALID);
#endif
}
bool bOpponentPedGen_AllowExterior = true;
bool bOpponentPedGen_AllowInteriors = false;
bool bOpponentPedGen_AllowNonNetworkSpawn = false;
bool bOpponentPedGen_AllowIsolated = false;
bool bOpponentPedGen_AllowRoad = false;
bool bOpponentPedGen_OnlyCoverEdges = false;
float fOpponentPedGen_RadiusXY = 20.0f;
float fOpponentPedGen_CutoffZ = 200.0f;
float fOpponentPedGen_MinimumSpacing = 0.0f;
s32 iOpponentPedGen_TimeoutMS = 0;
void Pathserver_StartOpponentPedGen()
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
if(debugDirector.IsFreeCamActive())
{
Vector3 vOrigin = debugDirector.GetFreeCamFrame().GetPosition();
u32 iFlags = 0;
if(bOpponentPedGen_AllowExterior) iFlags |= CPathServerOpponentPedGen::FLAG_MAY_SPAWN_IN_EXTERIOR;
if(bOpponentPedGen_AllowInteriors) iFlags |= CPathServerOpponentPedGen::FLAG_MAY_SPAWN_IN_INTERIOR;
if(bOpponentPedGen_AllowNonNetworkSpawn) iFlags |= CPathServerOpponentPedGen::FLAG_ALLOW_NOT_NETWORK_SPAWN_CANDIDATE_POLYS;
if(bOpponentPedGen_AllowIsolated) iFlags |= CPathServerOpponentPedGen::FLAG_ALLOW_ISOLATED_POLYS;
if(bOpponentPedGen_AllowRoad) iFlags |= CPathServerOpponentPedGen::FLAG_ALLOW_ROAD_POLYS;
if(bOpponentPedGen_OnlyCoverEdges) iFlags |= CPathServerOpponentPedGen::FLAG_ONLY_POINTS_AGAINST_EDGES;
CPathServer::GetOpponentPedGen().StartSearch(vOrigin, fOpponentPedGen_RadiusXY, fOpponentPedGen_CutoffZ, iFlags, fOpponentPedGen_MinimumSpacing, iOpponentPedGen_TimeoutMS);
}
}
void Pathserver_StartOpponentPedGenAngledArea()
{
u32 iFlags = 0;
if(bOpponentPedGen_AllowExterior) iFlags |= CPathServerOpponentPedGen::FLAG_MAY_SPAWN_IN_EXTERIOR;
if(bOpponentPedGen_AllowInteriors) iFlags |= CPathServerOpponentPedGen::FLAG_MAY_SPAWN_IN_INTERIOR;
if(bOpponentPedGen_AllowNonNetworkSpawn) iFlags |= CPathServerOpponentPedGen::FLAG_ALLOW_NOT_NETWORK_SPAWN_CANDIDATE_POLYS;
if(bOpponentPedGen_AllowIsolated) iFlags |= CPathServerOpponentPedGen::FLAG_ALLOW_ISOLATED_POLYS;
if(bOpponentPedGen_AllowRoad) iFlags |= CPathServerOpponentPedGen::FLAG_ALLOW_ROAD_POLYS;
if(bOpponentPedGen_OnlyCoverEdges) iFlags |= CPathServerOpponentPedGen::FLAG_ONLY_POINTS_AGAINST_EDGES;
CPathServer::GetOpponentPedGen().StartSearch(CPhysics::g_vClickedPos[0], CPhysics::g_vClickedPos[1], fOpponentPedGen_RadiusXY, iFlags, fOpponentPedGen_MinimumSpacing, iOpponentPedGen_TimeoutMS);
}
void Pathserver_CompleteOpponentPedGen()
{
if(!CPathServer::GetOpponentPedGen().IsSearchFailed())
{
Vector3 vSpawnPos;
s32 iNum = CPathServer::GetOpponentPedGen().GetNumResults();
for(s32 i=0; i<iNum; i++)
{
CPathServer::GetOpponentPedGen().GetResult(i, vSpawnPos);
}
}
CPathServer::GetOpponentPedGen().CancelSeach();
}
void PathServer_AddPedGenBlockingArea()
{
#ifdef GTA_ENGINE
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
const Vector3 vPos = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
const float fSize = 20.0f;
CPathServer::GetAmbientPedGen().AddPedGenBlockedArea(vPos, fSize, 10000);
#endif
}
#if __DEV
void CPathServer::PathServer_TestCalcPolyAreas()
{
#ifdef GTA_ENGINE
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
const Vector3 vPos = VEC3V_TO_VECTOR3(pPlayer->GetTransform().GetPosition());
const aiNavDomain domain = kNavDomainRegular;
TNavMeshIndex iIndex = CPathServer::GetNavMeshIndexFromPosition(vPos, domain);
CNavMesh * pNavMesh = CPathServer::GetNavMeshFromIndex(iIndex, domain);
if(pNavMesh)
{
for(u32 p=0; p<pNavMesh->GetNumPolys(); p++)
{
const float fArea = pNavMesh->GetPolyArea(p);
Assert(rage::FPIsFinite(fArea));
}
}
#endif
}
#endif
/*
void PathServer_TestDecompressVerts()
{
#ifdef GTA_ENGINE
CPed * pPlayer = FindPlayerPed();
if(!pPlayer) return;
const Vector3 vPos = pPlayer->GetPosition();
TNavMeshIndex iNavMesh = CPathServer::GetNavMeshIndexFromPosition(vPos);
CNavMesh * pNavMesh = CPathServer::GetNavMeshFromIndex(iNavMesh);
if(pNavMesh)
{
pNavMesh->TestDecompressAllVertices();
}
#endif
}
*/
/*
#define TESTNUM 512
void PathServer_TestMinMax()
{
TShortMinMax minMax[TESTNUM];
fwRandom::SetRandomSeed(12345678);
for(int t=0; t<TESTNUM; t++)
{
minMax[t].m_iMinX = (u16) fwRandom::GetRandomNumberInRange(-4000.0f, 4000.0f);
minMax[t].m_iMinY = (u16) fwRandom::GetRandomNumberInRange(-4000.0f, 4000.0f);
minMax[t].m_iMinZ = (u16) fwRandom::GetRandomNumberInRange(-4000.0f, 4000.0f);
minMax[t].m_iMaxX = (u16) fwRandom::GetRandomNumberInRange(-4000.0f, 4000.0f);
minMax[t].m_iMaxY = (u16) fwRandom::GetRandomNumberInRange(-4000.0f, 4000.0f);
minMax[t].m_iMaxZ = (u16) fwRandom::GetRandomNumberInRange(-4000.0f, 4000.0f);
if(minMax[t].m_iMinX > minMax[t].m_iMaxX) SWAP(minMax[t].m_iMinX, minMax[t].m_iMaxX);
if(minMax[t].m_iMinY > minMax[t].m_iMaxY) SWAP(minMax[t].m_iMinY, minMax[t].m_iMaxY);
if(minMax[t].m_iMinZ > minMax[t].m_iMaxZ) SWAP(minMax[t].m_iMinZ, minMax[t].m_iMaxZ);
}
int t1,t2;
static bool bCheckResults=false;
if(bCheckResults)
{
for(t1=0; t1<TESTNUM; t1++)
{
for(t2=0; t2<TESTNUM; t2++)
{
const bool bResultA = minMax[t1].Intersects(minMax[t2]);
const bool bResultB = minMax[t1].IntersectsXenon(minMax[t2]);
Assert(bResultA==bResultB);
}
}
}
sysPerformanceTimer timer("test");
timer.Start();
for(t1=0; t1<TESTNUM; t1++)
{
for(t2=0; t2<TESTNUM; t2++)
{
if(CNavMesh::ms_bUseVmxOptimisations)
{
minMax[t1].IntersectsXenon(minMax[t2]);
}
else
{
minMax[t1].Intersects(minMax[t2]);
}
}
}
timer.Stop();
float fTimeMs = timer.GetTimeMS();
printf("Time taken %.4f\n", fTimeMs);
}
*/
//***********************************************************************************
// PathServer_SetUpPerfTest
// This simply sets up a repeatable situation in GTAIV. The player is placed at
// a fixed location, and is told to navmesh to an unreachable target. A lot of
// polys & objects will be visited during the course of the search.
// The processing times of these paths requests should be a pretty stable yardstick
// for optimising the pathsearch algorithms.
//***********************************************************************************
void PathServer_SetUpPerfTest()
{
#ifdef GTA_ENGINE
Vector3 vStartPos(821.0f, -302.0f, 17.0f);
Vector3 vEndPos(814.8f, -301.5f, 26.0f);
CPed * pPlayer = FindPlayerPed();
if(pPlayer)
{
pPlayer->Teleport(vStartPos, pPlayer->GetCurrentHeading());
CTaskMoveFollowNavMesh * pNavTask = rage_new CTaskMoveFollowNavMesh(MOVEBLENDRATIO_RUN, vEndPos);
// Don't limit extents - visit as many polys/objects as possible
pNavTask->SetUseLargerSearchExtents(true);
CTaskComplexControlMovement * pCtrlMove = rage_new CTaskComplexControlMovement(pNavTask);
pPlayer->GetPedIntelligence()->AddTaskAtPriority(pCtrlMove, PED_TASK_PRIORITY_PRIMARY, true);
}
#endif
}
void OnSelectThreadRunModeCombo()
{
#ifdef GTA_ENGINE
Assert(CPathServer::m_iDebugThreadRunMode==0 || CPathServer::m_iDebugThreadRunMode==1);
if(CPathServer::m_iDebugThreadRunMode==0)
{
CPathServer::SuspendThread();
}
else
{
CPathServer::ResumeThread();
}
#endif
}
#ifdef GTA_ENGINE
u64 InitPathTestFlags()
{
u64 iFlags=0;
if(PathTest_bPreferPavements) iFlags |= PATH_FLAG_PREFER_PAVEMENTS;
if(PathTest_bNeverLeaveWater) iFlags |= PATH_FLAG_NEVER_LEAVE_WATER;
if(PathTest_bGoAsFarAsPossible) iFlags |= PATH_FLAG_USE_BEST_ALTERNATE_ROUTE_IF_NONE_FOUND;
if(PathTest_bNeverLeavePavements) iFlags |= PATH_FLAG_NEVER_LEAVE_PAVEMENTS;
if(PathTest_bNeverClimbOverStuff) iFlags |= PATH_FLAG_NEVER_CLIMB_OVER_STUFF;
if(PathTest_bNeverDropFromHeight) iFlags |= PATH_FLAG_NEVER_DROP_FROM_HEIGHT;
if(PathTest_bNeverUseLadders) iFlags |= PATH_FLAG_NEVER_USE_LADDERS;
if(PathTest_bFleeTarget) iFlags |= PATH_FLAG_FLEE_TARGET;
if(PathTest_bWander) iFlags |= PATH_FLAG_WANDER;
if(PathTest_bNeverEnterWater) iFlags |= PATH_FLAG_NEVER_ENTER_WATER;
if(PathTest_bDontAvoidDynamicObjects) iFlags |= PATH_FLAG_DONT_AVOID_DYNAMIC_OBJECTS;
if(PathTest_bPreferDownhill) iFlags |= PATH_FLAG_PREFER_DOWNHILL;
if(PathTest_bReduceObjectBBoxes) iFlags |= PATH_FLAG_REDUCE_OBJECT_BBOXES;
if(PathTest_bUseLargerSearchExtents) iFlags |= PATH_FLAG_USE_LARGER_SEARCH_EXTENTS;
if(PathTest_bMayUseFatalDrops) iFlags |= PATH_FLAG_MAY_USE_FATAL_DROPS;
if(PathTest_bIgnoreObjectsWithNoUprootLimit) iFlags |= PATH_FLAG_IGNORE_NON_SIGNIFICANT_OBJECTS;
if(PathTest_bCutSharpCorners) iFlags |= PATH_FLAG_CUT_SHARP_CORNERS;
if(PathTest_bAllowToNavigateUpSteepPolygons) iFlags |= PATH_FLAG_ALLOW_TO_NAVIGATE_UP_STEEP_POLYGONS;
if(PathTest_bScriptedRoute) iFlags |= PATH_FLAG_SCRIPTED_ROUTE;
if(PathTest_bPreserveZ) iFlags |= PATH_FLAG_PRESERVE_SLOPE_INFO_IN_PATH;
if(PathTest_bRandomisePoints) iFlags |= PATH_FLAG_RANDOMISE_POINTS;
if(PathTest_bUseDirectionalCover)
{
iFlags |= PATH_FLAG_USE_DIRECTIONAL_COVER;
}
return iFlags;
}
void SetPathTestStartPos()
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
CPathServer::ms_vPathTestStartPos = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() :
CPlayerInfo::ms_cachedMainPlayerPos;
}
void SetPathTestEndPos()
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
CPathServer::ms_vPathTestEndPos = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() :
CPlayerInfo::ms_cachedMainPlayerPos;
}
void SetPathTestCoverOriginPos()
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
CPathServer::ms_vPathTestCoverOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() :
CPlayerInfo::ms_cachedMainPlayerPos;
}
void SetPathTestReferenceVector()
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vCameraOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() :
CPlayerInfo::ms_cachedMainPlayerPos;
CPathServer::ms_vPathTestReferenceVector - vCameraOrigin - CPathServer::ms_vPathTestStartPos;
CPathServer::ms_vPathTestReferenceVector.Normalize();
}
void PathTestAddInfluenceSphere()
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vPos = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() :
CPlayerInfo::ms_cachedMainPlayerPos;
if(CPathServer::ms_iPathTestNumInfluenceSpheres < MAX_NUM_INFLUENCE_SPHERES)
{
TInfluenceSphere & sphere = CPathServer::ms_PathTestInfluenceSpheres[CPathServer::ms_iPathTestNumInfluenceSpheres];
sphere.Init(vPos, CPathServer::ms_fPathTestInfluenceSphereRadius, CPathServer::ms_fPathTestInfluenceMin, CPathServer::ms_fPathTestInfluenceMax);
CPathServer::ms_iPathTestNumInfluenceSpheres++;
}
}
void PathTestRemoveInfluenceSphere()
{
if(CPathServer::ms_iPathTestNumInfluenceSpheres > 0)
CPathServer::ms_iPathTestNumInfluenceSpheres--;
}
void PathTest_FindPath()
{
Vector3 vRef(0.0f,0.0f,0.0f);
u64 iFlags = InitPathTestFlags();
TRequestPathStruct reqStruct;
reqStruct.m_iFlags = iFlags;
reqStruct.m_vPathStart = CPathServer::ms_vPathTestStartPos;
reqStruct.m_vPathEnd = CPathServer::ms_vPathTestEndPos;
reqStruct.m_vReferenceVector = CPathServer::ms_vPathTestReferenceVector;
reqStruct.m_fReferenceDistance = CPathServer::ms_fPathTestReferenceDist;
reqStruct.m_vCoverOrigin = CPathServer::ms_vPathTestCoverOrigin;
reqStruct.m_fCompletionRadius = CPathServer::ms_fPathTestCompletionRadius;
reqStruct.m_fEntityRadius = CPathServer::ms_fPathTestEntityRadius;
reqStruct.m_iNumInfluenceSpheres = Min(CPathServer::ms_iPathTestNumInfluenceSpheres, MAX_NUM_INFLUENCE_SPHERES);
reqStruct.m_fMaxSlopeNavigable = PathTest_fPathTestMaxSlopeNavigable;
sysMemCpy(reqStruct.m_InfluenceSpheres, CPathServer::ms_PathTestInfluenceSpheres, sizeof(TInfluenceSphere)*reqStruct.m_iNumInfluenceSpheres);
TPathHandle hPath = CPathServer::RequestPath(reqStruct);
if(hPath != PATH_HANDLE_NULL)
{
while(CPathServer::IsRequestResultReady(hPath)==ERequest_NotReady)
{
sysIpcSleep(10);
}
CPathServer::CancelRequest(hPath);
}
}
void PathTest_TestLOS()
{
TPathHandle hLos = CPathServer::RequestLineOfSight(CPathServer::ms_vPathTestStartPos, CPathServer::ms_vPathTestEndPos, CPathServer::ms_fPathTestEntityRadius - PATHSERVER_PED_RADIUS, true, false, false, 0, NULL, PathTest_fPathTestMaxSlopeNavigable);
if(hLos != PATH_HANDLE_NULL)
{
while(CPathServer::IsRequestResultReady(hLos)==ERequest_NotReady)
{
sysIpcSleep(10);
}
CPathServer::CancelRequest(hLos);
}
}
void OnTestBlockingObjectSetFromCamera()
{
camDebugDirector& debugDirector = camInterface::GetDebugDirector();
Vector3 vOrigin = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetPosition() : VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetPosition());
Vector3 vFwd = debugDirector.IsFreeCamActive() ? debugDirector.GetFreeCamFrame().GetFront() : VEC3V_TO_VECTOR3(FindPlayerPed()->GetTransform().GetForward());
g_vTestBlockingObjectPos = vOrigin;
g_fTestBlockingObjectRot = fwAngle::GetRadianAngleBetweenPoints(vFwd.x, vFwd.y, 0.0f, 0.0f);
}
void OnCreateTestBlockingObject()
{
float fRot = g_fTestBlockingObjectRot * DtoR;
fRot = fwAngle::LimitRadianAngleSafe(fRot);
CPathServerGta::AddBlockingObject(g_vTestBlockingObjectPos, g_vTestBlockingObjectSize, fRot);
}
#endif // GTA_ENGINE
#if __BANK
void
CPathServer::InitWidgets()
{
static const char * pPathServerVisMode[] =
{
"Off",
"Path Requests",
"LOS Requests",
"Audio Requests",
"FloodFill Requests",
"ClearArea Requests",
"ClosestPosition Requests",
"Info",
"Memory Usage",
"Current NavMesh",
"Polygon Info"
};
static const char * pObjAdvoidanceMode[] =
{
"None",
"Tessellation",
"Clipping"
};
static const char * pThreadRunMode[] =
{
"Suspended", "Running"
};
/* static const char * pRelativeThreadPriority[] =
{
"-15 : THREAD_PRIORITY_IDLE",
" -2 : THREAD_PRIORITY_LOWEST",
" -1 : THREAD_PRIORITY_BELOW_NORMAL",
" 0 : THREAD_PRIORITY_NORMAL",
" 1 : THREAD_PRIORITY_ABOVE_NORMAL",
" 2 : THREAD_PRIORITY_HIGHEST",
" 15 : THREAD_PRIORITY_TIME_CRITICAL"
}; */
static const char * pDataSetNames[] =
{
"Regular", // kNavDomainRegular
"Height Meshes" // kNavDomainHeightMeshes
};
CompileTimeAssert(NELEM(pDataSetNames) == kNumNavDomains);
bkBank & bank = BANKMGR.CreateBank("Navigation");
//****************************************
// Basic navigation widgets:
const char ** ppNavMeshMode = &ms_pNavMeshVisModeTxt[0];
bank.AddCombo(
"NavMesh :",
&CPathServer::m_iVisualiseNavMeshes,
CPathServer::NavMeshVis_NumModes,
ppNavMeshMode,
NullCB, //OnSelectTaskCombo,
"Selects NavMesh visualisation mode"
);
bank.AddCombo(
"PathServer :",
&CPathServer::m_iVisualisePathServerInfo,
CPathServer::PathServerVis_NumModes,
pPathServerVisMode,
NullCB, //OnSelectTaskCombo,
"Selects PathServer visualisation mode"
);
bank.AddCombo("Data Set :",
&CPathServer::m_iVisualiseDataSet,
(int)kNumNavDomains,
pDataSetNames,
NullCB,
"Selects data set to visualise"
);
bank.AddToggle("Draw Hierarchical Nodes :", &CPathServer::m_bVisualiseHierarchicalNodes);
bank.AddToggle("Draw LinkWidths :", &CPathServer::m_bVisualiseLinkWidths);
#ifdef GTA_ENGINE
bank.PushGroup("Test Tool", false);
{
bank.AddToggle("PathTest_bGetPointsFromMeasuringTool", &PathTest_bGetPointsFromMeasuringTool);
bank.AddButton("Set start pos", SetPathTestStartPos);
bank.AddButton("Set end pos", SetPathTestEndPos);
bank.AddButton("Set reference vector", SetPathTestReferenceVector);
bank.AddSlider("Reference dist", &CPathServer::ms_fPathTestReferenceDist, 0.0f, 100.0f, 0.1f);
bank.AddSlider("Completion radius", &CPathServer::ms_fPathTestCompletionRadius, 0.0f, 100.0f, 0.1f);
bank.AddSlider("Entity radius", &CPathServer::ms_fPathTestEntityRadius, PATHSERVER_PED_RADIUS, PATHSERVER_MAX_PED_RADIUS, 0.1f);
bank.AddSlider("Max slope navigable", &PathTest_fPathTestMaxSlopeNavigable, 0, PI, 0.05f);
bank.AddToggle("PreferPavements", &PathTest_bPreferPavements);
bank.AddToggle("NeverLeaveWater", &PathTest_bNeverLeaveWater);
bank.AddToggle("GoAsFarAsPossible", &PathTest_bGoAsFarAsPossible);
bank.AddToggle("NeverLeavePavements", &PathTest_bNeverLeavePavements);
bank.AddToggle("NeverClimbOverStuff", &PathTest_bNeverClimbOverStuff);
bank.AddToggle("NeverDropFromHeight", &PathTest_bNeverDropFromHeight);
bank.AddToggle("NeverUseLadders", &PathTest_bNeverUseLadders);
bank.AddToggle("FleeTarget", &PathTest_bFleeTarget);
bank.AddToggle("Wander", &PathTest_bWander);
bank.AddToggle("NeverEnterWater", &PathTest_bNeverEnterWater);
bank.AddToggle("DontAvoidDynamicObjects", &PathTest_bDontAvoidDynamicObjects);
bank.AddToggle("PreferDownhill", &PathTest_bPreferDownhill);
bank.AddToggle("ReduceObjectBBoxes", &PathTest_bReduceObjectBBoxes);
bank.AddToggle("DontLimitSearchExtents", &PathTest_bUseLargerSearchExtents);
bank.AddToggle("MayUseFatalDrops", &PathTest_bMayUseFatalDrops);
bank.AddToggle("IgnoreObjectsWithNoUprootLimit", &PathTest_bIgnoreObjectsWithNoUprootLimit);
bank.AddToggle("AllowToTravelUnderwater", &PathTest_bAllowToTravelUnderwater);
bank.AddToggle("AllowToTravelUnderwater", &PathTest_bAllowToTravelUnderwater);
bank.AddToggle("UseDirectionalCover", &PathTest_bUseDirectionalCover);
bank.AddToggle("CutSharpCorners", &PathTest_bCutSharpCorners);
bank.AddToggle("AllowToNavigateUpSteepPolygons", &PathTest_bAllowToNavigateUpSteepPolygons);
bank.AddToggle("PathTest_bScriptedRoute", &PathTest_bScriptedRoute);
bank.AddToggle("PathTest_bPreserveZ", &PathTest_bPreserveZ);
bank.AddToggle("PathTest_bRandomisePoints", &PathTest_bRandomisePoints);
bank.AddButton("Set cover origin", SetPathTestCoverOriginPos);
bank.AddButton("Add influence sphere", PathTestAddInfluenceSphere);
bank.AddButton("Remove influence sphere", PathTestRemoveInfluenceSphere);
bank.AddSlider("Influence sphere radius", &CPathServer::ms_fPathTestInfluenceSphereRadius, 1.0f, 50.0f, 0.5f);
bank.AddSlider("Influence sphere min influence", &CPathServer::ms_fPathTestInfluenceMin, -50.0f, 50.0f, 0.5f);
bank.AddSlider("Influence sphere max influence", &CPathServer::ms_fPathTestInfluenceMax, -50.0f, 50.0f, 0.5f);
bank.AddButton("Find path", PathTest_FindPath);
bank.AddButton("Test LOS", PathTest_TestLOS);
bank.PopGroup();
}
#endif
bank.PushGroup("Display", false);
{
bank.AddSlider("Pathserver Text top-left (X)", &g_vPathserverDebugTopLeft.x, -1024.0f, 1024.0f, 1.0f);
bank.AddSlider("Pathserver Text top-left (Y)", &g_vPathserverDebugTopLeft.y, -1024.0f, 1024.0f, 1.0f);
#ifdef GTA_ENGINE
bank.AddToggle("Show Ped-Gen Blocking Areas", &CPathServer::ms_bDrawPedGenBlockingAreas);
bank.AddToggle("Show Ped-Wandering Blocking Areas", &CPathServer::ms_bDrawPedSwitchAreas);
bank.AddToggle("Visualise Paths", &CPathServer::m_bVisualisePaths);
bank.AddToggle("Only visualise dynamic navmeshes", &gOnlyVisualiseDynamicNavmeshes);
bank.AddButton("Clear all path history", CPathServer::ClearAllPathHistory);
bank.AddButton("Clear all open/closed flags", CPathServer::ClearAllOpenClosedFlags);
#endif
bank.AddToggle("Show QuadTrees", &CPathServer::m_bVisualiseQuadTrees, NullCB, NULL);
bank.AddToggle("Show All CoverPts", &CPathServer::m_bVisualiseAllCoverPoints, NullCB, NULL);
bank.AddSlider("Extrude-Up Amt", &CPathServer::m_fVisNavMeshVertexShiftAmount, 0.0f, 1.0f, 0.02f, NullCB, NULL);
bank.AddSlider("Debug Polys Range", &CPathServer::ms_fDebugVisPolysMaxDist, 10.0f, 400.0f, 1.0f, NullCB, NULL);
bank.AddSlider("Debug Nodes Range", &CPathServer::ms_fDebugVisNodesMaxDist, 10.0f, 400.0f, 1.0f, NullCB, NULL);
bank.AddToggle("Draw Dynamic Object MinMax's", &CPathServer::ms_bDrawDynamicObjectMinMaxs, NullCB, NULL);
bank.AddToggle("Draw Dynamic Object Grids", &CPathServer::ms_bDrawDynamicObjectGrids, NullCB, NULL);
bank.AddToggle("Draw dynamic objects axes", &CPathServer::ms_bDrawDynamicObjectAxes, NullCB, NULL);
bank.AddToggle("Show Climb-Overs (low)", &CPathServer::m_bDebugShowLowClimbOvers, NullCB, NULL);
bank.AddToggle("Show Climb-Overs (high)", &CPathServer::m_bDebugShowHighClimbOvers, NullCB, NULL);
bank.AddToggle("Show Drop-Downs", &CPathServer::m_bDebugShowDropDowns, NullCB, NULL);
bank.AddToggle("Show Special Links", &CPathServer::m_bDebugShowSpecialLinks, NullCB, NULL);
bank.AddToggle("Show Poly Volumes (above)", &CPathServer::m_bDebugShowPolyVolumesAbove, NullCB, NULL);
bank.AddToggle("Show Poly Volumes (below)", &CPathServer::m_bDebugShowPolyVolumesBelow, NullCB, NULL);
bank.PopGroup();
}
//****************************************
// Advanced navigation widgets:
bank.PushGroup("PathFinding", false);
{
bank.AddCombo(
"Obj Avoidance :",
&CPathServer::m_iObjAvoidanceModeComboIndex,
3,
pObjAdvoidanceMode,
OnSelectObjAvoidanceCombo,
"Selects the object avoidance method"
);
bank.AddSlider("Dynamic object velocity threshold", &ms_fDynamicObjectVelocityThreshold, 0.0f, 1000.0f, 0.1f);
bank.AddSlider("Non-pavement penalty (wander)", &CPathServerThread::ms_fNonPavementPenalty_Wander, 0.0f, 50000.0f, 1.0f);
bank.AddSlider("Non-pavement penalty (shortest path)", &CPathServerThread::ms_fNonPavementPenalty_ShortestPath, 0.0f, 50000.0f, 1.0f);
bank.AddSlider("Non-pavement penalty (flee)", &CPathServerThread::ms_fNonPavementPenalty_Flee, 0.0f, 50000.0f, 1.0f);
bank.AddSlider("Climb multiplier (wander)", &CPathServerThread::ms_fClimbMultiplier_Wander, 0.0f, 50.0f, 1.0f);
bank.AddSlider("Climb multiplier (shortest path)", &CPathServerThread::ms_fClimbMultiplier_ShortestPath, 0.0f, 50.0f, 1.0f);
bank.AddSlider("Climb multiplier (flee)", &CPathServerThread::ms_fClimbMultiplier_Flee, 0.0f, 50.0f, 1.0f);
bank.AddSlider("Override Ped Radius", &CTaskNavBase::ms_fOverrideRadius, 0.1f, 16.0f, 0.1f);
bank.AddToggle("Do poly tessellation", &CPathServer::ms_bDoPolyTessellation, NullCB, NULL);
bank.AddToggle("Do poly untessellation", &CPathServer::ms_bDoPolyUnTessellation, NullCB, NULL);
bank.AddToggle("Do preemptive tessellation", &CPathServer::ms_bDoPreemptiveTessellation, NullCB, NULL);
bank.AddToggle("Allow tessellation of open nodes", &CPathServer::ms_bAllowTessellationOfOpenNodes);
bank.AddToggle("Use objects grid cell cache", &CPathServer::ms_bUseGridCellCache);
bank.AddToggle("Use tessellated poly object cache", &CPathServer::ms_bUseTessellatedPolyObjectCache);
bank.AddToggle("Use LOS to early our path requests", &CPathServer::ms_bUseLosToEarlyOutPathRequests);
bank.AddSlider("\'small\' poly area when tessellating", &CPathServerThread::ms_fSmallPolySizeWhenTessellating, 0.1f, 1000.0f, 0.1f);
bank.AddToggle("Smooth routes using splines", &CPathServer::ms_bSmoothRoutesUsingSplines);
bank.AddToggle("Pull path out from edges", &CPathServer::ms_bPullPathOutFromEdges);
bank.AddToggle("Pull path out from edges twice", &CPathServer::ms_bPullPathOutFromEdgesTwice);
bank.AddToggle("Pull path out from edges string pull", &CPathServer::ms_bPullPathOutFromEdgesStringPull);
bank.AddSlider("Pull Distance", &CPathServerThread::ms_fPullOutFromEdgesDistance, 0.0f, 10.0f, 0.1f);
bank.AddSlider("Pull Distance Extra", &CPathServerThread::ms_fPullOutFromEdgesDistanceExtra, 0.0f, 10.0f, 0.1f);
// bank.AddToggle("Allow object climbing", &CPathServer::ms_bAllowObjectClimbing, NullCB, NULL);
bank.AddToggle("Allow navmesh climbs", &CPathServer::ms_bAllowNavMeshClimbs, NullCB, NULL);
// bank.AddToggle("Allow object pushing", &CPathServer::ms_bAllowObjectPushing, NullCB, NULL);
bank.AddToggle("Exclude vehicle doors", &fwPathServer::ms_bExcludeVehicleDoorsFromNavigation);
bank.AddToggle("Disallow climbable object links", &CPathServer::ms_bDisallowClimbObjectLinks);
bank.AddToggle("Mark visited polys", &CPathServer::ms_bMarkVisitedPolys, NullCB, NULL);
bank.AddToggle("Debug poly underfoot", &CPathServer::m_bDebugPolyUnderfoot, NullCB, NULL);
bank.AddToggle("Detailed Debug PathFinding", &CPathServer::ms_bDebugPathFinding, NullCB, NULL);
bank.AddToggle("Print Out Path Results", &CPathServer::ms_bOutputDetailsOfPaths, NullCB, NULL);
//bank.AddToggle("Early out sphere/ray tests on dynamic objects", &CPathServer::ms_bSphereRayEarlyOutTestOnObjects);
bank.AddSlider("Default plane epsilon for DynObjLOS", &CPathServer::ms_fDefaultDynamicObjectPlaneEpsilon, -10.0f, 10.0f, 0.05f);
bank.AddSlider("Height above navmesh for DynObjLOS", &CPathServerThread::ms_fHeightAboveNavMeshForDynObjLOS, 0.0f, 1.0f, 0.1f);
bank.AddSlider("Height above navmesh for 2nd DynObjLOS", &CPathServerThread::ms_fHeightAboveFirstTestFor2ndDynObjLOS, 0.0f, 1.0f, 0.1f);
bank.AddSlider("Max mass of pushable object", &CPathServerThread::ms_fMaxMassOfPushableObject, 0.0f, 1000.0f, 1.0f);
bank.AddSlider("Min mass of significant object", &CPathServerThread::ms_fMinMassOfSmallSignificant, 0.0f, 1000.0f, 1.0f);
bank.AddSlider("Min volume of significant object", &CPathServerThread::ms_fMinVolumeOfSignificant, 0.0f, 10.0f, 0.1f);
bank.AddSlider("Big volume of significant object (these are always significant)", &CPathServerThread::ms_fBigVolumeOfSignificant, 0.0f, 10.0f, 0.1f);
bank.AddToggle("Don't revisit open nodes", &CPathServer::ms_bDontRevisitOpenNodes, NullCB, NULL);
bank.AddSlider("Max pathfind search dist from origin:", &CPathServer::m_PathServerThread.m_Vars.m_fMaxPathFindDistFromOrigin, 10.0f, 200.0f, 1.0f);
bank.AddToggle("Check every poly for objects", &CPathServer::ms_bTestObjectsForEveryPoly, NullCB, NULL);
bank.AddToggle("Use GetPolyCentroidQuick() when possible", &CPathServer::ms_bUseOptimisedPolyCentroids, NullCB, NULL);
bank.AddToggle("Always use more points in polys", &CPathServer::ms_bAlwaysUseMorePointsInPolys);
bank.AddSlider("Smallest tesselated edge threshold sqr", &CNavMesh::ms_fSmallestTessellatedEdgeThresholdSqr, 0.1f, 64.0f, 0.1f);
bank.AddToggle("Use events to signal path-requests", &CPathServer::ms_bUseEventsForRequests);
bank.AddToggle("Process all pending paths at once", &CPathServer::ms_bProcessAllPendingPathsAtOnce);
bank.AddToggle("Sleep thread during long requests", &CPathServer::m_bSleepPathServerThreadOnLongPathRequests);
bank.AddSlider("Sleep on long path-requests (ms)", &CPathServer::m_iTimeToSleepDuringLongRequestsMs, 0, 1000, 1);
bank.AddSlider("Path-request duration before sleeping", &CPathServer::m_PathServerThread.ms_iPathRequestNumMillisecsBeforeSleepingThread, 1, 1000, 1);
bank.AddSlider("Thread sleep time between requests (ms)", &CPathServer::m_iTimeToSleepWaitingForRequestsMs, 0, 1000, 1);
bank.AddToggle("Use new path priority scoring", &CPathServer::ms_bUseNewPathPriorityScoring);
bank.AddSlider("Prefer-downhill scale factor", &CPathServerThread::ms_fPreferDownhillScaleFactor, 0.0f, 100.0f, 0.25f);
bank.AddSlider("Wanderer turn weight", &CPathServerThread::ms_fWanderTurnWeight, 0.0f, 10000.0f, 1.0f);
bank.AddSlider("Wanderer turn plane weight", &CPathServerThread::ms_fWanderTurnPlaneWeight, 0.0f, 10000.0f, 1.0f);
#if __BANK && defined(GTA_ENGINE)
bank.AddToggle("Only display the selected route", &CPathServer::ms_bOnlyDisplaySelectedRoute);
bank.AddToggle("Show path search extents", &CPathServer::ms_bShowSearchExtents);
#endif
#if __XENON
bank.AddToggle("XTrace the next path request", &CPathServer::ms_bUseXTraceOnTheNextPathRequest);
#endif
bank.AddButton(">>> Next Path Request", datCallback(CFA(PathServer_OnSelectNextPathRequest)));
bank.AddButton("<<< Prev Path Request", datCallback(CFA(PathServer_OnSelectPrevPathRequest)));
bank.AddButton("Repeat Path Query", datCallback(CFA(PathServer_RepeatPathQuery)));
bank.AddButton("Output \'.prob\' PathRequest File", datCallback(CFA(PathServer_OutputPathQuery)));
bank.AddButton("Request path but don't retrieve", PathServer_RequestPathButDontRetrieve);
bank.AddButton("Create LOS Stack Overflow Bug", PathServer_TestLosStackOverflow);
#if __DEV
static const char * pVisitedPolysMode[] =
{
"List",
"TimeStamp",
"Both (Debug)"
};
bank.AddCombo(
"Visited Poly Mode :",
&CPathServerThread::m_eVisitedPolyMarkingMode,
3,
pVisitedPolysMode,
NullCB,
"Selects how pathserver deals with resetting visited polygon flags"
);
#endif
bank.AddCombo(
"Thread :",
&CPathServer::m_iDebugThreadRunMode,
2,
pThreadRunMode,
OnSelectThreadRunModeCombo,
"Suspends/Resumes the main pathserver thread"
);
bank.AddToggle("Disable PathFinding", &CPathServer::m_bDisablePathFinding);
bank.AddToggle("Disable Object Avoidance", &CPathServer::m_bDisableObjectAvoidance);
bank.AddToggle("Disable Audio-Reqs", &CPathServer::m_bDisableAudioRequests);
bank.AddToggle("Disable GetClostestPos", &CPathServer::m_bDisableGetClosestPositionForPed);
bank.AddToggle("Stress-Test Paths", &CPathServer::m_bStressTestPathFinding);
bank.AddToggle("Stress-Test GetClostestPos", &CPathServer::m_bStressTestGetClosestPos);
bank.AddToggle("Visualise failed polygon requests", &CPathServer::m_bVisualisePolygonRequests);
bank.PopGroup();
}
bank.PushGroup("Default A* heuristics", false);
{
bank.AddSlider("ms_fDefaultCostFromTargetMultiplier", &CPathFindMovementCosts::ms_fDefaultCostFromTargetMultiplier, 0.0f, 200.0f, 0.1f);
bank.AddSlider("ms_fDefaultDistanceTravelledMultiplier", &CPathFindMovementCosts::ms_fDefaultDistanceTravelledMultiplier, 0.0f, 200.0f, 0.1f);
bank.AddSlider("ms_fDefaultClimbHighPenalty", &CPathFindMovementCosts::ms_fDefaultClimbHighPenalty, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultClimbLowPenalty", &CPathFindMovementCosts::ms_fDefaultClimbLowPenalty, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultDropDownPenalty", &CPathFindMovementCosts::ms_fDefaultDropDownPenalty, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultDropDownPenaltyPerMetre", &CPathFindMovementCosts::ms_fDefaultDropDownPenaltyPerMetre, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultClimbLadderPenalty", &CPathFindMovementCosts::ms_fDefaultClimbLadderPenalty, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultClimbLadderPenaltyPerMetre", &CPathFindMovementCosts::ms_fDefaultClimbLadderPenaltyPerMetre, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultEnterWaterPenalty", &CPathFindMovementCosts::ms_fDefaultEnterWaterPenalty, 0.0f, 10000.0f, 1.0f);
bank.AddSlider("ms_fDefaultLeaveWaterPenalty", &CPathFindMovementCosts::ms_fDefaultLeaveWaterPenalty, 0.0f, 5000.0f, 1.0f);
bank.AddSlider("ms_fDefaultBeInWaterPenalty", &CPathFindMovementCosts::ms_fDefaultBeInWaterPenalty, 0.0f, 2000.0f, 1.0f);
//bank.AddSlider("ms_fDefaultFixedCostToPushObject", &CPathFindMovementCosts::ms_fDefaultFixedCostToPushObject, 0.0f, 2000.0f, 1.0f);
//bank.AddSlider("ms_fDefaultFixedCostToClimbObject", &CPathFindMovementCosts::ms_fDefaultFixedCostToClimbObject, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultClimbObjectPenaltyPerMetre", &CPathFindMovementCosts::ms_fDefaultClimbObjectPenaltyPerMetre, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultWanderPenaltyForZeroPedDensity", &CPathFindMovementCosts::ms_fDefaultWanderPenaltyForZeroPedDensity, 0.0f, 2000.0f, 0.1f);
bank.AddSlider("ms_fDefaultMoveOntoSteepSurfacePenalty", &CPathFindMovementCosts::ms_fDefaultMoveOntoSteepSurfacePenalty, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultPenaltyForNoDirectionalCover", &CPathFindMovementCosts::ms_fDefaultPenaltyForNoDirectionalCover, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_fDefaultPenaltyForFavourCoverPerUnsetBit", &CPathFindMovementCosts::ms_fDefaultPenaltyForFavourCoverPerUnsetBit, 0.0f, 2000.0f, 1.0f);
bank.AddSlider("ms_iDefaultPenaltyForMovingToLowerPedDensity", &CPathFindMovementCosts::ms_iDefaultPenaltyForMovingToLowerPedDensity, 0, 2000, 1);
bank.AddSlider("ms_fFleePathDoubleBackCost", &CPathFindMovementCosts::ms_fFleePathDoubleBackCost, 0.0f, 2000.0f, 0.1f);
bank.AddSlider("ms_fFleePathDoubleBackCostSofter", &CPathFindMovementCosts::ms_fFleePathDoubleBackCostSofter, 0.0f, 2000.0f, 0.1f);
bank.AddSlider("ms_fDefaultAvoidTrainTracksPenalty", &CPathFindMovementCosts::ms_fDefaultAvoidTrainTracksPenalty, 0.0f, 100000.0f, 1.0f);
bank.PopGroup();
}
bank.PushGroup("Ped Generation", false);
{
bank.PushGroup("Ambient", false);
bank.AddButton("Turn off wandering at player pos", datCallback(CFA(PathServer_TestTurnOffWandering)));
bank.AddButton("Add pedgen blocking area at player pos", datCallback(CFA(PathServer_AddPedGenBlockingArea)));
bank.AddSlider("PedGen node floodfill dist", &CPathServer::ms_fPedGenAlgorithmNodeFloodFillDist, 0.0f, 50.0f, 1.0f);
bank.AddSlider("Percentage of ped-density polys per navmesh", &CPathServer::m_AmbientPedGeneration.m_iPedGenPercentagePerNavMesh, 0, 100, 1);
bank.AddSlider("Debug adjust spawn density in AABB (from measuring tool)", &CPedPopulation::m_iDebugAdjustSpawnDensity, -MAX_PED_DENSITY, MAX_PED_DENSITY, 1);
bank.PopGroup();
bank.PushGroup("Opponent", false);
bank.AddToggle("Visualise search", &CPathServer::ms_bVisualiseOpponentPedGeneration);
bank.AddButton("Start opponent pedgen (camera pos)", Pathserver_StartOpponentPedGen);
bank.AddButton("Start opponent pedgen (angled area - measuring rool)", Pathserver_StartOpponentPedGenAngledArea);
bank.AddButton("Complete opponent pedgen", Pathserver_CompleteOpponentPedGen);
bank.AddToggle("bOpponentPedGen_AllowExterior", &bOpponentPedGen_AllowExterior);
bank.AddToggle("bOpponentPedGen_AllowInteriors", &bOpponentPedGen_AllowInteriors);
bank.AddToggle("bOpponentPedGen_AllowNonNetworkSpawn", &bOpponentPedGen_AllowNonNetworkSpawn);
bank.AddToggle("bOpponentPedGen_AllowIsolated", &bOpponentPedGen_AllowIsolated);
bank.AddToggle("bOpponentPedGen_AllowRoad", &bOpponentPedGen_AllowRoad);
bank.AddToggle("bOpponentPedGen_OnlyCoverEdges", &bOpponentPedGen_OnlyCoverEdges);
bank.AddSlider("fOpponentPedGen_RadiusXY", &fOpponentPedGen_RadiusXY, 0.0f, 250.f, 1.0f);
bank.AddSlider("fOpponentPedGen_CutoffZ", &fOpponentPedGen_CutoffZ, -1000.0f, 1000.f, 10.0f);
bank.AddSlider("fOpponentPedGen_MinimumSpacing", &fOpponentPedGen_MinimumSpacing, 0.0f, 100.0f, 1.0f);
bank.AddSlider("fOpponentPedGen_TimeoutMS", &iOpponentPedGen_TimeoutMS, 0, 20000, 1);
bank.PopGroup();
bank.PopGroup();
}
bank.PushGroup("Misc", false);
{
bank.AddSlider("Request and Evict Freq (ms)", &ms_iRequestAndEvictFreqMS, 0, 10000, 1);
bank.AddToggle("Disable Streaming", &ms_bStreamingDisabled);
bank.AddToggle("Verify Adjacencies", &m_bVerifyAdjacencies);
bank.AddButton("Detessellate now", datCallback(CFA(DebugDetessellateNow)));
bank.AddToggle("Display NavMesh Load Times", &CNavMesh::ms_bDisplayTimeTakenToLoadNavMeshes);
bank.AddToggle("Force use of decompressed vertices", &CNavMesh::ms_bForceAllNavMeshesToUseUnCompressedVertices);
bank.AddToggle("Vis poly under camera", &g_VisPolyUnderCamera);
bank.AddButton("PathServer_TestColPolyVsPaths", PathServer_TestColPolyVsPaths);
bank.AddButton("Print poly under debug-camera", datCallback(CFA(PathServer_TestDebugPolyUnderCamera)));
bank.AddButton("Test NavMesh LOS from Player to Camera", datCallback(CFA(PathServer_TestLOS)));
bank.AddButton("Add Required Region At Camera", datCallback(CFA(PathServer_AddRequiredRegion)));
bank.AddButton("Remove Required Region", datCallback(CFA(PathServer_RemoveRequiredRegion)));
bank.AddButton("Test Audio Properties request for player", datCallback(CFA(PathServer_TestAudioPropertiesRequest)));
bank.AddButton("Test FloodFill for closest car node from player", datCallback(CFA(PathServer_TestFloodFillToClosestCarNode)));
bank.AddButton("Test clear area request at player position", datCallback(CFA(PathServer_TestClearAreaRequest)));
bank.AddButton("Test closest position request at player position", datCallback(CFA(PathServer_TestClosestPositionRequest)));
bank.AddButton("Test Evict Dynamic Object For Script", TestEvictDynamicObjectForScript);
bank.AddSlider("Navmesh load proximity", &CPathServer::m_fNavMeshLoadProximity, 0.0f, 1000.0f, 10.0f);
bank.AddSlider("Hierarchical-Nodes load proximity", &CPathServer::m_fHierarchicalNodesLoadProximity, 0.0f, 1000.0f, 10.0f);
bank.AddButton("Test switch off polygons for ped around camera", datCallback(CFA(PathServer_TestTurnOffPolysForPedsAroundCamera)));
bank.AddButton("Test disable polygons around camera", datCallback(CFA(PathServer_TestDisablePolysAroundCamera)));
#ifdef GTA_ENGINE
bank.AddToggle("Count Thread-Stalls", &CPathServer::m_bCheckForThreadStalls);
bank.AddToggle("Display Add DynObject Times", &CPathServer::m_bDisplayTimeTakenToAddDynamicObjects);
bank.AddButton("Find closest safe-pos to player", datCallback(CFA(PathServer_TestFindClosestPosOnAnySurface)));
bank.AddButton("Find closest safe-pos to player (pavement)", datCallback(CFA(PathServer_TestFindClosestPosOnPavement)));
bank.AddButton("Find closest safe-pos to player (no objects)", datCallback(CFA(PathServer_TestFindClosestPosOnAnySurfaceClearOfObjects)));
bank.AddButton("Find closest safe-pos to player (pavement & no objects)", datCallback(CFA(PathServer_TestFindClosestPosOnPavementClearOfObjects)));
bank.AddButton("Find closest safe-pos to player (pavement & no objects, extra-thorough, flood-fill)", datCallback(CFA(PathServer_TestFindClosestPosOnAnySurfaceClearOfObjectsExtraThorough)));
#if __DEV
bank.AddButton("Test calc poly areas", PathServer_TestCalcPolyAreas);
#endif
bank.AddToggle("Use prefetching", &CPathServerThread::ms_bUsePrefetching);
bank.AddButton("Set up perf test", datCallback(CFA(PathServer_SetUpPerfTest)));
bank.AddToggle("Draw ped tracking avoidance probes", &CNavMeshTrackedObject::ms_bDrawPedTrackingProbes);
#if __XENON && !__FINAL
bank.AddToggle("Use VMX optimisations", &CNavMesh::ms_bUseVmxOptimisations);
#endif
bank.AddToggle("Use prefetching", &CNavMesh::ms_bUsePrefetching);
//bank.AddButton("Test vmx minmax", datCallback(CFA(PathServer_TestMinMax)));
#endif
bank.AddSlider("Navmesh request/evict freq(ms)", &CPathServer::ms_iRequestAndEvictMeshesFreqMs, 0, 10000, 1);
bank.AddButton("Add user dynamic object at camera", AddUserDynamicObjectAtCameraPos);
bank.PopGroup();
}
bank.PushGroup("Audio", false);
{
bank.AddSlider("Min poly size for radius search:", &CPathServer::m_fAudioMinPolySizeForRadiusSearch, 0.0f, 100.0f, 0.1f);
bank.AddSlider("Velocity cube size:", &CPathServer::m_fAudioVelocityCubeSize, 0.0f, 100.0f, 0.1f);
bank.AddSlider("Velocity dot product:", &CPathServer::m_fAudioVelocityDotProduct, 0.0f, 1.0f, 0.01f);
bank.PopGroup();
}
bank.PushGroup("Blocking Bounds", false);
{
bank.AddToggle("Enable", &g_bTestBlockingObjectEnabled);
bank.AddSlider("Position X", &g_vTestBlockingObjectPos.x, WORLDLIMITS_REP_XMIN, WORLDLIMITS_REP_XMAX, 0.1f);
bank.AddSlider("Position Y", &g_vTestBlockingObjectPos.y, WORLDLIMITS_REP_YMIN, WORLDLIMITS_REP_YMAX, 0.1f);
bank.AddSlider("Position Z", &g_vTestBlockingObjectPos.z, -1000.0f, 1000.0f, 0.1f);
bank.AddSlider("Rotation (Z)", &g_fTestBlockingObjectRot, -180.0f, 180.0f, 1.0f);
bank.AddSeparator();
bank.AddButton("Set from player/camera", OnTestBlockingObjectSetFromCamera);
bank.AddSeparator();
bank.AddSlider("Width (X)", &g_vTestBlockingObjectSize.x, 0.25f, 20.0f, 0.1f);
bank.AddSlider("Depth (Y)", &g_vTestBlockingObjectSize.y, 0.25f, 20.0f, 0.1f);
bank.AddSlider("Height (Z)", &g_vTestBlockingObjectSize.z, 0.25f, 20.0f, 0.1f);
bank.AddSeparator();
bank.AddButton("Create blocking object here", OnCreateTestBlockingObject);
bank.PopGroup();
}
#ifdef GTA_ENGINE
#if NAVMESH_EXPORT
{
bank.PushGroup("Extra", false);
bank.AddSlider("Num sectors per block", &CPathServerExtents::m_iNumSectorsPerNavMesh, 0, 12, 1);
//bank.AddButton("Set defaults for animviewer!", datCallback(CFA(PathServer_SetDefaultsForAnimViewer)));
bank.PopGroup();
}
#endif // NAVMESH_EXPORT
#endif //GTA_ENGINE
}
#endif //__BANK
#endif // DEBUG_DRAW
#if __BANK
void CPathServer::DebugOutPathRequestResult(CPathRequest * pPathRequest)
{
const char * pPathType;
if(pPathRequest->m_bWander) pPathType = "Wander Path";
else if(pPathRequest->m_bFleeTarget) pPathType = "Flee Path";
else pPathType = "Normal Path";
Displayf("***********************************************************\n");
Displayf("Path Handle : 0x%x\n", pPathRequest->m_hHandle);
Displayf("Completion Code : %i\n", pPathRequest->m_iCompletionCode);
Displayf("Context : %p\n", pPathRequest->m_pContext);
Displayf("Path Type : \"%s\"\n", pPathType);
Displayf("Total Time Taken : %.4f\n", pPathRequest->m_fTotalProcessingTimeInMillisecs);
Displayf("Time To Find Start/End Polys : %.4f\n", pPathRequest->m_fMillisecsToFindPolys);
Displayf("Time To Find Polygon Path : %.4f\n", pPathRequest->m_fMillisecsToFindPath);
Displayf("Time To Refine Path : %.4f\n", pPathRequest->m_fMillisecsToRefinePath);
Displayf("Time To PostProcess Z Heights : %.4f\n", pPathRequest->m_fMillisecsToPostProcessZHeights);
Displayf("Time To Minimise Path Length : %.4f\n", pPathRequest->m_fMillisecsToMinimisePathLength);
Displayf("Time To Pull Out From Edges : %.4f\n", pPathRequest->m_fMillisecsToPullOutFromEdges);
Displayf("Num Visited Polys : %i\n", pPathRequest->m_iNumVisitedPolygons);
Displayf("Num Times Called TessellatePoly() : %i\n", pPathRequest->m_iNumTessellations);
Displayf("Num Times Called TestDynamicObjectLOS() : %i\n", pPathRequest->m_iNumTestDynamicObjectLOS);
Displayf("***********************************************************\n");
}
#endif
#endif