diff options
Diffstat (limited to 'deps/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp')
-rw-r--r-- | deps/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp | 303 |
1 files changed, 151 insertions, 152 deletions
diff --git a/deps/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp b/deps/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp index fcac11f072..85ad33259c 100644 --- a/deps/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp +++ b/deps/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp @@ -100,7 +100,7 @@ inline float dtQueryFilter::getCost(const float* pa, const float* pb, } #endif -static const float H_SCALE = 2.0f; // Search heuristic scale. +static const float H_SCALE = 0.999f; // Search heuristic scale. dtNavMeshQuery* dtAllocNavMeshQuery() @@ -222,7 +222,10 @@ dtStatus dtNavMeshQuery::findRandomPoint(const dtQueryFilter* filter, float (*fr dtPolyRef* randomRef, float* randomPt) const { dtAssert(m_nav); - + + if (!filter || !frand || !randomRef || !randomPt) + return DT_FAILURE | DT_INVALID_PARAM; + // Randomly pick one tile. Assume that all tiles cover roughly the same area. const dtMeshTile* tile = 0; float tsum = 0.0f; @@ -319,8 +322,13 @@ dtStatus dtNavMeshQuery::findRandomPointAroundCircle(dtPolyRef startRef, const f dtAssert(m_openList); // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + maxRadius < 0 || !dtMathIsfinite(maxRadius) || + !filter || !frand || !randomRef || !randomPt) + { return DT_FAILURE | DT_INVALID_PARAM; + } const dtMeshTile* startTile = 0; const dtPoly* startPoly = 0; @@ -506,85 +514,14 @@ dtStatus dtNavMeshQuery::findRandomPointAroundCircle(dtPolyRef startRef, const f dtStatus dtNavMeshQuery::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const { dtAssert(m_nav); - const dtMeshTile* tile = 0; - const dtPoly* poly = 0; - if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) - return DT_FAILURE | DT_INVALID_PARAM; - if (!tile) - return DT_FAILURE | DT_INVALID_PARAM; - - // Off-mesh connections don't have detail polygons. - if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) - { - const float* v0 = &tile->verts[poly->verts[0]*3]; - const float* v1 = &tile->verts[poly->verts[1]*3]; - const float d0 = dtVdist(pos, v0); - const float d1 = dtVdist(pos, v1); - const float u = d0 / (d0+d1); - dtVlerp(closest, v0, v1, u); - if (posOverPoly) - *posOverPoly = false; - return DT_SUCCESS; - } - - const unsigned int ip = (unsigned int)(poly - tile->polys); - const dtPolyDetail* pd = &tile->detailMeshes[ip]; - - // Clamp point to be inside the polygon. - float verts[DT_VERTS_PER_POLYGON*3]; - float edged[DT_VERTS_PER_POLYGON]; - float edget[DT_VERTS_PER_POLYGON]; - const int nv = poly->vertCount; - for (int i = 0; i < nv; ++i) - dtVcopy(&verts[i*3], &tile->verts[poly->verts[i]*3]); - - dtVcopy(closest, pos); - if (!dtDistancePtPolyEdgesSqr(pos, verts, nv, edged, edget)) - { - // Point is outside the polygon, dtClamp to nearest edge. - float dmin = edged[0]; - int imin = 0; - for (int i = 1; i < nv; ++i) - { - if (edged[i] < dmin) - { - dmin = edged[i]; - imin = i; - } - } - const float* va = &verts[imin*3]; - const float* vb = &verts[((imin+1)%nv)*3]; - dtVlerp(closest, va, vb, edget[imin]); - - if (posOverPoly) - *posOverPoly = false; - } - else + if (!m_nav->isValidPolyRef(ref) || + !pos || !dtVisfinite(pos) || + !closest) { - if (posOverPoly) - *posOverPoly = true; + return DT_FAILURE | DT_INVALID_PARAM; } - // Find height at the location. - for (int j = 0; j < pd->triCount; ++j) - { - const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4]; - const float* v[3]; - for (int k = 0; k < 3; ++k) - { - if (t[k] < poly->vertCount) - v[k] = &tile->verts[poly->verts[t[k]]*3]; - else - v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3]; - } - float h; - if (dtClosestHeightPointTriangle(closest, v[0], v[1], v[2], h)) - { - closest[1] = h; - break; - } - } - + m_nav->closestPointOnPoly(ref, pos, closest, posOverPoly); return DT_SUCCESS; } @@ -607,6 +544,9 @@ dtStatus dtNavMeshQuery::closestPointOnPolyBoundary(dtPolyRef ref, const float* const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; + + if (!pos || !dtVisfinite(pos) || !closest) + return DT_FAILURE | DT_INVALID_PARAM; // Collect vertices. float verts[DT_VERTS_PER_POLYGON*3]; @@ -648,7 +588,7 @@ dtStatus dtNavMeshQuery::closestPointOnPolyBoundary(dtPolyRef ref, const float* /// @par /// -/// Will return #DT_FAILURE if the provided position is outside the xz-bounds +/// Will return #DT_FAILURE | DT_INVALID_PARAM if the provided position is outside the xz-bounds /// of the polygon. /// dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* height) const @@ -659,44 +599,28 @@ dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* h const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; - + + if (!pos || !dtVisfinite2D(pos)) + return DT_FAILURE | DT_INVALID_PARAM; + + // We used to return success for offmesh connections, but the + // getPolyHeight in DetourNavMesh does not do this, so special + // case it here. if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) { const float* v0 = &tile->verts[poly->verts[0]*3]; const float* v1 = &tile->verts[poly->verts[1]*3]; - const float d0 = dtVdist2D(pos, v0); - const float d1 = dtVdist2D(pos, v1); - const float u = d0 / (d0+d1); + float t; + dtDistancePtSegSqr2D(pos, v0, v1, t); if (height) - *height = v0[1] + (v1[1] - v0[1]) * u; + *height = v0[1] + (v1[1] - v0[1])*t; + return DT_SUCCESS; } - else - { - const unsigned int ip = (unsigned int)(poly - tile->polys); - const dtPolyDetail* pd = &tile->detailMeshes[ip]; - for (int j = 0; j < pd->triCount; ++j) - { - const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4]; - const float* v[3]; - for (int k = 0; k < 3; ++k) - { - if (t[k] < poly->vertCount) - v[k] = &tile->verts[poly->verts[t[k]]*3]; - else - v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3]; - } - float h; - if (dtClosestHeightPointTriangle(pos, v[0], v[1], v[2], h)) - { - if (height) - *height = h; - return DT_SUCCESS; - } - } - } - - return DT_FAILURE | DT_INVALID_PARAM; + + return m_nav->getPolyHeight(tile, poly, pos, height) + ? DT_SUCCESS + : DT_FAILURE | DT_INVALID_PARAM; } class dtFindNearestPolyQuery : public dtPolyQuery @@ -767,6 +691,8 @@ dtStatus dtNavMeshQuery::findNearestPoly(const float* center, const float* halfE if (!nearestRef) return DT_FAILURE | DT_INVALID_PARAM; + + // queryPolygons below will check rest of params dtFindNearestPolyQuery query(this, center); @@ -972,8 +898,12 @@ dtStatus dtNavMeshQuery::queryPolygons(const float* center, const float* halfExt { dtAssert(m_nav); - if (!center || !halfExtents || !filter || !query) + if (!center || !dtVisfinite(center) || + !halfExtents || !dtVisfinite(halfExtents) || + !filter || !query) + { return DT_FAILURE | DT_INVALID_PARAM; + } float bmin[3], bmax[3]; dtVsub(bmin, center, halfExtents); @@ -1021,14 +951,20 @@ dtStatus dtNavMeshQuery::findPath(dtPolyRef startRef, dtPolyRef endRef, dtAssert(m_nav); dtAssert(m_nodePool); dtAssert(m_openList); - - if (pathCount) - *pathCount = 0; + + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + + *pathCount = 0; // Validate input if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef) || - !startPos || !endPos || !filter || maxPath <= 0 || !path || !pathCount) + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || !path || maxPath <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } if (startRef == endRef) { @@ -1263,18 +1199,21 @@ dtStatus dtNavMeshQuery::initSlicedFindPath(dtPolyRef startRef, dtPolyRef endRef m_query.status = DT_FAILURE; m_query.startRef = startRef; m_query.endRef = endRef; - dtVcopy(m_query.startPos, startPos); - dtVcopy(m_query.endPos, endPos); + if (startPos) + dtVcopy(m_query.startPos, startPos); + if (endPos) + dtVcopy(m_query.endPos, endPos); m_query.filter = filter; m_query.options = options; m_query.raycastLimitSqr = FLT_MAX; - if (!startRef || !endRef) - return DT_FAILURE | DT_INVALID_PARAM; - // Validate input - if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef)) + if (!m_nav->isValidPolyRef(startRef) || !m_nav->isValidPolyRef(endRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || !filter) + { return DT_FAILURE | DT_INVALID_PARAM; + } // trade quality with performance? if (options & DT_FINDPATH_ANY_ANGLE) @@ -1530,7 +1469,13 @@ dtStatus dtNavMeshQuery::updateSlicedFindPath(const int maxIter, int* doneIters) dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, const int maxPath) { + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + *pathCount = 0; + + if (!path || maxPath <= 0) + return DT_FAILURE | DT_INVALID_PARAM; if (dtStatusFailed(m_query.status)) { @@ -1615,12 +1560,13 @@ dtStatus dtNavMeshQuery::finalizeSlicedFindPath(dtPolyRef* path, int* pathCount, dtStatus dtNavMeshQuery::finalizeSlicedFindPathPartial(const dtPolyRef* existing, const int existingSize, dtPolyRef* path, int* pathCount, const int maxPath) { + if (!pathCount) + return DT_FAILURE | DT_INVALID_PARAM; + *pathCount = 0; - - if (existingSize == 0) - { - return DT_FAILURE; - } + + if (!existing || existingSize <= 0 || !path || !pathCount || maxPath <= 0) + return DT_FAILURE | DT_INVALID_PARAM; if (dtStatusFailed(m_query.status)) { @@ -1823,14 +1769,19 @@ dtStatus dtNavMeshQuery::findStraightPath(const float* startPos, const float* en int* straightPathCount, const int maxStraightPath, const int options) const { dtAssert(m_nav); - - *straightPathCount = 0; - - if (!maxStraightPath) + + if (!straightPathCount) return DT_FAILURE | DT_INVALID_PARAM; - - if (!path[0]) + + *straightPathCount = 0; + + if (!startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !path || pathSize <= 0 || !path[0] || + maxStraightPath <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } dtStatus stat = 0; @@ -2070,13 +2021,19 @@ dtStatus dtNavMeshQuery::moveAlongSurface(dtPolyRef startRef, const float* start dtAssert(m_nav); dtAssert(m_tinyNodePool); - *visitedCount = 0; - - // Validate input - if (!startRef) + if (!visitedCount) return DT_FAILURE | DT_INVALID_PARAM; - if (!m_nav->isValidPolyRef(startRef)) + + *visitedCount = 0; + + if (!m_nav->isValidPolyRef(startRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || !resultPos || !visited || + maxVisitedSize <= 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } dtStatus status = DT_SUCCESS; @@ -2484,16 +2441,23 @@ dtStatus dtNavMeshQuery::raycast(dtPolyRef startRef, const float* startPos, cons dtRaycastHit* hit, dtPolyRef prevRef) const { dtAssert(m_nav); - + + if (!hit) + return DT_FAILURE | DT_INVALID_PARAM; + hit->t = 0; hit->pathCount = 0; hit->pathCost = 0; // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) - return DT_FAILURE | DT_INVALID_PARAM; - if (prevRef && !m_nav->isValidPolyRef(prevRef)) + if (!m_nav->isValidPolyRef(startRef) || + !startPos || !dtVisfinite(startPos) || + !endPos || !dtVisfinite(endPos) || + !filter || + (prevRef && !m_nav->isValidPolyRef(prevRef))) + { return DT_FAILURE | DT_INVALID_PARAM; + } float dir[3], curPos[3], lastPos[3]; float verts[DT_VERTS_PER_POLYGON*3+3]; @@ -2735,11 +2699,18 @@ dtStatus dtNavMeshQuery::findPolysAroundCircle(dtPolyRef startRef, const float* dtAssert(m_nodePool); dtAssert(m_openList); + if (!resultCount) + return DT_FAILURE | DT_INVALID_PARAM; + *resultCount = 0; - - // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + radius < 0 || !dtMathIsfinite(radius) || + !filter || maxResult < 0) + { return DT_FAILURE | DT_INVALID_PARAM; + } m_nodePool->clear(); m_openList->clear(); @@ -2901,8 +2872,18 @@ dtStatus dtNavMeshQuery::findPolysAroundShape(dtPolyRef startRef, const float* v dtAssert(m_nav); dtAssert(m_nodePool); dtAssert(m_openList); - + + if (!resultCount) + return DT_FAILURE | DT_INVALID_PARAM; + *resultCount = 0; + + if (!m_nav->isValidPolyRef(startRef) || + !verts || nverts < 3 || + !filter || maxResult < 0) + { + return DT_FAILURE | DT_INVALID_PARAM; + } // Validate input if (!startRef || !m_nav->isValidPolyRef(startRef)) @@ -3088,13 +3069,20 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* { dtAssert(m_nav); dtAssert(m_tinyNodePool); - + + if (!resultCount) + return DT_FAILURE | DT_INVALID_PARAM; + *resultCount = 0; - // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + radius < 0 || !dtMathIsfinite(radius) || + !filter || maxResult < 0) + { return DT_FAILURE | DT_INVALID_PARAM; - + } + static const int MAX_STACK = 48; dtNode* stack[MAX_STACK]; int nstack = 0; @@ -3301,13 +3289,19 @@ dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* const int maxSegments) const { dtAssert(m_nav); + + if (!segmentCount) + return DT_FAILURE | DT_INVALID_PARAM; *segmentCount = 0; - + const dtMeshTile* tile = 0; const dtPoly* poly = 0; if (dtStatusFailed(m_nav->getTileAndPolyByRef(ref, &tile, &poly))) return DT_FAILURE | DT_INVALID_PARAM; + + if (!filter || !segmentVerts || maxSegments < 0) + return DT_FAILURE | DT_INVALID_PARAM; int n = 0; static const int MAX_INTERVAL = 16; @@ -3455,8 +3449,13 @@ dtStatus dtNavMeshQuery::findDistanceToWall(dtPolyRef startRef, const float* cen dtAssert(m_openList); // Validate input - if (!startRef || !m_nav->isValidPolyRef(startRef)) + if (!m_nav->isValidPolyRef(startRef) || + !centerPos || !dtVisfinite(centerPos) || + maxRadius < 0 || !dtMathIsfinite(maxRadius) || + !filter || !hitDist || !hitPos || !hitNormal) + { return DT_FAILURE | DT_INVALID_PARAM; + } m_nodePool->clear(); m_openList->clear(); |