diff --git a/DetourTileCache/Include/DetourTileCache.h b/DetourTileCache/Include/DetourTileCache.h index cbd1d36..c45910c 100644 --- a/DetourTileCache/Include/DetourTileCache.h +++ b/DetourTileCache/Include/DetourTileCache.h @@ -35,13 +35,38 @@ enum ObstacleState DT_OBSTACLE_REMOVING, }; +enum ObstacleType +{ + DT_OBSTACLE_CYLINDER, + DT_OBSTACLE_BOX, +}; + +struct dtObstacleCylinder +{ + float pos[ 3 ]; + float radius; + float height; +}; + +struct dtObstacleBox +{ + float bmin[ 3 ]; + float bmax[ 3 ]; +}; + static const int DT_MAX_TOUCHED_TILES = 8; struct dtTileCacheObstacle { - float pos[3], radius, height; + union + { + dtObstacleCylinder cylinder; + dtObstacleBox box; + }; + dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES]; dtCompressedTileRef pending[DT_MAX_TOUCHED_TILES]; unsigned short salt; + unsigned char type; unsigned char state; unsigned char ntouched; unsigned char npending; @@ -106,6 +131,8 @@ public: dtStatus removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize); dtStatus addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result); + dtStatus addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result); + dtStatus removeObstacle(const dtObstacleRef ref); dtStatus queryTiles(const float* bmin, const float* bmax, diff --git a/DetourTileCache/Include/DetourTileCacheBuilder.h b/DetourTileCache/Include/DetourTileCacheBuilder.h index 854183c..d1ef80e 100644 --- a/DetourTileCache/Include/DetourTileCacheBuilder.h +++ b/DetourTileCache/Include/DetourTileCacheBuilder.h @@ -127,6 +127,9 @@ void dtFreeTileCachePolyMesh(dtTileCacheAlloc* alloc, dtTileCachePolyMesh* lmesh dtStatus dtMarkCylinderArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch, const float* pos, const float radius, const float height, const unsigned char areaId); +dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch, + const float* bmin, const float* bmax, const unsigned char areaId); + dtStatus dtBuildTileCacheRegions(dtTileCacheAlloc* alloc, dtTileCacheLayer& layer, const int walkableClimb); diff --git a/DetourTileCache/Source/DetourTileCache.cpp b/DetourTileCache/Source/DetourTileCache.cpp index e573fba..cf57504 100644 --- a/DetourTileCache/Source/DetourTileCache.cpp +++ b/DetourTileCache/Source/DetourTileCache.cpp @@ -370,9 +370,44 @@ 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)); + req->action = REQUEST_ADD; + req->ref = getObstacleRef(ob); + + if (result) + *result = req->ref; + + 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)); @@ -607,8 +642,16 @@ 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); + } } } @@ -702,10 +745,20 @@ 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); + } } diff --git a/DetourTileCache/Source/DetourTileCacheBuilder.cpp b/DetourTileCache/Source/DetourTileCacheBuilder.cpp index 995e592..a81a7b4 100644 --- a/DetourTileCache/Source/DetourTileCacheBuilder.cpp +++ b/DetourTileCache/Source/DetourTileCacheBuilder.cpp @@ -2002,6 +2002,44 @@ 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 dtBuildTileCacheLayer(dtTileCacheCompressor* comp, dtTileCacheLayerHeader* header,