209 lines
5.0 KiB
C++
209 lines
5.0 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "DetourCrowd/DetourSharedBoundary.h"
|
|
|
|
void dtSharedBoundary::Initialize()
|
|
{
|
|
CurrentTime = 0.0f;
|
|
NextClearTime = 0.0f;
|
|
|
|
for (int32 Idx = 0; Idx < DT_MAX_AREAS; Idx++)
|
|
{
|
|
SingleAreaFilter.setAreaCost(Idx, DT_UNWALKABLE_POLY_COST);
|
|
}
|
|
}
|
|
|
|
void dtSharedBoundary::Tick(dtReal DeltaTime)
|
|
{
|
|
CurrentTime += DeltaTime;
|
|
|
|
// clear unused entries
|
|
if (CurrentTime > NextClearTime)
|
|
{
|
|
const dtReal MaxLifeTime = 2.0f;
|
|
NextClearTime = CurrentTime + MaxLifeTime;
|
|
|
|
for (TSparseArray<dtSharedBoundaryData>::TIterator It(Data); It; ++It)
|
|
{
|
|
const dtReal LastAccess = CurrentTime - It->AccessTime;
|
|
if (LastAccess >= MaxLifeTime)
|
|
{
|
|
It.RemoveCurrent();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 dtSharedBoundary::CacheData(dtReal* Center, dtReal Radius, dtPolyRef CenterPoly, dtNavMeshQuery* NavQuery, dtQueryFilter* NavFilter)
|
|
{
|
|
// bail if requested poly is not valid (e.g. rebuild in progress)
|
|
if (NavQuery && !NavQuery->isValidPolyRef(CenterPoly, NavFilter))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
Radius *= 1.5f;
|
|
|
|
int32 DataIdx = FindData(Center, Radius, CenterPoly, NavFilter);
|
|
const bool bHasValidData = IsValid(DataIdx, NavQuery, NavFilter);
|
|
if (!bHasValidData)
|
|
{
|
|
if (DataIdx >= 0)
|
|
{
|
|
// remove in next cleanup
|
|
Data[DataIdx].AccessTime = 0.0f;
|
|
}
|
|
|
|
dtSharedBoundaryData NewData;
|
|
dtVcopy(NewData.Center, Center);
|
|
NewData.Radius = Radius;
|
|
NewData.Filter = NavFilter;
|
|
NewData.SingleAreaId = 0;
|
|
|
|
FindEdges(NewData, CenterPoly, NavQuery, NavFilter);
|
|
DataIdx = Data.Add(NewData);
|
|
}
|
|
|
|
Data[DataIdx].AccessTime = CurrentTime;
|
|
return DataIdx;
|
|
}
|
|
|
|
int32 dtSharedBoundary::CacheData(dtReal* Center, dtReal Radius, dtPolyRef CenterPoly, dtNavMeshQuery* NavQuery, uint8 SingleAreaId)
|
|
{
|
|
SingleAreaFilter.setAreaCost(SingleAreaId, 1.0f);
|
|
|
|
// bail if requested poly is not valid (e.g. rebuild in progress)
|
|
if (NavQuery && !NavQuery->isValidPolyRef(CenterPoly, &SingleAreaFilter))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
Radius *= 1.5f;
|
|
|
|
int32 DataIdx = FindData(Center, Radius, CenterPoly, SingleAreaId);
|
|
const bool bHasValidData = IsValid(DataIdx, NavQuery, &SingleAreaFilter);
|
|
if (!bHasValidData)
|
|
{
|
|
if (DataIdx >= 0)
|
|
{
|
|
// remove in next cleanup
|
|
Data[DataIdx].AccessTime = 0.0f;
|
|
}
|
|
|
|
dtSharedBoundaryData NewData;
|
|
dtVcopy(NewData.Center, Center);
|
|
NewData.Radius = Radius;
|
|
NewData.SingleAreaId = SingleAreaId;
|
|
|
|
FindEdges(NewData, CenterPoly, NavQuery, &SingleAreaFilter);
|
|
DataIdx = Data.Add(NewData);
|
|
}
|
|
|
|
SingleAreaFilter.setAreaCost(SingleAreaId, DT_UNWALKABLE_POLY_COST);
|
|
Data[DataIdx].AccessTime = CurrentTime;
|
|
return DataIdx;
|
|
}
|
|
|
|
void dtSharedBoundary::FindEdges(dtSharedBoundaryData& SharedData, dtPolyRef CenterPoly, dtNavMeshQuery* NavQuery, dtQueryFilter* NavFilter)
|
|
{
|
|
const int32 MaxWalls = 64;
|
|
int32 NumWalls = 0;
|
|
dtReal WallSegments[MaxWalls * 3 * 2] = { 0 };
|
|
dtPolyRef WallPolys[MaxWalls * 2] = { 0 };
|
|
|
|
const int32 MaxNeis = 64;
|
|
int32 NumNeis = 0;
|
|
dtPolyRef NeiPolys[MaxNeis] = { 0 };
|
|
|
|
NavQuery->findWallsInNeighbourhood(CenterPoly, SharedData.Center, SharedData.Radius, NavFilter,
|
|
NeiPolys, &NumNeis, MaxNeis, WallSegments, WallPolys, &NumWalls, MaxWalls);
|
|
|
|
dtSharedBoundaryEdge NewEdge;
|
|
for (int32 Idx = 0; Idx < NumWalls; Idx++)
|
|
{
|
|
dtVcopy(NewEdge.v0, &WallSegments[Idx * 6]);
|
|
dtVcopy(NewEdge.v1, &WallSegments[Idx * 6 + 3]);
|
|
NewEdge.p0 = WallPolys[Idx * 2];
|
|
NewEdge.p1 = WallPolys[Idx * 2 + 1];
|
|
|
|
SharedData.Edges.Add(NewEdge);
|
|
}
|
|
|
|
SharedData.Polys.Reserve(NumNeis);
|
|
for (int32 Idx = 0; Idx < NumNeis; Idx++)
|
|
{
|
|
SharedData.Polys.Add(NeiPolys[Idx]);
|
|
}
|
|
}
|
|
|
|
int32 dtSharedBoundary::FindData(dtReal* Center, dtReal Radius, dtPolyRef ReqPoly, dtQueryFilter* NavFilter) const
|
|
{
|
|
const dtReal RadiusThr = 50.0f;
|
|
const dtReal DistThrSq = dtSqr(Radius * 0.5f);
|
|
|
|
for (int32 Idx = 0; Idx < Data.Num(); Idx++)
|
|
{
|
|
if (Data[Idx].Filter == NavFilter)
|
|
{
|
|
const dtReal DistSq = dtVdistSqr(Center, Data[Idx].Center);
|
|
if (DistSq <= DistThrSq && dtAbs(Data[Idx].Radius - Radius) < RadiusThr)
|
|
{
|
|
if (Data[Idx].Polys.Contains(ReqPoly))
|
|
{
|
|
return Idx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int32 dtSharedBoundary::FindData(dtReal* Center, dtReal Radius, dtPolyRef ReqPoly, uint8 SingleAreaId) const
|
|
{
|
|
const dtReal DistThrSq = dtSqr(Radius * 0.5f);
|
|
const dtReal RadiusThr = 50.0f;
|
|
|
|
for (int32 Idx = 0; Idx < Data.Num(); Idx++)
|
|
{
|
|
if (Data[Idx].SingleAreaId == SingleAreaId)
|
|
{
|
|
const dtReal DistSq = dtVdistSqr(Center, Data[Idx].Center);
|
|
if (DistSq <= DistThrSq && dtAbs(Data[Idx].Radius - Radius) < RadiusThr)
|
|
{
|
|
if (Data[Idx].Polys.Contains(ReqPoly))
|
|
{
|
|
return Idx;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool dtSharedBoundary::HasSample(int32 Idx) const
|
|
{
|
|
return (Idx >= 0) && (Idx < Data.GetMaxIndex()) && Data.IsAllocated(Idx);
|
|
}
|
|
|
|
bool dtSharedBoundary::IsValid(int32 Idx, dtNavMeshQuery* NavQuery, dtQueryFilter* NavFilter) const
|
|
{
|
|
bool bValid = HasSample(Idx);
|
|
if (bValid)
|
|
{
|
|
for (auto It = Data[Idx].Polys.CreateConstIterator(); It; ++It)
|
|
{
|
|
const dtPolyRef TestRef = *It;
|
|
const bool bValidRef = NavQuery->isValidPolyRef(TestRef, NavFilter);
|
|
if (!bValidRef)
|
|
{
|
|
bValid = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return bValid;
|
|
}
|