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.
335 lines
6.4 KiB
335 lines
6.4 KiB
#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); |
|
}
|
|
|