Recast: rename reachability table to traversal table

The static pathing code is split into 2 elements, the disjoint sets (poly groups), and the traversal table (which links poly groups, visually known as poly islands) together through jump or offmesh links. Reachability covers more than just traversal in the context of this game engine, therefore it has been renamed to avoid future confusion.
This commit is contained in:
Kawe Mazidjatari 2024-07-05 17:48:48 +02:00
parent 44928a3c7c
commit 1a3f7b6bda
7 changed files with 79 additions and 68 deletions

View File

@ -396,25 +396,25 @@ dtNavMesh* Editor::loadAll(std::string path)
} }
// Read read static pathing data. // Read read static pathing data.
if (header.params.disjointPolyGroupCount >= DT_MIN_POLY_GROUP_COUNT) if (header.params.polyGroupCount >= DT_MIN_POLY_GROUP_COUNT)
{ {
for (int i = 0; i < header.params.reachabilityTableCount; i++) for (int i = 0; i < header.params.traversalTableCount; i++)
{ {
int* reachabilityTable = (int*)rdAlloc(header.params.reachabilityTableSize, RD_ALLOC_PERM); int* traversalTable = (int*)rdAlloc(header.params.traversalTableSize, RD_ALLOC_PERM);
if (!reachabilityTable) if (!traversalTable)
break; break;
memset(reachabilityTable, 0, header.params.reachabilityTableSize); memset(traversalTable, 0, header.params.traversalTableSize);
readLen = fread(reachabilityTable, header.params.reachabilityTableSize, 1, fp); readLen = fread(traversalTable, header.params.traversalTableSize, 1, fp);
if (readLen != 1) if (readLen != 1)
{ {
rdFree(reachabilityTable); rdFree(traversalTable);
fclose(fp); fclose(fp);
return 0; return 0;
} }
mesh->m_setTables[i] = reachabilityTable; mesh->m_traversalTables[i] = traversalTable;
} }
} }
@ -474,16 +474,16 @@ void Editor::saveAll(std::string path, const dtNavMesh* mesh)
} }
// Only store if we have 3 or more poly groups. // Only store if we have 3 or more poly groups.
if (mesh->m_params.disjointPolyGroupCount >= DT_MIN_POLY_GROUP_COUNT) if (mesh->m_params.polyGroupCount >= DT_MIN_POLY_GROUP_COUNT)
{ {
rdAssert(mesh->m_setTables); rdAssert(mesh->m_traversalTables);
for (int i = 0; i < header.params.reachabilityTableCount; i++) for (int i = 0; i < header.params.traversalTableCount; i++)
{ {
const int* const tableData = mesh->m_setTables[i]; const int* const tableData = mesh->m_traversalTables[i];
rdAssert(tableData); rdAssert(tableData);
fwrite(tableData, sizeof(int), (header.params.reachabilityTableSize/4), fp); fwrite(tableData, sizeof(int), (header.params.traversalTableSize/4), fp);
} }
} }

View File

@ -222,10 +222,10 @@ void Editor_TileMesh::handleSettings()
if (imguiButton(h.name)) if (imguiButton(h.name))
{ {
m_agentRadius = h.radius; m_agentRadius = h.radius;
m_agentMaxClimb = h.climb_height; m_agentMaxClimb = h.climbHeight;
m_agentHeight = h.height; m_agentHeight = h.height;
m_navmeshName = h.name; m_navmeshName = h.name;
m_tileSize = h.tile_size; m_tileSize = h.tileSize;
} }
} }
Editor::handleCommonSettings(); Editor::handleCommonSettings();
@ -615,9 +615,9 @@ bool Editor_TileMesh::handleBuild()
params.tileHeight = m_tileSize*m_cellSize; params.tileHeight = m_tileSize*m_cellSize;
params.maxTiles = m_maxTiles; params.maxTiles = m_maxTiles;
params.maxPolys = m_maxPolysPerTile; params.maxPolys = m_maxPolysPerTile;
params.disjointPolyGroupCount = 0; params.polyGroupCount = 0;
params.reachabilityTableSize = 0; params.traversalTableSize = 0;
params.reachabilityTableCount = DT_NUM_REACHABILITY_TABLES; params.traversalTableCount = DT_NUM_TRAVERSAL_TABLES;
params.magicDataCount = 0; params.magicDataCount = 0;
dtStatus status; dtStatus status;
@ -794,10 +794,10 @@ void Editor_TileMesh::buildAllHulls()
for (const hulldef& h : hulls) for (const hulldef& h : hulls)
{ {
m_agentRadius = h.radius; m_agentRadius = h.radius;
m_agentMaxClimb = h.climb_height; m_agentMaxClimb = h.climbHeight;
m_agentHeight = h.height; m_agentHeight = h.height;
m_navmeshName = h.name; m_navmeshName = h.name;
m_tileSize = h.tile_size; m_tileSize = h.tileSize;
m_ctx->resetLog(); m_ctx->resetLog();

View File

@ -27,10 +27,8 @@ struct hulldef
const char* name; const char* name;
float radius; float radius;
float height; float height;
float climb_height; float climbHeight;
float tileSize;
float tile_size;
//TODO: voxel size, tile size
}; };
extern const hulldef hulls[5]; extern const hulldef hulls[5];

View File

@ -35,16 +35,16 @@ inline const char* NavMesh_GetNameForType(const NavMeshType_e navMeshType)
} }
inline const int g_traverseAnimTypeSetTableIndices[ANIMTYPE_COUNT] = { inline const int g_traverseAnimTypeSetTableIndices[ANIMTYPE_COUNT] = {
// NAVMESH_SMALL has 5 reachability tables, so each traverse anim type indexes // NAVMESH_SMALL has 5 traversal tables, so each traverse anim type indexes
// into its own. // into its own.
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
// All other navmeshes have 1 reachability table, so we need to subtract the // All other navmeshes have 1 traversal table, so we need to subtract the
// number from the enumerant to index into the first one. // number from the enumerant to index into the first one.
-5, -6, -7, -8 -5, -6, -7, -8
}; };
inline int NavMesh_GetReachabilityTableIndexForTraverseAnimType(const TraverseAnimType_e animType) inline int NavMesh_GetTraversalTableIndexForAnimType(const TraverseAnimType_e animType)
{ {
Assert(animType >= 0 && animType < V_ARRAYSIZE(g_traverseAnimTypeSetTableIndices)); Assert(animType >= 0 && animType < V_ARRAYSIZE(g_traverseAnimTypeSetTableIndices));
return animType + g_traverseAnimTypeSetTableIndices[animType]; return animType + g_traverseAnimTypeSetTableIndices[animType];

View File

@ -75,8 +75,8 @@ static const unsigned short DT_STRAY_POLY_GROUP = 1;
/// on the same (or connected) poly island before trying to compute a path). /// on the same (or connected) poly island before trying to compute a path).
static const int DT_MIN_POLY_GROUP_COUNT = 3; static const int DT_MIN_POLY_GROUP_COUNT = 3;
/// The number of reachability tables that will be used for static pathing. /// The number of traversal tables that will be used for static pathing.
static const int DT_NUM_REACHABILITY_TABLES = 4; static const int DT_NUM_TRAVERSAL_TABLES = 4;
/// @{ /// @{
/// @name Tile Serialization Constants /// @name Tile Serialization Constants
@ -398,12 +398,12 @@ struct dtNavMeshParams
float tileHeight; ///< The height of each tile. (Along the z-axis.) float tileHeight; ///< The height of each tile. (Along the z-axis.)
int maxTiles; ///< The maximum number of tiles the navigation mesh can contain. This and maxPolys are used to calculate how many bits are needed to identify tiles and polygons uniquely. int maxTiles; ///< The maximum number of tiles the navigation mesh can contain. This and maxPolys are used to calculate how many bits are needed to identify tiles and polygons uniquely.
int maxPolys; ///< The maximum number of polygons each tile can contain. This and maxTiles are used to calculate how many bits are needed to identify tiles and polygons uniquely. int maxPolys; ///< The maximum number of polygons each tile can contain. This and maxTiles are used to calculate how many bits are needed to identify tiles and polygons uniquely.
int disjointPolyGroupCount; ///< The total number of unique polygon groups. int polyGroupCount; ///< The total number of disjoint polygon groups.
int reachabilityTableSize; ///< The total size of the reachability (static pathing) table. This is computed using calcStaticPathingTableSize(disjointPolyGroupcount). int traversalTableSize; ///< The total size of the static traversal table. This is computed using calcTraversalTableSize(polyGroupcount).
int reachabilityTableCount; ///< The total number of reachability (static pathing) tables in this navmesh. Each TraverseAnimType uses its own table as their available jump links should match their behavior and abilities. int traversalTableCount; ///< The total number of traversal tables in this navmesh. Each TraverseAnimType uses its own table as their available jump links should match their behavior and abilities.
// NOTE: this seems to be used for some wallrunning code. This allocates a buffer of size 0x30 * magicDataCount, // NOTE: this seems to be used for some wallrunning code. This allocates a buffer of size 0x30 * magicDataCount,
// then copies in the data 0x30 * magicDataCount at the end of the navmesh file (past the reachability tables). // then copies in the data 0x30 * magicDataCount at the end of the navmesh file (past the traversal tables).
// See [r5apex_ds + F43600] for buffer allocation and data copy, see note at dtNavMesh::m_someMagicData for usage. // See [r5apex_ds + F43600] for buffer allocation and data copy, see note at dtNavMesh::m_someMagicData for usage.
int magicDataCount; int magicDataCount;
}; };
@ -738,7 +738,7 @@ public:
dtMeshTile** m_posLookup; ///< Tile hash lookup. dtMeshTile** m_posLookup; ///< Tile hash lookup.
dtMeshTile* m_nextFree; ///< Freelist of tiles. dtMeshTile* m_nextFree; ///< Freelist of tiles.
dtMeshTile* m_tiles; ///< List of tiles. dtMeshTile* m_tiles; ///< List of tiles.
int** m_setTables; ///< Array of set tables. int** m_traversalTables; ///< Array of set tables.
///< FIXME: unknown structure pointer, used for some wallrunning code, see [r5apex_ds + F12687] for usage. ///< FIXME: unknown structure pointer, used for some wallrunning code, see [r5apex_ds + F12687] for usage.
///< See note at dtNavMeshParams::magicDataCount for buffer allocation. ///< See note at dtNavMeshParams::magicDataCount for buffer allocation.
@ -764,10 +764,23 @@ public:
friend class dtNavMeshQuery; friend class dtNavMeshQuery;
}; };
/// Returns the total size needed for the static pathing table. /// Returns the cell index for the static traversal table.
/// @param[in] numPolyGroups The total number of poly groups. /// @param[in] numPolyGroups The total number of poly groups.
/// @param[in] polyGroup1 The poly group ID of the first island.
/// @param[in] polyGroup2 The poly group ID of the second island.
/// @return The cell index for the static traversal table.
/// @ingroup detour /// @ingroup detour
inline int calcStaticPathingTableSize(const int numPolyGroups) inline int calcTraversalTableCellIndex(const int numPolyGroups,
const unsigned short polyGroup1, const unsigned short polyGroup2)
{
return polyGroup1*((numPolyGroups+31)/32)+(polyGroup2/32);
}
/// Returns the total size needed for the static traversal table.
/// @param[in] numPolyGroups The total number of poly groups.
/// @return the total size needed for the static traversal table.
/// @ingroup detour
inline int calcTraversalTableSize(const int numPolyGroups)
{ {
return sizeof(int)*(numPolyGroups*((numPolyGroups+31)/32)); return sizeof(int)*(numPolyGroups*((numPolyGroups+31)/32));
} }

View File

@ -194,7 +194,7 @@ dtNavMesh::dtNavMesh() :
m_posLookup(0), m_posLookup(0),
m_nextFree(0), m_nextFree(0),
m_tiles(0), m_tiles(0),
m_setTables(0), m_traversalTables(0),
m_someMagicData(0), m_someMagicData(0),
m_meshFlags(0), m_meshFlags(0),
m_tileFlags(0), m_tileFlags(0),
@ -226,15 +226,15 @@ dtNavMesh::~dtNavMesh() // TODO: see [r5apex_ds + F43720] to re-implement this c
rdFree(m_posLookup); rdFree(m_posLookup);
rdFree(m_tiles); rdFree(m_tiles);
for (int i = 0; i < m_params.reachabilityTableCount; i++) for (int i = 0; i < m_params.traversalTableCount; i++)
{ {
int* reachabilityTable = m_setTables[i]; int* traversalTable = m_traversalTables[i];
if (reachabilityTable) if (traversalTable)
rdFree(reachabilityTable); rdFree(traversalTable);
} }
rdFree(m_setTables); rdFree(m_traversalTables);
} }
dtStatus dtNavMesh::init(const dtNavMeshParams* params) dtStatus dtNavMesh::init(const dtNavMeshParams* params)
@ -260,16 +260,16 @@ dtStatus dtNavMesh::init(const dtNavMeshParams* params)
memset(m_tiles, 0, sizeof(dtMeshTile) * m_maxTiles); memset(m_tiles, 0, sizeof(dtMeshTile) * m_maxTiles);
memset(m_posLookup, 0, sizeof(dtMeshTile*) * m_tileLutSize); memset(m_posLookup, 0, sizeof(dtMeshTile*) * m_tileLutSize);
const int reachabilityTableCount = params->reachabilityTableCount; const int traversalTableCount = params->traversalTableCount;
if (reachabilityTableCount) if (traversalTableCount)
{ {
const int setTableBufSize = sizeof(int**)*reachabilityTableCount; const int setTableBufSize = sizeof(int**)*traversalTableCount;
m_setTables = (int**)rdAlloc(setTableBufSize, RD_ALLOC_PERM); m_traversalTables = (int**)rdAlloc(setTableBufSize, RD_ALLOC_PERM);
if (!m_setTables) if (!m_traversalTables)
return DT_FAILURE | DT_OUT_OF_MEMORY; return DT_FAILURE | DT_OUT_OF_MEMORY;
memset(m_setTables, 0, setTableBufSize); memset(m_traversalTables, 0, setTableBufSize);
} }
m_nextFree = 0; m_nextFree = 0;
@ -306,9 +306,9 @@ dtStatus dtNavMesh::init(unsigned char* data, const int dataSize, const int flag
params.tileHeight = header->bmax[1] - header->bmin[1]; params.tileHeight = header->bmax[1] - header->bmin[1];
params.maxTiles = 1; params.maxTiles = 1;
params.maxPolys = header->polyCount; params.maxPolys = header->polyCount;
params.disjointPolyGroupCount = 0; params.polyGroupCount = 0;
params.reachabilityTableSize = 0; params.traversalTableSize = 0;
params.reachabilityTableCount = DT_NUM_REACHABILITY_TABLES; params.traversalTableCount = DT_NUM_TRAVERSAL_TABLES;
params.magicDataCount = 0; params.magicDataCount = 0;
dtStatus status = init(&params); dtStatus status = init(&params);

View File

@ -269,10 +269,10 @@ static unsigned char classifyOffMeshPoint(const float* pt, const float* bmin, co
return 0xff; return 0xff;
} }
static void setPolyGroupsReachability(int* const tableData, const int numPolyGroups, static void setPolyGroupsTraversalReachability(int* const tableData, const int numPolyGroups,
const int polyGroup1, const int polyGroup2, const bool isReachable) const unsigned short polyGroup1, const unsigned short polyGroup2, const bool isReachable)
{ {
const int index = polyGroup1*((numPolyGroups+31)/32)+(polyGroup2/32); const int index = calcTraversalTableCellIndex(numPolyGroups, polyGroup1, polyGroup2);
const int value = 1<<(polyGroup2 & 31); const int value = 1<<(polyGroup2 & 31);
if (isReachable) if (isReachable)
@ -401,39 +401,39 @@ bool dtCreateStaticPathingData(dtNavMesh* nav)
} }
} }
const int tableSize = calcStaticPathingTableSize(numPolyGroups); const int tableSize = calcTraversalTableSize(numPolyGroups);
const int tableCount = DT_NUM_REACHABILITY_TABLES; const int tableCount = DT_NUM_TRAVERSAL_TABLES;
rdAssert(nav->m_setTables); rdAssert(nav->m_traversalTables);
// NOTE: the game allocates 4 reachability table buffers, original // NOTE: the game allocates 4 traversal table buffers, original
// navmeshes have slightly different data per table. Currently ours are all // navmeshes have slightly different data per table. Currently ours are all
// the same. Not a big problem as this just-works, but it might be nice to // the same. Not a big problem as this just-works, but it might be nice to
// figure out why we need 4 tables and what the differences are. // figure out why we need 4 tables and what the differences are.
for (int i = 0; i < tableCount; i++) for (int i = 0; i < tableCount; i++)
{ {
int* const reachabilityTable = (int*)rdAlloc(sizeof(int)*tableSize, RD_ALLOC_PERM); int* const traversalTable = (int*)rdAlloc(sizeof(int)*tableSize, RD_ALLOC_PERM);
if (!reachabilityTable) if (!traversalTable)
return false; return false;
nav->m_setTables[i] = reachabilityTable; nav->m_traversalTables[i] = traversalTable;
memset(reachabilityTable, 0, sizeof(int)*tableSize); memset(traversalTable, 0, sizeof(int)*tableSize);
for (int j = 0; j < numPolyGroups; j++) for (unsigned short j = 0; j < numPolyGroups; j++)
{ {
for (int k = 0; k < numPolyGroups; k++) for (unsigned short k = 0; k < numPolyGroups; k++)
{ {
// Only reachable if its the same polygroup or if they are linked! // Only reachable if its the same polygroup or if they are linked!
const bool isReachable = j == k || data.find(j) == data.find(k); const bool isReachable = j == k || data.find(j) == data.find(k);
setPolyGroupsReachability(reachabilityTable, numPolyGroups, j, k, isReachable); setPolyGroupsTraversalReachability(traversalTable, numPolyGroups, j, k, isReachable);
} }
} }
} }
nav->m_params.disjointPolyGroupCount = numPolyGroups; nav->m_params.polyGroupCount = numPolyGroups;
nav->m_params.reachabilityTableSize = tableSize; nav->m_params.traversalTableSize = tableSize;
nav->m_params.reachabilityTableCount = tableCount; nav->m_params.traversalTableCount = tableCount;
return true; return true;
} }