From d2148ff57dbe012db50c4aa6a0065f458cae715d Mon Sep 17 00:00:00 2001 From: Mikko Mononen Date: Thu, 17 Nov 2011 19:11:12 +0000 Subject: [PATCH] Added better state control for tile cache obstacles. --- DetourTileCache/Include/DetourTileCache.h | 9 ++- DetourTileCache/Source/DetourTileCache.cpp | 81 +++++++++++++++++----- 2 files changed, 69 insertions(+), 21 deletions(-) diff --git a/DetourTileCache/Include/DetourTileCache.h b/DetourTileCache/Include/DetourTileCache.h index 2d46e15..9f30d26 100644 --- a/DetourTileCache/Include/DetourTileCache.h +++ b/DetourTileCache/Include/DetourTileCache.h @@ -29,9 +29,10 @@ struct dtCompressedTile enum ObstacleState { - OBS_EMPTY, - OBS_NEW, - OBS_PROCESSED, + DT_OBSTACLE_EMPTY, + DT_OBSTACLE_PROCESSING, + DT_OBSTACLE_PROCESSED, + DT_OBSTACLE_REMOVING, }; static const int DT_MAX_TOUCHED_TILES = 8; @@ -39,9 +40,11 @@ struct dtTileCacheObstacle { float pos[3], radius, height; dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES]; + dtCompressedTileRef pending[DT_MAX_TOUCHED_TILES]; unsigned short salt; unsigned char state; unsigned char ntouched; + unsigned char npending; dtTileCacheObstacle* next; }; diff --git a/DetourTileCache/Source/DetourTileCache.cpp b/DetourTileCache/Source/DetourTileCache.cpp index 2af3cfe..889848e 100644 --- a/DetourTileCache/Source/DetourTileCache.cpp +++ b/DetourTileCache/Source/DetourTileCache.cpp @@ -363,7 +363,7 @@ dtObstacleRef dtTileCache::addObstacle(const float* pos, const float radius, con unsigned short salt = ob->salt; memset(ob, 0, sizeof(dtTileCacheObstacle)); ob->salt = salt; - ob->state = OBS_NEW; + ob->state = DT_OBSTACLE_PROCESSING; dtVcopy(ob->pos, pos); ob->radius = radius; ob->height = height; @@ -454,8 +454,6 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh) if (req->action == REQUEST_ADD) { - // Add and init obstacle. - ob->state = OBS_PROCESSED; // Find touched tiles. float bmin[3], bmax[3]; getObstacleBounds(ob, bmin, bmax); @@ -464,29 +462,32 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh) queryTiles(bmin, bmax, ob->touched, &ntouched, DT_MAX_TOUCHED_TILES); ob->ntouched = (unsigned char)ntouched; // Add tiles to update list. + ob->npending = 0; for (int j = 0; j < ob->ntouched; ++j) { - if (m_nupdate < MAX_UPDATE && !contains(m_update, m_nupdate, ob->touched[j])) - m_update[m_nupdate++] = ob->touched[j]; + if (m_nupdate < MAX_UPDATE) + { + if (!contains(m_update, m_nupdate, ob->touched[j])) + m_update[m_nupdate++] = ob->touched[j]; + ob->pending[ob->npending++] = ob->touched[j]; + } } } else if (req->action == REQUEST_REMOVE) { - // Remove obstacle. - ob->state = OBS_EMPTY; + // Prepare to remove obstacle. + ob->state = DT_OBSTACLE_REMOVING; // Add tiles to update list. + ob->npending = 0; for (int j = 0; j < ob->ntouched; ++j) { - if (m_nupdate < MAX_UPDATE && !contains(m_update, m_nupdate, ob->touched[j])) - m_update[m_nupdate++] = ob->touched[j]; + if (m_nupdate < MAX_UPDATE) + { + if (!contains(m_update, m_nupdate, ob->touched[j])) + m_update[m_nupdate++] = ob->touched[j]; + ob->pending[ob->npending++] = ob->touched[j]; + } } - // Update salt, salt should never be zero. - ob->salt = (ob->salt+1) & ((1<<16)-1); - if (ob->salt == 0) - ob->salt++; - // Return obstacle to free list. - ob->next = m_nextFreeObstacle; - m_nextFreeObstacle = ob; } } @@ -496,8 +497,52 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh) // Process updates if (m_nupdate) { - dtStatus status = buildNavMeshTile(m_update[m_nupdate-1], navmesh); + // Build mesh + const dtCompressedTileRef ref = m_update[0]; + dtStatus status = buildNavMeshTile(ref, navmesh); m_nupdate--; + if (m_nupdate > 0) + memmove(m_update, m_update+1, m_nupdate*sizeof(dtCompressedTileRef)); + + // Update obstacle states. + for (int i = 0; i < m_params.maxObstacles; ++i) + { + dtTileCacheObstacle* ob = &m_obstacles[i]; + if (ob->state == DT_OBSTACLE_PROCESSING || ob->state == DT_OBSTACLE_REMOVING) + { + // Remove handled tile from pending list. + for (int j = 0; j < (int)ob->npending; j++) + { + if (ob->pending[j] == ref) + { + ob->pending[j] = ob->pending[(int)ob->npending-1]; + ob->npending--; + break; + } + } + + // If all pending tiles processed, change state. + if (ob->npending == 0) + { + if (ob->state == DT_OBSTACLE_PROCESSING) + { + ob->state = DT_OBSTACLE_PROCESSED; + } + else if (ob->state == DT_OBSTACLE_REMOVING) + { + ob->state = DT_OBSTACLE_EMPTY; + // Update salt, salt should never be zero. + ob->salt = (ob->salt+1) & ((1<<16)-1); + if (ob->salt == 0) + ob->salt++; + // Return obstacle to free list. + ob->next = m_nextFreeObstacle; + m_nextFreeObstacle = ob; + } + } + } + } + if (dtStatusFailed(status)) return status; } @@ -550,7 +595,7 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* for (int i = 0; i < m_params.maxObstacles; ++i) { const dtTileCacheObstacle* ob = &m_obstacles[i]; - if (ob->state != OBS_PROCESSED) + if (ob->state == DT_OBSTACLE_EMPTY || ob->state == DT_OBSTACLE_REMOVING) continue; if (contains(ob->touched, ob->ntouched, ref)) {