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

#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);
}