update recast

This commit is contained in:
Johxz 2018-02-28 22:15:31 -06:00
parent 78caec2718
commit 594866f24c
34 changed files with 1138 additions and 407 deletions

View file

@ -77,6 +77,7 @@ dtTileCache::dtTileCache() :
m_nupdate(0)
{
memset(&m_params, 0, sizeof(m_params));
memset(m_reqs, 0, sizeof(ObstacleRequest) * MAX_REQUESTS);
}
dtTileCache::~dtTileCache()
@ -369,9 +370,10 @@ dtStatus dtTileCache::addObstacle(const float* pos, const float radius, const fl
memset(ob, 0, sizeof(dtTileCacheObstacle));
ob->salt = salt;
ob->state = DT_OBSTACLE_PROCESSING;
dtVcopy(ob->pos, pos);
ob->radius = radius;
ob->height = height;
ob->type = DT_OBSTACLE_CYLINDER;
dtVcopy(ob->cylinder.pos, pos);
ob->cylinder.radius = radius;
ob->cylinder.height = height;
ObstacleRequest* req = &m_reqs[m_nreqs++];
memset(req, 0, sizeof(ObstacleRequest));
@ -384,6 +386,79 @@ dtStatus dtTileCache::addObstacle(const float* pos, const float radius, const fl
return DT_SUCCESS;
}
dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result)
{
if (m_nreqs >= MAX_REQUESTS)
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
dtTileCacheObstacle* ob = 0;
if (m_nextFreeObstacle)
{
ob = m_nextFreeObstacle;
m_nextFreeObstacle = ob->next;
ob->next = 0;
}
if (!ob)
return DT_FAILURE | DT_OUT_OF_MEMORY;
unsigned short salt = ob->salt;
memset(ob, 0, sizeof(dtTileCacheObstacle));
ob->salt = salt;
ob->state = DT_OBSTACLE_PROCESSING;
ob->type = DT_OBSTACLE_BOX;
dtVcopy(ob->box.bmin, bmin);
dtVcopy(ob->box.bmax, bmax);
ObstacleRequest* req = &m_reqs[m_nreqs++];
memset(req, 0, sizeof(ObstacleRequest));
req->action = REQUEST_ADD;
req->ref = getObstacleRef(ob);
if (result)
*result = req->ref;
return DT_SUCCESS;
}
dtStatus dtTileCache::addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, dtObstacleRef* result)
{
if (m_nreqs >= MAX_REQUESTS)
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
dtTileCacheObstacle* ob = 0;
if (m_nextFreeObstacle)
{
ob = m_nextFreeObstacle;
m_nextFreeObstacle = ob->next;
ob->next = 0;
}
if (!ob)
return DT_FAILURE | DT_OUT_OF_MEMORY;
unsigned short salt = ob->salt;
memset(ob, 0, sizeof(dtTileCacheObstacle));
ob->salt = salt;
ob->state = DT_OBSTACLE_PROCESSING;
ob->type = DT_OBSTACLE_ORIENTED_BOX;
dtVcopy(ob->orientedBox.center, center);
dtVcopy(ob->orientedBox.halfExtents, halfExtents);
float coshalf= cosf(0.5f*yRadians);
float sinhalf = sinf(-0.5f*yRadians);
ob->orientedBox.rotAux[0] = coshalf*sinhalf;
ob->orientedBox.rotAux[1] = coshalf*coshalf - 0.5f;
ObstacleRequest* req = &m_reqs[m_nreqs++];
memset(req, 0, sizeof(ObstacleRequest));
req->action = REQUEST_ADD;
req->ref = getObstacleRef(ob);
if (result)
*result = req->ref;
return DT_SUCCESS;
}
dtStatus dtTileCache::removeObstacle(const dtObstacleRef ref)
{
if (!ref)
@ -440,7 +515,8 @@ dtStatus dtTileCache::queryTiles(const float* bmin, const float* bmax,
return DT_SUCCESS;
}
dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh)
dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
bool* upToDate)
{
if (m_nupdate == 0)
{
@ -499,12 +575,13 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh)
m_nreqs = 0;
}
dtStatus status = DT_SUCCESS;
// Process updates
if (m_nupdate)
{
// Build mesh
const dtCompressedTileRef ref = m_update[0];
dtStatus status = buildNavMeshTile(ref, navmesh);
status = buildNavMeshTile(ref, navmesh);
m_nupdate--;
if (m_nupdate > 0)
memmove(m_update, m_update+1, m_nupdate*sizeof(dtCompressedTileRef));
@ -547,12 +624,12 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh)
}
}
}
if (dtStatusFailed(status))
return status;
}
return DT_SUCCESS;
if (upToDate)
*upToDate = m_nupdate == 0 && m_nreqs == 0;
return status;
}
@ -604,8 +681,21 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
continue;
if (contains(ob->touched, ob->ntouched, ref))
{
dtMarkCylinderArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
ob->pos, ob->radius, ob->height, 0);
if (ob->type == DT_OBSTACLE_CYLINDER)
{
dtMarkCylinderArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
ob->cylinder.pos, ob->cylinder.radius, ob->cylinder.height, 0);
}
else if (ob->type == DT_OBSTACLE_BOX)
{
dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
ob->box.bmin, ob->box.bmax, 0);
}
else if (ob->type == DT_OBSTACLE_ORIENTED_BOX)
{
dtMarkBoxArea(*bc.layer, tile->header->bmin, m_params.cs, m_params.ch,
ob->orientedBox.center, ob->orientedBox.halfExtents, ob->orientedBox.rotAux, 0);
}
}
}
@ -616,7 +706,7 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
bc.lcset = dtAllocTileCacheContourSet(m_talloc);
if (!bc.lcset)
return status;
return DT_FAILURE | DT_OUT_OF_MEMORY;
status = dtBuildTileCacheContours(m_talloc, *bc.layer, walkableClimbVx,
m_params.maxSimplificationError, *bc.lcset);
if (dtStatusFailed(status))
@ -624,7 +714,7 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
bc.lmesh = dtAllocTileCachePolyMesh(m_talloc);
if (!bc.lmesh)
return status;
return DT_FAILURE | DT_OUT_OF_MEMORY;
status = dtBuildTileCachePolyMesh(m_talloc, *bc.lcset, *bc.lmesh);
if (dtStatusFailed(status))
return status;
@ -699,10 +789,32 @@ void dtTileCache::calcTightTileBounds(const dtTileCacheLayerHeader* header, floa
void dtTileCache::getObstacleBounds(const struct dtTileCacheObstacle* ob, float* bmin, float* bmax) const
{
bmin[0] = ob->pos[0] - ob->radius;
bmin[1] = ob->pos[1];
bmin[2] = ob->pos[2] - ob->radius;
bmax[0] = ob->pos[0] + ob->radius;
bmax[1] = ob->pos[1] + ob->height;
bmax[2] = ob->pos[2] + ob->radius;
if (ob->type == DT_OBSTACLE_CYLINDER)
{
const dtObstacleCylinder &cl = ob->cylinder;
bmin[0] = cl.pos[0] - cl.radius;
bmin[1] = cl.pos[1];
bmin[2] = cl.pos[2] - cl.radius;
bmax[0] = cl.pos[0] + cl.radius;
bmax[1] = cl.pos[1] + cl.height;
bmax[2] = cl.pos[2] + cl.radius;
}
else if (ob->type == DT_OBSTACLE_BOX)
{
dtVcopy(bmin, ob->box.bmin);
dtVcopy(bmax, ob->box.bmax);
}
else if (ob->type == DT_OBSTACLE_ORIENTED_BOX)
{
const dtObstacleOrientedBox &orientedBox = ob->orientedBox;
float maxr = 1.41f*dtMax(orientedBox.halfExtents[0], orientedBox.halfExtents[2]);
bmin[0] = orientedBox.center[0] - maxr;
bmax[0] = orientedBox.center[0] + maxr;
bmin[1] = orientedBox.center[1] - orientedBox.halfExtents[1];
bmax[1] = orientedBox.center[1] + orientedBox.halfExtents[1];
bmin[2] = orientedBox.center[2] - maxr;
bmax[2] = orientedBox.center[2] + maxr;
}
}

View file

@ -29,9 +29,7 @@ template<class T> class dtFixedArray
dtTileCacheAlloc* m_alloc;
T* m_ptr;
const int m_size;
inline T* operator=(T* p);
inline void operator=(dtFixedArray<T>& p);
inline dtFixedArray();
public:
inline dtFixedArray(dtTileCacheAlloc* a, const int s) : m_alloc(a), m_ptr((T*)a->alloc(sizeof(T)*s)), m_size(s) {}
inline ~dtFixedArray() { if (m_alloc) m_alloc->free(m_ptr); }
@ -2004,6 +2002,98 @@ dtStatus dtMarkCylinderArea(dtTileCacheLayer& layer, const float* orig, const fl
return DT_SUCCESS;
}
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
const float* bmin, const float* bmax, const unsigned char areaId)
{
const int w = (int)layer.header->width;
const int h = (int)layer.header->height;
const float ics = 1.0f/cs;
const float ich = 1.0f/ch;
int minx = (int)floorf((bmin[0]-orig[0])*ics);
int miny = (int)floorf((bmin[1]-orig[1])*ich);
int minz = (int)floorf((bmin[2]-orig[2])*ics);
int maxx = (int)floorf((bmax[0]-orig[0])*ics);
int maxy = (int)floorf((bmax[1]-orig[1])*ich);
int maxz = (int)floorf((bmax[2]-orig[2])*ics);
if (maxx < 0) return DT_SUCCESS;
if (minx >= w) return DT_SUCCESS;
if (maxz < 0) return DT_SUCCESS;
if (minz >= h) return DT_SUCCESS;
if (minx < 0) minx = 0;
if (maxx >= w) maxx = w-1;
if (minz < 0) minz = 0;
if (maxz >= h) maxz = h-1;
for (int z = minz; z <= maxz; ++z)
{
for (int x = minx; x <= maxx; ++x)
{
const int y = layer.heights[x+z*w];
if (y < miny || y > maxy)
continue;
layer.areas[x+z*w] = areaId;
}
}
return DT_SUCCESS;
}
dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch,
const float* center, const float* halfExtents, const float* rotAux, const unsigned char areaId)
{
const int w = (int)layer.header->width;
const int h = (int)layer.header->height;
const float ics = 1.0f/cs;
const float ich = 1.0f/ch;
float cx = (center[0] - orig[0])*ics;
float cz = (center[2] - orig[2])*ics;
float maxr = 1.41f*dtMax(halfExtents[0], halfExtents[2]);
int minx = (int)floorf(cx - maxr*ics);
int maxx = (int)floorf(cx + maxr*ics);
int minz = (int)floorf(cz - maxr*ics);
int maxz = (int)floorf(cz + maxr*ics);
int miny = (int)floorf((center[1]-halfExtents[1]-orig[1])*ich);
int maxy = (int)floorf((center[1]+halfExtents[1]-orig[1])*ich);
if (maxx < 0) return DT_SUCCESS;
if (minx >= w) return DT_SUCCESS;
if (maxz < 0) return DT_SUCCESS;
if (minz >= h) return DT_SUCCESS;
if (minx < 0) minx = 0;
if (maxx >= w) maxx = w-1;
if (minz < 0) minz = 0;
if (maxz >= h) maxz = h-1;
float xhalf = halfExtents[0]*ics + 0.5f;
float zhalf = halfExtents[2]*ics + 0.5f;
for (int z = minz; z <= maxz; ++z)
{
for (int x = minx; x <= maxx; ++x)
{
float x2 = 2.0f*(float(x) - cx);
float z2 = 2.0f*(float(z) - cz);
float xrot = rotAux[1]*x2 + rotAux[0]*z2;
if (xrot > xhalf || xrot < -xhalf)
continue;
float zrot = rotAux[1]*z2 - rotAux[0]*x2;
if (zrot > zhalf || zrot < -zhalf)
continue;
const int y = layer.heights[x+z*w];
if (y < miny || y > maxy)
continue;
layer.areas[x+z*w] = areaId;
}
}
return DT_SUCCESS;
}
dtStatus dtBuildTileCacheLayer(dtTileCacheCompressor* comp,
dtTileCacheLayerHeader* header,
@ -2027,7 +2117,11 @@ dtStatus dtBuildTileCacheLayer(dtTileCacheCompressor* comp,
const int bufferSize = gridSize*3;
unsigned char* buffer = (unsigned char*)dtAlloc(bufferSize, DT_ALLOC_TEMP);
if (!buffer)
{
dtFree(data);
return DT_FAILURE | DT_OUT_OF_MEMORY;
}
memcpy(buffer, heights, gridSize);
memcpy(buffer+gridSize, areas, gridSize);
memcpy(buffer+gridSize*2, cons, gridSize);
@ -2038,7 +2132,11 @@ dtStatus dtBuildTileCacheLayer(dtTileCacheCompressor* comp,
int compressedSize = 0;
dtStatus status = comp->compress(buffer, bufferSize, compressed, maxCompressedSize, &compressedSize);
if (dtStatusFailed(status))
{
dtFree(buffer);
dtFree(data);
return status;
}
*outData = data;
*outDataSize = headerSize + compressedSize;