diff --git a/extern/recastnavigation/.gitignore b/extern/recastnavigation/.gitignore index 7c12d58f06..98f17e4b73 100644 --- a/extern/recastnavigation/.gitignore +++ b/extern/recastnavigation/.gitignore @@ -9,6 +9,16 @@ *.so *.idb +## Linux exes have no extension +RecastDemo/Bin/RecastDemo +RecastDemo/Bin/Tests + +# Build directory +RecastDemo/Build + +# Ignore meshes +RecastDemo/Bin/Meshes/* + ## Logs and databases # *.log *.sql @@ -28,6 +38,9 @@ Thumbs.db ## xcode specific *xcuserdata* +## SDL contrib +RecastDemo/Contrib/SDL/* + ## Generated doc files Docs/html diff --git a/extern/recastnavigation/.id b/extern/recastnavigation/.id index 4ff8c7be69..f15ce513c2 100644 --- a/extern/recastnavigation/.id +++ b/extern/recastnavigation/.id @@ -1 +1 @@ -3087e805b02d5eb8fff7851234fa2b3f71290eba +c40188c796f089f89a42e0b939d934178dbcfc5c diff --git a/extern/recastnavigation/DebugUtils/Source/DetourDebugDraw.cpp b/extern/recastnavigation/DebugUtils/Source/DetourDebugDraw.cpp index dd4bad3fd1..4ca0581c77 100644 --- a/extern/recastnavigation/DebugUtils/Source/DetourDebugDraw.cpp +++ b/extern/recastnavigation/DebugUtils/Source/DetourDebugDraw.cpp @@ -101,7 +101,9 @@ static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshTile* tile, } for (int m = 0, n = 2; m < 3; n=m++) { - if (((t[3] >> (n*2)) & 0x3) == 0) continue; // Skip inner detail edges. + if ((dtGetDetailTriEdgeFlags(t[3], n) & DT_DETAIL_EDGE_BOUNDARY) == 0) + continue; + if (distancePtLine2d(tv[n],v0,v1) < thr && distancePtLine2d(tv[m],v0,v1) < thr) { diff --git a/extern/recastnavigation/Detour/Include/DetourNavMesh.h b/extern/recastnavigation/Detour/Include/DetourNavMesh.h index 02ee5e78c1..98293c49dc 100644 --- a/extern/recastnavigation/Detour/Include/DetourNavMesh.h +++ b/extern/recastnavigation/Detour/Include/DetourNavMesh.h @@ -130,6 +130,11 @@ enum dtRaycastOptions DT_RAYCAST_USE_COSTS = 0x01, ///< Raycast should calculate movement cost along the ray and fill RaycastHit::cost }; +enum dtDetailTriEdgeFlags +{ + DT_DETAIL_EDGE_BOUNDARY = 0x01, ///< Detail triangle edge is part of the poly boundary +}; + /// Limit raycasting during any angle pahfinding /// The limit is given as a multiple of the character radius @@ -287,7 +292,8 @@ struct dtMeshTile /// The detail mesh's unique vertices. [(x, y, z) * dtMeshHeader::detailVertCount] float* detailVerts; - /// The detail mesh's triangles. [(vertA, vertB, vertC) * dtMeshHeader::detailTriCount] + /// The detail mesh's triangles. [(vertA, vertB, vertC, triFlags) * dtMeshHeader::detailTriCount]. + /// See dtDetailTriEdgeFlags and dtGetDetailTriEdgeFlags. unsigned char* detailTris; /// The tile bounding volume nodes. [Size: dtMeshHeader::bvNodeCount] @@ -305,6 +311,15 @@ private: dtMeshTile& operator=(const dtMeshTile&); }; +/// Get flags for edge in detail triangle. +/// @param triFlags[in] The flags for the triangle (last component of detail vertices above). +/// @param edgeIndex[in] The index of the first vertex of the edge. For instance, if 0, +/// returns flags for edge AB. +inline int dtGetDetailTriEdgeFlags(unsigned char triFlags, int edgeIndex) +{ + return (triFlags >> (edgeIndex * 2)) & 0x3; +} + /// Configuration parameters used to define multi-tile navigation meshes. /// The values are used to allocate space during the initialization of a navigation mesh. /// @see dtNavMesh::init() @@ -636,6 +651,8 @@ private: /// Find nearest polygon within a tile. dtPolyRef findNearestPolyInTile(const dtMeshTile* tile, const float* center, const float* halfExtents, float* nearestPt) const; + /// Returns whether position is over the poly and the height at the position if so. + bool getPolyHeight(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* height) const; /// Returns closest point on polygon. void closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const; @@ -655,6 +672,8 @@ private: unsigned int m_tileBits; ///< Number of tile bits in the tile ID. unsigned int m_polyBits; ///< Number of poly bits in the tile ID. #endif + + friend class dtNavMeshQuery; }; /// Allocates a navigation mesh object using the Detour allocator. diff --git a/extern/recastnavigation/Detour/Include/DetourNavMeshQuery.h b/extern/recastnavigation/Detour/Include/DetourNavMeshQuery.h index 1c23e4857b..0b40371beb 100644 --- a/extern/recastnavigation/Detour/Include/DetourNavMeshQuery.h +++ b/extern/recastnavigation/Detour/Include/DetourNavMeshQuery.h @@ -119,8 +119,6 @@ public: }; - - /// Provides information about raycast hit /// filled by dtNavMeshQuery::raycast /// @ingroup detour diff --git a/extern/recastnavigation/Detour/Source/DetourCommon.cpp b/extern/recastnavigation/Detour/Source/DetourCommon.cpp index 3886f14b04..b89d7512c4 100644 --- a/extern/recastnavigation/Detour/Source/DetourCommon.cpp +++ b/extern/recastnavigation/Detour/Source/DetourCommon.cpp @@ -203,14 +203,18 @@ void dtCalcPolyCenter(float* tc, const unsigned short* idx, int nidx, const floa bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b, const float* c, float& h) { + const float EPS = 1e-6f; float v0[3], v1[3], v2[3]; - dtVsub(v0, c,a); - dtVsub(v1, b,a); - dtVsub(v2, p,a); + dtVsub(v0, c, a); + dtVsub(v1, b, a); + dtVsub(v2, p, a); // Compute scaled barycentric coordinates float denom = v0[0] * v1[2] - v0[2] * v1[0]; + if (fabsf(denom) < EPS) + return false; + float u = v1[2] * v2[0] - v1[0] * v2[2]; float v = v0[0] * v2[2] - v0[2] * v2[0]; @@ -220,13 +224,9 @@ bool dtClosestHeightPointTriangle(const float* p, const float* a, const float* b v = -v; } - // The (sloppy) epsilon is needed to allow to get height of points which - // are interpolated along the edges of the triangles. - float epsilon = - 1e-4f * denom; - // If point lies inside the triangle, return interpolated ycoord. - if (u >= epsilon && v >= epsilon && (u+v) <= denom - epsilon) { - h = a[1] + (v0[1]*u + v1[1]*v) / denom; + if (u >= 0.0f && v >= 0.0f && (u + v) <= denom) { + h = a[1] + (v0[1] * u + v1[1] * v) / denom; return true; } return false; diff --git a/extern/recastnavigation/Detour/Source/DetourNavMesh.cpp b/extern/recastnavigation/Detour/Source/DetourNavMesh.cpp index 17df26d8c0..a655d1d89a 100644 --- a/extern/recastnavigation/Detour/Source/DetourNavMesh.cpp +++ b/extern/recastnavigation/Detour/Source/DetourNavMesh.cpp @@ -616,63 +616,84 @@ void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile) } } -void dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const +namespace { - const dtMeshTile* tile = 0; - const dtPoly* poly = 0; - getTileAndPolyByRefUnsafe(ref, &tile, &poly); - - // Off-mesh connections don't have detail polygons. - if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) + template + void closestPointOnDetailEdges(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* closest) { - 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; + const unsigned int ip = (unsigned int)(poly - tile->polys); + const dtPolyDetail* pd = &tile->detailMeshes[ip]; + + float dmin = FLT_MAX; + float tmin = 0; + const float* pmin = 0; + const float* pmax = 0; + + for (int i = 0; i < pd->triCount; i++) + { + const unsigned char* tris = &tile->detailTris[(pd->triBase + i) * 4]; + const int ANY_BOUNDARY_EDGE = + (DT_DETAIL_EDGE_BOUNDARY << 0) | + (DT_DETAIL_EDGE_BOUNDARY << 2) | + (DT_DETAIL_EDGE_BOUNDARY << 4); + if (onlyBoundary && (tris[3] & ANY_BOUNDARY_EDGE) == 0) + continue; + + const float* v[3]; + for (int j = 0; j < 3; ++j) + { + if (tris[j] < poly->vertCount) + v[j] = &tile->verts[poly->verts[tris[j]] * 3]; + else + v[j] = &tile->detailVerts[(pd->vertBase + (tris[j] - poly->vertCount)) * 3]; + } + + for (int k = 0, j = 2; k < 3; j = k++) + { + if ((dtGetDetailTriEdgeFlags(tris[3], j) & DT_DETAIL_EDGE_BOUNDARY) == 0 && + (onlyBoundary || tris[j] < tris[k])) + { + // Only looking at boundary edges and this is internal, or + // this is an inner edge that we will see again or have already seen. + continue; + } + + float t; + float d = dtDistancePtSegSqr2D(pos, v[j], v[k], t); + if (d < dmin) + { + dmin = d; + tmin = t; + pmin = v[j]; + pmax = v[k]; + } + } + } + + dtVlerp(closest, pmin, pmax, tmin); } - +} + +bool dtNavMesh::getPolyHeight(const dtMeshTile* tile, const dtPoly* poly, const float* pos, float* height) const +{ + // Off-mesh connections do not have detail polys and getting height + // over them does not make sense. + if (poly->getType() == DT_POLYTYPE_OFFMESH_CONNECTION) + return false; + 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 (posOverPoly) - *posOverPoly = true; - } + if (!dtPointInPolygon(pos, verts, nv)) + return false; + + if (!height) + return true; // Find height at the location. for (int j = 0; j < pd->triCount; ++j) @@ -687,12 +708,53 @@ void dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* close v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3]; } float h; - if (dtClosestHeightPointTriangle(closest, v[0], v[1], v[2], h)) + if (dtClosestHeightPointTriangle(pos, v[0], v[1], v[2], h)) { - closest[1] = h; - break; + *height = h; + return true; } } + + // If all triangle checks failed above (can happen with degenerate triangles + // or larger floating point values) the point is on an edge, so just select + // closest. This should almost never happen so the extra iteration here is + // ok. + float closest[3]; + closestPointOnDetailEdges(tile, poly, pos, closest); + *height = closest[1]; + return true; +} + +void dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const +{ + const dtMeshTile* tile = 0; + const dtPoly* poly = 0; + getTileAndPolyByRefUnsafe(ref, &tile, &poly); + + dtVcopy(closest, pos); + if (getPolyHeight(tile, poly, pos, &closest[1])) + { + if (posOverPoly) + *posOverPoly = true; + return; + } + + if (posOverPoly) + *posOverPoly = false; + + // 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]; + float t; + dtDistancePtSegSqr2D(pos, v0, v1, t); + dtVlerp(closest, v0, v1, t); + return; + } + + // Outside poly that is not an offmesh connection. + closestPointOnDetailEdges(tile, poly, pos, closest); } dtPolyRef dtNavMesh::findNearestPolyInTile(const dtMeshTile* tile, diff --git a/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp b/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp index c5ef385f95..839ee1e815 100644 --- a/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp +++ b/extern/recastnavigation/Detour/Source/DetourNavMeshQuery.cpp @@ -514,88 +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; - - if (!pos || !dtVisfinite(pos) || !closest) - 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; } @@ -662,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 @@ -676,44 +602,25 @@ dtStatus dtNavMeshQuery::getPolyHeight(dtPolyRef ref, const float* pos, float* h 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 diff --git a/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp b/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp index 68ab726aab..9a423cab8a 100644 --- a/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp +++ b/extern/recastnavigation/Recast/Source/RecastMeshDetail.cpp @@ -1141,7 +1141,8 @@ static void getHeightData(rcContext* ctx, const rcCompactHeightfield& chf, static unsigned char getEdgeFlags(const float* va, const float* vb, const float* vpoly, const int npoly) { - // Return true if edge (va,vb) is part of the polygon. + // The flag returned by this function matches dtDetailTriEdgeFlags in Detour. + // Figure out if edge (va,vb) is part of the polygon boundary. static const float thrSqr = rcSqr(0.001f); for (int i = 0, j = npoly-1; i < npoly; j=i++) {