Recast: separate disjoint set remap code from creation code

We need to create the disjoint sets first, then build all traverse links, and finally from there determine all unlinked poly's and remap disjoint sets. Doing this prior to traverse link generation causes polygons that are only linked through traverse links to remain tagged as unlinked.
This commit is contained in:
Kawe Mazidjatari 2024-08-11 12:54:48 +02:00
parent 2bc4dc9c3f
commit 0a88d801a0
3 changed files with 69 additions and 41 deletions

View File

@ -710,6 +710,11 @@ void Editor::buildStaticPathingData()
m_ctx->log(RC_LOG_ERROR, "buildStaticPathingData: Failed to build traverse links.");
}
if (!dtUpdateDisjointPolyGroups(m_navMesh, data))
{
m_ctx->log(RC_LOG_ERROR, "buildStaticPathingData: Failed to update disjoint poly groups.");
}
if (!dtCreateTraverseTableData(m_navMesh, data, NavMesh_GetTraverseTableCountForNavMeshType(m_selectedNavMeshType)))
{
m_ctx->log(RC_LOG_ERROR, "buildStaticPathingData: Failed to build traverse table data.");

View File

@ -182,6 +182,13 @@ private:
/// @return True if the disjoint set data was successfully created.
bool dtCreateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint);
/// Updates navigation mesh disjoint poly groups from the provided navmesh.
/// @ingroup detour
/// @param[in] nav The navigation mesh to use.
/// @param[Out] disjoint The disjoint set data.
/// @return True if the disjoint set data was successfully updated.
bool dtUpdateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint);
/// Builds navigation mesh static traverse table from the provided navmesh.
/// @ingroup detour
/// @param[in] nav The navigation mesh to use.

View File

@ -277,7 +277,7 @@ bool dtCreateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint)
}
}
// First pass to group linked and unlinked poly islands.
// First pass to group poly islands.
std::set<unsigned short> linkedGroups;
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
@ -315,14 +315,7 @@ bool dtCreateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint)
const bool noLinkedGroups = linkedGroups.empty();
if (noLinkedGroups)
{
// This poly isn't connected to anything, mark it so the game
// won't consider this poly in path generation.
if (poly.firstLink == DT_NULL_LINK)
poly.groupId = DT_STRAY_POLY_GROUP;
else
poly.groupId = (unsigned short)disjoint.insertNew();
}
poly.groupId = (unsigned short)disjoint.insertNew();
else
{
const unsigned short rootGroup = *linkedGroups.begin();
@ -354,38 +347,6 @@ bool dtCreateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint)
}
}
// Gather all unique polygroups and map them to a contiguous range.
std::map<unsigned short, unsigned short> groupMap;
disjoint.init(DT_FIRST_USABLE_POLY_GROUP);
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
{
dtPoly& poly = tile->polys[j];
unsigned short oldId = poly.groupId;
if (oldId != DT_STRAY_POLY_GROUP && groupMap.find(oldId) == groupMap.end())
groupMap[oldId] = (unsigned short)disjoint.insertNew();
}
}
// Fourth pass to apply the new mapping to all polys.
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
{
dtPoly& poly = tile->polys[j];
if (poly.groupId != DT_STRAY_POLY_GROUP)
poly.groupId = groupMap[poly.groupId];
}
}
// Third pass to handle off-mesh connections.
// note(amos): this has to happen after the first and second pass as these
// are for grouping directly connected polygons together, else groups linked
@ -433,6 +394,61 @@ bool dtCreateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint)
return true;
}
bool dtUpdateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint)
{
// Fourth pass to mark all unlinked poly's.
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
{
dtPoly& poly = tile->polys[j];
// This poly isn't connected to anything, mark it so the game
// won't consider this poly in path generation.
if (poly.firstLink == DT_NULL_LINK)
poly.groupId = DT_STRAY_POLY_GROUP;
}
}
// Gather all unique polygroups and map them to a contiguous range.
std::map<unsigned short, unsigned short> groupMap;
disjoint.init(DT_FIRST_USABLE_POLY_GROUP);
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
{
dtPoly& poly = tile->polys[j];
unsigned short oldId = poly.groupId;
if (oldId != DT_STRAY_POLY_GROUP && groupMap.find(oldId) == groupMap.end())
groupMap[oldId] = (unsigned short)disjoint.insertNew();
}
}
// Apply the new mapping to all polys.
for (int i = 0; i < nav->getMaxTiles(); ++i)
{
dtMeshTile* tile = nav->getTile(i);
if (!tile || !tile->header || !tile->dataSize) continue;
const int pcount = tile->header->polyCount;
for (int j = 0; j < pcount; j++)
{
dtPoly& poly = tile->polys[j];
if (poly.groupId != DT_STRAY_POLY_GROUP)
poly.groupId = groupMap[poly.groupId];
}
}
nav->setPolyGroupcount(disjoint.getSetCount());
return true;
}
// todo(amos): remove param 'tableCount' and make struct 'dtTraverseTableCreateParams'
bool dtCreateTraverseTableData(dtNavMesh* nav, const dtDisjointSet& disjoint, const int tableCount)
{