diff --git a/Detour/Include/DetourNavMeshQuery.h b/Detour/Include/DetourNavMeshQuery.h index b6101b6..ac48ee7 100644 --- a/Detour/Include/DetourNavMeshQuery.h +++ b/Detour/Include/DetourNavMeshQuery.h @@ -304,14 +304,18 @@ public: int* resultCount, const int maxResult) const; // Returns wall segments of specified polygon. + // If 'segmentRefs' is specified, both the wall and portal segments are returned. + // Wall segments will have null (0) polyref, and portal segments store the polygon they lead to. // Params: // ref - (in) ref to the polygon. // filter - (in) path polygon filter. - // segments[6*maxSegments] - (out) wall segments (2 endpoints per segment). + // segmentVerts[6*maxSegments] - (out) wall segments (2 endpoints per segment). + // segmentRefs[maxSegments] - (out,opt) reference to a neighbour. // segmentCount - (out) number of wall segments. // maxSegments - (in) max number of segments that can be stored in 'segments'. dtStatus getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter, - float* segments, int* segmentCount, const int maxSegments) const; + float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount, + const int maxSegments) const; // Returns closest point on navigation polygon. // Uses detail polygons to find the closest point to the navigation polygon surface. diff --git a/Detour/Source/DetourNavMeshQuery.cpp b/Detour/Source/DetourNavMeshQuery.cpp index 545773b..949e205 100644 --- a/Detour/Source/DetourNavMeshQuery.cpp +++ b/Detour/Source/DetourNavMeshQuery.cpp @@ -2353,11 +2353,12 @@ dtStatus dtNavMeshQuery::findLocalNeighbourhood(dtPolyRef startRef, const float* struct dtSegInterval { + dtPolyRef ref; short tmin, tmax; }; static void insertInterval(dtSegInterval* ints, int& nints, const int maxInts, - const short tmin, const short tmax) + const short tmin, const short tmax, const dtPolyRef ref) { if (nints+1 > maxInts) return; // Find insertion point. @@ -2372,13 +2373,15 @@ static void insertInterval(dtSegInterval* ints, int& nints, const int maxInts, if (nints-idx) memmove(ints+idx+1, ints+idx, sizeof(dtSegInterval)*(nints-idx)); // Store + ints[idx].ref = ref; ints[idx].tmin = tmin; ints[idx].tmax = tmax; nints++; } dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* filter, - float* segments, int* segmentCount, const int maxSegments) const + float* segmentVerts, dtPolyRef* segmentRefs, int* segmentCount, + const int maxSegments) const { dtAssert(m_nav); @@ -2394,6 +2397,8 @@ dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* dtSegInterval ints[MAX_INTERVAL]; int nints; + const bool storePortals = segmentRefs != 0; + dtStatus status = DT_SUCCESS; for (int i = 0, j = (int)poly->vertCount-1; i < (int)poly->vertCount; j = i++) @@ -2415,58 +2420,91 @@ dtStatus dtNavMeshQuery::getPolyWallSegments(dtPolyRef ref, const dtQueryFilter* m_nav->getTileAndPolyByRefUnsafe(link->ref, &neiTile, &neiPoly); if (filter->passFilter(link->ref, neiTile, neiPoly)) { - insertInterval(ints, nints, MAX_INTERVAL, link->bmin, link->bmax); + insertInterval(ints, nints, MAX_INTERVAL, link->bmin, link->bmax, link->ref); } } } } } - else if (poly->neis[j]) + else { // Internal edge - const unsigned int idx = (unsigned int)(poly->neis[j]-1); - const dtPolyRef ref = m_nav->getPolyRefBase(tile) | idx; - if (filter->passFilter(ref, tile, &tile->polys[idx])) + dtPolyRef ref = 0; + if (poly->neis[j]) + { + const unsigned int idx = (unsigned int)(poly->neis[j]-1); + ref = m_nav->getPolyRefBase(tile) | idx; + if (!filter->passFilter(ref, tile, &tile->polys[idx])) + ref = 0; + } + + // If the edge leads to another polygon and portals are not stored, skip. + if (ref != 0 && !storePortals) continue; + + if (n < maxSegments) + { + const float* vj = &tile->verts[poly->verts[j]*3]; + const float* vi = &tile->verts[poly->verts[i]*3]; + float* seg = &segmentVerts[n*6]; + dtVcopy(seg+0, vj); + dtVcopy(seg+3, vi); + if (segmentRefs) + segmentRefs[n] = ref; + n++; + } + else + { + status |= DT_BUFFER_TOO_SMALL; + } + + continue; } // Add sentinels - insertInterval(ints, nints, MAX_INTERVAL, -1, 0); - insertInterval(ints, nints, MAX_INTERVAL, 255, 256); + insertInterval(ints, nints, MAX_INTERVAL, -1, 0, 0); + insertInterval(ints, nints, MAX_INTERVAL, 255, 256, 0); - // Store segment. + // Store segments. const float* vj = &tile->verts[poly->verts[j]*3]; const float* vi = &tile->verts[poly->verts[i]*3]; for (int k = 1; k < nints; ++k) { - // Find the space inbetween the opening areas. - const int imin = ints[k-1].tmax; - const int imax = ints[k].tmin; - if (imin == imax) continue; - if (imin == 0 && imax == 255) + // Portal segment. + if (storePortals && ints[k].ref) { + const float tmin = ints[k].tmin/255.0f; + const float tmax = ints[k].tmax/255.0f; if (n < maxSegments) { - float* seg = &segments[n*6]; + float* seg = &segmentVerts[n*6]; + dtVlerp(seg+0, vj,vi, tmin); + dtVlerp(seg+3, vj,vi, tmax); + if (segmentRefs) + segmentRefs[n] = ints[k].ref; n++; - dtVcopy(seg+0, vj); - dtVcopy(seg+3, vi); } else { status |= DT_BUFFER_TOO_SMALL; } } - else + + // Wall segment. + const int imin = ints[k-1].tmax; + const int imax = ints[k].tmin; + if (imin != imax) { const float tmin = imin/255.0f; const float tmax = imax/255.0f; if (n < maxSegments) { - float* seg = &segments[n*6]; - n++; + float* seg = &segmentVerts[n*6]; dtVlerp(seg+0, vj,vi, tmin); dtVlerp(seg+3, vj,vi, tmax); + if (segmentRefs) + segmentRefs[n] = 0; + n++; } else { diff --git a/DetourCrowd/Source/DetourLocalBoundary.cpp b/DetourCrowd/Source/DetourLocalBoundary.cpp index e3fdbcc..7ad28b4 100644 --- a/DetourCrowd/Source/DetourLocalBoundary.cpp +++ b/DetourCrowd/Source/DetourLocalBoundary.cpp @@ -106,7 +106,7 @@ void dtLocalBoundary::update(dtPolyRef ref, const float* pos, const float collis int nsegs = 0; for (int j = 0; j < nlocals; ++j) { - navquery->getPolyWallSegments(locals[j], filter, segs, &nsegs, MAX_SEGS_PER_POLY); + navquery->getPolyWallSegments(locals[j], filter, segs, 0, &nsegs, MAX_SEGS_PER_POLY); for (int k = 0; k < nsegs; ++k) { const float* s = &segs[k*6]; diff --git a/RecastDemo/Bin/Recast.app/Contents/MacOS/Recast b/RecastDemo/Bin/Recast.app/Contents/MacOS/Recast index 340c8f0..00d4283 100755 Binary files a/RecastDemo/Bin/Recast.app/Contents/MacOS/Recast and b/RecastDemo/Bin/Recast.app/Contents/MacOS/Recast differ diff --git a/RecastDemo/Source/NavMeshTesterTool.cpp b/RecastDemo/Source/NavMeshTesterTool.cpp index 4581354..693a216 100644 --- a/RecastDemo/Source/NavMeshTesterTool.cpp +++ b/RecastDemo/Source/NavMeshTesterTool.cpp @@ -1127,10 +1127,12 @@ void NavMeshTesterTool::handleRender() dd.depthMask(true); } - static const int MAX_SEGS = DT_VERTS_PER_POLYGON*2; + static const int MAX_SEGS = DT_VERTS_PER_POLYGON*4; float segs[MAX_SEGS*6]; + dtPolyRef refs[MAX_SEGS]; + memset(refs, 0, sizeof(dtPolyRef)*MAX_SEGS); int nsegs = 0; - m_navQuery->getPolyWallSegments(m_polys[i], &m_filter, segs, &nsegs, MAX_SEGS); + m_navQuery->getPolyWallSegments(m_polys[i], &m_filter, segs, refs, &nsegs, MAX_SEGS); dd.begin(DU_DRAW_LINES, 2.0f); for (int j = 0; j < nsegs; ++j) { @@ -1152,15 +1154,24 @@ void NavMeshTesterTool::handleRender() dtVmad(p1, p0, norm, agentRadius*0.5f); // Skip backfacing segments. - unsigned int col = duRGBA(255,255,255,192); - if (dtTriArea2D(m_spos, s, s+3) < 0.0f) - col = duRGBA(255,255,255,64); + if (refs[j]) + { + unsigned int col = duRGBA(255,255,255,32); + dd.vertex(s[0],s[1]+agentClimb,s[2],col); + dd.vertex(s[3],s[4]+agentClimb,s[5],col); + } + else + { + unsigned int col = duRGBA(192,32,16,192); + if (dtTriArea2D(m_spos, s, s+3) < 0.0f) + col = duRGBA(96,32,16,192); - dd.vertex(p0[0],p0[1]+agentClimb,p0[2],duRGBA(0,0,0,128)); - dd.vertex(p1[0],p1[1]+agentClimb,p1[2],duRGBA(0,0,0,128)); + dd.vertex(p0[0],p0[1]+agentClimb,p0[2],col); + dd.vertex(p1[0],p1[1]+agentClimb,p1[2],col); - dd.vertex(s[0],s[1]+agentClimb,s[2],col); - dd.vertex(s[3],s[4]+agentClimb,s[5],col); + dd.vertex(s[0],s[1]+agentClimb,s[2],col); + dd.vertex(s[3],s[4]+agentClimb,s[5],col); + } } dd.end();