You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
336 lines
6.4 KiB
336 lines
6.4 KiB
3 years ago
|
#include "InvokeHelper.h"
|
||
|
#include "DetourNavMesh.h"
|
||
|
#include "DetourNavMeshQuery.h"
|
||
|
#include <cstring>
|
||
|
#include <unordered_map>
|
||
|
#include "DetourCommon.h"
|
||
|
|
||
|
static const int NAVMESHSET_MAGIC = 'M' << 24 | 'S' << 16 | 'E' << 8 | 'T'; //'MSET';
|
||
|
static const int NAVMESHSET_VERSION = 1;
|
||
|
|
||
|
struct NavMeshSetHeader
|
||
|
{
|
||
|
int magic;
|
||
|
int version;
|
||
|
int numTiles;
|
||
|
dtNavMeshParams params;
|
||
|
};
|
||
|
|
||
|
struct NavMeshTileHeader
|
||
|
{
|
||
|
dtTileRef tileRef;
|
||
|
int dataSize;
|
||
|
};
|
||
|
|
||
|
int32_t InitNav(const char* buffer, int32_t n, dtNavMesh*& navMesh)
|
||
|
{
|
||
|
int index = 0;
|
||
|
// Read header.
|
||
|
NavMeshSetHeader header;
|
||
|
|
||
|
int count = sizeof(NavMeshSetHeader);
|
||
|
if (index + count > n)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
memcpy(&header, buffer + index, count);
|
||
|
index += count;
|
||
|
|
||
|
if (header.magic != NAVMESHSET_MAGIC)
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
if (header.version != NAVMESHSET_VERSION)
|
||
|
{
|
||
|
return -3;
|
||
|
}
|
||
|
|
||
|
dtNavMesh* mesh = dtAllocNavMesh();
|
||
|
if (!mesh)
|
||
|
{
|
||
|
return -4;
|
||
|
}
|
||
|
dtStatus status = mesh->init(&header.params);
|
||
|
if (dtStatusFailed(status))
|
||
|
{
|
||
|
return -5;
|
||
|
}
|
||
|
|
||
|
// Read tiles.
|
||
|
for (int i = 0; i < header.numTiles; ++i)
|
||
|
{
|
||
|
NavMeshTileHeader tileHeader;
|
||
|
|
||
|
count = sizeof(NavMeshTileHeader);
|
||
|
if (index + count > n)
|
||
|
{
|
||
|
return -6;
|
||
|
}
|
||
|
memcpy(&tileHeader, buffer + index, count);
|
||
|
index += count;
|
||
|
|
||
|
if (!tileHeader.tileRef || !tileHeader.dataSize)
|
||
|
break;
|
||
|
|
||
|
unsigned char* data = (unsigned char*)dtAlloc(tileHeader.dataSize, DT_ALLOC_PERM);
|
||
|
if (!data) break;
|
||
|
memset(data, 0, tileHeader.dataSize);
|
||
|
|
||
|
count = tileHeader.dataSize;
|
||
|
if (index + count > n)
|
||
|
{
|
||
|
return -7;
|
||
|
}
|
||
|
memcpy(data, buffer + index, count);
|
||
|
index += count;
|
||
|
|
||
|
mesh->addTile(data, tileHeader.dataSize, DT_TILE_FREE_DATA, tileHeader.tileRef, 0);
|
||
|
}
|
||
|
navMesh = mesh;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static const int MAX_POLYS = 256;
|
||
|
static const int MAX_SMOOTH = 2048;
|
||
|
|
||
|
class NavMeshContex
|
||
|
{
|
||
|
public:
|
||
|
dtNavMesh* navMesh;
|
||
|
dtNavMeshQuery* navQuery;
|
||
|
|
||
|
NavMeshContex()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
int32_t Init(const char* buffer, int32_t n)
|
||
|
{
|
||
|
int32_t ret = InitNav(buffer, n, navMesh);
|
||
|
std::string s;
|
||
|
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
navQuery = new dtNavMeshQuery();
|
||
|
navQuery->init(navMesh, 2048);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
~NavMeshContex()
|
||
|
{
|
||
|
if (navQuery != nullptr)
|
||
|
{
|
||
|
dtFreeNavMeshQuery(navQuery);
|
||
|
}
|
||
|
if (navMesh != nullptr)
|
||
|
{
|
||
|
dtFreeNavMesh(navMesh);
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
|
||
|
NavMesh* NavMesh::instance = nullptr;
|
||
|
|
||
|
NavMesh::NavMesh()
|
||
|
{
|
||
|
}
|
||
|
|
||
|
NavMesh* NavMesh::GetInstace()
|
||
|
{
|
||
|
if (NavMesh::instance == nullptr)
|
||
|
{
|
||
|
NavMesh::instance = new NavMesh();
|
||
|
}
|
||
|
return NavMesh::instance;
|
||
|
}
|
||
|
|
||
|
NavMeshContex* NavMesh::New(int32_t id, const char* buffer, int32_t n)
|
||
|
{
|
||
|
NavMeshContex* navMeshContex = new NavMeshContex();
|
||
|
int32_t ret = navMeshContex->Init(buffer, n);
|
||
|
|
||
|
if (ret != 0)
|
||
|
{
|
||
|
delete navMeshContex;
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
navMeshContexs[id] = navMeshContex;
|
||
|
return navMeshContex;
|
||
|
}
|
||
|
|
||
|
NavMeshContex* NavMesh::Get(int32_t id)
|
||
|
{
|
||
|
const auto it = navMeshContexs.find(id);
|
||
|
if (it != navMeshContexs.end())
|
||
|
{
|
||
|
return it->second;
|
||
|
}
|
||
|
return nullptr;
|
||
|
}
|
||
|
|
||
|
void NavMesh::Clear()
|
||
|
{
|
||
|
for (auto kv : navMeshContexs)
|
||
|
{
|
||
|
delete kv.second;
|
||
|
}
|
||
|
navMeshContexs.clear();
|
||
|
}
|
||
|
|
||
|
NavMeshContex* RecastLoad(int32_t id, const char* buffer, int32_t n)
|
||
|
{
|
||
|
return NavMesh::GetInstace()->New(id, buffer, n);
|
||
|
}
|
||
|
|
||
|
NavMeshContex* RecastGet(int32_t id)
|
||
|
{
|
||
|
return NavMesh::GetInstace()->Get(id);
|
||
|
}
|
||
|
|
||
|
void RecastClear()
|
||
|
{
|
||
|
NavMesh::GetInstace()->Clear();
|
||
|
}
|
||
|
|
||
|
int32_t RecastFind(NavMeshContex* navMeshContex, float* extents, float* startPos, float* endPos, float* straightPath)
|
||
|
{
|
||
|
//FILE* fp = fopen("./test.log", "wb");
|
||
|
if (navMeshContex == nullptr)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
if (startPos == nullptr)
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
if (endPos == nullptr)
|
||
|
{
|
||
|
return -3;
|
||
|
}
|
||
|
if (straightPath == nullptr)
|
||
|
{
|
||
|
return -4;
|
||
|
}
|
||
|
if (extents == nullptr)
|
||
|
{
|
||
|
return -5;
|
||
|
}
|
||
|
|
||
|
//char ss[200];
|
||
|
//int nn = sprintf(ss, "startPos,%f,%f,%f\n", startPos[0], startPos[1], startPos[2]);
|
||
|
//fwrite(ss, nn, 1, fp);
|
||
|
//fflush(fp);
|
||
|
|
||
|
dtPolyRef startRef = 0;
|
||
|
dtPolyRef endRef = 0;
|
||
|
float startNearestPt[3];
|
||
|
float endNearestPt[3];
|
||
|
|
||
|
dtQueryFilter filter;
|
||
|
filter.setIncludeFlags(0xffff);
|
||
|
filter.setExcludeFlags(0);
|
||
|
|
||
|
navMeshContex->navQuery->findNearestPoly(startPos, extents, &filter, &startRef, startNearestPt);
|
||
|
navMeshContex->navQuery->findNearestPoly(endPos, extents, &filter, &endRef, endNearestPt);
|
||
|
|
||
|
dtPolyRef polys[MAX_POLYS];
|
||
|
int npolys;
|
||
|
unsigned char straightPathFlags[MAX_POLYS];
|
||
|
dtPolyRef straightPathPolys[MAX_POLYS];
|
||
|
int nstraightPath = 0;
|
||
|
|
||
|
navMeshContex->navQuery->findPath(startRef, endRef, startNearestPt, endNearestPt, &filter, polys, &npolys, MAX_POLYS);
|
||
|
|
||
|
if (npolys)
|
||
|
{
|
||
|
float epos1[3];
|
||
|
dtVcopy(epos1, endNearestPt);
|
||
|
|
||
|
if (polys[npolys - 1] != endRef)
|
||
|
{
|
||
|
navMeshContex->navQuery->closestPointOnPoly(polys[npolys - 1], endNearestPt, epos1, 0);
|
||
|
}
|
||
|
|
||
|
navMeshContex->navQuery->findStraightPath(startNearestPt, endNearestPt, polys, npolys, straightPath, straightPathFlags, straightPathPolys, &nstraightPath, MAX_POLYS, DT_STRAIGHTPATH_ALL_CROSSINGS);
|
||
|
}
|
||
|
|
||
|
return nstraightPath;
|
||
|
}
|
||
|
|
||
|
int32_t RecastFindNearestPoint(NavMeshContex* navMeshContex, float* extents, float* startPos, float* nearestPos)
|
||
|
{
|
||
|
if (navMeshContex == nullptr)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
if (startPos == nullptr)
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
if (nearestPos == nullptr)
|
||
|
{
|
||
|
return -3;
|
||
|
}
|
||
|
if (extents == nullptr)
|
||
|
{
|
||
|
return -5;
|
||
|
}
|
||
|
|
||
|
dtPolyRef startRef = 0;
|
||
|
|
||
|
dtQueryFilter filter;
|
||
|
filter.setIncludeFlags(0xffff);
|
||
|
filter.setExcludeFlags(0);
|
||
|
|
||
|
navMeshContex->navQuery->findNearestPoly(startPos, extents, &filter, &startRef, nearestPos);
|
||
|
return startRef;
|
||
|
}
|
||
|
|
||
|
static float frand()
|
||
|
{
|
||
|
// return ((float)(rand() & 0xffff)/(float)0xffff);
|
||
|
return (float)rand() / (float)RAND_MAX;
|
||
|
}
|
||
|
|
||
|
int32_t RecastFindRandomPoint(NavMeshContex* navMeshContex, float* pos)
|
||
|
{
|
||
|
if (navMeshContex == nullptr)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
if (pos == nullptr)
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
dtQueryFilter filter;
|
||
|
filter.setIncludeFlags(0xffff);
|
||
|
filter.setExcludeFlags(0);
|
||
|
|
||
|
dtPolyRef startRef = 0;
|
||
|
return navMeshContex->navQuery->findRandomPoint(&filter, frand, &startRef, pos);
|
||
|
}
|
||
|
|
||
|
int32_t RecastFindRandomPointAroundCircle(NavMeshContex* navMeshContex, float* extents, const float* centerPos, const float maxRadius, float* pos)
|
||
|
{
|
||
|
if (navMeshContex == nullptr)
|
||
|
{
|
||
|
return -1;
|
||
|
}
|
||
|
if (pos == nullptr)
|
||
|
{
|
||
|
return -2;
|
||
|
}
|
||
|
dtQueryFilter filter;
|
||
|
filter.setIncludeFlags(0xffff);
|
||
|
filter.setExcludeFlags(0);
|
||
|
|
||
|
dtPolyRef startRef = 0;
|
||
|
dtPolyRef randomRef = 0;
|
||
|
float startNearestPt[3];
|
||
|
navMeshContex->navQuery->findNearestPoly(centerPos, extents, &filter, &startRef, startNearestPt);
|
||
|
return navMeshContex->navQuery->findRandomPointAroundCircle(startRef, centerPos, maxRadius, &filter, frand, &randomRef, pos);
|
||
|
}
|