diff --git a/DetourTileCache/Include/DetourTileCache.h b/DetourTileCache/Include/DetourTileCache.h index c45910c..aba0c13 100644 --- a/DetourTileCache/Include/DetourTileCache.h +++ b/DetourTileCache/Include/DetourTileCache.h @@ -38,7 +38,8 @@ enum ObstacleState enum ObstacleType { DT_OBSTACLE_CYLINDER, - DT_OBSTACLE_BOX, + DT_OBSTACLE_BOX, // AABB + DT_OBSTACLE_ORIENTED_BOX, // OBB }; struct dtObstacleCylinder @@ -54,6 +55,13 @@ struct dtObstacleBox float bmax[ 3 ]; }; +struct dtObstacleOrientedBox +{ + float center[ 3 ]; + float extents[ 3 ]; + float rotAux[ 2 ]; //{ cos(0.5f*angle)*sin(-0.5f*angle); cos(0.5f*angle)*cos(0.5f*angle) - 0.5 } +}; + static const int DT_MAX_TOUCHED_TILES = 8; struct dtTileCacheObstacle { @@ -61,6 +69,7 @@ struct dtTileCacheObstacle { dtObstacleCylinder cylinder; dtObstacleBox box; + dtObstacleOrientedBox orientedBox; }; dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES]; @@ -130,8 +139,14 @@ public: dtStatus removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize); + // Cylinder obstacle. dtStatus addObstacle(const float* pos, const float radius, const float height, dtObstacleRef* result); + + // Aabb obstacle. dtStatus addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result); + + // Box obstacle: can be rotated in Y. + dtStatus addBoxObstacle(const float* center, const float* extents, const float yRadians, dtObstacleRef* result); dtStatus removeObstacle(const dtObstacleRef ref); diff --git a/DetourTileCache/Include/DetourTileCacheBuilder.h b/DetourTileCache/Include/DetourTileCacheBuilder.h index d1ef80e..7b95abc 100644 --- a/DetourTileCache/Include/DetourTileCacheBuilder.h +++ b/DetourTileCache/Include/DetourTileCacheBuilder.h @@ -130,6 +130,9 @@ dtStatus dtMarkCylinderArea(dtTileCacheLayer& layer, const float* orig, const fl dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch, const float* bmin, const float* bmax, const unsigned char areaId); +dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch, + const float* center, const float* extents, const float* rotAux, 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 cf57504..1b152df 100644 --- a/DetourTileCache/Source/DetourTileCache.cpp +++ b/DetourTileCache/Source/DetourTileCache.cpp @@ -420,6 +420,45 @@ dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, dtObs return DT_SUCCESS; } +dtStatus dtTileCache::addBoxObstacle(const float* center, const float* extents, 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.extents, extents); + + 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) @@ -650,7 +689,12 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* 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); + 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.extents, ob->orientedBox.rotAux, 0); } } } @@ -761,4 +805,16 @@ void dtTileCache::getObstacleBounds(const struct dtTileCacheObstacle* ob, float* 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.extents[0], orientedBox.extents[2]); + bmin[0] = orientedBox.center[0] - maxr; + bmax[0] = orientedBox.center[0] + maxr; + bmin[1] = orientedBox.center[1] - orientedBox.extents[1]; + bmax[1] = orientedBox.center[1] + orientedBox.extents[1]; + bmin[2] = orientedBox.center[2] - maxr; + bmax[2] = orientedBox.center[2] + maxr; + } } diff --git a/DetourTileCache/Source/DetourTileCacheBuilder.cpp b/DetourTileCache/Source/DetourTileCacheBuilder.cpp index a81a7b4..56ee134 100644 --- a/DetourTileCache/Source/DetourTileCacheBuilder.cpp +++ b/DetourTileCache/Source/DetourTileCacheBuilder.cpp @@ -2041,6 +2041,60 @@ dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float c return DT_SUCCESS; } +dtStatus dtMarkBoxArea(dtTileCacheLayer& layer, const float* orig, const float cs, const float ch, + const float* center, const float* extents, 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(extents[0], extents[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]-extents[1]-orig[1])*ich); + int maxy = (int)floorf((center[1]+extents[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 = extents[0]*ics + 0.5f; + float zhalf = extents[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, const unsigned char* heights,