aboutsummaryrefslogtreecommitdiff
path: root/dep/recastnavigation/Detour/DetourNavMesh.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dep/recastnavigation/Detour/DetourNavMesh.cpp')
-rw-r--r--dep/recastnavigation/Detour/DetourNavMesh.cpp403
1 files changed, 285 insertions, 118 deletions
diff --git a/dep/recastnavigation/Detour/DetourNavMesh.cpp b/dep/recastnavigation/Detour/DetourNavMesh.cpp
index 49100b09816..51740509950 100644
--- a/dep/recastnavigation/Detour/DetourNavMesh.cpp
+++ b/dep/recastnavigation/Detour/DetourNavMesh.cpp
@@ -297,6 +297,7 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
float amin[2], amax[2];
calcSlabEndPoints(va,vb, amin,amax, side);
+ const float apos = getSlabCoord(va, side);
// Remove links pointing to 'side' and compact the links array.
float bmin[2], bmax[2];
@@ -316,6 +317,13 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
const float* vc = &tile->verts[poly->verts[j]*3];
const float* vd = &tile->verts[poly->verts[(j+1) % nv]*3];
+ const float bpos = getSlabCoord(vc, side);
+
+ // Segments are not close enough.
+ if (dtAbs(apos-bpos) > 0.01f)
+ continue;
+
+ // Check if the segments touch.
calcSlabEndPoints(vc,vd, bmin,bmax, side);
if (!overlapSlabs(amin,amax, bmin,bmax, 0.01f, tile->header->walkableClimb)) continue;
@@ -334,9 +342,11 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
return n;
}
-void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, int side)
+void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, dtMeshTile* target)
{
- if (!tile) return;
+ if (!tile || !target) return;
+
+ const unsigned int targetNum = decodePolyIdTile(getTileRef(target));
for (int i = 0; i < tile->header->polyCount; ++i)
{
@@ -345,7 +355,8 @@ void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, int side)
unsigned int pj = DT_NULL_LINK;
while (j != DT_NULL_LINK)
{
- if (tile->links[j].side == side)
+ if (tile->links[j].side != 0xff &&
+ decodePolyIdTile(tile->links[j].ref) == targetNum)
{
// Revove link.
unsigned int nj = tile->links[j].next;
@@ -376,20 +387,25 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
dtPoly* poly = &tile->polys[i];
// Create new links.
- unsigned short m = DT_EXT_LINK | (unsigned short)side;
+// unsigned short m = DT_EXT_LINK | (unsigned short)side;
const int nv = poly->vertCount;
for (int j = 0; j < nv; ++j)
{
// Skip non-portal edges.
- if (poly->neis[j] != m) continue;
+ if ((poly->neis[j] & DT_EXT_LINK) == 0)
+ continue;
+
+ const int dir = (int)(poly->neis[j] & 0xff);
+ if (side != -1 && dir != side)
+ continue;
// Create new links
const float* va = &tile->verts[poly->verts[j]*3];
const float* vb = &tile->verts[poly->verts[(j+1) % nv]*3];
dtPolyRef nei[4];
float neia[4*2];
- int nnei = findConnectingPolys(va,vb, target, dtOppositeTile(side), nei,neia,4);
+ int nnei = findConnectingPolys(va,vb, target, dtOppositeTile(dir), nei,neia,4);
for (int k = 0; k < nnei; ++k)
{
unsigned int idx = allocLink(tile);
@@ -398,13 +414,13 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
dtLink* link = &tile->links[idx];
link->ref = nei[k];
link->edge = (unsigned char)j;
- link->side = (unsigned char)side;
+ link->side = (unsigned char)dir;
link->next = poly->firstLink;
poly->firstLink = idx;
// Compress portal limits to a byte value.
- if (side == 0 || side == 4)
+ if (dir == 0 || dir == 4)
{
float tmin = (neia[k*2+0]-va[2]) / (vb[2]-va[2]);
float tmax = (neia[k*2+1]-va[2]) / (vb[2]-va[2]);
@@ -413,7 +429,7 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
link->bmin = (unsigned char)(dtClamp(tmin, 0.0f, 1.0f)*255.0f);
link->bmax = (unsigned char)(dtClamp(tmax, 0.0f, 1.0f)*255.0f);
}
- else if (side == 2 || side == 6)
+ else if (dir == 2 || dir == 6)
{
float tmin = (neia[k*2+0]-va[0]) / (vb[0]-va[0]);
float tmax = (neia[k*2+1]-va[0]) / (vb[0]-va[0]);
@@ -434,7 +450,7 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int
// Connect off-mesh links.
// We are interested on links which land from target tile to this tile.
- const unsigned char oppositeSide = (unsigned char)dtOppositeTile(side);
+ const unsigned char oppositeSide = (side == -1) ? 0xff : (unsigned char)dtOppositeTile(side);
for (int i = 0; i < target->header->offMeshConCount; ++i)
{
@@ -443,6 +459,9 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int
continue;
dtPoly* targetPoly = &target->polys[targetCon->poly];
+ // Skip off-mesh connections which start location could not be connected at all.
+ if (targetPoly->firstLink == DT_NULL_LINK)
+ continue;
const float ext[3] = { targetCon->rad, target->header->walkableClimb, targetCon->rad };
@@ -476,19 +495,19 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int
// Link target poly to off-mesh connection.
if (targetCon->flags & DT_OFFMESH_CON_BIDIR)
{
- unsigned int idx = allocLink(tile);
- if (idx != DT_NULL_LINK)
+ unsigned int tidx = allocLink(tile);
+ if (tidx != DT_NULL_LINK)
{
const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref);
dtPoly* landPoly = &tile->polys[landPolyIdx];
- dtLink* link = &tile->links[idx];
+ dtLink* link = &tile->links[tidx];
link->ref = getPolyRefBase(target) | (dtPolyRef)(targetCon->poly);
link->edge = 0xff;
- link->side = (unsigned char)side;
+ link->side = (unsigned char)(side == -1 ? 0xff : side);
link->bmin = link->bmax = 0;
// Add to linked list.
link->next = landPoly->firstLink;
- landPoly->firstLink = idx;
+ landPoly->firstLink = tidx;
}
}
}
@@ -532,13 +551,13 @@ void dtNavMesh::connectIntLinks(dtMeshTile* tile)
}
}
-void dtNavMesh::connectIntOffMeshLinks(dtMeshTile* tile)
+void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile)
{
if (!tile) return;
dtPolyRef base = getPolyRefBase(tile);
- // Find Off-mesh connection end points.
+ // Base off-mesh connection start points.
for (int i = 0; i < tile->header->offMeshConCount; ++i)
{
dtOffMeshConnection* con = &tile->offMeshCons[i];
@@ -546,72 +565,109 @@ void dtNavMesh::connectIntOffMeshLinks(dtMeshTile* tile)
const float ext[3] = { con->rad, tile->header->walkableClimb, con->rad };
- for (int j = 0; j < 2; ++j)
- {
- unsigned char side = j == 0 ? 0xff : con->side;
+ // Find polygon to connect to.
+ const float* p = &con->pos[0]; // First vertex
+ float nearestPt[3];
+ dtPolyRef ref = findNearestPolyInTile(tile, p, ext, nearestPt);
+ if (!ref) continue;
+ // findNearestPoly may return too optimistic results, further check to make sure.
+ if (dtSqr(nearestPt[0]-p[0])+dtSqr(nearestPt[2]-p[2]) > dtSqr(con->rad))
+ continue;
+ // Make sure the location is on current mesh.
+ float* v = &tile->verts[poly->verts[0]*3];
+ dtVcopy(v, nearestPt);
- if (side == 0xff)
- {
- // Find polygon to connect to.
- const float* p = &con->pos[j*3];
- float nearestPt[3];
- dtPolyRef ref = findNearestPolyInTile(tile, p, ext, nearestPt);
- if (!ref) continue;
- // findNearestPoly may return too optimistic results, further check to make sure.
- if (dtSqr(nearestPt[0]-p[0])+dtSqr(nearestPt[2]-p[2]) > dtSqr(con->rad))
- continue;
- // Make sure the location is on current mesh.
- float* v = &tile->verts[poly->verts[j]*3];
- dtVcopy(v, nearestPt);
-
- // Link off-mesh connection to target poly.
- unsigned int idx = allocLink(tile);
- if (idx != DT_NULL_LINK)
- {
- dtLink* link = &tile->links[idx];
- link->ref = ref;
- link->edge = (unsigned char)j;
- link->side = 0xff;
- link->bmin = link->bmax = 0;
- // Add to linked list.
- link->next = poly->firstLink;
- poly->firstLink = idx;
- }
+ // Link off-mesh connection to target poly.
+ unsigned int idx = allocLink(tile);
+ if (idx != DT_NULL_LINK)
+ {
+ dtLink* link = &tile->links[idx];
+ link->ref = ref;
+ link->edge = (unsigned char)0;
+ link->side = 0xff;
+ link->bmin = link->bmax = 0;
+ // Add to linked list.
+ link->next = poly->firstLink;
+ poly->firstLink = idx;
+ }
- // Start end-point is always connect back to off-mesh connection,
- // Destination end-point only if it is bidirectional link.
- if (j == 0 || (j == 1 && (con->flags & DT_OFFMESH_CON_BIDIR)))
- {
- // Link target poly to off-mesh connection.
- unsigned int idx = allocLink(tile);
- if (idx != DT_NULL_LINK)
- {
- const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref);
- dtPoly* landPoly = &tile->polys[landPolyIdx];
- dtLink* link = &tile->links[idx];
- link->ref = base | (dtPolyRef)(con->poly);
- link->edge = 0xff;
- link->side = 0xff;
- link->bmin = link->bmax = 0;
- // Add to linked list.
- link->next = landPoly->firstLink;
- landPoly->firstLink = idx;
- }
- }
-
- }
+ // Start end-point is always connect back to off-mesh connection.
+ unsigned int tidx = allocLink(tile);
+ if (tidx != DT_NULL_LINK)
+ {
+ const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref);
+ dtPoly* landPoly = &tile->polys[landPolyIdx];
+ dtLink* link = &tile->links[tidx];
+ link->ref = base | (dtPolyRef)(con->poly);
+ link->edge = 0xff;
+ link->side = 0xff;
+ link->bmin = link->bmax = 0;
+ // Add to linked list.
+ link->next = landPoly->firstLink;
+ landPoly->firstLink = tidx;
}
}
}
-dtStatus dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip,
- const float* pos, float* closest) const
+void dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest, bool* posOverPoly) const
{
- const dtPoly* poly = &tile->polys[ip];
+ const dtMeshTile* tile = 0;
+ const dtPoly* poly = 0;
+ getTileAndPolyByRefUnsafe(ref, &tile, &poly);
- float closestDistSqr = FLT_MAX;
+ // 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;
+ }
+
+ 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 = FLT_MAX;
+ int imin = -1;
+ for (int i = 0; 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;
+ }
+
+ // Find height at the location.
for (int j = 0; j < pd->triCount; ++j)
{
const unsigned char* t = &tile->detailTris[(pd->triBase+j)*4];
@@ -623,17 +679,13 @@ dtStatus dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned in
else
v[k] = &tile->detailVerts[(pd->vertBase+(t[k]-poly->vertCount))*3];
}
- float pt[3];
- dtClosestPtPointTriangle(pt, pos, v[0], v[1], v[2]);
- float d = dtVdistSqr(pos, pt);
- if (d < closestDistSqr)
+ float h;
+ if (dtClosestHeightPointTriangle(pos, v[0], v[1], v[2], h))
{
- dtVcopy(closest, pt);
- closestDistSqr = d;
+ closest[1] = h;
+ break;
}
}
-
- return DT_SUCCESS;
}
dtPolyRef dtNavMesh::findNearestPolyInTile(const dtMeshTile* tile,
@@ -655,13 +707,27 @@ dtPolyRef dtNavMesh::findNearestPolyInTile(const dtMeshTile* tile,
{
dtPolyRef ref = polys[i];
float closestPtPoly[3];
- if (closestPointOnPolyInTile(tile, decodePolyIdPoly(ref), center, closestPtPoly) != DT_SUCCESS)
- continue;
- float d = dtVdistSqr(center, closestPtPoly);
+ float diff[3];
+ bool posOverPoly = false;
+ float d = 0;
+ closestPointOnPoly(ref, center, closestPtPoly, &posOverPoly);
+
+ // If a point is directly over a polygon and closer than
+ // climb height, favor that instead of straight line nearest point.
+ dtVsub(diff, center, closestPtPoly);
+ if (posOverPoly)
+ {
+ d = dtAbs(diff[1]) - tile->header->walkableClimb;
+ d = d > 0 ? d*d : 0;
+ }
+ else
+ {
+ d = dtVlenSqr(diff);
+ }
+
if (d < nearestDistanceSqr)
{
- if (nearestPt)
- dtVcopy(nearestPt, closestPtPoly);
+ dtVcopy(nearestPt, closestPtPoly);
nearestDistanceSqr = d;
nearest = ref;
}
@@ -730,8 +796,11 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co
dtPolyRef base = getPolyRefBase(tile);
for (int i = 0; i < tile->header->polyCount; ++i)
{
- // Calc polygon bounds.
dtPoly* p = &tile->polys[i];
+ // Do not return off-mesh connection polygons.
+ if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
+ continue;
+ // Calc polygon bounds.
const float* v = &tile->verts[p->verts[0]*3];
dtVcopy(bmin, v);
dtVcopy(bmax, v);
@@ -773,7 +842,7 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
return DT_FAILURE | DT_WRONG_VERSION;
// Make sure the location is free.
- if (getTileAt(header->x, header->y))
+ if (getTileAt(header->x, header->y, header->layer))
return DT_FAILURE;
// Allocate a tile.
@@ -845,6 +914,10 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
tile->bvTree = (dtBVNode*)d; d += bvtreeSize;
tile->offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize;
+ // If there are no items in the bvtree, reset the tree pointer.
+ if (!bvtreeSize)
+ tile->bvTree = 0;
+
// Build links freelist
tile->linksFreeList = 0;
tile->links[header->maxLinkCount-1].next = DT_NULL_LINK;
@@ -858,18 +931,36 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
tile->flags = flags;
connectIntLinks(tile);
- connectIntOffMeshLinks(tile);
+ baseOffMeshLinks(tile);
// Create connections with neighbour tiles.
+ static const int MAX_NEIS = 32;
+ dtMeshTile* neis[MAX_NEIS];
+ int nneis;
+
+ // Connect with layers in current tile.
+ nneis = getTilesAt(header->x, header->y, neis, MAX_NEIS);
+ for (int j = 0; j < nneis; ++j)
+ {
+ if (neis[j] != tile)
+ {
+ connectExtLinks(tile, neis[j], -1);
+ connectExtLinks(neis[j], tile, -1);
+ }
+ connectExtOffMeshLinks(tile, neis[j], -1);
+ connectExtOffMeshLinks(neis[j], tile, -1);
+ }
+
+ // Connect with neighbour tiles.
for (int i = 0; i < 8; ++i)
{
- dtMeshTile* nei = getNeighbourTileAt(header->x, header->y, i);
- if (nei)
+ nneis = getNeighbourTilesAt(header->x, header->y, i, neis, MAX_NEIS);
+ for (int j = 0; j < nneis; ++j)
{
- connectExtLinks(tile, nei, i);
- connectExtLinks(nei, tile, dtOppositeTile(i));
- connectExtOffMeshLinks(tile, nei, i);
- connectExtOffMeshLinks(nei, tile, dtOppositeTile(i));
+ connectExtLinks(tile, neis[j], i);
+ connectExtLinks(neis[j], tile, dtOppositeTile(i));
+ connectExtOffMeshLinks(tile, neis[j], i);
+ connectExtOffMeshLinks(neis[j], tile, dtOppositeTile(i));
}
}
@@ -879,55 +970,106 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
return DT_SUCCESS;
}
-const dtMeshTile* dtNavMesh::getTileAt(int x, int y) const
+const dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer) const
{
// Find tile based on hash.
int h = computeTileHash(x,y,m_tileLutMask);
dtMeshTile* tile = m_posLookup[h];
while (tile)
{
- if (tile->header && tile->header->x == x && tile->header->y == y)
+ if (tile->header &&
+ tile->header->x == x &&
+ tile->header->y == y &&
+ tile->header->layer == layer)
+ {
return tile;
+ }
tile = tile->next;
}
return 0;
}
-dtMeshTile* dtNavMesh::getNeighbourTileAt(int x, int y, int side) const
+int dtNavMesh::getNeighbourTilesAt(const int x, const int y, const int side, dtMeshTile** tiles, const int maxTiles) const
{
+ int nx = x, ny = y;
switch (side)
{
- case 0: x++; break;
- case 1: x++; y++; break;
- case 2: y++; break;
- case 3: x--; y++; break;
- case 4: x--; break;
- case 5: x--; y--; break;
- case 6: y--; break;
- case 7: x++; y--; break;
+ case 0: nx++; break;
+ case 1: nx++; ny++; break;
+ case 2: ny++; break;
+ case 3: nx--; ny++; break;
+ case 4: nx--; break;
+ case 5: nx--; ny--; break;
+ case 6: ny--; break;
+ case 7: nx++; ny--; break;
};
+ return getTilesAt(nx, ny, tiles, maxTiles);
+}
+
+int dtNavMesh::getTilesAt(const int x, const int y, dtMeshTile** tiles, const int maxTiles) const
+{
+ int n = 0;
+
// Find tile based on hash.
int h = computeTileHash(x,y,m_tileLutMask);
dtMeshTile* tile = m_posLookup[h];
while (tile)
{
- if (tile->header && tile->header->x == x && tile->header->y == y)
- return tile;
+ if (tile->header &&
+ tile->header->x == x &&
+ tile->header->y == y)
+ {
+ if (n < maxTiles)
+ tiles[n++] = tile;
+ }
tile = tile->next;
}
- return 0;
+
+ return n;
+}
+
+/// @par
+///
+/// This function will not fail if the tiles array is too small to hold the
+/// entire result set. It will simply fill the array to capacity.
+int dtNavMesh::getTilesAt(const int x, const int y, dtMeshTile const** tiles, const int maxTiles) const
+{
+ int n = 0;
+
+ // Find tile based on hash.
+ int h = computeTileHash(x,y,m_tileLutMask);
+ dtMeshTile* tile = m_posLookup[h];
+ while (tile)
+ {
+ if (tile->header &&
+ tile->header->x == x &&
+ tile->header->y == y)
+ {
+ if (n < maxTiles)
+ tiles[n++] = tile;
+ }
+ tile = tile->next;
+ }
+
+ return n;
}
-dtTileRef dtNavMesh::getTileRefAt(int x, int y) const
+
+dtTileRef dtNavMesh::getTileRefAt(const int x, const int y, const int layer) const
{
// Find tile based on hash.
int h = computeTileHash(x,y,m_tileLutMask);
dtMeshTile* tile = m_posLookup[h];
while (tile)
{
- if (tile->header && tile->header->x == x && tile->header->y == y)
+ if (tile->header &&
+ tile->header->x == x &&
+ tile->header->y == y &&
+ tile->header->layer == layer)
+ {
return getTileRef(tile);
+ }
tile = tile->next;
}
return 0;
@@ -970,6 +1112,7 @@ void dtNavMesh::calcTileLoc(const float* pos, int* tx, int* ty) const
dtStatus dtNavMesh::getTileAndPolyByRef(const dtPolyRef ref, const dtMeshTile** tile, const dtPoly** poly) const
{
+ if (!ref) return DT_FAILURE;
unsigned int salt, it, ip;
decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM;
@@ -995,6 +1138,7 @@ void dtNavMesh::getTileAndPolyByRefUnsafe(const dtPolyRef ref, const dtMeshTile*
bool dtNavMesh::isValidPolyRef(dtPolyRef ref) const
{
+ if (!ref) return false;
unsigned int salt, it, ip;
decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false;
@@ -1040,14 +1184,27 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz
}
// Remove connections to neighbour tiles.
- for (int i = 0; i < 8; ++i)
+ // Create connections with neighbour tiles.
+ static const int MAX_NEIS = 32;
+ dtMeshTile* neis[MAX_NEIS];
+ int nneis;
+
+ // Connect with layers in current tile.
+ nneis = getTilesAt(tile->header->x, tile->header->y, neis, MAX_NEIS);
+ for (int j = 0; j < nneis; ++j)
{
- dtMeshTile* nei = getNeighbourTileAt(tile->header->x,tile->header->y,i);
- if (!nei) continue;
- unconnectExtLinks(nei, dtOppositeTile(i));
+ if (neis[j] == tile) continue;
+ unconnectExtLinks(neis[j], tile);
}
-
+ // Connect with neighbour tiles.
+ for (int i = 0; i < 8; ++i)
+ {
+ nneis = getNeighbourTilesAt(tile->header->x, tile->header->y, i, neis, MAX_NEIS);
+ for (int j = 0; j < nneis; ++j)
+ unconnectExtLinks(neis[j], tile);
+ }
+
// Reset tile.
if (tile->flags & DT_TILE_FREE_DATA)
{
@@ -1091,7 +1248,7 @@ dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSiz
dtTileRef dtNavMesh::getTileRef(const dtMeshTile* tile) const
{
if (!tile) return 0;
- const unsigned int it = tile - m_tiles;
+ const unsigned int it = (unsigned int)(tile - m_tiles);
return (dtTileRef)encodePolyId(tile->salt, it, 0);
}
@@ -1112,7 +1269,7 @@ dtTileRef dtNavMesh::getTileRef(const dtMeshTile* tile) const
dtPolyRef dtNavMesh::getPolyRefBase(const dtMeshTile* tile) const
{
if (!tile) return 0;
- const unsigned int it = tile - m_tiles;
+ const unsigned int it = (unsigned int)(tile - m_tiles);
return encodePolyId(tile->salt, it, 0);
}
@@ -1216,6 +1373,9 @@ dtStatus dtNavMesh::getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyR
{
unsigned int salt, it, ip;
+ if (!polyRef)
+ return DT_FAILURE;
+
// Get current polygon
decodePolyId(polyRef, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM;
@@ -1256,6 +1416,9 @@ const dtOffMeshConnection* dtNavMesh::getOffMeshConnectionByRef(dtPolyRef ref) c
{
unsigned int salt, it, ip;
+ if (!ref)
+ return 0;
+
// Get current polygon
decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return 0;
@@ -1276,6 +1439,7 @@ const dtOffMeshConnection* dtNavMesh::getOffMeshConnectionByRef(dtPolyRef ref) c
dtStatus dtNavMesh::setPolyFlags(dtPolyRef ref, unsigned short flags)
{
+ if (!ref) return DT_FAILURE;
unsigned int salt, it, ip;
decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM;
@@ -1292,6 +1456,7 @@ dtStatus dtNavMesh::setPolyFlags(dtPolyRef ref, unsigned short flags)
dtStatus dtNavMesh::getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) const
{
+ if (!ref) return DT_FAILURE;
unsigned int salt, it, ip;
decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM;
@@ -1307,6 +1472,7 @@ dtStatus dtNavMesh::getPolyFlags(dtPolyRef ref, unsigned short* resultFlags) con
dtStatus dtNavMesh::setPolyArea(dtPolyRef ref, unsigned char area)
{
+ if (!ref) return DT_FAILURE;
unsigned int salt, it, ip;
decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM;
@@ -1322,6 +1488,7 @@ dtStatus dtNavMesh::setPolyArea(dtPolyRef ref, unsigned char area)
dtStatus dtNavMesh::getPolyArea(dtPolyRef ref, unsigned char* resultArea) const
{
+ if (!ref) return DT_FAILURE;
unsigned int salt, it, ip;
decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM;