From cad8f043e5d383005cb0a95617b1d9c50e58e0b9 Mon Sep 17 00:00:00 2001 From: Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> Date: Sat, 10 Aug 2024 01:37:49 +0200 Subject: [PATCH] Recast: move traverse link generation logic to the Editor class We need access to the input geometry and other intermediate data to properly generate them. --- src/naveditor/Editor.cpp | 317 +++++++++++++++++- src/naveditor/include/Editor.h | 4 + .../Detour/Include/DetourNavMeshBuilder.h | 6 - .../Detour/Source/DetourNavMeshBuilder.cpp | 315 ----------------- 4 files changed, 320 insertions(+), 322 deletions(-) diff --git a/src/naveditor/Editor.cpp b/src/naveditor/Editor.cpp index 2d0ec0f0..2ac9fe96 100644 --- a/src/naveditor/Editor.cpp +++ b/src/naveditor/Editor.cpp @@ -354,6 +354,321 @@ void Editor::handleUpdate(const float dt) updateToolStates(dt); } +enum TraverseType_e // todo(amos): move elsewhere +{ + TRAVERSE_UNUSED_0 = 0, + + TRAVERSE_CROSS_GAP_SMALL, + TRAVERSE_CLIMB_OBJECT_SMALL, + TRAVERSE_CROSS_GAP_MEDIUM, + + TRAVERSE_UNUSED_4, + TRAVERSE_UNUSED_5, + TRAVERSE_UNUSED_6, + + TRAVERSE_CROSS_GAP_LARGE, + + TRAVERSE_CLIMB_WALL_MEDIUM, + TRAVERSE_CLIMB_WALL_TALL, + TRAVERSE_CLIMB_BUILDING, + + TRAVERSE_JUMP_SHORT, + TRAVERSE_JUMP_MEDIUM, + TRAVERSE_JUMP_LARGE, + + TRAVERSE_UNUSED_14, + TRAVERSE_UNUSED_15, + + TRAVERSE_UNKNOWN_16, // USED!!! + TRAVERSE_UNKNOWN_17, // USED!!! + + TRAVERSE_UNKNOWN_18, + TRAVERSE_UNKNOWN_19, // NOTE: does not exists in MSET5!!! + + TRAVERSE_CLIMB_TARGET_SMALL, + TRAVERSE_CLIMB_TARGET_LARGE, + + TRAVERSE_UNUSED_22, + TRAVERSE_UNUSED_23, + + TRAVERSE_UNKNOWN_24, + + TRAVERSE_UNUSED_25, + TRAVERSE_UNUSED_26, + TRAVERSE_UNUSED_27, + TRAVERSE_UNUSED_28, + TRAVERSE_UNUSED_29, + TRAVERSE_UNUSED_30, + TRAVERSE_UNUSED_31, + + // These aren't traverse type! + NUM_TRAVERSE_TYPES, + INVALID_TRAVERSE_TYPE = DT_NULL_TRAVERSE_TYPE +}; + +struct TraverseType_s // todo(amos): move elsewhere +{ + float minSlope; + float maxSlope; + + unsigned char minDist; + unsigned char maxDist; + + bool forceSamePolyGroup; + bool forceDifferentPolyGroup; +}; + +static TraverseType_s s_traverseTypes[NUM_TRAVERSE_TYPES] = // todo(amos): move elsewhere +{ + {0.0f, 0.0f, 0, 0, false, false}, // Unused + + {0.0f, 67.f, 2, 12, false, false }, + {5.0f, 78.f, 5, 16, false, false }, + {0.0f, 38.f, 11, 22, false, false }, + + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + + {0.0f, 6.5f, 80, 107, false, true}, + {19.0f, 84.0f, 7, 21, false, false}, + {27.0f, 87.5f, 16, 45, false, false}, + {44.0f, 89.5f, 33, 225, false, false}, + {0.0f, 7.0f, 41, 79, false, false}, + {2.2f, 47.0f, 41, 100, false, false}, + {5.7f, 58.5f, 81, 179, false, false}, + + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + + {0.0f, 12.5f, 22, 41, false, false}, + {4.6f, 53.0f, 21, 58, false, false}, + + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + + {29.0f, 47.0f, 16, 40, false, false}, // Maps to type 19 in MSET 5 + {46.5f, 89.0f, 33, 199, false, false}, // Maps to type 20 in MSET 5 + + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + + {0.0f, 89.0f, 5, 251, false, false}, // Does not exist in MSET 5 + + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused + {0.0f, 0.0f, 0, 0, false, false}, // Unused +}; + +TraverseType_e GetBestTraverseType(const float slopeAngle, const unsigned char traverseDist, const bool samePolyGroup) +{ + TraverseType_e bestTraverseType = INVALID_TRAVERSE_TYPE; + + for (int i = 0; i < NUM_TRAVERSE_TYPES; ++i) + { + const TraverseType_s& traverseType = s_traverseTypes[i]; + + // Skip unused types... + if (traverseType.minSlope == 0.0f && traverseType.maxSlope == 0.0f && + traverseType.minDist == 0 && traverseType.maxDist == 0) + { + continue; + } + + if (slopeAngle < traverseType.minSlope || + slopeAngle > traverseType.maxSlope) + { + continue; + } + + if (traverseDist < traverseType.minDist || + traverseDist > traverseType.maxDist) + { + continue; + } + + // NOTE: currently only type 7 is enforced in this check, perhaps we + // should limit some other types on same/diff poly groups as well? + if ((traverseType.forceSamePolyGroup && !samePolyGroup) || + (traverseType.forceDifferentPolyGroup && samePolyGroup)) + { + continue; + } + + bestTraverseType = (TraverseType_e)i; + break; + } + + return bestTraverseType; +} + +bool CanOverlapPoly(const TraverseType_e traverseType) +{ + // todo(amos): find the best threshold... + return s_traverseTypes[traverseType].minSlope > 5.0f; +} + +// TODO: create lookup table and look for distance + slope to determine the +// correct jumpType. +// TODO: make sure we don't generate duplicate pairs of jump types between +// 2 polygons. +void Editor::connectTileTraverseLinks(dtMeshTile* const tile) +{ + for (int i = 0; i < tile->header->polyCount; ++i) + { + dtPoly* const startPoly = &tile->polys[i]; + + for (int j = 0; j < startPoly->vertCount; ++j) + { + // Hard edges only! + if (startPoly->neis[j] != 0) + continue; + + // Polygon 1 edge + const float* const startPolySpos = &tile->verts[startPoly->verts[j] * 3]; + const float* const startPolyEpos = &tile->verts[startPoly->verts[(j + 1) % startPoly->vertCount] * 3]; + + float startPolyEdgeMid[3]; + rdVsad(startPolyEdgeMid, startPolySpos, startPolyEpos, 0.5f); + + float startEdgeDir[3]; + rdVsub(startEdgeDir, startPolyEpos, startPolySpos); + + for (int k = 0; k < tile->header->polyCount; ++k) + { + if (i == k) continue; // Skip self + + dtPoly* const endPoly = &tile->polys[k]; + + for (int m = 0; m < endPoly->vertCount; ++m) + { + // Hard edges only! + if (endPoly->neis[m] != 0) + continue; + + // Polygon 2 edge + const float* const endPolySpos = &tile->verts[endPoly->verts[m] * 3]; + const float* const endPolyEpos = &tile->verts[endPoly->verts[(m + 1) % endPoly->vertCount] * 3]; + + float endPolyEdgeMid[3]; + rdVsad(endPolyEdgeMid, endPolySpos, endPolyEpos, 0.5f); + + float endEdgeDir[3]; + rdVsub(endEdgeDir, endPolyEpos, endPolySpos); + + const float dotProduct = rdVdot(startEdgeDir, endEdgeDir); + + // Edges facing the same direction should not be linked. + // Doing so causes links to go through from underneath + // geometry. E.g. we have an HVAC on a roof, and we try + // to link our roof poly edge facing north to the edge + // of the poly on the HVAC also facing north, the link + // will go through the HVAC and thus cause the NPC to + // jump through it. + if (dotProduct > 0) + continue; + + float t, s; + if (rdIntersectSegSeg2D(startPolySpos, startPolyEpos, endPolySpos, endPolyEpos, t, s)) + continue; + + const unsigned char distance = dtCalcLinkDistance(startPolyEdgeMid, endPolyEdgeMid); + const float slopeAngle = rdMathFabsf(rdCalcSlopeAngle(startPolyEdgeMid, endPolyEdgeMid)); + const bool samePolyGroup = startPoly->groupId == endPoly->groupId; + + const TraverseType_e traverseType = GetBestTraverseType(slopeAngle, distance, samePolyGroup); + + if (!CanOverlapPoly(traverseType)) + { + bool overlaps = false; + + float linkMidPoint[3]; + rdVsad(linkMidPoint, startPolyEdgeMid, endPolyEdgeMid, 0.5f); + + for (int e = 0; e < tile->header->polyCount; e++) + { + const dtPoly* posTestPoly = &tile->polys[e]; + float polyVerts[DT_VERTS_PER_POLYGON * 3]; + + const int nverts = posTestPoly->vertCount; + for (int o = 0; o < nverts; ++o) + rdVcopy(&polyVerts[o * 3], &tile->verts[posTestPoly->verts[o] * 3]); + + if (rdPointInPolygon(linkMidPoint, polyVerts, nverts)) + { + overlaps = true; + break; + } + } + + if (overlaps) + continue; + } + + if (traverseType != DT_NULL_TRAVERSE_TYPE) + { + // Need at least 2 links + const unsigned int forwardIdx = tile->allocLink(); + + if (forwardIdx == DT_NULL_LINK) // TODO: should move on to next tile. + continue; + + const unsigned int reverseIdx = tile->allocLink(); + + if (reverseIdx == DT_NULL_LINK) // TODO: should move on to next tile. + { + tile->freeLink(forwardIdx); + continue; + } + + dtLink* const forwardLink = &tile->links[forwardIdx]; + + forwardLink->ref = m_navMesh->getPolyRefBase(tile) | (dtPolyRef)k; + forwardLink->edge = (unsigned char)j; + forwardLink->side = 0xFF; + forwardLink->next = startPoly->firstLink; + startPoly->firstLink = forwardIdx; + forwardLink->traverseType = (unsigned char)traverseType; + forwardLink->traverseDist = distance; + + dtLink* const reverseLink = &tile->links[reverseIdx]; + + reverseLink->ref = m_navMesh->getPolyRefBase(tile) | (dtPolyRef)i; + reverseLink->edge = (unsigned char)m; + reverseLink->side = 0xFF; + reverseLink->next = endPoly->firstLink; + endPoly->firstLink = reverseIdx; + reverseLink->traverseType = (unsigned char)traverseType; + reverseLink->traverseDist = distance; + + forwardLink->reverseLink = (unsigned short)reverseIdx; + reverseLink->reverseLink = (unsigned short)forwardIdx; + } + } + } + } + } +} + +bool Editor::createTraverseLinks() +{ + rdAssert(m_navMesh); + + for (int i = 0; i < m_navMesh->getMaxTiles(); i++) + { + dtMeshTile* tile = m_navMesh->getTile(i); + if (!tile->header) continue; + + connectTileTraverseLinks(tile); + } + + return true; +} + void Editor::buildStaticPathingData() { if (!m_navMesh) return; @@ -365,7 +680,7 @@ void Editor::buildStaticPathingData() m_ctx->log(RC_LOG_ERROR, "buildStaticPathingData: Failed to build disjoint poly groups."); } - if (!dtCreateTraverseLinks(m_navMesh)) + if (!createTraverseLinks()) { m_ctx->log(RC_LOG_ERROR, "buildStaticPathingData: Failed to build traverse links."); } diff --git a/src/naveditor/include/Editor.h b/src/naveditor/include/Editor.h index 860262cb..c75a81ff 100644 --- a/src/naveditor/include/Editor.h +++ b/src/naveditor/include/Editor.h @@ -24,6 +24,8 @@ #include "game/server/ai_navmesh.h" +struct dtMeshTile; + struct hulldef { const char* name; @@ -242,6 +244,8 @@ public: void resetCommonSettings(); void handleCommonSettings(); + void connectTileTraverseLinks(dtMeshTile* const tile); // Make private. + bool createTraverseLinks(); void buildStaticPathingData(); private: diff --git a/src/thirdparty/recast/Detour/Include/DetourNavMeshBuilder.h b/src/thirdparty/recast/Detour/Include/DetourNavMeshBuilder.h index be11137f..5ab82f37 100644 --- a/src/thirdparty/recast/Detour/Include/DetourNavMeshBuilder.h +++ b/src/thirdparty/recast/Detour/Include/DetourNavMeshBuilder.h @@ -182,12 +182,6 @@ private: /// @return True if the disjoint set data was successfully created. bool dtCreateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint); -/// Builds navigation mesh traverse links from the provided navmesh. -/// @ingroup detour -/// @param[in] nav The navigation mesh to use. -/// @return True if the traverse links were successfully created. -bool dtCreateTraverseLinks(dtNavMesh* nav); - /// Builds navigation mesh static traverse table from the provided navmesh. /// @ingroup detour /// @param[in] nav The navigation mesh to use. diff --git a/src/thirdparty/recast/Detour/Source/DetourNavMeshBuilder.cpp b/src/thirdparty/recast/Detour/Source/DetourNavMeshBuilder.cpp index dfa1a85a..1835ba45 100644 --- a/src/thirdparty/recast/Detour/Source/DetourNavMeshBuilder.cpp +++ b/src/thirdparty/recast/Detour/Source/DetourNavMeshBuilder.cpp @@ -461,321 +461,6 @@ bool dtCreateDisjointPolyGroups(dtNavMesh* nav, dtDisjointSet& disjoint) return true; } -enum TraverseType_e // todo(amos): move elsewhere -{ - TRAVERSE_UNUSED_0 = 0, - - TRAVERSE_CROSS_GAP_SMALL, - TRAVERSE_CLIMB_OBJECT_SMALL, - TRAVERSE_CROSS_GAP_MEDIUM, - - TRAVERSE_UNUSED_4, - TRAVERSE_UNUSED_5, - TRAVERSE_UNUSED_6, - - TRAVERSE_CROSS_GAP_LARGE, - - TRAVERSE_CLIMB_WALL_MEDIUM, - TRAVERSE_CLIMB_WALL_TALL, - TRAVERSE_CLIMB_BUILDING, - - TRAVERSE_JUMP_SHORT, - TRAVERSE_JUMP_MEDIUM, - TRAVERSE_JUMP_LARGE, - - TRAVERSE_UNUSED_14, - TRAVERSE_UNUSED_15, - - TRAVERSE_UNKNOWN_16, // USED!!! - TRAVERSE_UNKNOWN_17, // USED!!! - - TRAVERSE_UNKNOWN_18, - TRAVERSE_UNKNOWN_19, // NOTE: does not exists in MSET5!!! - - TRAVERSE_CLIMB_TARGET_SMALL, - TRAVERSE_CLIMB_TARGET_LARGE, - - TRAVERSE_UNUSED_22, - TRAVERSE_UNUSED_23, - - TRAVERSE_UNKNOWN_24, - - TRAVERSE_UNUSED_25, - TRAVERSE_UNUSED_26, - TRAVERSE_UNUSED_27, - TRAVERSE_UNUSED_28, - TRAVERSE_UNUSED_29, - TRAVERSE_UNUSED_30, - TRAVERSE_UNUSED_31, - - // These aren't traverse type! - NUM_TRAVERSE_TYPES, - INVALID_TRAVERSE_TYPE = DT_NULL_TRAVERSE_TYPE -}; - -struct TraverseType_s // todo(amos): move elsewhere -{ - float minSlope; - float maxSlope; - - unsigned char minDist; - unsigned char maxDist; - - bool forceSamePolyGroup; - bool forceDifferentPolyGroup; -}; - -static TraverseType_s s_traverseTypes[NUM_TRAVERSE_TYPES] = // todo(amos): move elsewhere -{ - {0.0f, 0.0f, 0, 0, false, false}, // Unused - - {0.0f, 67.f, 2, 12, false, false }, - {5.0f, 78.f, 5, 16, false, false }, - {0.0f, 38.f, 11, 22, false, false }, - - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - - {0.0f, 6.5f, 80, 107, false, true}, - {19.0f, 84.0f, 7, 21, false, false}, - {27.0f, 87.5f, 16, 45, false, false}, - {44.0f, 89.5f, 33, 225, false, false}, - {0.0f, 7.0f, 41, 79, false, false}, - {2.2f, 47.0f, 41, 100, false, false}, - {5.7f, 58.5f, 81, 179, false, false}, - - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - - {0.0f, 12.5f, 22, 41, false, false}, - {4.6f, 53.0f, 21, 58, false, false}, - - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - - {29.0f, 47.0f, 16, 40, false, false}, // Maps to type 19 in MSET 5 - {46.5f, 89.0f, 33, 199, false, false}, // Maps to type 20 in MSET 5 - - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - - {0.0f, 89.0f, 5, 251, false, false}, // Does not exist in MSET 5 - - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused - {0.0f, 0.0f, 0, 0, false, false}, // Unused -}; - -TraverseType_e GetBestTraverseType(const float slopeAngle, const unsigned char traverseDist, const bool samePolyGroup) -{ - TraverseType_e bestTraverseType = INVALID_TRAVERSE_TYPE; - - for (int i = 0; i < NUM_TRAVERSE_TYPES; ++i) - { - const TraverseType_s& traverseType = s_traverseTypes[i]; - - // Skip unused types... - if (traverseType.minSlope == 0.0f && traverseType.maxSlope == 0.0f && - traverseType.minDist == 0 && traverseType.maxDist == 0) - { - continue; - } - - if (slopeAngle < traverseType.minSlope || - slopeAngle > traverseType.maxSlope) - { - continue; - } - - if (traverseDist < traverseType.minDist || - traverseDist > traverseType.maxDist) - { - continue; - } - - // NOTE: currently only type 7 is enforced in this check, perhaps we - // should limit some other types on same/diff poly groups as well? - if ((traverseType.forceSamePolyGroup && !samePolyGroup) || - (traverseType.forceDifferentPolyGroup && samePolyGroup)) - { - continue; - } - - bestTraverseType = (TraverseType_e)i; - break; - } - - return bestTraverseType; -} - -bool CanOverlapPoly(const TraverseType_e traverseType) -{ - // todo(amos): find the best threshold... - return s_traverseTypes[traverseType].minSlope > 5.0f; -} - -// TODO: create lookup table and look for distance + slope to determine the -// correct jumpType. -// TODO: make sure we don't generate duplicate pairs of jump types between -// 2 polygons. -static void connectTileTraverseLinks(dtNavMesh* const nav, dtMeshTile* const tile) -{ - for (int i = 0; i < tile->header->polyCount; ++i) - { - dtPoly* const startPoly = &tile->polys[i]; - - for (int j = 0; j < startPoly->vertCount; ++j) - { - // Hard edges only! - if (startPoly->neis[j] != 0) - continue; - - // Polygon 1 edge - const float* const startPolySpos = &tile->verts[startPoly->verts[j] * 3]; - const float* const startPolyEpos = &tile->verts[startPoly->verts[(j + 1) % startPoly->vertCount] * 3]; - - float startPolyEdgeMid[3]; - rdVsad(startPolyEdgeMid, startPolySpos, startPolyEpos, 0.5f); - - float startEdgeDir[3]; - rdVsub(startEdgeDir, startPolyEpos, startPolySpos); - - for (int k = 0; k < tile->header->polyCount; ++k) - { - if (i == k) continue; // Skip self - - dtPoly* const endPoly = &tile->polys[k]; - - for (int m = 0; m < endPoly->vertCount; ++m) - { - // Hard edges only! - if (endPoly->neis[m] != 0) - continue; - - // Polygon 2 edge - const float* const endPolySpos = &tile->verts[endPoly->verts[m] * 3]; - const float* const endPolyEpos = &tile->verts[endPoly->verts[(m + 1) % endPoly->vertCount] * 3]; - - float endPolyEdgeMid[3]; - rdVsad(endPolyEdgeMid, endPolySpos, endPolyEpos, 0.5f); - - float endEdgeDir[3]; - rdVsub(endEdgeDir, endPolyEpos, endPolySpos); - - const float dotProduct = rdVdot(startEdgeDir, endEdgeDir); - - // Edges facing the same direction should not be linked. - // Doing so causes links to go through from underneath - // geometry. E.g. we have an HVAC on a roof, and we try - // to link our roof poly edge facing north to the edge - // of the poly on the HVAC also facing north, the link - // will go through the HVAC and thus cause the NPC to - // jump through it. - if (dotProduct > 0) - continue; - - float t, s; - if (rdIntersectSegSeg2D(startPolySpos, startPolyEpos, endPolySpos, endPolyEpos, t, s)) - continue; - - const unsigned char distance = dtCalcLinkDistance(startPolyEdgeMid, endPolyEdgeMid); - const float slopeAngle = rdMathFabsf(rdCalcSlopeAngle(startPolyEdgeMid, endPolyEdgeMid)); - const bool samePolyGroup = startPoly->groupId == endPoly->groupId; - - const TraverseType_e traverseType = GetBestTraverseType(slopeAngle, distance, samePolyGroup); - - if (!CanOverlapPoly(traverseType)) - { - bool overlaps = false; - - float linkMidPoint[3]; - rdVsad(linkMidPoint, startPolyEdgeMid, endPolyEdgeMid, 0.5f); - - for (int e = 0; e < tile->header->polyCount; e++) - { - const dtPoly* posTestPoly = &tile->polys[e]; - float polyVerts[DT_VERTS_PER_POLYGON*3]; - - const int nverts = posTestPoly->vertCount; - for (int o = 0; o < nverts; ++o) - rdVcopy(&polyVerts[o * 3], &tile->verts[posTestPoly->verts[o] * 3]); - - if (rdPointInPolygon(linkMidPoint, polyVerts, nverts)) - { - overlaps = true; - break; - } - } - - if (overlaps) - continue; - } - - if (traverseType != DT_NULL_TRAVERSE_TYPE) - { - // Need at least 2 links - const unsigned int forwardIdx = tile->allocLink(); - - if (forwardIdx == DT_NULL_LINK) // TODO: should move on to next tile. - continue; - - const unsigned int reverseIdx = tile->allocLink(); - - if (reverseIdx == DT_NULL_LINK) // TODO: should move on to next tile. - { - tile->freeLink(forwardIdx); - continue; - } - - dtLink* const forwardLink = &tile->links[forwardIdx]; - - forwardLink->ref = nav->getPolyRefBase(tile) | (dtPolyRef)k; - forwardLink->edge = (unsigned char)j; - forwardLink->side = 0xFF; - forwardLink->next = startPoly->firstLink; - startPoly->firstLink = forwardIdx; - forwardLink->traverseType = (unsigned char)traverseType; - forwardLink->traverseDist = distance; - - dtLink* const reverseLink = &tile->links[reverseIdx]; - - reverseLink->ref = nav->getPolyRefBase(tile) | (dtPolyRef)i; - reverseLink->edge = (unsigned char)m; - reverseLink->side = 0xFF; - reverseLink->next = endPoly->firstLink; - endPoly->firstLink = reverseIdx; - reverseLink->traverseType = (unsigned char)traverseType; - reverseLink->traverseDist = distance; - - forwardLink->reverseLink = (unsigned short)reverseIdx; - reverseLink->reverseLink = (unsigned short)forwardIdx; - } - } - } - } - } -} - -bool dtCreateTraverseLinks(dtNavMesh* nav) -{ - rdAssert(nav); - - for (int i = 0; i < nav->getMaxTiles(); i++) - { - dtMeshTile* tile = nav->getTile(i); - if (!tile->header) continue; - - connectTileTraverseLinks(nav, tile); - } - - return true; -} - // todo(amos): remove param 'tableCount' and make struct 'dtTraverseTableCreateParams' bool dtCreateTraverseTableData(dtNavMesh* nav, const dtDisjointSet& disjoint, const int tableCount) {