#include "InvokeHelper.h" #include "DetourNavMesh.h" #include "DetourNavMeshQuery.h" #include #include #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); }