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

716 lines
25 KiB
C++

// Rage headers
#include "file\device.h"
#include "file\stream.h"
#include "data\struct.h"
#include "file\asset.h"
#include "paging\rscbuilder.h"
#include "vector/geometry.h"
// Framework headers
#include "ai/navmesh/priqueue.h"
#include "fwmaths\random.h"
#include "fwmaths\vector.h"
// Game headers
#include "PathServer\PathServer.h"
#ifdef GTA_ENGINE
NAVMESH_OPTIMISATIONS()
#endif
#if !__HIERARCHICAL_NODES_ENABLED
CHierarchicalNavLink * CPathServerThread::Hierarchical_GetClosestLinkToPos(const Vector3 & UNUSED_PARAM(vPos), const float UNUSED_PARAM(fMaxSearchDist)) { return NULL; }
void CPathServerThread::Hierarchical_GetClosestNodeToPos(const Vector3 & UNUSED_PARAM(vPos), const float UNUSED_PARAM(fMaxSearchDistSqr), CHierarchicalNavNode ** UNUSED_PARAM(ppOut_ClosestNode), CHierarchicalNavNode ** UNUSED_PARAM(ppOut_ClosestPavementNode), CHierarchicalNavNode ** UNUSED_PARAM(ppOut_ClosestNonIsolatedNode)) { }
bool CPathServerThread::Hierarchical_FindPath(CPathRequest * UNUSED_PARAM(pPathRequest)) { return false; }
bool CPathServerThread::Hierarchical_LineOfSight(const Vector3 & UNUSED_PARAM(vStartPos), const Vector3 & UNUSED_PARAM(vEndPos), THierNodeAndLink * UNUSED_PARAM(pNodeList), const int UNUSED_PARAM(iNumNodes), Vector3 * UNUSED_PARAM(pvIsectPoints), int * UNUSED_PARAM(piMaxNumIsectPoints), int * UNUSED_PARAM(piNumIsectPoints)) { return false; }
void CPathServerThread::Hierarchical_StringPull(CPathRequest * UNUSED_PARAM(pPathRequest)) { }
#else
CHierarchicalNavLink *
CPathServerThread::Hierarchical_GetClosestLinkToPos(const Vector3 & vPos, const float fMaxSearchDist)
{
const TNavMeshIndex iNavMesh = CPathServer::GetNavMeshIndexFromPosition(vPos);
if(iNavMesh==NAVMESH_NAVMESH_INDEX_NONE)
return NULL;
CHierarchicalNavData * pNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex(iNavMesh);
if(!pNavData)
return NULL;
u32 n, l;
Vector3 vNodePos, vLinkNodePos, vClosestPosOnLink;
const Vector3 vMin(vPos.x - fMaxSearchDist, vPos.y - fMaxSearchDist, vPos.z - fMaxSearchDist);
const Vector3 vMax(vPos.x + fMaxSearchDist, vPos.y + fMaxSearchDist, vPos.z + fMaxSearchDist);
float fMinDistSqrXY = FLT_MAX;
CHierarchicalNavLink * pClosestLink = NULL;
static const float fMaxZ = 8.0f;
for(n=0; n<pNavData->GetNumNodes(); n++)
{
//*****************************************************
// Examine nodes which are within the search distance
CHierarchicalNavNode * pNode = pNavData->GetNode(n);
pNode->GetNodePosition(vNodePos, pNavData->GetMin(), pNavData->GetSize());
if(vNodePos.x < vMin.x || vNodePos.y < vMin.y || vNodePos.z < vMin.z ||
vNodePos.x > vMax.x || vNodePos.y > vMax.y || vNodePos.z > vMax.z)
continue;
//*************************************************************************************
// For this node, examine all of its links and see if the position is on any of them
const u32 iNumLinks = pNode->GetNumLinks();
for(l=0; l<iNumLinks; l++)
{
CHierarchicalNavLink * pLink = pNavData->GetLink(pNode->GetStartOfLinkData()+l);
CHierarchicalNavData * pLinkEndNav = CPathServer::GetHierarchicalNavFromNavMeshIndex(pLink->GetNavMeshIndex());
if(!pLinkEndNav)
continue;
CHierarchicalNavNode * pLinkEndNode = pLinkEndNav->GetNode(pLink->GetNodeIndex());
pLinkEndNode->GetNodePosition(vLinkNodePos, pLinkEndNav->GetMin(), pLinkEndNav->GetSize());
const Vector3 vDiff = vLinkNodePos - vNodePos;
const float fTVal = (vDiff.Mag2() > 0.0f) ? geomTValues::FindTValueSegToPoint(vNodePos, vDiff, vPos) : 0.0f;
vClosestPosOnLink = vNodePos + ((vLinkNodePos - vNodePos) * fTVal);
if(Abs(vClosestPosOnLink.z) > fMaxZ)
continue;
// TODO: Check that this point is actually on the link, using the left/right width values
const float fDistSqrXY = (vLinkNodePos - vNodePos).XYMag2();
if(fDistSqrXY < fMinDistSqrXY)
{
pClosestLink = pLink;
fMinDistSqrXY = fDistSqrXY;
}
}
}
return pClosestLink;
}
//***********************************************************************************************************
void
CPathServerThread::Hierarchical_GetClosestNodeToPos(
const Vector3 & vPos,
const float fMaxSearchDistSqr,
CHierarchicalNavNode ** ppOut_ClosestNode,
CHierarchicalNavNode ** ppOut_ClosestPavementNode,
CHierarchicalNavNode ** ppOut_ClosestNonIsolatedNode)
{
// We'll just use the hierarchical navdata underfoot for now.
// In due course we will need to examine all 4 within fMaxSearchDistSqr...
const int iNumNavMeshes = 1;
TNavMeshIndex iNavMeshes[4];
iNavMeshes[0] = CPathServer::GetNavMeshIndexFromPosition(vPos);
Vector3 vNodePos;
float fDistSqr;
float fClosestNodeDistSqr = FLT_MAX;
float fClosestPavementNodeDistSqr = FLT_MAX;
CHierarchicalNavNode * pClosestNode = NULL;
CHierarchicalNavNode * pClosestPavementNode = NULL;
for(int i=0; i<iNumNavMeshes; i++)
{
const TNavMeshIndex iIndex = iNavMeshes[0];
Assert(iIndex <= NAVMESH_MAX_MAP_INDEX);
if(CPathServer::GetHierarchicalNavFromNavMeshIndex(iIndex))
{
CHierarchicalNavData * pHierNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex(iIndex);
Assert(pHierNavData);
const Vector3 & vNavMins = pHierNavData->GetMin();
const Vector3 & vNavSize = pHierNavData->GetSize();
for(u32 n=0; n<pHierNavData->GetNumNodes(); n++)
{
CHierarchicalNavNode * pNode = pHierNavData->GetNode(n);
pNode->GetNodePosition(vNodePos, vNavMins, vNavSize);
fDistSqr = (vNodePos - vPos).Mag2();
if(fDistSqr < fClosestNodeDistSqr)
{
fClosestNodeDistSqr = fDistSqr;
pClosestNode = pNode;
}
if(pNode->GetPedDensity() && fDistSqr < fClosestPavementNodeDistSqr)
{
fClosestPavementNodeDistSqr = fDistSqr;
pClosestPavementNode = pNode;
}
}
}
}
if(fClosestNodeDistSqr < fMaxSearchDistSqr && ppOut_ClosestNode)
{
*ppOut_ClosestNode = pClosestNode;
}
if(fClosestPavementNodeDistSqr < fMaxSearchDistSqr && ppOut_ClosestPavementNode)
{
*ppOut_ClosestPavementNode = pClosestPavementNode;
}
// TODO: the same for non-isolated nodes
if(ppOut_ClosestNonIsolatedNode)
*ppOut_ClosestNonIsolatedNode = NULL;
}
bool
CPathServerThread::Hierarchical_FindPath(CPathRequest * pPathRequest)
{
static const float fStartNodeSearchDistSqr = 20.0f*20.0f;
static const float fEndNodeSearchDistSqr = 20.0f*20.0f;
pPathRequest->m_iCompletionCode = PATH_ENDNODES_NOT_FOUND;
const Vector3 & vStartPos = pPathRequest->m_vPathStart;
const Vector3 & vEndPos = pPathRequest->m_vPathEnd;
const bool bHasPathEnd = (!pPathRequest->m_bWander && !pPathRequest->m_bFleeTarget);
// Find the start node. For wander paths we want to make sure we choose a pavement or non-isolated poly
CHierarchicalNavNode * pStartNodeNormal = NULL, * pStartNodePavement = NULL, * pStartNodeNonIsolated = NULL;
Hierarchical_GetClosestNodeToPos(vStartPos, fStartNodeSearchDistSqr, &pStartNodeNormal, &pStartNodePavement, &pStartNodeNonIsolated);
CHierarchicalNavNode * pStartNode = NULL;
if(pPathRequest->m_bWander)
{
if(pStartNodePavement) pStartNode = pStartNodePavement;
else if(pStartNodeNonIsolated) pStartNode = pStartNodeNonIsolated;
else pStartNode = pStartNodeNormal;
}
else
{
pStartNode = pStartNodeNormal;
}
if(!pStartNode)
return false;
CHierarchicalNavNode * pEndNode = NULL;
if(bHasPathEnd)
{
Hierarchical_GetClosestNodeToPos(vEndPos, fEndNodeSearchDistSqr, &pEndNode, NULL, NULL);
}
if(bHasPathEnd && !pEndNode)
return false;
CHierarchicalNavData * pStartNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex(pStartNode->GetNavMeshIndex());
if(!pStartNavData)
return false;
CHierarchicalNavData * pEndNavData = bHasPathEnd ? CPathServer::GetHierarchicalNavFromNavMeshIndex(pEndNode->GetNavMeshIndex()) : NULL;
if(bHasPathEnd && !pEndNavData)
return false;
pPathRequest->m_iCompletionCode = PATH_NOT_FOUND;
Vector3 vStartNodePos, vEndNodePos;
pStartNode->GetNodePosition(vStartNodePos, pStartNavData->GetMin(), pStartNavData->GetSize());
if(bHasPathEnd)
pEndNode->GetNodePosition(vEndNodePos, pEndNavData->GetMin(), pEndNavData->GetSize());
//********************************************
// Start performance timer for the pathsearch
#if !__FINAL
m_PerfTimer->Reset();
m_PerfTimer->Start();
#endif
CHierarchicalNavNode * pFinishingNode = NULL;
CHierarchicalNavNode * pClosestAlternativeFinishingNode = NULL;
float fClosestAlternativeFinishDist = FLT_MAX;
float fFurthestAlternativeFinishDist = 0.0f;
const float fRefDistSqr = (pPathRequest->m_fReferenceDistance * pPathRequest->m_fReferenceDistance);
m_Vars.m_VisitedHierarchicalPathNodes[0] = pStartNode;
m_Vars.m_iNumVisitedNodes = 1;
//*********************************************
// Put the start node into the priority queue
pStartNode->SetIsOpen(true);
const float fInitialCost = (vEndPos - vStartPos).Mag();
m_PathSearchPriorityQueue->Clear();
m_PathSearchPriorityQueue->Insert(
fInitialCost,
0.0f,
pStartNode,
vStartNodePos,
(pPathRequest->m_bWander) ? pPathRequest->m_vReferenceVector : VEC3_ZERO,
0
);
TBinHeapNodeVars parentNodeVars;
Vector3 vLinkedNodePos;
while(m_PathSearchPriorityQueue->RemoveTop(
parentNodeVars.fCost,
parentNodeVars.fDistanceTravelled,
parentNodeVars.pNode,
parentNodeVars.vPosition,
parentNodeVars.vDirFromPrev,
parentNodeVars.iFlags))
{
const u32 iParentNavMeshIndex = parentNodeVars.pNode->GetNavMeshIndex();
CHierarchicalNavData * pParentNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex(iParentNavMeshIndex);
const u32 iParentNodeIndex = pParentNavData->GetNodeIndex(parentNodeVars.pNode);
Assert(parentNodeVars.pNode->GetIsOpen());
Assert(!parentNodeVars.pNode->GetIsClosed());
//*********************************************
// Have the path completion criteria been met?
if(pPathRequest->m_bWander || pPathRequest->m_bFleeTarget)
{
const float fDistSqrFromStart = (parentNodeVars.vPosition - vStartPos).Mag2();
if(fDistSqrFromStart > fRefDistSqr)
break;
if(fDistSqrFromStart > fFurthestAlternativeFinishDist)
{
fClosestAlternativeFinishDist = fDistSqrFromStart;
pClosestAlternativeFinishingNode = parentNodeVars.pNode;
}
}
else
{
if(parentNodeVars.pNode == pEndNode)
{
pFinishingNode = parentNodeVars.pNode;
pPathRequest->m_iCompletionCode = PATH_FOUND;
break;
}
const float fDistSqrFromEnd = (parentNodeVars.vPosition - vEndPos).Mag2();
if(fDistSqrFromEnd < fEndNodeSearchDistSqr && fDistSqrFromEnd < fClosestAlternativeFinishDist)
{
fClosestAlternativeFinishDist = fDistSqrFromEnd;
pClosestAlternativeFinishingNode = parentNodeVars.pNode;
}
}
//**********************************************************************
// Visit the surrounding nodes which are not already in the closed list
const u32 iLinksStart = parentNodeVars.pNode->GetStartOfLinkData();
const u32 iNumLinks = parentNodeVars.pNode->GetNumLinks();
for(u32 l=0; l<iNumLinks; l++)
{
CHierarchicalNavLink * pLink = pParentNavData->GetLink(iLinksStart + l);
CHierarchicalNavData * pLinkedNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex(pLink->GetNavMeshIndex());
if(!pLinkedNavData)
continue;
CHierarchicalNavNode * pLinkedNode = pLinkedNavData->GetNode(pLink->GetNodeIndex());
//************************************************************
// Check for any conditions which rule out visiting this node
// Already closed/visited?
if(pLinkedNode->GetIsClosed() || (pLinkedNode->GetIsOpen() && CPathServer::ms_bDontRevisitOpenNodes))
continue;
if(pPathRequest->m_bWander)
{
// Cannot wander off pavement. TODO: Make this use PAVEMENT and not PED-DENSITY..
if(parentNodeVars.pNode->GetPedDensity() && !pLinkedNode->GetPedDensity())
continue;
// Cannot wander onto a node which has ped spawning disabled (likely via a script cmd)
if(parentNodeVars.pNode->GetPedSpawningEnabled() && !pLinkedNode->GetPedSpawningEnabled())
continue;
}
pathAssertf(!(pPathRequest->m_bWander && pStartNode->GetPedDensity()>0 && pLinkedNode->GetPedDensity()==0), "WTF!?!?!?");
//********************************************
// Calculate the cost for moving to this node
pLinkedNode->GetNodePosition(vLinkedNodePos, pLinkedNavData->GetMin(), pLinkedNavData->GetSize());
Vector3 vFromParent = vLinkedNodePos - parentNodeVars.vPosition;
Vector3 vToTarget = vEndPos - vLinkedNodePos;
float fDistFromParent = vFromParent.InvMagFast();
float fDistToTarget = vToTarget.InvMagFast();
vFromParent.Scale(fDistFromParent);
vToTarget.Scale(fDistToTarget);
fDistFromParent = 1.0f / fDistFromParent;
fDistToTarget = 1.0f / fDistToTarget;
float fCost;
if(pPathRequest->m_bFleeTarget)
{
fCost = 0.0f;
}
else if(pPathRequest->m_bWander)
{
const float fDirDot = DotProduct(parentNodeVars.vDirFromPrev, vFromParent);
static const float fDirectionPenalty = 50.0f;
if(fDirDot < 0.0f)
{
// Incur an extra penalty for going back on oneself
fCost = (fDirectionPenalty * -fDirDot) + fDirectionPenalty;
}
else
{
// Penalize going ahead based on direction difference
fCost = (1.0f - fDirDot) * fDirectionPenalty;
}
}
else
{
static const float fCostFromTargetMultiplier = 16.0f;
//fCost = parentNodeVars.fCost + parentNodeVars.fDistanceTravelled + (fDistToTarget * fCostFromTargetMultiplier);
fCost = parentNodeVars.fCost +
parentNodeVars.fDistanceTravelled + fDistFromParent + ((fDistToTarget*fDistToTarget) * fCostFromTargetMultiplier);
}
CPathServerBinHeap::Node * pBinHeapNode = NULL;
if(pLinkedNode->GetIsOpen())
{
pBinHeapNode = m_PathSearchPriorityQueue->GetBinHeap()->FindNode(pLinkedNode);
if(pBinHeapNode && pBinHeapNode->Key <= fCost)
continue;
}
else
{
pLinkedNode->SetIsOpen(true);
}
pLinkedNode->SetParentNavMeshIndex(iParentNavMeshIndex);
pLinkedNode->SetParentNodeIndex(iParentNodeIndex);
if(pBinHeapNode)
{
pBinHeapNode->vPointInPoly[0] = vLinkedNodePos.x;
pBinHeapNode->vPointInPoly[1] = vLinkedNodePos.y;
pBinHeapNode->vPointInPoly[2] = vLinkedNodePos.z;
pBinHeapNode->vDirFromPrevious[0] = vFromParent.x;
pBinHeapNode->vDirFromPrevious[1] = vFromParent.y;
pBinHeapNode->vDirFromPrevious[2] = vFromParent.z;
pBinHeapNode->fDistanceTravelled = parentNodeVars.fDistanceTravelled + fDistFromParent;
m_PathSearchPriorityQueue->GetBinHeap()->DecreaseKey(pBinHeapNode, fCost);
}
else
{
if(m_Vars.m_iNumVisitedNodes == MAX_PATH_VISITED_NODES)
break;
m_Vars.m_VisitedHierarchicalPathNodes[m_Vars.m_iNumVisitedNodes] = pLinkedNode;
m_Vars.m_iNumVisitedNodes++;
#if __DEV
if(CPathServer::ms_bMarkVisitedPolys)
pLinkedNode->SetIsDebugMarked(true);
#endif
if(!m_PathSearchPriorityQueue->Insert(
fCost,
parentNodeVars.fDistanceTravelled + fDistFromParent,
pLinkedNode, vLinkedNodePos, vFromParent, 0))
{
// We've run out of space in "m_PathStackEntryStore" for the path-search..
pPathRequest->m_bRequestActive = false;
pPathRequest->m_bComplete = true;
pPathRequest->m_iNumPoints = 0;
pPathRequest->m_iCompletionCode = PATH_RAN_OUT_OF_PATH_STACK_SPACE;
return false;
}
}
}
//*************************************
// Now mark the parent node as closed
parentNodeVars.pNode->SetIsClosed(true);
}
if(!pFinishingNode && pClosestAlternativeFinishingNode)
{
pFinishingNode = pClosestAlternativeFinishingNode;
pPathRequest->m_iCompletionCode = PATH_FOUND;
}
#if !__FINAL
m_PerfTimer->Stop();
pPathRequest->m_fMillisecsToFindPath = (float) m_PerfTimer->GetTimeMS();
#endif
//***************************************************************
// Path-searching has completed, now trace back the path
if(pPathRequest->m_iCompletionCode == PATH_FOUND)
{
Assert(pFinishingNode);
m_Vars.m_iNumPathNodes = 0;
CHierarchicalNavNode * pNodePtr = pFinishingNode;
while(m_Vars.m_iNumPathNodes < MAX_HIERARCHICAL_PATH_NODES)
{
Assert(pNodePtr);
m_Vars.m_HierarchicalPathNodes[m_Vars.m_iNumPathNodes].m_pNode = pNodePtr;
m_Vars.m_HierarchicalPathNodes[m_Vars.m_iNumPathNodes].m_pLink = NULL;
m_Vars.m_iNumPathNodes++;
//*****************************************
// Obtain the pointer to the parent node.
const u32 iParentNavmesh = pNodePtr->GetParentNavMeshIndex();
if(iParentNavmesh == NAVMESH_NAVMESH_INDEX_NONE)
break;
CHierarchicalNavData * pParentNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex(iParentNavmesh);
Assert(pParentNavData);
if(!pParentNavData)
break;
pNodePtr = pParentNavData->GetNode(pNodePtr->GetParentNodeIndex());
}
//***************************************************************************************************
// Now we'll need to reverse the array because it currently goes from pFinishingNode -> pStartNode
int i,l;
const int iHalfSize = m_Vars.m_iNumPathNodes/2;
for(i=0; i<iHalfSize; i++)
{
pNodePtr = m_Vars.m_HierarchicalPathNodes[i].m_pNode;
m_Vars.m_HierarchicalPathNodes[i].m_pNode = m_Vars.m_HierarchicalPathNodes[m_Vars.m_iNumPathNodes-i-1].m_pNode;
m_Vars.m_HierarchicalPathNodes[m_Vars.m_iNumPathNodes-i-1].m_pNode = pNodePtr;
}
//*****************************************************************************
// Now go through and fill in the links which are stored in the list of nodes
CHierarchicalNavNode * pNode = m_Vars.m_HierarchicalPathNodes[0].m_pNode;
CHierarchicalNavData * pNodeNav = CPathServer::GetHierarchicalNavFromNavMeshIndex(pNode->GetNavMeshIndex());
for(i=0; i<m_Vars.m_iNumPathNodes-1; i++)
{
CHierarchicalNavNode * pNextNode = m_Vars.m_HierarchicalPathNodes[i+1].m_pNode;
CHierarchicalNavData * pNextNodeNav = CPathServer::GetHierarchicalNavFromNavMeshIndex(pNextNode->GetNavMeshIndex());
s32 iNumLinks = pNode->GetNumLinks();
for(l=0; l<iNumLinks; l++)
{
CHierarchicalNavLink * pLink = pNodeNav->GetLink(pNode->GetStartOfLinkData() + l);
if(pLink->GetNavMeshIndex()==pNextNode->GetNavMeshIndex() && pLink->GetNodeIndex()==pNextNodeNav->GetNodeIndex(pNextNode))
{
m_Vars.m_HierarchicalPathNodes[i].m_pLink = pLink;
break;
}
}
Assert(l != iNumLinks); // have to find the link!
pNode = pNextNode;
pNodeNav = pNextNodeNav;
}
//***********************************************************************************************
// Do the string-pulling which uses the link width left/right values to provide some measure of
// the free space along each node link, so we can attempt to remove some of the kinks in the
// path and create a better shortest-path route
#if !__FINAL
m_PerfTimer->Reset();
m_PerfTimer->Start();
#endif
Hierarchical_StringPull(pPathRequest);
#if !__FINAL
m_PerfTimer->Stop();
pPathRequest->m_fMillisecsToRefinePath = (float) m_PerfTimer->GetTimeMS();
#endif
return true;
}
else
{
return false;
}
}
//***************************************************************************************
// Hierarchical_LineOfSight
// Performs a line of sight from start to end, using the left/right width values of each
// link to define a flat volume in which visibility is possible.
bool
CPathServerThread::Hierarchical_LineOfSight(const Vector3 & vStartPos, const Vector3 & vEndPos, THierNodeAndLink * pNodeList, const int iNumNodes, Vector3 * ASSERT_ONLY(pvIsectPoints), int * ASSERT_ONLY(piMaxNumIsectPoints), int * piNumIsectPoints)
{
Assert((!pvIsectPoints && !piMaxNumIsectPoints && !piNumIsectPoints) || (pvIsectPoints && piMaxNumIsectPoints && piNumIsectPoints));
if(piNumIsectPoints)
*piNumIsectPoints = 0;
Vector3 vCurrentPos, vNextPos, vNextAgainPos;
Vector3 vIntersectCurr, vIntersectNext;
for(int i=0; i<iNumNodes; i++)
{
THierNodeAndLink * pCurrent = &pNodeList[i];
THierNodeAndLink * pNext = &pNodeList[i+1];
THierNodeAndLink * pNextAgain = &pNodeList[i+2];
CHierarchicalNavNode * pCurrentNode = pCurrent->m_pNode;
CHierarchicalNavData * pCurrentNav = CPathServer::GetHierarchicalNavFromNavMeshIndex(pCurrentNode->GetNavMeshIndex());
pCurrentNode->GetNodePosition(vCurrentPos, pCurrentNav->GetMin(), pCurrentNav->GetSize());
CHierarchicalNavNode * pNextNode = pNext->m_pNode;
CHierarchicalNavData * pNextNav = CPathServer::GetHierarchicalNavFromNavMeshIndex(pNextNode->GetNavMeshIndex());
pNextNode->GetNodePosition(vNextPos, pNextNav->GetMin(), pNextNav->GetSize());
CHierarchicalNavNode * pNextAgainNode = pNextAgain->m_pNode;
CHierarchicalNavData * pNextAgainNav = CPathServer::GetHierarchicalNavFromNavMeshIndex(pNextAgainNode->GetNavMeshIndex());
pNextAgainNode->GetNodePosition(vNextAgainPos, pNextAgainNav->GetMin(), pNextAgainNav->GetSize());
const bool bClockwiseTurn = ( CrossProduct(vNextPos - vCurrentPos, vNextAgainPos - vNextPos).z < 0.0f );
if(bClockwiseTurn)
{
if(pCurrent->m_pLink->GetWidthToRight()==0)
return false;
}
else
{
if(pCurrent->m_pLink->GetWidthToLeft()==0)
return false;
}
Vector3 vCurrNearLeft, vCurrNearRight, vCurrFarLeft, vCurrFarRight;
pCurrent->m_pLink->GetLinkExtents(vCurrentPos, vNextPos, vCurrNearLeft, vCurrNearRight, vCurrFarLeft, vCurrFarRight);
Vector3 vNextNearLeft, vNextNearRight, vNextFarLeft, vNextFarRight;
pNext->m_pLink->GetLinkExtents(vNextPos, vNextAgainPos, vNextNearLeft, vNextNearRight, vNextFarLeft, vNextFarRight);
// Intersect vStart->vEnd with the left edges of the current & next link
const int iIsectCurrLeft = CNavMesh::LineSegsIntersect2D(vStartPos, vEndPos, vCurrNearLeft, vCurrFarLeft, &vIntersectCurr);
const int iIsectNextLeft = CNavMesh::LineSegsIntersect2D(vStartPos, vEndPos, vNextNearLeft, vNextFarLeft, &vIntersectNext);
if((iIsectCurrLeft==SEGMENTS_INTERSECT && iIsectNextLeft==SEGMENTS_INTERSECT) ||
(iIsectCurrLeft==SEGMENTS_INTERSECT && iIsectNextLeft==LINES_INTERSECT) ||
(iIsectCurrLeft==LINES_INTERSECT && iIsectNextLeft==SEGMENTS_INTERSECT))
{
if((vIntersectCurr - vStartPos).Mag2() < (vIntersectNext - vStartPos).Mag2())
return false;
}
const int iIsectCurrRight = CNavMesh::LineSegsIntersect2D(vStartPos, vEndPos, vCurrNearRight, vCurrFarRight, &vIntersectCurr);
const int iIsectNextRight = CNavMesh::LineSegsIntersect2D(vStartPos, vEndPos, vNextNearRight, vNextFarRight, &vIntersectNext);
if((iIsectCurrRight==SEGMENTS_INTERSECT && iIsectNextRight==SEGMENTS_INTERSECT) ||
(iIsectCurrRight==SEGMENTS_INTERSECT && iIsectNextRight==LINES_INTERSECT) ||
(iIsectCurrRight==LINES_INTERSECT && iIsectNextRight==SEGMENTS_INTERSECT))
{
if((vIntersectCurr - vStartPos).Mag2() < (vIntersectNext - vStartPos).Mag2())
return false;
}
}
return true;
}
void
CPathServerThread::Hierarchical_StringPull(CPathRequest * pPathRequest)
{
// Add the initial node.
CHierarchicalNavData * pNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex( m_Vars.m_HierarchicalPathNodes[0].m_pNode->GetNavMeshIndex() );
m_Vars.m_HierarchicalPathNodes[0].m_pNode->GetNodePosition(pPathRequest->m_PathPoints[0], pNavData->GetMin(), pNavData->GetSize());
pPathRequest->m_iNumPoints = 1;
if(m_Vars.m_iNumPathNodes > 2)
{
int iStartIndex = 0;
int iTestIndex = 2;
bool bQuit = false;
while(!bQuit)
{
Vector3 vStartPos, vEndPos;
CHierarchicalNavNode * pStartNode = m_Vars.m_HierarchicalPathNodes[iStartIndex].m_pNode;
CHierarchicalNavData * pStartNav = CPathServer::GetHierarchicalNavFromNavMeshIndex(pStartNode->GetNavMeshIndex());
pStartNode->GetNodePosition(vStartPos, pStartNav->GetMin(), pStartNav->GetSize());
CHierarchicalNavNode * pEndNode = m_Vars.m_HierarchicalPathNodes[iTestIndex].m_pNode;
CHierarchicalNavData * pEndNav = CPathServer::GetHierarchicalNavFromNavMeshIndex(pEndNode->GetNavMeshIndex());
pEndNode->GetNodePosition(vEndPos, pEndNav->GetMin(), pEndNav->GetSize());
// int iNumIsectPts = 0;
// int iMaxNumIsectPts = MAX_NUM_PATH_POINTS - pPathRequest->m_iNumPoints;
const bool bLOS = Hierarchical_LineOfSight(
vStartPos, vEndPos, &m_Vars.m_HierarchicalPathNodes[iStartIndex], (iTestIndex-iStartIndex)-1,
NULL, NULL, NULL
// &pPathRequest->m_PathPoints[pPathRequest->m_iNumPoints],
// &iMaxNumIsectPts,
// &iNumIsectPts
);
// If a line-of-sight exists, then proceed to the next node.
if(bLOS)
{
iTestIndex++;
if(iTestIndex >= m_Vars.m_iNumPathNodes)
bQuit = true;
// pPathRequest->m_iNumPoints += iNumIsectPts;
// if(pPathRequest->m_iNumPoints >= MAX_NUM_PATH_POINTS)
// bQuit = true;
}
else
{
// Assert(iNumIsectPts==0);
pNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex( m_Vars.m_HierarchicalPathNodes[iTestIndex-1].m_pNode->GetNavMeshIndex() );
m_Vars.m_HierarchicalPathNodes[iTestIndex-1].m_pNode->GetNodePosition(pPathRequest->m_PathPoints[pPathRequest->m_iNumPoints], pNavData->GetMin(), pNavData->GetSize());
pPathRequest->m_iNumPoints++;
iStartIndex = iTestIndex-1;
iTestIndex = iStartIndex + 2;
if(iTestIndex >= m_Vars.m_iNumPathNodes || pPathRequest->m_iNumPoints >= MAX_NUM_PATH_POINTS)
bQuit = true;
}
}
}
// Add the final node.
if(pPathRequest->m_iNumPoints < MAX_NUM_PATH_POINTS)
{
pNavData = CPathServer::GetHierarchicalNavFromNavMeshIndex( m_Vars.m_HierarchicalPathNodes[m_Vars.m_iNumPathNodes-1].m_pNode->GetNavMeshIndex() );
m_Vars.m_HierarchicalPathNodes[m_Vars.m_iNumPathNodes-1].m_pNode->GetNodePosition(pPathRequest->m_PathPoints[pPathRequest->m_iNumPoints], pNavData->GetMin(), pNavData->GetSize());
pPathRequest->m_iNumPoints++;
}
}
#endif // __HIERARCHICAL_NODES_ENABLED