Off-Mesh connections across tile boundaries. Fixed getPolysAround(). Detour links per poly use linked list. Adjusted off-mesh connection tool.

This commit is contained in:
Mikko Mononen 2010-01-26 12:48:58 +00:00
parent e973b71d4b
commit a56bf3ec2d
16 changed files with 4140 additions and 7625 deletions

View File

@ -62,9 +62,9 @@ static void drawPolyBoundaries(duDebugDraw* dd, const dtMeshHeader* header,
if (p->neis[j] & DT_EXT_LINK) if (p->neis[j] & DT_EXT_LINK)
{ {
bool con = false; bool con = false;
for (int k = 0; k < p->linkCount; ++k) for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = header->links[k].next)
{ {
if (header->links[p->linkBase+k].edge == j) if (header->links[k].edge == j)
{ {
con = true; con = true;
break; break;
@ -175,15 +175,26 @@ static void drawMeshTile(duDebugDraw* dd, const dtNavMesh* mesh, const dtMeshTil
const dtOffMeshConnection* con = &header->offMeshCons[i - header->offMeshBase]; const dtOffMeshConnection* con = &header->offMeshCons[i - header->offMeshBase];
const float* va = &header->verts[p->verts[0]*3]; const float* va = &header->verts[p->verts[0]*3];
const float* vb = &header->verts[p->verts[1]*3]; const float* vb = &header->verts[p->verts[1]*3];
// Check to see if start and end end-points have links.
bool startSet = false;
bool endSet = false;
for (unsigned int k = p->firstLink; k != DT_NULL_LINK; k = header->links[k].next)
{
if (header->links[k].edge == 0)
startSet = true;
if (header->links[k].edge == 1)
endSet = true;
}
// End points and their on-mesh locations. // End points and their on-mesh locations.
if (con->ref[0]) if (startSet)
{ {
dd->vertex(va[0],va[1],va[2], col); dd->vertex(va[0],va[1],va[2], col);
dd->vertex(con->pos[0],con->pos[1],con->pos[2], col); dd->vertex(con->pos[0],con->pos[1],con->pos[2], col);
duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, duRGBA(0,48,64,196)); duAppendCircle(dd, con->pos[0],con->pos[1]+0.1f,con->pos[2], con->rad, duRGBA(0,48,64,196));
} }
if (con->ref[1]) if (endSet)
{ {
dd->vertex(vb[0],vb[1],vb[2], col); dd->vertex(vb[0],vb[1],vb[2], col);
dd->vertex(con->pos[3],con->pos[4],con->pos[5], col); dd->vertex(con->pos[3],con->pos[4],con->pos[5], col);

View File

@ -29,6 +29,7 @@ static const int DT_NAVMESH_MAGIC = 'DNAV';
static const int DT_NAVMESH_VERSION = 2; static const int DT_NAVMESH_VERSION = 2;
static const unsigned short DT_EXT_LINK = 0x8000; static const unsigned short DT_EXT_LINK = 0x8000;
static const unsigned int DT_NULL_LINK = 0xffffffff;
// Flags returned by findStraightPath(). // Flags returned by findStraightPath().
enum dtStraightPathFlags enum dtStraightPathFlags
@ -55,11 +56,10 @@ struct dtQueryFilter
// Structure describing the navigation polygon data. // Structure describing the navigation polygon data.
struct dtPoly struct dtPoly
{ {
unsigned int firstLink; // Index to first link in linked list.
unsigned short verts[DT_VERTS_PER_POLYGON]; // Indices to vertices of the poly. unsigned short verts[DT_VERTS_PER_POLYGON]; // Indices to vertices of the poly.
unsigned short neis[DT_VERTS_PER_POLYGON]; // Refs to neighbours of the poly. unsigned short neis[DT_VERTS_PER_POLYGON]; // Refs to neighbours of the poly.
unsigned short linkBase; // Base index to header 'links' array.
unsigned short flags; // Flags (see dtPolyFlags). unsigned short flags; // Flags (see dtPolyFlags).
unsigned char linkCount; // Number of links for
unsigned char vertCount; // Number of vertices. unsigned char vertCount; // Number of vertices.
}; };
@ -76,7 +76,7 @@ struct dtPolyDetail
struct dtLink struct dtLink
{ {
dtPolyRef ref; // Neighbour reference. dtPolyRef ref; // Neighbour reference.
unsigned short poly; // Index to polygon which owns this link. unsigned int next; // Index to next link.
unsigned char edge; // Index to polygon edge which owns this link. unsigned char edge; // Index to polygon edge which owns this link.
unsigned char side; // If boundary link, defines on which side the link is. unsigned char side; // If boundary link, defines on which side the link is.
unsigned char bmin, bmax; // If boundary link, defines the sub edge area. unsigned char bmin, bmax; // If boundary link, defines the sub edge area.
@ -92,9 +92,9 @@ struct dtOffMeshConnection
{ {
float pos[6]; // Both end point locations. float pos[6]; // Both end point locations.
float rad; // Link connection radius. float rad; // Link connection radius.
dtPolyRef ref[2]; // End point polys.
unsigned short poly; // Poly Id unsigned short poly; // Poly Id
unsigned char flags; // Link flags unsigned char flags; // Link flags
unsigned char side; // End point side.
}; };
struct dtMeshHeader struct dtMeshHeader
@ -104,7 +104,6 @@ struct dtMeshHeader
int polyCount; // Number of polygons in the tile. int polyCount; // Number of polygons in the tile.
int vertCount; // Number of vertices in the tile. int vertCount; // Number of vertices in the tile.
int linkCount; // Number of links in the tile (will be updated when tile is added).
int maxLinkCount; // Number of allocated links. int maxLinkCount; // Number of allocated links.
int detailMeshCount; // Number of detail meshes. int detailMeshCount; // Number of detail meshes.
int detailVertCount; // Number of detail vertices. int detailVertCount; // Number of detail vertices.
@ -112,9 +111,10 @@ struct dtMeshHeader
int bvNodeCount; // Number of BVtree nodes. int bvNodeCount; // Number of BVtree nodes.
int offMeshConCount; // Number of Off-Mesh links. int offMeshConCount; // Number of Off-Mesh links.
int offMeshBase; // Index to first polygon which is Off-Mesh link. int offMeshBase; // Index to first polygon which is Off-Mesh link.
float walkableHeight; unsigned int linksFreeList; // Index to next free link.
float walkableRadius; float walkableHeight; // Height of the agent.
float walkableClimb; float walkableRadius; // Radius of the agent
float walkableClimb; // Max climb height of the agent.
float bmin[3], bmax[3]; // Bounding box of the tile. float bmin[3], bmax[3]; // Bounding box of the tile.
float bvQuantFactor; // BVtree quantization factor (world to bvnode coords) float bvQuantFactor; // BVtree quantization factor (world to bvnode coords)
dtPoly* polys; // Pointer to the polygons (will be updated when tile is added). dtPoly* polys; // Pointer to the polygons (will be updated when tile is added).
@ -358,19 +358,31 @@ public:
bool isInClosedList(dtPolyRef ref) const; bool isInClosedList(dtPolyRef ref) const;
// Encodes a tile id. // Encodes a tile id.
inline dtPolyRef dtEncodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const inline dtPolyRef encodePolyId(unsigned int salt, unsigned int it, unsigned int ip) const
{ {
return (salt << (m_polyBits+m_tileBits)) | ((it+1) << m_polyBits) | ip; return (salt << (m_polyBits+m_tileBits)) | ((it+1) << m_polyBits) | ip;
} }
// Decodes a tile id. // Decodes a tile id.
inline void dtDecodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const inline void decodePolyId(dtPolyRef ref, unsigned int& salt, unsigned int& it, unsigned int& ip) const
{ {
salt = (ref >> (m_polyBits+m_tileBits)) & ((1<<m_saltBits)-1); salt = (ref >> (m_polyBits+m_tileBits)) & ((1<<m_saltBits)-1);
it = ((ref >> m_polyBits) - 1) & ((1<<m_tileBits)-1); it = ((ref >> m_polyBits) - 1) & ((1<<m_tileBits)-1);
ip = ref & ((1<<m_polyBits)-1); ip = ref & ((1<<m_polyBits)-1);
} }
// Decodes a tile id.
inline unsigned int decodePolyIdTile(dtPolyRef ref) const
{
return ((ref >> m_polyBits) - 1) & ((1<<m_tileBits)-1);
}
// Decodes a tile id.
inline unsigned int decodePolyIdPoly(dtPolyRef ref) const
{
return ref & ((1<<m_polyBits)-1);
}
private: private:
// Returns neighbour tile based on side. // Returns neighbour tile based on side.
@ -379,15 +391,29 @@ private:
int findConnectingPolys(const float* va, const float* vb, int findConnectingPolys(const float* va, const float* vb,
dtMeshTile* tile, int side, dtMeshTile* tile, int side,
dtPolyRef* con, float* conarea, int maxcon); dtPolyRef* con, float* conarea, int maxcon);
// Builds internal polygons links for a tile. // Builds internal polygons links for a tile.
void buildIntLinks(dtMeshTile* tile); void connectIntLinks(dtMeshTile* tile);
// Builds internal polygons links for a tile.
void connectIntOffMeshLinks(dtMeshTile* tile);
// Builds external polygon links for a tile. // Builds external polygon links for a tile.
void buildExtLinks(dtMeshTile* tile, dtMeshTile* target, int side); void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
// Builds external polygon links for a tile.
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
// Removes external links at specified side. // Removes external links at specified side.
void removeExtLinks(dtMeshTile* tile, int side); void unconnectExtLinks(dtMeshTile* tile, int side);
// Queries polygons within a tile. // Queries polygons within a tile.
int queryTilePolygons(dtMeshTile* tile, const float* qmin, const float* qmax, dtQueryFilter* filter, int queryPolygonsInTile(dtMeshTile* tile, const float* qmin, const float* qmax, dtQueryFilter* filter,
dtPolyRef* polys, const int maxPolys); dtPolyRef* polys, const int maxPolys);
// Find nearest polygon within a tile.
dtPolyRef findNearestPolyInTile(dtMeshTile* tile, const float* center, const float* extents,
dtQueryFilter* filter, float* nearestPt);
// Returns closest point on polygon.
bool closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip, const float* pos, float* closest) const;
unsigned short getPolyFlags(dtPolyRef ref); unsigned short getPolyFlags(dtPolyRef ref);
float getCost(dtPolyRef prev, dtPolyRef from, dtPolyRef to) const; float getCost(dtPolyRef prev, dtPolyRef from, dtPolyRef to) const;
float getFirstCost(const float* pos, dtPolyRef from, dtPolyRef to) const; float getFirstCost(const float* pos, dtPolyRef from, dtPolyRef to) const;
@ -409,11 +435,7 @@ private:
dtMeshTile** m_posLookup; // Tile hash lookup. dtMeshTile** m_posLookup; // Tile hash lookup.
dtMeshTile* m_nextFree; // Freelist of tiles. dtMeshTile* m_nextFree; // Freelist of tiles.
dtMeshTile* m_tiles; // List of tiles. dtMeshTile* m_tiles; // List of tiles.
// TODO: dont grow!
dtLink* m_tmpLinks; // Temp array used to build links between tiles.
int m_ntmpLinks; // Size of the temp link array.
unsigned int m_saltBits; // Number of salt bits in the tile ID. unsigned int m_saltBits; // Number of salt bits in the tile ID.
unsigned int m_tileBits; // Number of tile bits in the tile ID. unsigned int m_tileBits; // Number of tile bits in the tile ID.
unsigned int m_polyBits; // Number of poly bits in the tile ID. unsigned int m_polyBits; // Number of poly bits in the tile ID.

View File

@ -25,7 +25,7 @@
#include "DetourCommon.h" #include "DetourCommon.h"
inline int opposite(int side) { return (side+2) & 0x3; } inline int opposite(int side) { return (side+4) & 0x7; }
inline bool overlapBoxes(const float* amin, const float* amax, inline bool overlapBoxes(const float* amin, const float* amax,
const float* bmin, const float* bmax) const float* bmin, const float* bmax)
@ -50,14 +50,14 @@ static void calcRect(const float* va, const float* vb,
float* bmin, float* bmax, float* bmin, float* bmax,
int side, float padx, float pady) int side, float padx, float pady)
{ {
if ((side&1) == 0) if (side == 0 || side == 4)
{ {
bmin[0] = min(va[2],vb[2]) + padx; bmin[0] = min(va[2],vb[2]) + padx;
bmin[1] = min(va[1],vb[1]) - pady; bmin[1] = min(va[1],vb[1]) - pady;
bmax[0] = max(va[2],vb[2]) - padx; bmax[0] = max(va[2],vb[2]) - padx;
bmax[1] = max(va[1],vb[1]) + pady; bmax[1] = max(va[1],vb[1]) + pady;
} }
else else if (side == 2 || side == 6)
{ {
bmin[0] = min(va[0],vb[0]) + padx; bmin[0] = min(va[0],vb[0]) + padx;
bmin[1] = min(va[1],vb[1]) - pady; bmin[1] = min(va[1],vb[1]) - pady;
@ -74,6 +74,22 @@ inline int computeTileHash(int x, int y, const int mask)
return (int)(n & mask); return (int)(n & mask);
} }
inline unsigned int allocLink(dtMeshTile* tile)
{
if (tile->header->linksFreeList == DT_NULL_LINK)
return DT_NULL_LINK;
unsigned int link = tile->header->linksFreeList;
tile->header->linksFreeList = tile->header->links[link].next;
return link;
}
inline void freeLink(dtMeshTile* tile, unsigned int link)
{
tile->header->links[link].next = tile->header->linksFreeList;
tile->header->linksFreeList = link;
}
inline bool passFilter(dtQueryFilter* filter, unsigned short flags) inline bool passFilter(dtQueryFilter* filter, unsigned short flags)
{ {
return (flags & filter->includeFlags) != 0 && (flags & filter->excludeFlags) == 0; return (flags & filter->includeFlags) != 0 && (flags & filter->excludeFlags) == 0;
@ -91,8 +107,6 @@ dtNavMesh::dtNavMesh() :
m_posLookup(0), m_posLookup(0),
m_nextFree(0), m_nextFree(0),
m_tiles(0), m_tiles(0),
m_tmpLinks(0),
m_ntmpLinks(0),
m_saltBits(0), m_saltBits(0),
m_tileBits(0), m_tileBits(0),
m_polyBits(0), m_polyBits(0),
@ -115,7 +129,6 @@ dtNavMesh::~dtNavMesh()
m_tiles[i].dataSize = 0; m_tiles[i].dataSize = 0;
} }
} }
delete [] m_tmpLinks;
delete m_nodePool; delete m_nodePool;
delete m_openList; delete m_openList;
delete [] m_posLookup; delete [] m_posLookup;
@ -236,67 +249,49 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
return n; return n;
} }
void dtNavMesh::removeExtLinks(dtMeshTile* tile, int side) void dtNavMesh::unconnectExtLinks(dtMeshTile* tile, int side)
{ {
if (!tile) return; if (!tile) return;
dtMeshHeader* h = tile->header; dtMeshHeader* header = tile->header;
// Remove links pointing to 'side' and compact the links array. for (int i = 0; i < header->polyCount; ++i)
dtLink* pool = m_tmpLinks;
int nlinks = 0;
for (int i = 0; i < h->polyCount; ++i)
{ {
dtPoly* poly = &h->polys[i]; dtPoly* poly = &header->polys[i];
int plinks = nlinks; unsigned int j = poly->firstLink;
int nplinks = 0; unsigned int pj = DT_NULL_LINK;
for (int j = 0; j < poly->linkCount; ++j) while (j != DT_NULL_LINK)
{ {
dtLink* link = &h->links[poly->linkBase+j]; if (header->links[j].side == side)
if ((int)link->side != side)
{ {
if (nlinks < h->maxLinkCount) // Revove link.
{ unsigned int nj = header->links[j].next;
dtLink* dst = &pool[nlinks++]; if (pj == DT_NULL_LINK)
memcpy(dst, link, sizeof(dtLink)); poly->firstLink = nj;
nplinks++; else
} header->links[pj].next = nj;
freeLink(tile, j);
j = nj;
}
else
{
// Advance
pj = j;
j = header->links[j].next;
} }
} }
poly->linkBase = plinks;
poly->linkCount = nplinks;
} }
h->linkCount = nlinks;
if (h->linkCount)
memcpy(h->links, m_tmpLinks, sizeof(dtLink)*nlinks);
} }
void dtNavMesh::buildExtLinks(dtMeshTile* tile, dtMeshTile* target, int side) void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
{ {
if (!tile) return; if (!tile) return;
dtMeshHeader* h = tile->header; dtMeshHeader* header = tile->header;
// Remove links pointing to 'side' and compact the links array. // Connect border links.
dtLink* pool = m_tmpLinks; for (int i = 0; i < header->polyCount; ++i)
int nlinks = 0;
for (int i = 0; i < h->polyCount; ++i)
{ {
dtPoly* poly = &h->polys[i]; dtPoly* poly = &header->polys[i];
int plinks = nlinks;
int nplinks = 0;
// Copy internal and other external links.
for (int j = 0; j < poly->linkCount; ++j)
{
dtLink* link = &h->links[poly->linkBase+j];
if ((int)link->side != side)
{
if (nlinks < h->maxLinkCount)
{
dtLink* dst = &pool[nlinks++];
memcpy(dst, link, sizeof(dtLink));
nplinks++;
}
}
}
// Create new links. // 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; const int nv = poly->vertCount;
@ -306,168 +301,216 @@ void dtNavMesh::buildExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
if (poly->neis[j] != m) continue; if (poly->neis[j] != m) continue;
// Create new links // Create new links
const float* va = &h->verts[poly->verts[j]*3]; const float* va = &header->verts[poly->verts[j]*3];
const float* vb = &h->verts[poly->verts[(j+1) % nv]*3]; const float* vb = &header->verts[poly->verts[(j+1) % nv]*3];
dtPolyRef nei[4]; dtPolyRef nei[4];
float neia[4*2]; float neia[4*2];
int nnei = findConnectingPolys(va,vb, target, opposite(side), nei,neia,4); int nnei = findConnectingPolys(va,vb, target, opposite(side), nei,neia,4);
for (int k = 0; k < nnei; ++k) for (int k = 0; k < nnei; ++k)
{ {
if (nlinks < h->maxLinkCount) unsigned int idx = allocLink(tile);
if (idx != DT_NULL_LINK)
{ {
dtLink* link = &pool[nlinks++]; dtLink* link = &header->links[idx];
link->ref = nei[k]; link->ref = nei[k];
link->poly = (unsigned short)i;
link->edge = (unsigned char)j; link->edge = (unsigned char)j;
link->side = (unsigned char)side; link->side = (unsigned char)side;
link->next = poly->firstLink;
poly->firstLink = idx;
// Compress portal limits to a byte value. // Compress portal limits to a byte value.
if (side == 0 || side == 2) if (side == 0 || side == 4)
{ {
const float lmin = min(va[2], vb[2]); const float lmin = min(va[2], vb[2]);
const float lmax = max(va[2], vb[2]); const float lmax = max(va[2], vb[2]);
link->bmin = (unsigned char)(clamp((neia[k*2+0]-lmin)/(lmax-lmin), 0.0f, 1.0f)*255.0f); link->bmin = (unsigned char)(clamp((neia[k*2+0]-lmin)/(lmax-lmin), 0.0f, 1.0f)*255.0f);
link->bmax = (unsigned char)(clamp((neia[k*2+1]-lmin)/(lmax-lmin), 0.0f, 1.0f)*255.0f); link->bmax = (unsigned char)(clamp((neia[k*2+1]-lmin)/(lmax-lmin), 0.0f, 1.0f)*255.0f);
} }
else else if (side == 2 || side == 6)
{ {
const float lmin = min(va[0], vb[0]); const float lmin = min(va[0], vb[0]);
const float lmax = max(va[0], vb[0]); const float lmax = max(va[0], vb[0]);
link->bmin = (unsigned char)(clamp((neia[k*2+0]-lmin)/(lmax-lmin), 0.0f, 1.0f)*255.0f); link->bmin = (unsigned char)(clamp((neia[k*2+0]-lmin)/(lmax-lmin), 0.0f, 1.0f)*255.0f);
link->bmax = (unsigned char)(clamp((neia[k*2+1]-lmin)/(lmax-lmin), 0.0f, 1.0f)*255.0f); link->bmax = (unsigned char)(clamp((neia[k*2+1]-lmin)/(lmax-lmin), 0.0f, 1.0f)*255.0f);
}
nplinks++;
}
}
}
poly->linkBase = plinks;
poly->linkCount = nplinks;
}
h->linkCount = nlinks;
if (h->linkCount)
memcpy(h->links, m_tmpLinks, sizeof(dtLink)*nlinks);
}
void dtNavMesh::buildIntLinks(dtMeshTile* tile)
{
if (!tile) return;
dtMeshHeader* h = tile->header;
dtPolyRef base = getTileId(tile);
dtLink* pool = h->links;
int nlinks = 0;
unsigned int salt, it, ip, tileIdx;
dtDecodePolyId(base, salt, tileIdx, ip);
// Find Off-mesh connection end points.
for (int i = 0; i < h->offMeshConCount; ++i)
{
dtOffMeshConnection* con = &h->offMeshCons[i];
dtPoly* poly = &h->polys[con->poly];
dtQueryFilter defaultFilter;
con->ref[0] = 0;
con->ref[1] = 0;
const float ext[3] = { con->rad, h->walkableClimb, con->rad };
for (int j = 0; j < 2; ++j)
{
// Find polygon to connect to.
const float* p = &con->pos[j*3];
float nearestPt[3];
dtPolyRef ref = findNearestPoly(p, ext, &defaultFilter, nearestPt);
// findNearestPoly may return too optimistic results, further check to make sure.
if (sqr(nearestPt[0]-p[0])+sqr(nearestPt[2]-p[2]) > sqr(con->rad))
continue;
// TODO: Handle cross tile links.
dtDecodePolyId(ref, salt, it, ip);
if (it != tileIdx)
continue;
// Make sure the location is on current mesh.
float* v = &h->verts[poly->verts[j]*3];
vcopy(v, nearestPt);
con->ref[j] = ref;
}
}
for (int i = 0; i < h->polyCount; ++i)
{
dtPoly* poly = &h->polys[i];
poly->linkBase = nlinks;
poly->linkCount = 0;
if (poly->flags & DT_POLY_OFFMESH_CONNECTION)
{
// Find Off-Mesh link and fill in information.
dtOffMeshConnection* con = &h->offMeshCons[i - h->offMeshBase];
// Connect both ends.
for (int j = 0; j < 2; ++j)
{
if (nlinks < h->maxLinkCount)
{
dtLink* link = &pool[nlinks++];
link->ref = con->ref[j];
link->poly = (unsigned short)i;
link->edge = (unsigned char)j;
link->side = 0xff;
link->bmin = link->bmax = 0;
poly->linkCount++;
}
}
}
else
{
// Polygon edges.
for (int j = 0; j < poly->vertCount; ++j)
{
// Skip hard and non-internal edges.
if (poly->neis[j] == 0 || (poly->neis[j] & DT_EXT_LINK)) continue;
if (nlinks < h->maxLinkCount)
{
dtLink* link = &pool[nlinks++];
link->ref = base | (unsigned int)(poly->neis[j]-1);
link->poly = (unsigned short)i;
link->edge = (unsigned char)j;
link->side = 0xff;
link->bmin = link->bmax = 0;
poly->linkCount++;
}
}
// Check this polygon is Off-Mesh link target and connect.
// TODO: Speed this up.
dtPolyRef curRef = base | (unsigned int)i;
for (int j = 0; j < h->offMeshConCount; ++j)
{
const dtOffMeshConnection* con = &h->offMeshCons[j];
// Test both end points.
for (int k = 0; k < 2; ++k)
{
if (con->ref[k] == curRef)
{
if (nlinks < h->maxLinkCount)
{
dtLink* link = &pool[nlinks++];
link->ref = base | (dtPolyRef)con->poly;
link->poly = (unsigned short)i;
link->edge = 0;
link->side = 0xff;
link->bmin = link->bmax = 0;
poly->linkCount++;
}
} }
} }
} }
}
}
}
void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side)
{
if (!tile) return;
dtMeshHeader* header = tile->header;
// Connect off-mesh links.
// We are interested on links which land from target tile to this tile.
dtMeshHeader* targetHeader = target->header;
const unsigned char oppositeSide = (unsigned char)opposite(side);
dtQueryFilter defaultFilter;
for (int i = 0; i < targetHeader->offMeshConCount; ++i)
{
dtOffMeshConnection* targetCon = &targetHeader->offMeshCons[i];
if (targetCon->side != oppositeSide)
continue;
dtPoly* targetPoly = &targetHeader->polys[targetCon->poly];
const float ext[3] = { targetCon->rad, targetHeader->walkableClimb, targetCon->rad };
// Find polygon to connect to.
const float* p = &targetCon->pos[3];
float nearestPt[3];
dtPolyRef ref = findNearestPolyInTile(tile, p, ext, &defaultFilter, nearestPt);
if (!ref) continue;
// findNearestPoly may return too optimistic results, further check to make sure.
if (sqr(nearestPt[0]-p[0])+sqr(nearestPt[2]-p[2]) > sqr(targetCon->rad))
continue;
// Make sure the location is on current mesh.
float* v = &targetHeader->verts[targetPoly->verts[1]*3];
vcopy(v, nearestPt);
// Link off-mesh connection to target poly.
unsigned int idx = allocLink(target);
if (idx != DT_NULL_LINK)
{
dtLink* link = &targetHeader->links[idx];
link->ref = ref;
link->edge = (unsigned char)1;
link->side = oppositeSide;
link->bmin = link->bmax = 0;
// Add to linked list.
link->next = targetPoly->firstLink;
targetPoly->firstLink = idx;
}
// Link target poly to off-mesh connection.
idx = allocLink(tile);
if (idx != DT_NULL_LINK)
{
unsigned short landPolyIdx = decodePolyIdPoly(ref);
dtPoly* landPoly = &header->polys[landPolyIdx];
dtLink* link = &header->links[idx];
link->ref = getTileId(target) | (unsigned int)(targetCon->poly);
link->edge = 0;
link->side = side;
link->bmin = link->bmax = 0;
// Add to linked list.
link->next = landPoly->firstLink;
landPoly->firstLink = idx;
} }
} }
h->linkCount = nlinks; }
void dtNavMesh::connectIntLinks(dtMeshTile* tile)
{
if (!tile) return;
dtMeshHeader* header = tile->header;
dtPolyRef base = getTileId(tile);
for (int i = 0; i < header->polyCount; ++i)
{
dtPoly* poly = &header->polys[i];
poly->firstLink = DT_NULL_LINK;
if (poly->flags & DT_POLY_OFFMESH_CONNECTION)
continue;
// Build edge links backwards so that the links will be
// in the linked list from lowest index to highest.
for (int j = poly->vertCount-1; j >= 0; --j)
{
// Skip hard and non-internal edges.
if (poly->neis[j] == 0 || (poly->neis[j] & DT_EXT_LINK)) continue;
unsigned int idx = allocLink(tile);
if (idx != DT_NULL_LINK)
{
dtLink* link = &header->links[idx];
link->ref = base | (unsigned int)(poly->neis[j]-1);
link->edge = (unsigned char)j;
link->side = 0xff;
link->bmin = link->bmax = 0;
// Add to linked list.
link->next = poly->firstLink;
poly->firstLink = idx;
}
}
}
}
void dtNavMesh::connectIntOffMeshLinks(dtMeshTile* tile)
{
if (!tile) return;
dtMeshHeader* header = tile->header;
dtPolyRef base = getTileId(tile);
// Find Off-mesh connection end points.
for (int i = 0; i < header->offMeshConCount; ++i)
{
dtOffMeshConnection* con = &header->offMeshCons[i];
dtPoly* poly = &header->polys[con->poly];
dtQueryFilter defaultFilter;
const float ext[3] = { con->rad, header->walkableClimb, con->rad };
for (int j = 0; j < 2; ++j)
{
unsigned char side = j == 0 ? 0xff : con->side;
if (side == 0xff)
{
// Find polygon to connect to.
const float* p = &con->pos[j*3];
float nearestPt[3];
dtPolyRef ref = findNearestPolyInTile(tile, p, ext, &defaultFilter, nearestPt);
if (!ref) continue;
// findNearestPoly may return too optimistic results, further check to make sure.
if (sqr(nearestPt[0]-p[0])+sqr(nearestPt[2]-p[2]) > sqr(con->rad))
continue;
// Make sure the location is on current mesh.
float* v = &header->verts[poly->verts[j]*3];
vcopy(v, nearestPt);
// Link off-mesh connection to target poly.
unsigned int idx = allocLink(tile);
if (idx != DT_NULL_LINK)
{
dtLink* link = &header->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 target poly to off-mesh connection.
idx = allocLink(tile);
if (idx != DT_NULL_LINK)
{
unsigned short landPolyIdx = decodePolyIdPoly(ref);
dtPoly* landPoly = &header->polys[landPolyIdx];
dtLink* link = &header->links[idx];
link->ref = base | (unsigned int)(con->poly);
link->edge = 0;
link->side = 0xff;
link->bmin = link->bmax = 0;
// Add to linked list.
link->next = landPoly->firstLink;
landPoly->firstLink = idx;
}
}
}
}
} }
bool dtNavMesh::addTileAt(int x, int y, unsigned char* data, int dataSize, bool ownsData) bool dtNavMesh::addTileAt(int x, int y, unsigned char* data, int dataSize, bool ownsData)
@ -483,18 +526,7 @@ bool dtNavMesh::addTileAt(int x, int y, unsigned char* data, int dataSize, bool
return false; return false;
if (header->version != DT_NAVMESH_VERSION) if (header->version != DT_NAVMESH_VERSION)
return false; return false;
// Make sure the tmp link array is large enough.
if (header->maxLinkCount > m_ntmpLinks)
{
m_ntmpLinks = header->maxLinkCount;
delete [] m_tmpLinks;
m_tmpLinks = 0;
m_tmpLinks = new dtLink[m_ntmpLinks];
}
if (!m_tmpLinks)
return false;
// Allocate a tile. // Allocate a tile.
dtMeshTile* tile = m_nextFree; dtMeshTile* tile = m_nextFree;
m_nextFree = tile->next; m_nextFree = tile->next;
@ -526,6 +558,12 @@ bool dtNavMesh::addTileAt(int x, int y, unsigned char* data, int dataSize, bool
header->bvTree = (dtBVNode*)d; d += bvtreeSize; header->bvTree = (dtBVNode*)d; d += bvtreeSize;
header->offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize; header->offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize;
// Build links freelist
header->linksFreeList = 0;
header->links[header->maxLinkCount-1].next = DT_NULL_LINK;
for (int i = 0; i < header->maxLinkCount-1; ++i)
header->links[i].next = i+1;
// Init tile. // Init tile.
tile->header = header; tile->header = header;
tile->x = x; tile->x = x;
@ -534,16 +572,19 @@ bool dtNavMesh::addTileAt(int x, int y, unsigned char* data, int dataSize, bool
tile->dataSize = dataSize; tile->dataSize = dataSize;
tile->ownsData = ownsData; tile->ownsData = ownsData;
buildIntLinks(tile); connectIntLinks(tile);
connectIntOffMeshLinks(tile);
// Create connections connections. // Create connections connections.
for (int i = 0; i < 4; ++i) for (int i = 0; i < 8; ++i)
{ {
dtMeshTile* nei = getNeighbourTileAt(x,y,i); dtMeshTile* nei = getNeighbourTileAt(x,y,i);
if (nei) if (nei)
{ {
buildExtLinks(tile, nei, i); connectExtLinks(tile, nei, i);
buildExtLinks(nei, tile, opposite(i)); connectExtLinks(nei, tile, opposite(i));
connectExtOffMeshLinks(tile, nei, i);
connectExtOffMeshLinks(nei, tile, opposite(i));
} }
} }
@ -582,7 +623,7 @@ const dtMeshTile* dtNavMesh::getTile(int i) const
const dtMeshTile* dtNavMesh::getTileByRef(dtPolyRef ref, int* polyIndex) const const dtMeshTile* dtNavMesh::getTileByRef(dtPolyRef ref, int* polyIndex) const
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip); decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return 0; if (it >= (unsigned int)m_maxTiles) return 0;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0; if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0;
@ -595,9 +636,13 @@ dtMeshTile* dtNavMesh::getNeighbourTileAt(int x, int y, int side)
switch (side) switch (side)
{ {
case 0: x++; break; case 0: x++; break;
case 1: y++; break; case 1: x++; y++; break;
case 2: x--; break; case 2: y++; break;
case 3: 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;
}; };
return getTileAt(x,y); return getTileAt(x,y);
} }
@ -625,11 +670,11 @@ bool dtNavMesh::removeTileAt(int x, int y, unsigned char** data, int* dataSize)
return false; return false;
// Remove connections to neighbour tiles. // Remove connections to neighbour tiles.
for (int i = 0; i < 4; ++i) for (int i = 0; i < 8; ++i)
{ {
dtMeshTile* nei = getNeighbourTileAt(x,y,i); dtMeshTile* nei = getNeighbourTileAt(x,y,i);
if (!nei) continue; if (!nei) continue;
removeExtLinks(nei, opposite(i)); unconnectExtLinks(nei, opposite(i));
} }
@ -663,19 +708,25 @@ dtPolyRef dtNavMesh::getTileId(const dtMeshTile* tile) const
{ {
if (!tile) return 0; if (!tile) return 0;
const unsigned int it = tile - m_tiles; const unsigned int it = tile - m_tiles;
return dtEncodePolyId(tile->salt, it, 0); return encodePolyId(tile->salt, it, 0);
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
bool dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const bool dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip); decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false; if (it >= (unsigned int)m_maxTiles) return false;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false;
const dtMeshHeader* header = m_tiles[it].header; const dtMeshHeader* header = m_tiles[it].header;
if (ip >= (unsigned int)header->polyCount) return false; if (ip >= (unsigned int)header->polyCount) return false;
return closestPointOnPolyInTile(&m_tiles[it], ip, pos, closest);
}
bool dtNavMesh::closestPointOnPolyInTile(const dtMeshTile* tile, unsigned int ip, const float* pos, float* closest) const
{
const dtMeshHeader* header = tile->header;
const dtPoly* poly = &header->polys[ip]; const dtPoly* poly = &header->polys[ip];
float closestDistSqr = FLT_MAX; float closestDistSqr = FLT_MAX;
@ -708,7 +759,7 @@ bool dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* close
bool dtNavMesh::closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const bool dtNavMesh::closestPointOnPolyBoundary(dtPolyRef ref, const float* pos, float* closest) const
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip); decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false; if (it >= (unsigned int)m_maxTiles) return false;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false;
const dtMeshHeader* header = m_tiles[it].header; const dtMeshHeader* header = m_tiles[it].header;
@ -759,16 +810,8 @@ bool dtNavMesh::getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef p
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
// Get previous poly
dtDecodePolyId(prevRef, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false;
const dtMeshHeader* prevHeader = m_tiles[it].header;
if (ip >= (unsigned int)prevHeader->polyCount) return false;
const dtPoly* prevPoly = &prevHeader->polys[ip];
// Get current polygon // Get current polygon
dtDecodePolyId(polyRef, salt, it, ip); decodePolyId(polyRef, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false; if (it >= (unsigned int)m_maxTiles) return false;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false;
const dtMeshHeader* header = m_tiles[it].header; const dtMeshHeader* header = m_tiles[it].header;
@ -782,20 +825,20 @@ bool dtNavMesh::getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef p
// Figure out which way to hand out the vertices. // Figure out which way to hand out the vertices.
int idx0 = 0, idx1 = 1; int idx0 = 0, idx1 = 1;
for (int i = 0; i < prevPoly->linkCount; ++i) // Find link that points to first vertex.
for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = header->links[i].next)
{ {
const dtLink* link = &prevHeader->links[prevPoly->linkBase+i]; if (header->links[i].edge == 0)
if (link->ref != polyRef)
continue;
// If first link does not point to the prev, then we need to reverse the order.
if (header->links[poly->linkBase+0].ref != prevRef)
{ {
idx0 = 1; if (header->links[i].ref != prevRef)
idx1 = 0; {
idx0 = 1;
idx1 = 0;
}
break; break;
} }
} }
vcopy(startPos, &header->verts[poly->verts[idx0]*3]); vcopy(startPos, &header->verts[poly->verts[idx0]*3]);
vcopy(endPos, &header->verts[poly->verts[idx1]*3]); vcopy(endPos, &header->verts[poly->verts[idx1]*3]);
@ -806,7 +849,7 @@ bool dtNavMesh::getOffMeshConnectionPolyEndPoints(dtPolyRef prevRef, dtPolyRef p
bool dtNavMesh::getPolyHeight(dtPolyRef ref, const float* pos, float* height) const bool dtNavMesh::getPolyHeight(dtPolyRef ref, const float* pos, float* height) const
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip); decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false; if (it >= (unsigned int)m_maxTiles) return false;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false;
const dtMeshHeader* header = m_tiles[it].header; const dtMeshHeader* header = m_tiles[it].header;
@ -881,9 +924,42 @@ dtPolyRef dtNavMesh::findNearestPoly(const float* center, const float* extents,
return nearest; return nearest;
} }
int dtNavMesh::queryTilePolygons(dtMeshTile* tile, const float* qmin, const float* qmax, dtPolyRef dtNavMesh::findNearestPolyInTile(dtMeshTile* tile, const float* center, const float* extents,
dtQueryFilter* filter, dtQueryFilter* filter, float* nearestPt)
dtPolyRef* polys, const int maxPolys) {
float bmin[3], bmax[3];
vsub(bmin, center, extents);
vadd(bmax, center, extents);
// Get nearby polygons from proximity grid.
dtPolyRef polys[128];
int polyCount = queryPolygonsInTile(tile, bmin, bmax, filter, polys, 128);
// Find nearest polygon amongst the nearby polygons.
dtPolyRef nearest = 0;
float nearestDistanceSqr = FLT_MAX;
for (int i = 0; i < polyCount; ++i)
{
dtPolyRef ref = polys[i];
float closestPtPoly[3];
if (!closestPointOnPolyInTile(tile, decodePolyIdPoly(ref), center, closestPtPoly))
continue;
float d = vdistSqr(center, closestPtPoly);
if (d < nearestDistanceSqr)
{
if (nearestPt)
vcopy(nearestPt, closestPtPoly);
nearestDistanceSqr = d;
nearest = ref;
}
}
return nearest;
}
int dtNavMesh::queryPolygonsInTile(dtMeshTile* tile, const float* qmin, const float* qmax,
dtQueryFilter* filter,
dtPolyRef* polys, const int maxPolys)
{ {
const dtMeshHeader* header = tile->header; const dtMeshHeader* header = tile->header;
if (header->bvTree) if (header->bvTree)
@ -972,13 +1048,8 @@ int dtNavMesh::queryPolygons(const float* center, const float* extents, dtQueryF
dtPolyRef* polys, const int maxPolys) dtPolyRef* polys, const int maxPolys)
{ {
float bmin[3], bmax[3]; float bmin[3], bmax[3];
bmin[0] = center[0] - extents[0]; vsub(bmin, center, extents);
bmin[1] = center[1] - extents[1]; vadd(bmax, center, extents);
bmin[2] = center[2] - extents[2];
bmax[0] = center[0] + extents[0];
bmax[1] = center[1] + extents[1];
bmax[2] = center[2] + extents[2];
// Find tiles the query touches. // Find tiles the query touches.
const int minx = (int)floorf((bmin[0]-m_orig[0]) / m_tileWidth); const int minx = (int)floorf((bmin[0]-m_orig[0]) / m_tileWidth);
@ -994,7 +1065,7 @@ int dtNavMesh::queryPolygons(const float* center, const float* extents, dtQueryF
{ {
dtMeshTile* tile = getTileAt(x,y); dtMeshTile* tile = getTileAt(x,y);
if (!tile) continue; if (!tile) continue;
n += queryTilePolygons(tile, bmin, bmax, filter, polys+n, maxPolys-n); n += queryPolygonsInTile(tile, bmin, bmax, filter, polys+n, maxPolys-n);
if (n >= maxPolys) return n; if (n >= maxPolys) return n;
} }
} }
@ -1052,14 +1123,14 @@ int dtNavMesh::findPath(dtPolyRef startRef, dtPolyRef endRef,
// Get poly and tile. // Get poly and tile.
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(bestNode->id, salt, it, ip); decodePolyId(bestNode->id, salt, it, ip);
// The API input has been cheked already, skip checking internal data. // The API input has been cheked already, skip checking internal data.
const dtMeshHeader* header = m_tiles[it].header; const dtMeshHeader* header = m_tiles[it].header;
const dtPoly* poly = &header->polys[ip]; const dtPoly* poly = &header->polys[ip];
for (int i = 0; i < poly->linkCount; ++i) for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = header->links[i].next)
{ {
dtPolyRef neighbour = header->links[poly->linkBase+i].ref; dtPolyRef neighbour = header->links[i].ref;
if (neighbour) if (neighbour)
{ {
// Skip parent node. // Skip parent node.
@ -1388,7 +1459,7 @@ int dtNavMesh::moveAlongPathCorridor(const float* startPos, const float* endPos,
{ {
// Get current polygon and poly vertices. // Get current polygon and poly vertices.
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(path[n], salt, it, ip); decodePolyId(path[n], salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return n; if (it >= (unsigned int)m_maxTiles) return n;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return n; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return n;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return n; if (ip >= (unsigned int)m_tiles[it].header->polyCount) return n;
@ -1465,7 +1536,7 @@ bool dtNavMesh::getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float
unsigned short& fromFlags, unsigned short& toFlags) const unsigned short& fromFlags, unsigned short& toFlags) const
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(from, salt, it, ip); decodePolyId(from, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false; if (it >= (unsigned int)m_maxTiles) return false;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return false; if (ip >= (unsigned int)m_tiles[it].header->polyCount) return false;
@ -1473,13 +1544,13 @@ bool dtNavMesh::getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float
const dtPoly* fromPoly = &fromHeader->polys[ip]; const dtPoly* fromPoly = &fromHeader->polys[ip];
fromFlags = fromPoly->flags; fromFlags = fromPoly->flags;
for (int i = 0; i < fromPoly->linkCount; ++i) for (unsigned int i = fromPoly->firstLink; i != DT_NULL_LINK; i = fromHeader->links[i].next)
{ {
const dtLink* link = &fromHeader->links[fromPoly->linkBase+i]; const dtLink* link = &fromHeader->links[i];
if (link->ref != to) if (link->ref != to)
continue; continue;
dtDecodePolyId(to, salt, it, ip); decodePolyId(to, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false; if (it >= (unsigned int)m_maxTiles) return false;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return false; if (ip >= (unsigned int)m_tiles[it].header->polyCount) return false;
@ -1489,18 +1560,33 @@ bool dtNavMesh::getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float
if (fromPoly->flags & DT_POLY_OFFMESH_CONNECTION) if (fromPoly->flags & DT_POLY_OFFMESH_CONNECTION)
{ {
const int v = fromHeader->links[fromPoly->linkBase+0].ref == to ? 0 : 1; // Find link that points to first vertex.
vcopy(left, &fromHeader->verts[fromPoly->verts[v]*3]); for (unsigned int i = fromPoly->firstLink; i != DT_NULL_LINK; i = fromHeader->links[i].next)
vcopy(right, &fromHeader->verts[fromPoly->verts[v]*3]); {
return true; if (fromHeader->links[i].ref == to)
{
const int v = fromHeader->links[i].edge;
vcopy(left, &fromHeader->verts[fromPoly->verts[v]*3]);
vcopy(right, &fromHeader->verts[fromPoly->verts[v]*3]);
return true;
}
}
return false;
} }
if (toPoly->flags & DT_POLY_OFFMESH_CONNECTION) if (toPoly->flags & DT_POLY_OFFMESH_CONNECTION)
{ {
const int v = toHeader->links[toPoly->linkBase+0].ref == from ? 0 : 1; for (unsigned int i = toPoly->firstLink; i != DT_NULL_LINK; i = toHeader->links[i].next)
vcopy(left, &toHeader->verts[toPoly->verts[v]*3]); {
vcopy(right, &toHeader->verts[toPoly->verts[v]*3]); if (toHeader->links[i].ref == from)
return true; {
const int v = toHeader->links[i].edge;
vcopy(left, &toHeader->verts[toPoly->verts[v]*3]);
vcopy(right, &toHeader->verts[toPoly->verts[v]*3]);
return true;
}
}
return false;
} }
// Find portal vertices. // Find portal vertices.
@ -1510,7 +1596,7 @@ bool dtNavMesh::getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float
vcopy(right, &fromHeader->verts[v1*3]); vcopy(right, &fromHeader->verts[v1*3]);
// If the link is at tile boundary, clamp the vertices to // If the link is at tile boundary, clamp the vertices to
// the link width. // the link width.
if (link->side == 0 || link->side == 2) if (link->side == 0 || link->side == 4)
{ {
// Unpack portal limits. // Unpack portal limits.
const float smin = min(left[2],right[2]); const float smin = min(left[2],right[2]);
@ -1523,7 +1609,7 @@ bool dtNavMesh::getPortalPoints(dtPolyRef from, dtPolyRef to, float* left, float
right[2] = max(right[2],lmin); right[2] = max(right[2],lmin);
right[2] = min(right[2],lmax); right[2] = min(right[2],lmax);
} }
else if (link->side == 1 || link->side == 3) else if (link->side == 2 || link->side == 6)
{ {
// Unpack portal limits. // Unpack portal limits.
const float smin = min(left[0],right[0]); const float smin = min(left[0],right[0]);
@ -1556,7 +1642,7 @@ bool dtNavMesh::getEdgeMidPoint(dtPolyRef from, dtPolyRef to, float* mid) const
unsigned short dtNavMesh::getPolyFlags(dtPolyRef ref) unsigned short dtNavMesh::getPolyFlags(dtPolyRef ref)
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip); decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return 0; if (it >= (unsigned int)m_maxTiles) return 0;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0; if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0;
@ -1586,8 +1672,8 @@ int dtNavMesh::raycast(dtPolyRef centerRef, const float* startPos, const float*
// Cast ray against current polygon. // Cast ray against current polygon.
// The API input has been cheked already, skip checking internal data. // The API input has been cheked already, skip checking internal data.
unsigned int salt, it, ip; unsigned int it = decodePolyIdTile(curRef);
dtDecodePolyId(curRef, salt, it, ip); unsigned int ip = decodePolyIdPoly(curRef);
const dtMeshHeader* header = m_tiles[it].header; const dtMeshHeader* header = m_tiles[it].header;
const dtPoly* poly = &header->polys[ip]; const dtPoly* poly = &header->polys[ip];
@ -1615,9 +1701,10 @@ int dtNavMesh::raycast(dtPolyRef centerRef, const float* startPos, const float*
// Follow neighbours. // Follow neighbours.
dtPolyRef nextRef = 0; dtPolyRef nextRef = 0;
for (int i = 0; i < poly->linkCount; ++i)
for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = header->links[i].next)
{ {
const dtLink* link = &header->links[poly->linkBase+i]; const dtLink* link = &header->links[i];
if ((int)link->edge == segMax) if ((int)link->edge == segMax)
{ {
// If the link is internal, just return the ref. // If the link is internal, just return the ref.
@ -1634,7 +1721,7 @@ int dtNavMesh::raycast(dtPolyRef centerRef, const float* startPos, const float*
const float* right = &header->verts[v1*3]; const float* right = &header->verts[v1*3];
// Check that the intersection lies inside the link portal. // Check that the intersection lies inside the link portal.
if (link->side == 0 || link->side == 2) if (link->side == 0 || link->side == 4)
{ {
// Calculate link size. // Calculate link size.
const float smin = min(left[2],right[2]); const float smin = min(left[2],right[2]);
@ -1650,7 +1737,7 @@ int dtNavMesh::raycast(dtPolyRef centerRef, const float* startPos, const float*
break; break;
} }
} }
else if (link->side == 1 || link->side == 3) else if (link->side == 2 || link->side == 6)
{ {
// Calculate link size. // Calculate link size.
const float smin = min(left[0],right[0]); const float smin = min(left[0],right[0]);
@ -1733,15 +1820,15 @@ int dtNavMesh::findPolysAround(dtPolyRef centerRef, const float* centerPos, floa
dtNode* bestNode = m_openList->pop(); dtNode* bestNode = m_openList->pop();
// Get poly and tile. // Get poly and tile.
unsigned int salt, it, ip;
dtDecodePolyId(bestNode->id, salt, it, ip);
// The API input has been cheked already, skip checking internal data. // The API input has been cheked already, skip checking internal data.
unsigned int it = decodePolyIdTile(bestNode->id);
unsigned int ip = decodePolyIdPoly(bestNode->id);
const dtMeshHeader* header = m_tiles[it].header; const dtMeshHeader* header = m_tiles[it].header;
const dtPoly* poly = &header->polys[ip]; const dtPoly* poly = &header->polys[ip];
for (int i = 0; i < poly->linkCount; ++i) for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = header->links[i].next)
{ {
const dtLink* link = &header->links[poly->linkBase+i]; const dtLink* link = &header->links[i];
dtPolyRef neighbour = link->ref; dtPolyRef neighbour = link->ref;
if (neighbour) if (neighbour)
{ {
@ -1839,9 +1926,9 @@ float dtNavMesh::findDistanceToWall(dtPolyRef centerRef, const float* centerPos,
dtNode* bestNode = m_openList->pop(); dtNode* bestNode = m_openList->pop();
// Get poly and tile. // Get poly and tile.
unsigned int salt, it, ip;
dtDecodePolyId(bestNode->id, salt, it, ip);
// The API input has been cheked already, skip checking internal data. // The API input has been cheked already, skip checking internal data.
unsigned int it = decodePolyIdTile(bestNode->id);
unsigned int ip = decodePolyIdPoly(bestNode->id);
const dtMeshHeader* header = m_tiles[it].header; const dtMeshHeader* header = m_tiles[it].header;
const dtPoly* poly = &header->polys[ip]; const dtPoly* poly = &header->polys[ip];
@ -1853,9 +1940,9 @@ float dtNavMesh::findDistanceToWall(dtPolyRef centerRef, const float* centerPos,
{ {
// Tile border. // Tile border.
bool solid = true; bool solid = true;
for (int i = 0; i < poly->linkCount; ++i) for (unsigned int k = poly->firstLink; k != DT_NULL_LINK; k = header->links[k].next)
{ {
const dtLink* link = &header->links[poly->linkBase+i]; const dtLink* link = &header->links[k];
if (link->edge == j && link->ref != 0 && passFilter(filter, getPolyFlags(link->ref))) if (link->edge == j && link->ref != 0 && passFilter(filter, getPolyFlags(link->ref)))
{ {
solid = false; solid = false;
@ -1864,7 +1951,7 @@ float dtNavMesh::findDistanceToWall(dtPolyRef centerRef, const float* centerPos,
} }
if (!solid) continue; if (!solid) continue;
} }
else if (poly->neis[j] && passFilter(filter, getPolyFlags(poly->neis[j]))) else if (poly->neis[j] && passFilter(filter, header->polys[poly->neis[j]].flags))
{ {
// Internal edge // Internal edge
continue; continue;
@ -1888,9 +1975,9 @@ float dtNavMesh::findDistanceToWall(dtPolyRef centerRef, const float* centerPos,
hitPos[2] = vj[2] + (vi[2] - vj[2])*tseg; hitPos[2] = vj[2] + (vi[2] - vj[2])*tseg;
} }
for (int i = 0; i < poly->linkCount; ++i) for (unsigned int i = poly->firstLink; i != DT_NULL_LINK; i = header->links[i].next)
{ {
const dtLink* link = &header->links[poly->linkBase+i]; const dtLink* link = &header->links[i];
dtPolyRef neighbour = link->ref; dtPolyRef neighbour = link->ref;
if (neighbour) if (neighbour)
{ {
@ -1959,7 +2046,7 @@ float dtNavMesh::findDistanceToWall(dtPolyRef centerRef, const float* centerPos,
const dtPoly* dtNavMesh::getPolyByRef(dtPolyRef ref) const const dtPoly* dtNavMesh::getPolyByRef(dtPolyRef ref) const
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip); decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return 0; if (it >= (unsigned int)m_maxTiles) return 0;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0; if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0;
@ -1969,7 +2056,7 @@ const dtPoly* dtNavMesh::getPolyByRef(dtPolyRef ref) const
const float* dtNavMesh::getPolyVertsByRef(dtPolyRef ref) const const float* dtNavMesh::getPolyVertsByRef(dtPolyRef ref) const
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip); decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return 0; if (it >= (unsigned int)m_maxTiles) return 0;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0; if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0;
@ -1979,7 +2066,7 @@ const float* dtNavMesh::getPolyVertsByRef(dtPolyRef ref) const
const dtLink* dtNavMesh::getPolyLinksByRef(dtPolyRef ref) const const dtLink* dtNavMesh::getPolyLinksByRef(dtPolyRef ref) const
{ {
unsigned int salt, it, ip; unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip); decodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return 0; if (it >= (unsigned int)m_maxTiles) return 0;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0; if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return 0;
if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0; if (ip >= (unsigned int)m_tiles[it].header->polyCount) return 0;

View File

@ -210,134 +210,35 @@ static int createBVTree(const unsigned short* verts, const int nverts,
return curNode; return curNode;
} }
/* static unsigned char classifyOffMeshPoint(const float* pt, const float* bmin, const float* bmax)
static int queryPolygons(dtMeshHeader* header,
const float* qmin, const float* qmax,
unsigned short* polys, const int maxPolys)
{ {
const dtBVNode* node = &header->bvtree[0]; static const unsigned char XP = 1<<0;
const dtBVNode* end = &header->bvtree[header->nbvtree]; static const unsigned char ZP = 1<<1;
static const unsigned char XM = 1<<2;
// Calculate quantized box static const unsigned char ZM = 1<<3;
unsigned short bmin[3], bmax[3];
// Clamp query box to world box. unsigned char outcode = 0;
float minx = clamp(qmin[0], header->bmin[0], header->bmax[0]) - header->bmin[0]; outcode |= (pt[0] >= bmax[0]) ? XP : 0;
float miny = clamp(qmin[1], header->bmin[1], header->bmax[1]) - header->bmin[1]; outcode |= (pt[2] >= bmax[2]) ? ZP : 0;
float minz = clamp(qmin[2], header->bmin[2], header->bmax[2]) - header->bmin[2]; outcode |= (pt[0] < bmin[0]) ? XM : 0;
float maxx = clamp(qmax[0], header->bmin[0], header->bmax[0]) - header->bmin[0]; outcode |= (pt[2] < bmin[2]) ? ZM : 0;
float maxy = clamp(qmax[1], header->bmin[1], header->bmax[1]) - header->bmin[1];
float maxz = clamp(qmax[2], header->bmin[2], header->bmax[2]) - header->bmin[2]; switch (outcode)
// Quantize
bmin[0] = (unsigned short)(header->bvquant * minx) & 0xfffe;
bmin[1] = (unsigned short)(header->bvquant * miny) & 0xfffe;
bmin[2] = (unsigned short)(header->bvquant * minz) & 0xfffe;
bmax[0] = (unsigned short)(header->bvquant * maxx + 1) | 1;
bmax[1] = (unsigned short)(header->bvquant * maxy + 1) | 1;
bmax[2] = (unsigned short)(header->bvquant * maxz + 1) | 1;
// Traverse tree
dtPolyRef base = getTileId(tile);
int n = 0;
while (node < end)
{ {
bool overlap = checkOverlapBox(bmin, bmax, node->bmin, node->bmax); case XP: return 0;
bool isLeafNode = node->i >= 0; case XP|ZP: return 1;
case ZP: return 2;
if (isLeafNode && overlap) case XM|ZP: return 3;
{ case XM: return 4;
if (n < maxPolys) case XM|ZM: return 5;
polys[n++] = base | (dtPolyRef)node->i; case ZM: return 6;
} case XP|ZM: return 7;
};
if (overlap || isLeafNode) return 0xff;
node++;
else
{
const int escapeIndex = -node->i;
node += escapeIndex;
}
}
return n;
} }
dtMeshHeader* header // TODO: Better error handling.
{
bool dtNavMesh::closestPointOnPoly(dtPolyRef ref, const float* pos, float* closest) const
{
unsigned int salt, it, ip;
dtDecodePolyId(ref, salt, it, ip);
if (it >= (unsigned int)m_maxTiles) return false;
if (m_tiles[it].salt != salt || m_tiles[it].header == 0) return false;
const dtMeshHeader* header = m_tiles[it].header;
if (ip >= (unsigned int)header->npolys) return false;
const dtPoly* poly = &header->polys[ip];
float closestDistSqr = FLT_MAX;
const dtPolyDetail* pd = &header->dmeshes[ip];
for (int j = 0; j < pd->ntris; ++j)
{
const unsigned char* t = &header->dtris[(pd->tbase+j)*4];
const float* v[3];
for (int k = 0; k < 3; ++k)
{
if (t[k] < poly->nv)
v[k] = &header->verts[poly->v[t[k]]*3];
else
v[k] = &header->dverts[(pd->vbase+(t[k]-poly->nv))*3];
}
float pt[3];
closestPtPointTriangle(pt, pos, v[0], v[1], v[2]);
float d = vdistSqr(pos, pt);
if (d < closestDistSqr)
{
vcopy(closest, pt);
closestDistSqr = d;
}
}
return true;
}
}
unsigned short findNearestPoly(dtMeshHeader* header, const float* center, const float* extents)
{
// Get nearby polygons from proximity grid.
float bmin[3], bmax[3];
bmin[0] = center[0] - extents[0];
bmin[1] = center[1] - extents[1];
bmin[2] = center[2] - extents[2];
bmax[0] = center[0] + extents[0];
bmax[1] = center[1] + extents[1];
bmax[2] = center[2] + extents[2];
unsigned short polys[128];
int npolys = queryPolygons(header, bmin, bmax, polys, 128);
// Find nearest polygon amongst the nearby polygons.
unsigned short nearest = 0xffff;
float nearestDistanceSqr = FLT_MAX;
for (int i = 0; i < npolys; ++i)
{
dtPolyRef ref = polys[i];
float closest[3];
if (!closestPointOnPoly(ref, center, closest))
continue;
float d = vdistSqr(center, closest);
if (d < nearestDistanceSqr)
{
nearestDistanceSqr = d;
nearest = ref;
}
}
return nearest;
}
*/
bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize) bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData, int* outDataSize)
{ {
if (params->nvp > DT_VERTS_PER_POLYGON) if (params->nvp > DT_VERTS_PER_POLYGON)
@ -353,9 +254,36 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
const int nvp = params->nvp; const int nvp = params->nvp;
// Classify off-mesh connection points. We store only the connections
// whose start point is inside the tile.
unsigned char* offMeshConFlags = new unsigned char [params->offMeshConCount*2];
if (!offMeshConFlags)
return false;
int storedOffMeshConCount = 0;
int offMeshConLinkCount = 0;
printf("classify\n");
for (int i = 0; i < params->offMeshConCount; ++i)
{
offMeshConFlags[i*2+0] = classifyOffMeshPoint(&params->offMeshConVerts[(i*2+0)*3], params->bmin, params->bmax);
offMeshConFlags[i*2+1] = classifyOffMeshPoint(&params->offMeshConVerts[(i*2+1)*3], params->bmin, params->bmax);
printf(" %d, %d\n", (int)offMeshConFlags[i*2+0], (int)offMeshConFlags[i*2+1]);
// Cound how many links should be allocated for off-mesh connections.
if (offMeshConFlags[i*2+0] == 0xff)
offMeshConLinkCount++;
if (offMeshConFlags[i*2+1] == 0xff)
offMeshConLinkCount++;
if (offMeshConFlags[i*2+0] == 0xff)
storedOffMeshConCount++;
}
// Off-mesh connectionss are stored as polygons, adjust values. // Off-mesh connectionss are stored as polygons, adjust values.
const int totPolyCount = params->polyCount + params->offMeshConCount; const int totPolyCount = params->polyCount + storedOffMeshConCount;
const int totVertCount = params->vertCount + params->offMeshConCount*2; const int totVertCount = params->vertCount + storedOffMeshConCount*2;
// Find portal edges which are at tile borders. // Find portal edges which are at tile borders.
int edgeCount = 0; int edgeCount = 0;
@ -387,8 +315,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
} }
} }
const int maxLinkCount = edgeCount + portalCount*2 + params->offMeshConCount*4; const int maxLinkCount = edgeCount + portalCount*2 + offMeshConLinkCount*2;
// Find unique detail vertices. // Find unique detail vertices.
int uniqueDetailVertCount = 0; int uniqueDetailVertCount = 0;
@ -415,7 +342,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
const int detailVertsSize = align4(sizeof(float)*3*uniqueDetailVertCount); const int detailVertsSize = align4(sizeof(float)*3*uniqueDetailVertCount);
const int detailTrisSize = align4(sizeof(unsigned char)*4*params->detailTriCount); const int detailTrisSize = align4(sizeof(unsigned char)*4*params->detailTriCount);
const int bvTreeSize = align4(sizeof(dtBVNode)*params->polyCount*2); const int bvTreeSize = align4(sizeof(dtBVNode)*params->polyCount*2);
const int offMeshConsSize = align4(sizeof(dtOffMeshConnection)*params->offMeshConCount); const int offMeshConsSize = align4(sizeof(dtOffMeshConnection)*storedOffMeshConCount);
const int dataSize = headerSize + vertsSize + polysSize + linksSize + const int dataSize = headerSize + vertsSize + polysSize + linksSize +
detailMeshesSize + detailVertsSize + detailTrisSize + detailMeshesSize + detailVertsSize + detailTrisSize +
@ -454,7 +381,7 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
header->walkableHeight = params->walkableHeight; header->walkableHeight = params->walkableHeight;
header->walkableRadius = params->walkableRadius; header->walkableRadius = params->walkableRadius;
header->walkableClimb = params->walkableClimb; header->walkableClimb = params->walkableClimb;
header->offMeshConCount = params->offMeshConCount; header->offMeshConCount = storedOffMeshConCount;
header->bvNodeCount = params->polyCount*2; header->bvNodeCount = params->polyCount*2;
const int offMeshVertsBase = params->vertCount; const int offMeshVertsBase = params->vertCount;
@ -471,12 +398,18 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
v[2] = params->bmin[2] + iv[2] * params->cs; v[2] = params->bmin[2] + iv[2] * params->cs;
} }
// Off-mesh link vertices. // Off-mesh link vertices.
int n = 0;
for (int i = 0; i < params->offMeshConCount; ++i) for (int i = 0; i < params->offMeshConCount; ++i)
{ {
const float* linkv = &params->offMeshConVerts[i*2*3]; // Only store connections which start from this tile.
float* v = &navVerts[(offMeshVertsBase + i*2)*3]; if (offMeshConFlags[i*2+0] == 0xff)
vcopy(&v[0], &linkv[0]); {
vcopy(&v[3], &linkv[3]); const float* linkv = &params->offMeshConVerts[i*2*3];
float* v = &navVerts[(offMeshVertsBase + n*2)*3];
vcopy(&v[0], &linkv[0]);
vcopy(&v[3], &linkv[3]);
n++;
}
} }
// Store polygons // Store polygons
@ -497,13 +430,19 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
src += nvp*2; src += nvp*2;
} }
// Off-mesh connection vertices. // Off-mesh connection vertices.
n = 0;
for (int i = 0; i < params->offMeshConCount; ++i) for (int i = 0; i < params->offMeshConCount; ++i)
{ {
dtPoly* p = &navPolys[offMeshPolyBase+i]; // Only store connections which start from this tile.
p->vertCount = 2; if (offMeshConFlags[i*2+0] == 0xff)
p->verts[0] = (unsigned short)(offMeshVertsBase + i*2+0); {
p->verts[1] = (unsigned short)(offMeshVertsBase + i*2+1); dtPoly* p = &navPolys[offMeshPolyBase+n];
p->flags = DT_POLY_OFFMESH_CONNECTION; // Off-mesh link poly. p->vertCount = 2;
p->verts[0] = (unsigned short)(offMeshVertsBase + n*2+0);
p->verts[1] = (unsigned short)(offMeshVertsBase + n*2+1);
p->flags = DT_POLY_OFFMESH_CONNECTION; // Off-mesh link poly.
n++;
}
} }
// Store portal edges. // Store portal edges.
@ -523,11 +462,11 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
if (va[0] == params->tileSize && vb[0] == params->tileSize) // x+ if (va[0] == params->tileSize && vb[0] == params->tileSize) // x+
poly->neis[j] = DT_EXT_LINK | 0; poly->neis[j] = DT_EXT_LINK | 0;
else if (va[2] == params->tileSize && vb[2] == params->tileSize) // z+ else if (va[2] == params->tileSize && vb[2] == params->tileSize) // z+
poly->neis[j] = DT_EXT_LINK | 1;
else if (va[0] == 0 && vb[0] == 0) // x-
poly->neis[j] = DT_EXT_LINK | 2; poly->neis[j] = DT_EXT_LINK | 2;
else if (va[0] == 0 && vb[0] == 0) // x-
poly->neis[j] = DT_EXT_LINK | 4;
else if (va[2] == 0 && vb[2] == 0) // z- else if (va[2] == 0 && vb[2] == 0) // z-
poly->neis[j] = DT_EXT_LINK | 3; poly->neis[j] = DT_EXT_LINK | 6;
} }
} }
} }
@ -562,18 +501,27 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
nvp, params->cs, params->ch, params->polyCount*2, navBvtree); nvp, params->cs, params->ch, params->polyCount*2, navBvtree);
// Store Off-Mesh connections. // Store Off-Mesh connections.
n = 0;
for (int i = 0; i < params->offMeshConCount; ++i) for (int i = 0; i < params->offMeshConCount; ++i)
{ {
dtOffMeshConnection* con = &offMeshCons[i]; // Only store connections which start from this tile.
con->poly = offMeshPolyBase + i; if (offMeshConFlags[i*2+0] == 0xff)
// Copy connection end-points. {
const float* endPts = &params->offMeshConVerts[i*2*3]; dtOffMeshConnection* con = &offMeshCons[n];
vcopy(&con->pos[0], &endPts[0]); con->poly = offMeshPolyBase + n;
vcopy(&con->pos[3], &endPts[3]); // Copy connection end-points.
con->rad = params->offMeshConRad[i]; const float* endPts = &params->offMeshConVerts[i*2*3];
con->flags = params->offMeshConDir[i]; vcopy(&con->pos[0], &endPts[0]);
vcopy(&con->pos[3], &endPts[3]);
con->rad = params->offMeshConRad[i];
con->flags = params->offMeshConDir[i];
con->side = offMeshConFlags[i*2+1];
n++;
}
} }
delete [] offMeshConFlags;
*outData = data; *outData = data;
*outDataSize = dataSize; *outDataSize = dataSize;

File diff suppressed because it is too large Load Diff

View File

@ -254,7 +254,7 @@
<dict> <dict>
<key>PBXSmartGroupTreeModuleColumnWidthsKey</key> <key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
<array> <array>
<real>282</real> <real>358</real>
</array> </array>
<key>PBXSmartGroupTreeModuleColumnsKey_v4</key> <key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
<array> <array>
@ -288,7 +288,7 @@
</array> </array>
</array> </array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key> <key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 41}, {282, 643}}</string> <string>{{0, 0}, {358, 643}}</string>
</dict> </dict>
<key>PBXTopSmartGroupGIDs</key> <key>PBXTopSmartGroupGIDs</key>
<array/> <array/>
@ -298,11 +298,11 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{0, 0}, {299, 661}}</string> <string>{{0, 0}, {375, 661}}</string>
<key>GroupTreeTableConfiguration</key> <key>GroupTreeTableConfiguration</key>
<array> <array>
<string>MainColumn</string> <string>MainColumn</string>
<real>282</real> <real>358</real>
</array> </array>
<key>RubberWindowFrame</key> <key>RubberWindowFrame</key>
<string>11 76 1256 702 0 0 1280 778 </string> <string>11 76 1256 702 0 0 1280 778 </string>
@ -310,7 +310,7 @@
<key>Module</key> <key>Module</key>
<string>PBXSmartGroupTreeModule</string> <string>PBXSmartGroupTreeModule</string>
<key>Proportion</key> <key>Proportion</key>
<string>299pt</string> <string>375pt</string>
</dict> </dict>
<dict> <dict>
<key>Dock</key> <key>Dock</key>
@ -323,7 +323,7 @@
<key>PBXProjectModuleGUID</key> <key>PBXProjectModuleGUID</key>
<string>6B8632A30F78115100E2684A</string> <string>6B8632A30F78115100E2684A</string>
<key>PBXProjectModuleLabel</key> <key>PBXProjectModuleLabel</key>
<string>DetourNavMesh.h</string> <string>DetourNavMesh.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key> <key>PBXSplitModuleInNavigatorKey</key>
<dict> <dict>
<key>Split0</key> <key>Split0</key>
@ -331,11 +331,11 @@
<key>PBXProjectModuleGUID</key> <key>PBXProjectModuleGUID</key>
<string>6B8632A40F78115100E2684A</string> <string>6B8632A40F78115100E2684A</string>
<key>PBXProjectModuleLabel</key> <key>PBXProjectModuleLabel</key>
<string>DetourNavMesh.h</string> <string>DetourNavMesh.cpp</string>
<key>_historyCapacity</key> <key>_historyCapacity</key>
<integer>0</integer> <integer>0</integer>
<key>bookmark</key> <key>bookmark</key>
<string>6BCF34F411060322009445BF</string> <string>6BF7BE92110F1BDA002B3F46</string>
<key>history</key> <key>history</key>
<array> <array>
<string>6B57D358108C66B200DDD053</string> <string>6B57D358108C66B200DDD053</string>
@ -355,39 +355,38 @@
<string>6BB7FDC010F37703006DA0A6</string> <string>6BB7FDC010F37703006DA0A6</string>
<string>6BB7FDC110F37703006DA0A6</string> <string>6BB7FDC110F37703006DA0A6</string>
<string>6BB7FE1010F37CF7006DA0A6</string> <string>6BB7FE1010F37CF7006DA0A6</string>
<string>6BB7FE3B10F3817A006DA0A6</string>
<string>6BB7FF6D10F4E8E2006DA0A6</string> <string>6BB7FF6D10F4E8E2006DA0A6</string>
<string>6BB3605210FE5CBD00A9B4B8</string>
<string>6BB3606210FE5E8F00A9B4B8</string>
<string>6B69736710FFBDCA00984788</string>
<string>6B69739F10FFCA4500984788</string> <string>6B69739F10FFCA4500984788</string>
<string>6BCF325E1104CFE7009445BF</string>
<string>6BCF325F1104CFE7009445BF</string> <string>6BCF325F1104CFE7009445BF</string>
<string>6BCF331911059E23009445BF</string>
<string>6BCF331A11059E23009445BF</string> <string>6BCF331A11059E23009445BF</string>
<string>6BCF33351105B2B5009445BF</string>
<string>6BCF33651105BBA2009445BF</string> <string>6BCF33651105BBA2009445BF</string>
<string>6BCF33671105BBA2009445BF</string> <string>6BCF33671105BBA2009445BF</string>
<string>6BCF336A1105BBA2009445BF</string>
<string>6BCF33AF1105BE51009445BF</string> <string>6BCF33AF1105BE51009445BF</string>
<string>6BCF33E21105E5BB009445BF</string>
<string>6BCF34031105E98C009445BF</string> <string>6BCF34031105E98C009445BF</string>
<string>6BCF34041105E98C009445BF</string> <string>6BCF34041105E98C009445BF</string>
<string>6BCF341A1105EC43009445BF</string> <string>6BCF341A1105EC43009445BF</string>
<string>6BCF34211105EC43009445BF</string> <string>6B4260231109DE9500C48C36</string>
<string>6BCF343A1105ECAB009445BF</string> <string>6B4260301109E1EE00C48C36</string>
<string>6BCF34441105ECEB009445BF</string> <string>6B84BED0110E1818007D997B</string>
<string>6BCF34691105EF2D009445BF</string> <string>6B84BEE2110E1983007D997B</string>
<string>6BCF34831105F555009445BF</string> <string>6B84BEFE110E1E10007D997B</string>
<string>6BCF34901105F821009445BF</string> <string>6B84BEFF110E1E10007D997B</string>
<string>6BCF34911105F821009445BF</string> <string>6BF7BDBE110EF674002B3F46</string>
<string>6BCF34A41105F894009445BF</string> <string>6BF7BE1F110F0792002B3F46</string>
<string>6BCF34B01105FA03009445BF</string> <string>6BF7BE39110F1576002B3F46</string>
<string>6BCF34B11105FA03009445BF</string> <string>6BF7BE5C110F170A002B3F46</string>
<string>6BCF34E2110602BB009445BF</string> <string>6BF7BE5D110F170A002B3F46</string>
<string>6BCF34E3110602BB009445BF</string> <string>6BF7BE5E110F170A002B3F46</string>
<string>6BCF34F111060322009445BF</string> <string>6BF7BE60110F170A002B3F46</string>
<string>6BCF34F211060322009445BF</string> <string>6BF7BE73110F1832002B3F46</string>
<string>6BF7BE74110F1832002B3F46</string>
<string>6BF7BE75110F1832002B3F46</string>
<string>6BF7BE76110F1832002B3F46</string>
<string>6BF7BE82110F196C002B3F46</string>
<string>6BF7BE83110F196C002B3F46</string>
<string>6BF7BE8C110F1AFC002B3F46</string>
<string>6BF7BE8D110F1AFC002B3F46</string>
<string>6BF7BE1E110F0792002B3F46</string>
</array> </array>
<key>prevStack</key> <key>prevStack</key>
<array> <array>
@ -409,236 +408,118 @@
<string>6BB7FE2210F37CF7006DA0A6</string> <string>6BB7FE2210F37CF7006DA0A6</string>
<string>6BB7FE2310F37CF7006DA0A6</string> <string>6BB7FE2310F37CF7006DA0A6</string>
<string>6BB7FE5410F3817A006DA0A6</string> <string>6BB7FE5410F3817A006DA0A6</string>
<string>6BB7FEB810F4B5E1006DA0A6</string>
<string>6BB7FECF10F4B5E1006DA0A6</string> <string>6BB7FECF10F4B5E1006DA0A6</string>
<string>6BB7FF2410F4D699006DA0A6</string> <string>6BB7FF2410F4D699006DA0A6</string>
<string>6BB7FF9610F4E8E2006DA0A6</string> <string>6BB7FF9610F4E8E2006DA0A6</string>
<string>6BB700C310FA3AB1006DA0A6</string> <string>6BB700C310FA3AB1006DA0A6</string>
<string>6BE7320610FE6CEF00C1B074</string>
<string>6B69737210FFBDCA00984788</string>
<string>6B69739810FFC43600984788</string> <string>6B69739810FFC43600984788</string>
<string>6B6973A210FFCA4500984788</string> <string>6B6973A210FFCA4500984788</string>
<string>6BCF31FD1104C9F0009445BF</string>
<string>6BCF31FE1104C9F0009445BF</string>
<string>6BCF31FF1104C9F0009445BF</string>
<string>6BCF32001104C9F0009445BF</string>
<string>6BCF32011104C9F0009445BF</string>
<string>6BCF32021104C9F0009445BF</string>
<string>6BCF32031104C9F0009445BF</string>
<string>6BCF32041104C9F0009445BF</string>
<string>6BCF32051104C9F0009445BF</string>
<string>6BCF32061104C9F0009445BF</string>
<string>6BCF32071104C9F0009445BF</string>
<string>6BCF32081104C9F0009445BF</string>
<string>6BCF32091104C9F0009445BF</string>
<string>6BCF320A1104C9F0009445BF</string>
<string>6BCF320B1104C9F0009445BF</string>
<string>6BCF320C1104C9F0009445BF</string>
<string>6BCF320D1104C9F0009445BF</string>
<string>6BCF320E1104C9F0009445BF</string>
<string>6BCF32111104C9F0009445BF</string>
<string>6BCF32121104C9F0009445BF</string>
<string>6BCF32151104C9F0009445BF</string>
<string>6BCF322E1104CA22009445BF</string>
<string>6BCF322F1104CA22009445BF</string>
<string>6BCF32441104CDB5009445BF</string> <string>6BCF32441104CDB5009445BF</string>
<string>6BCF32451104CDB5009445BF</string>
<string>6BCF32461104CDB5009445BF</string>
<string>6BCF32471104CDB5009445BF</string>
<string>6BCF32481104CDB5009445BF</string>
<string>6BCF32491104CDB5009445BF</string>
<string>6BCF324A1104CDB5009445BF</string> <string>6BCF324A1104CDB5009445BF</string>
<string>6BCF324C1104CDB5009445BF</string>
<string>6BCF324E1104CDB5009445BF</string>
<string>6BCF324F1104CDB5009445BF</string>
<string>6BCF32501104CDB5009445BF</string>
<string>6BCF32511104CDB5009445BF</string>
<string>6BCF32521104CDB5009445BF</string>
<string>6BCF32681104CFE7009445BF</string>
<string>6BCF32691104CFE7009445BF</string>
<string>6BCF326A1104CFE7009445BF</string>
<string>6BCF326B1104CFE7009445BF</string>
<string>6BCF326C1104CFE7009445BF</string>
<string>6BCF326D1104CFE7009445BF</string>
<string>6BCF326E1104CFE7009445BF</string>
<string>6BCF326F1104CFE7009445BF</string>
<string>6BCF32701104CFE7009445BF</string>
<string>6BCF32711104CFE7009445BF</string>
<string>6BCF32721104CFE7009445BF</string>
<string>6BCF32731104CFE7009445BF</string>
<string>6BCF32741104CFE7009445BF</string>
<string>6BCF32751104CFE7009445BF</string>
<string>6BCF32761104CFE7009445BF</string>
<string>6BCF32771104CFE7009445BF</string>
<string>6BCF32781104CFE7009445BF</string>
<string>6BCF32791104CFE7009445BF</string>
<string>6BCF327A1104CFE7009445BF</string>
<string>6BCF32861104D114009445BF</string>
<string>6BCF32871104D114009445BF</string>
<string>6BCF32881104D114009445BF</string>
<string>6BCF32891104D114009445BF</string>
<string>6BCF32A31104D31E009445BF</string>
<string>6BCF32A51104D31E009445BF</string>
<string>6BCF32A61104D31E009445BF</string>
<string>6BCF32B41104D3E5009445BF</string>
<string>6BCF32C51104D678009445BF</string>
<string>6BCF32ED1104D7F5009445BF</string>
<string>6BCF32EE1104D7F5009445BF</string>
<string>6BCF32F51104D815009445BF</string>
<string>6BCF33021104D891009445BF</string>
<string>6BCF33041104D891009445BF</string>
<string>6BCF33061104D891009445BF</string>
<string>6BCF331611059D39009445BF</string>
<string>6BCF331C11059E23009445BF</string>
<string>6BCF331D11059E23009445BF</string>
<string>6BCF331E11059E23009445BF</string> <string>6BCF331E11059E23009445BF</string>
<string>6BCF331F11059E23009445BF</string>
<string>6BCF332611059EA9009445BF</string>
<string>6BCF332C1105A59B009445BF</string>
<string>6BCF33381105B2B5009445BF</string> <string>6BCF33381105B2B5009445BF</string>
<string>6BCF33541105B986009445BF</string> <string>6BCF33541105B986009445BF</string>
<string>6BCF33551105B986009445BF</string>
<string>6BCF33561105B986009445BF</string>
<string>6BCF33571105B986009445BF</string>
<string>6BCF33581105B986009445BF</string>
<string>6BCF33591105B986009445BF</string>
<string>6BCF335A1105B986009445BF</string>
<string>6BCF336E1105BBA2009445BF</string>
<string>6BCF336F1105BBA2009445BF</string>
<string>6BCF33701105BBA2009445BF</string>
<string>6BCF33711105BBA2009445BF</string>
<string>6BCF33721105BBA2009445BF</string>
<string>6BCF33731105BBA2009445BF</string>
<string>6BCF33741105BBA2009445BF</string>
<string>6BCF33751105BBA2009445BF</string>
<string>6BCF33761105BBA2009445BF</string>
<string>6BCF33781105BBA2009445BF</string>
<string>6BCF337A1105BBA2009445BF</string>
<string>6BCF337C1105BBA2009445BF</string>
<string>6BCF337D1105BBA2009445BF</string>
<string>6BCF337E1105BBA2009445BF</string>
<string>6BCF337F1105BBA2009445BF</string>
<string>6BCF33801105BBA2009445BF</string>
<string>6BCF33811105BBA2009445BF</string> <string>6BCF33811105BBA2009445BF</string>
<string>6BCF33881105BBC8009445BF</string>
<string>6BCF338E1105BCB7009445BF</string>
<string>6BCF338F1105BCB7009445BF</string>
<string>6BCF339A1105BD0E009445BF</string>
<string>6BCF339B1105BD0E009445BF</string>
<string>6BCF339C1105BD0E009445BF</string>
<string>6BCF339D1105BD0E009445BF</string>
<string>6BCF339E1105BD0E009445BF</string>
<string>6BCF339F1105BD0E009445BF</string>
<string>6BCF33A41105BD41009445BF</string>
<string>6BCF33A91105BDAD009445BF</string>
<string>6BCF33B21105BE51009445BF</string>
<string>6BCF33B31105BE51009445BF</string>
<string>6BCF33B41105BE51009445BF</string>
<string>6BCF33B51105BE51009445BF</string>
<string>6BCF33B61105BE51009445BF</string>
<string>6BCF33BD1105BEE9009445BF</string>
<string>6BCF33CA1105C466009445BF</string>
<string>6BCF33D31105C5EF009445BF</string>
<string>6BCF33E41105E5BB009445BF</string>
<string>6BCF33E51105E5BB009445BF</string>
<string>6BCF33E61105E5BB009445BF</string>
<string>6BCF33E71105E5BB009445BF</string>
<string>6BCF33E81105E5BB009445BF</string>
<string>6BCF33E91105E5BB009445BF</string>
<string>6BCF33EA1105E5BB009445BF</string>
<string>6BCF33EB1105E5BB009445BF</string>
<string>6BCF33EC1105E5BB009445BF</string>
<string>6BCF33ED1105E5BB009445BF</string>
<string>6BCF33F21105E621009445BF</string>
<string>6BCF33F91105E71B009445BF</string>
<string>6BCF33FA1105E71B009445BF</string>
<string>6BCF340B1105E98C009445BF</string> <string>6BCF340B1105E98C009445BF</string>
<string>6BCF340C1105E98C009445BF</string> <string>6BCF340C1105E98C009445BF</string>
<string>6BCF340D1105E98C009445BF</string>
<string>6BCF340E1105E98C009445BF</string>
<string>6BCF340F1105E98C009445BF</string>
<string>6BCF34101105E98C009445BF</string>
<string>6BCF34111105E98C009445BF</string>
<string>6BCF34121105E98C009445BF</string>
<string>6BCF34131105E98C009445BF</string> <string>6BCF34131105E98C009445BF</string>
<string>6BCF34141105E98C009445BF</string>
<string>6BCF34231105EC43009445BF</string>
<string>6BCF34241105EC43009445BF</string>
<string>6BCF34251105EC43009445BF</string>
<string>6BCF34261105EC43009445BF</string>
<string>6BCF34271105EC43009445BF</string>
<string>6BCF34281105EC43009445BF</string>
<string>6BCF34291105EC43009445BF</string>
<string>6BCF342A1105EC43009445BF</string>
<string>6BCF342B1105EC43009445BF</string>
<string>6BCF342C1105EC43009445BF</string>
<string>6BCF342D1105EC43009445BF</string>
<string>6BCF342E1105EC43009445BF</string>
<string>6BCF342F1105EC43009445BF</string>
<string>6BCF34301105EC43009445BF</string>
<string>6BCF34311105EC43009445BF</string>
<string>6BCF34321105EC43009445BF</string>
<string>6BCF34331105EC43009445BF</string>
<string>6BCF34341105EC43009445BF</string>
<string>6BCF343D1105ECAB009445BF</string>
<string>6BCF343E1105ECAB009445BF</string>
<string>6BCF343F1105ECAB009445BF</string>
<string>6BCF34401105ECAB009445BF</string>
<string>6BCF34461105ECEB009445BF</string>
<string>6BCF344A1105ED03009445BF</string>
<string>6BCF34591105EE81009445BF</string>
<string>6BCF345F1105EEA7009445BF</string>
<string>6BCF346C1105EF2D009445BF</string>
<string>6BCF34751105F503009445BF</string>
<string>6BCF34761105F503009445BF</string>
<string>6BCF34771105F503009445BF</string>
<string>6BCF347D1105F519009445BF</string>
<string>6BCF347E1105F519009445BF</string>
<string>6BCF34851105F555009445BF</string>
<string>6BCF34861105F555009445BF</string>
<string>6BCF34941105F821009445BF</string>
<string>6BCF34951105F821009445BF</string> <string>6BCF34951105F821009445BF</string>
<string>6BCF34961105F821009445BF</string> <string>6B4260411109E27F00C48C36</string>
<string>6BCF34971105F821009445BF</string> <string>6B4260471109E83800C48C36</string>
<string>6BCF349D1105F845009445BF</string> <string>6B4260481109E83800C48C36</string>
<string>6BCF34A71105F894009445BF</string> <string>6BF7BDC7110EF674002B3F46</string>
<string>6BCF34A81105F894009445BF</string> <string>6BF7BDC8110EF674002B3F46</string>
<string>6BCF34A91105F894009445BF</string> <string>6BF7BDC9110EF674002B3F46</string>
<string>6BCF34AE1105F8DB009445BF</string> <string>6BF7BDCA110EF674002B3F46</string>
<string>6BCF34B31105FA03009445BF</string> <string>6BF7BDCB110EF674002B3F46</string>
<string>6BCF34B41105FA03009445BF</string> <string>6BF7BDCC110EF674002B3F46</string>
<string>6BCF34B51105FA03009445BF</string> <string>6BF7BDCD110EF674002B3F46</string>
<string>6BCF34BE1105FD0F009445BF</string> <string>6BF7BDCE110EF674002B3F46</string>
<string>6BCF34BF1105FD0F009445BF</string> <string>6BF7BDCF110EF674002B3F46</string>
<string>6BCF34C01105FD0F009445BF</string> <string>6BF7BDD0110EF674002B3F46</string>
<string>6BCF34C11105FD0F009445BF</string> <string>6BF7BDD1110EF674002B3F46</string>
<string>6BCF34C21105FD0F009445BF</string> <string>6BF7BDD2110EF674002B3F46</string>
<string>6BCF34C31105FD0F009445BF</string> <string>6BF7BDD3110EF674002B3F46</string>
<string>6BCF34C41105FD0F009445BF</string> <string>6BF7BDD4110EF674002B3F46</string>
<string>6BCF34C51105FD0F009445BF</string> <string>6BF7BDD5110EF674002B3F46</string>
<string>6BCF34C61105FD0F009445BF</string> <string>6BF7BDD6110EF674002B3F46</string>
<string>6BCF34C71105FD0F009445BF</string> <string>6BF7BDD7110EF674002B3F46</string>
<string>6BCF34C81105FD0F009445BF</string> <string>6BF7BDD8110EF674002B3F46</string>
<string>6BCF34C91105FD0F009445BF</string> <string>6BF7BDD9110EF674002B3F46</string>
<string>6BCF34CA1105FD0F009445BF</string> <string>6BF7BDDA110EF674002B3F46</string>
<string>6BCF34CB1105FD0F009445BF</string> <string>6BF7BDDB110EF674002B3F46</string>
<string>6BCF34CC1105FD0F009445BF</string> <string>6BF7BDDC110EF674002B3F46</string>
<string>6BCF34D01105FF32009445BF</string> <string>6BF7BDDD110EF674002B3F46</string>
<string>6BCF34D11105FF32009445BF</string> <string>6BF7BDDE110EF674002B3F46</string>
<string>6BCF34D21105FF32009445BF</string> <string>6BF7BDDF110EF674002B3F46</string>
<string>6BCF34D31105FF32009445BF</string> <string>6BF7BDE0110EF674002B3F46</string>
<string>6BCF34E5110602BB009445BF</string> <string>6BF7BDE1110EF674002B3F46</string>
<string>6BCF34E6110602BB009445BF</string> <string>6BF7BDE2110EF674002B3F46</string>
<string>6BCF34E7110602BB009445BF</string> <string>6BF7BDE3110EF674002B3F46</string>
<string>6BCF34E8110602BB009445BF</string> <string>6BF7BDE4110EF674002B3F46</string>
<string>6BCF34E9110602BB009445BF</string> <string>6BF7BDE5110EF674002B3F46</string>
<string>6BCF34EA110602BB009445BF</string> <string>6BF7BDE6110EF674002B3F46</string>
<string>6BCF34EB110602BB009445BF</string> <string>6BF7BDE7110EF674002B3F46</string>
<string>6BCF34EC110602BB009445BF</string> <string>6BF7BDE8110EF674002B3F46</string>
<string>6BCF34ED110602BB009445BF</string> <string>6BF7BDE9110EF674002B3F46</string>
<string>6BCF34EE110602BB009445BF</string> <string>6BF7BDEA110EF674002B3F46</string>
<string>6BCF34EF110602BB009445BF</string> <string>6BF7BDF7110EF76D002B3F46</string>
<string>6BCF34F311060322009445BF</string> <string>6BF7BDF8110EF76D002B3F46</string>
<string>6BF7BDF9110EF76D002B3F46</string>
<string>6BF7BDFA110EF76D002B3F46</string>
<string>6BF7BE07110EF794002B3F46</string>
<string>6BF7BE11110EF7F7002B3F46</string>
<string>6BF7BE1A110F023C002B3F46</string>
<string>6BF7BE1B110F023C002B3F46</string>
<string>6BF7BE1C110F023C002B3F46</string>
<string>6BF7BE22110F0792002B3F46</string>
<string>6BF7BE23110F0792002B3F46</string>
<string>6BF7BE24110F0792002B3F46</string>
<string>6BF7BE25110F0792002B3F46</string>
<string>6BF7BE26110F0792002B3F46</string>
<string>6BF7BE2C110F13F9002B3F46</string>
<string>6BF7BE2D110F13F9002B3F46</string>
<string>6BF7BE40110F1576002B3F46</string>
<string>6BF7BE41110F1576002B3F46</string>
<string>6BF7BE42110F1576002B3F46</string>
<string>6BF7BE43110F1576002B3F46</string>
<string>6BF7BE44110F1576002B3F46</string>
<string>6BF7BE45110F1576002B3F46</string>
<string>6BF7BE46110F1576002B3F46</string>
<string>6BF7BE47110F1576002B3F46</string>
<string>6BF7BE48110F1576002B3F46</string>
<string>6BF7BE49110F1576002B3F46</string>
<string>6BF7BE4A110F1576002B3F46</string>
<string>6BF7BE4B110F1576002B3F46</string>
<string>6BF7BE4C110F1576002B3F46</string>
<string>6BF7BE4D110F1576002B3F46</string>
<string>6BF7BE4E110F1576002B3F46</string>
<string>6BF7BE56110F160F002B3F46</string>
<string>6BF7BE57110F160F002B3F46</string>
<string>6BF7BE64110F170A002B3F46</string>
<string>6BF7BE65110F170A002B3F46</string>
<string>6BF7BE66110F170A002B3F46</string>
<string>6BF7BE67110F170A002B3F46</string>
<string>6BF7BE68110F170A002B3F46</string>
<string>6BF7BE69110F170A002B3F46</string>
<string>6BF7BE6A110F170A002B3F46</string>
<string>6BF7BE6B110F170A002B3F46</string>
<string>6BF7BE6C110F170A002B3F46</string>
<string>6BF7BE6D110F170A002B3F46</string>
<string>6BF7BE78110F1832002B3F46</string>
<string>6BF7BE79110F1832002B3F46</string>
<string>6BF7BE7A110F1832002B3F46</string>
<string>6BF7BE7B110F1832002B3F46</string>
<string>6BF7BE7C110F1832002B3F46</string>
<string>6BF7BE7D110F1832002B3F46</string>
<string>6BF7BE85110F196C002B3F46</string>
<string>6BF7BE86110F196C002B3F46</string>
<string>6BF7BE87110F196C002B3F46</string>
<string>6BF7BE88110F196C002B3F46</string>
<string>6BF7BE89110F196C002B3F46</string>
<string>6BF7BE8A110F196C002B3F46</string>
<string>6BF7BE8E110F1AFC002B3F46</string>
<string>6BF7BE8F110F1AFC002B3F46</string>
</array> </array>
</dict> </dict>
<key>SplitCount</key> <key>SplitCount</key>
@ -652,18 +533,18 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{0, 0}, {952, 547}}</string> <string>{{0, 0}, {876, 556}}</string>
<key>RubberWindowFrame</key> <key>RubberWindowFrame</key>
<string>11 76 1256 702 0 0 1280 778 </string> <string>11 76 1256 702 0 0 1280 778 </string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXNavigatorGroup</string> <string>PBXNavigatorGroup</string>
<key>Proportion</key> <key>Proportion</key>
<string>547pt</string> <string>556pt</string>
</dict> </dict>
<dict> <dict>
<key>Proportion</key> <key>Proportion</key>
<string>109pt</string> <string>100pt</string>
<key>Tabs</key> <key>Tabs</key>
<array> <array>
<dict> <dict>
@ -677,7 +558,7 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{10, 27}, {952, 90}}</string> <string>{{10, 27}, {876, 88}}</string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>XCDetailModule</string> <string>XCDetailModule</string>
@ -693,7 +574,9 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{10, 27}, {952, 212}}</string> <string>{{10, 27}, {876, 73}}</string>
<key>RubberWindowFrame</key>
<string>11 76 1256 702 0 0 1280 778 </string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXProjectFindModule</string> <string>PBXProjectFindModule</string>
@ -731,9 +614,7 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{10, 27}, {952, 82}}</string> <string>{{10, 27}, {876, 125}}</string>
<key>RubberWindowFrame</key>
<string>11 76 1256 702 0 0 1280 778 </string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXBuildResultsModule</string> <string>PBXBuildResultsModule</string>
@ -742,7 +623,7 @@
</dict> </dict>
</array> </array>
<key>Proportion</key> <key>Proportion</key>
<string>952pt</string> <string>876pt</string>
</dict> </dict>
</array> </array>
<key>Name</key> <key>Name</key>
@ -761,11 +642,11 @@
</array> </array>
<key>TableOfContents</key> <key>TableOfContents</key>
<array> <array>
<string>6BCF32211104C9F0009445BF</string> <string>6BF7BDEC110EF674002B3F46</string>
<string>1CA23ED40692098700951B8B</string> <string>1CA23ED40692098700951B8B</string>
<string>6BCF32221104C9F0009445BF</string> <string>6BF7BDED110EF674002B3F46</string>
<string>6B8632A30F78115100E2684A</string> <string>6B8632A30F78115100E2684A</string>
<string>6BCF32231104C9F0009445BF</string> <string>6BF7BDEE110EF674002B3F46</string>
<string>1CA23EDF0692099D00951B8B</string> <string>1CA23EDF0692099D00951B8B</string>
<string>1CA23EE00692099D00951B8B</string> <string>1CA23EE00692099D00951B8B</string>
<string>1CA23EE10692099D00951B8B</string> <string>1CA23EE10692099D00951B8B</string>
@ -816,12 +697,12 @@
<key>GeometryConfiguration</key> <key>GeometryConfiguration</key>
<dict> <dict>
<key>Frame</key> <key>Frame</key>
<string>{{0, 0}, {1256, 209}}</string> <string>{{0, 0}, {1256, 367}}</string>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXDebugCLIModule</string> <string>PBXDebugCLIModule</string>
<key>Proportion</key> <key>Proportion</key>
<string>209pt</string> <string>367pt</string>
</dict> </dict>
<dict> <dict>
<key>ContentConfiguration</key> <key>ContentConfiguration</key>
@ -840,8 +721,8 @@
<string>yes</string> <string>yes</string>
<key>sizes</key> <key>sizes</key>
<array> <array>
<string>{{0, 0}, {627, 93}}</string> <string>{{0, 0}, {623, 80}}</string>
<string>{{627, 0}, {629, 93}}</string> <string>{{623, 0}, {633, 80}}</string>
</array> </array>
</dict> </dict>
<key>VerticalSplitView</key> <key>VerticalSplitView</key>
@ -856,8 +737,8 @@
<string>yes</string> <string>yes</string>
<key>sizes</key> <key>sizes</key>
<array> <array>
<string>{{0, 0}, {1256, 93}}</string> <string>{{0, 0}, {1256, 80}}</string>
<string>{{0, 93}, {1256, 354}}</string> <string>{{0, 76}, {1256, 213}}</string>
</array> </array>
</dict> </dict>
</dict> </dict>
@ -877,7 +758,7 @@
<key>DebugSTDIOWindowFrame</key> <key>DebugSTDIOWindowFrame</key>
<string>{{200, 200}, {500, 300}}</string> <string>{{200, 200}, {500, 300}}</string>
<key>Frame</key> <key>Frame</key>
<string>{{0, 214}, {1256, 447}}</string> <string>{{0, 372}, {1256, 289}}</string>
<key>PBXDebugSessionStackFrameViewKey</key> <key>PBXDebugSessionStackFrameViewKey</key>
<dict> <dict>
<key>DebugVariablesTableConfiguration</key> <key>DebugVariablesTableConfiguration</key>
@ -887,16 +768,16 @@
<string>Value</string> <string>Value</string>
<real>85</real> <real>85</real>
<string>Summary</string> <string>Summary</string>
<real>399</real> <real>403</real>
</array> </array>
<key>Frame</key> <key>Frame</key>
<string>{{627, 0}, {629, 93}}</string> <string>{{623, 0}, {633, 80}}</string>
</dict> </dict>
</dict> </dict>
<key>Module</key> <key>Module</key>
<string>PBXDebugSessionModule</string> <string>PBXDebugSessionModule</string>
<key>Proportion</key> <key>Proportion</key>
<string>447pt</string> <string>289pt</string>
</dict> </dict>
</array> </array>
<key>Name</key> <key>Name</key>
@ -914,14 +795,14 @@
</array> </array>
<key>TableOfContents</key> <key>TableOfContents</key>
<array> <array>
<string>6BCF32241104C9F0009445BF</string> <string>6BF7BDFC110EF76D002B3F46</string>
<string>1CCC7628064C1048000F2A68</string> <string>1CCC7628064C1048000F2A68</string>
<string>1CCC7629064C1048000F2A68</string> <string>1CCC7629064C1048000F2A68</string>
<string>6BCF32251104C9F0009445BF</string> <string>6BF7BDFD110EF76D002B3F46</string>
<string>6BCF32261104C9F0009445BF</string> <string>6BF7BDFE110EF76D002B3F46</string>
<string>6BCF32271104C9F0009445BF</string> <string>6BF7BDFF110EF76D002B3F46</string>
<string>6BCF32281104C9F0009445BF</string> <string>6BF7BE00110EF76D002B3F46</string>
<string>6BCF32291104C9F0009445BF</string> <string>6BF7BE01110EF76D002B3F46</string>
</array> </array>
<key>ToolbarConfigUserDefaultsMinorVersion</key> <key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string> <string>2</string>
@ -953,8 +834,8 @@
<integer>5</integer> <integer>5</integer>
<key>WindowOrderList</key> <key>WindowOrderList</key>
<array> <array>
<string>6BCF32991104D1B2009445BF</string> <string>6BF7BE0B110EF794002B3F46</string>
<string>6BCF329A1104D1B2009445BF</string> <string>6BF7BE0C110EF794002B3F46</string>
<string>/Users/memon/Code/recastnavigation/RecastDemo/Build/Xcode/Recast.xcodeproj</string> <string>/Users/memon/Code/recastnavigation/RecastDemo/Build/Xcode/Recast.xcodeproj</string>
</array> </array>
<key>WindowString</key> <key>WindowString</key>

View File

@ -35,7 +35,8 @@ class NavMeshTesterTool : public SampleTool
enum ToolMode enum ToolMode
{ {
TOOLMODE_PATHFIND, TOOLMODE_PATHFIND_ITER,
TOOLMODE_PATHFIND_STRAIGHT,
TOOLMODE_RAYCAST, TOOLMODE_RAYCAST,
TOOLMODE_DISTANCE_TO_WALL, TOOLMODE_DISTANCE_TO_WALL,
TOOLMODE_FIND_POLYS_AROUND, TOOLMODE_FIND_POLYS_AROUND,

View File

@ -29,6 +29,7 @@ class OffMeshConnectionTool : public SampleTool
float m_hitPos[3]; float m_hitPos[3];
bool m_hitPosSet; bool m_hitPosSet;
bool m_bidir; bool m_bidir;
unsigned char m_oldFlags;
public: public:
OffMeshConnectionTool(); OffMeshConnectionTool();

View File

@ -89,6 +89,7 @@ public:
virtual void handleRenderOverlay(double* proj, double* model, int* view); virtual void handleRenderOverlay(double* proj, double* model, int* view);
virtual void handleMeshChanged(class InputGeom* geom); virtual void handleMeshChanged(class InputGeom* geom);
virtual bool handleBuild(); virtual bool handleBuild();
// virtual void handleNavMeshChanged();
virtual class InputGeom* getInputGeom() { return m_geom; } virtual class InputGeom* getInputGeom() { return m_geom; }
virtual class dtNavMesh* getNavMesh() { return m_navMesh; } virtual class dtNavMesh* getNavMesh() { return m_navMesh; }

View File

@ -183,8 +183,8 @@ void InputGeom::deleteOffMeshConnection(int i)
void InputGeom::drawOffMeshConnections(duDebugDraw* dd, bool hilight) void InputGeom::drawOffMeshConnections(duDebugDraw* dd, bool hilight)
{ {
unsigned int conColor = duRGBA(192,192,192,hilight?192:64); unsigned int conColor = duRGBA(192,0,128,192);
unsigned int baseColor = duRGBA(0,0,0,hilight?192:64); unsigned int baseColor = duRGBA(0,0,0,64);
dd->depthMask(false); dd->depthMask(false);
dd->begin(DU_DRAW_LINES, 2.0f); dd->begin(DU_DRAW_LINES, 2.0f);
@ -200,9 +200,12 @@ void InputGeom::drawOffMeshConnections(duDebugDraw* dd, bool hilight)
duAppendCircle(dd, v[0],v[1]+0.1f,v[2], m_offMeshConRads[i], baseColor); duAppendCircle(dd, v[0],v[1]+0.1f,v[2], m_offMeshConRads[i], baseColor);
duAppendCircle(dd, v[3],v[4]+0.1f,v[5], m_offMeshConRads[i], baseColor); duAppendCircle(dd, v[3],v[4]+0.1f,v[5], m_offMeshConRads[i], baseColor);
duAppendArc(dd, v[0],v[1],v[2], v[3],v[4],v[5], 0.25f, if (hilight)
(m_offMeshConDirs[i]&1) ? 0.6f : 0.0f, 0.6f, conColor); {
duAppendArc(dd, v[0],v[1],v[2], v[3],v[4],v[5], 0.25f,
(m_offMeshConDirs[i]&1) ? 0.6f : 0.0f, 0.6f, conColor);
}
} }
dd->end(); dd->end();

View File

@ -49,7 +49,7 @@ NavMeshTesterTool::NavMeshTesterTool() :
m_navMesh(0), m_navMesh(0),
m_agentRadius(0), m_agentRadius(0),
m_agentHeight(0), m_agentHeight(0),
m_toolMode(TOOLMODE_PATHFIND), m_toolMode(TOOLMODE_PATHFIND_ITER),
m_startRef(0), m_startRef(0),
m_endRef(0), m_endRef(0),
m_npolys(0), m_npolys(0),
@ -87,7 +87,7 @@ void NavMeshTesterTool::init(Sample* sample)
m_navMesh = sample->getNavMesh(); m_navMesh = sample->getNavMesh();
recalc(); recalc();
if (m_toolMode == TOOLMODE_PATHFIND) if (m_toolMode == TOOLMODE_PATHFIND_ITER || m_toolMode == TOOLMODE_PATHFIND_STRAIGHT)
{ {
unsigned char flags = DU_DRAWNAVMESH_CLOSEDLIST; unsigned char flags = DU_DRAWNAVMESH_CLOSEDLIST;
if (m_navMesh) if (m_navMesh)
@ -99,9 +99,14 @@ void NavMeshTesterTool::init(Sample* sample)
void NavMeshTesterTool::handleMenu() void NavMeshTesterTool::handleMenu()
{ {
if (imguiCheck("Pathfind", m_toolMode == TOOLMODE_PATHFIND)) if (imguiCheck("Pathfind Iter", m_toolMode == TOOLMODE_PATHFIND_ITER))
{ {
m_toolMode = TOOLMODE_PATHFIND; m_toolMode = TOOLMODE_PATHFIND_ITER;
recalc();
}
if (imguiCheck("Pathfind Straight", m_toolMode == TOOLMODE_PATHFIND_STRAIGHT))
{
m_toolMode = TOOLMODE_PATHFIND_STRAIGHT;
recalc(); recalc();
} }
if (imguiCheck("Distance to Wall", m_toolMode == TOOLMODE_DISTANCE_TO_WALL)) if (imguiCheck("Distance to Wall", m_toolMode == TOOLMODE_DISTANCE_TO_WALL))
@ -148,7 +153,7 @@ void NavMeshTesterTool::handleMenu()
recalc(); recalc();
} }
if (m_toolMode == TOOLMODE_PATHFIND) if (m_toolMode == TOOLMODE_PATHFIND_ITER || m_toolMode == TOOLMODE_PATHFIND_STRAIGHT)
{ {
unsigned char flags = DU_DRAWNAVMESH_CLOSEDLIST; unsigned char flags = DU_DRAWNAVMESH_CLOSEDLIST;
if (m_navMesh) if (m_navMesh)
@ -243,22 +248,16 @@ void NavMeshTesterTool::recalc()
else else
m_endRef = 0; m_endRef = 0;
if (m_toolMode == TOOLMODE_PATHFIND) if (m_toolMode == TOOLMODE_PATHFIND_ITER)
{ {
if (m_sposSet && m_eposSet && m_startRef && m_endRef) if (m_sposSet && m_eposSet && m_startRef && m_endRef)
{ {
m_npolys = m_navMesh->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, m_polys, MAX_POLYS); m_npolys = m_navMesh->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, m_polys, MAX_POLYS);
m_nstraightPath = 0;
m_nsmoothPath = 0; m_nsmoothPath = 0;
if (m_npolys) if (m_npolys)
{ {
m_nstraightPath = m_navMesh->findStraightPath(m_spos, m_epos, m_polys, m_npolys,
m_straightPath, m_straightPathFlags,
m_straightPathPolys, MAX_POLYS);
// Iterate over the path to find smooth path on the detail mesh surface. // Iterate over the path to find smooth path on the detail mesh surface.
const dtPolyRef* polys = m_polys; const dtPolyRef* polys = m_polys;
int npolys = m_npolys; int npolys = m_npolys;
@ -380,10 +379,28 @@ void NavMeshTesterTool::recalc()
else else
{ {
m_npolys = 0; m_npolys = 0;
m_nstraightPath = 0;
m_nsmoothPath = 0; m_nsmoothPath = 0;
} }
} }
else if (m_toolMode == TOOLMODE_PATHFIND_STRAIGHT)
{
if (m_sposSet && m_eposSet && m_startRef && m_endRef)
{
m_npolys = m_navMesh->findPath(m_startRef, m_endRef, m_spos, m_epos, &m_filter, m_polys, MAX_POLYS);
m_nstraightPath = 0;
if (m_npolys)
{
m_nstraightPath = m_navMesh->findStraightPath(m_spos, m_epos, m_polys, m_npolys,
m_straightPath, m_straightPathFlags,
m_straightPathPolys, MAX_POLYS);
}
}
else
{
m_npolys = 0;
m_nstraightPath = 0;
}
}
else if (m_toolMode == TOOLMODE_RAYCAST) else if (m_toolMode == TOOLMODE_RAYCAST)
{ {
m_nstraightPath = 0; m_nstraightPath = 0;
@ -463,7 +480,27 @@ void NavMeshTesterTool::handleRender()
if (m_eposSet) if (m_eposSet)
drawAgent(m_epos, m_agentRadius, m_agentHeight, 0/*m_agentMaxClimb*/, endCol); drawAgent(m_epos, m_agentRadius, m_agentHeight, 0/*m_agentMaxClimb*/, endCol);
if (m_toolMode == TOOLMODE_PATHFIND) if (m_toolMode == TOOLMODE_PATHFIND_ITER)
{
duDebugDrawNavMeshPoly(&dd, m_navMesh, m_startRef, startCol);
duDebugDrawNavMeshPoly(&dd, m_navMesh, m_endRef, endCol);
if (m_npolys)
{
for (int i = 1; i < m_npolys-1; ++i)
duDebugDrawNavMeshPoly(&dd, m_navMesh, m_polys[i], pathCol);
}
if (m_nsmoothPath)
{
const unsigned int pathCol = duRGBA(0,0,0,220);
dd.begin(DU_DRAW_LINES, 3.0f);
for (int i = 0; i < m_nsmoothPath; ++i)
dd.vertex(m_smoothPath[i*3], m_smoothPath[i*3+1]+0.1f, m_smoothPath[i*3+2], pathCol);
dd.end();
}
}
else if (m_toolMode == TOOLMODE_PATHFIND_STRAIGHT)
{ {
duDebugDrawNavMeshPoly(&dd, m_navMesh, m_startRef, startCol); duDebugDrawNavMeshPoly(&dd, m_navMesh, m_startRef, startCol);
duDebugDrawNavMeshPoly(&dd, m_navMesh, m_endRef, endCol); duDebugDrawNavMeshPoly(&dd, m_navMesh, m_endRef, endCol);
@ -506,19 +543,6 @@ void NavMeshTesterTool::handleRender()
dd.vertex(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2], pathCol); dd.vertex(m_straightPath[i*3], m_straightPath[i*3+1]+0.4f, m_straightPath[i*3+2], pathCol);
} }
dd.end(); dd.end();
/* for (int i = 1; i < m_nstraightPath-1; ++i)
{
duDebugDrawNavMeshPoly(&dd, m_navMesh, m_straightPathPolys[i], duRGBA(255,255,255,64));
}*/
}
if (m_nsmoothPath)
{
const unsigned int pathCol = duRGBA(0,0,0,220);
dd.begin(DU_DRAW_LINES, 3.0f);
for (int i = 0; i < m_nsmoothPath; ++i)
dd.vertex(m_smoothPath[i*3], m_smoothPath[i*3+1]+0.1f, m_smoothPath[i*3+2], pathCol);
dd.end();
} }
} }
else if (m_toolMode == TOOLMODE_RAYCAST) else if (m_toolMode == TOOLMODE_RAYCAST)

View File

@ -38,19 +38,27 @@
OffMeshConnectionTool::OffMeshConnectionTool() : OffMeshConnectionTool::OffMeshConnectionTool() :
m_sample(0), m_sample(0),
m_hitPosSet(0), m_hitPosSet(0),
m_bidir(true) m_bidir(true),
m_oldFlags(0)
{ {
} }
OffMeshConnectionTool::~OffMeshConnectionTool() OffMeshConnectionTool::~OffMeshConnectionTool()
{ {
if (m_sample)
{
m_sample->setNavMeshDrawFlags(m_oldFlags);
}
} }
void OffMeshConnectionTool::init(Sample* sample) void OffMeshConnectionTool::init(Sample* sample)
{ {
m_sample = sample; m_sample = sample;
if (m_sample) if (m_sample)
m_sample->setNavMeshDrawFlags(0); {
m_oldFlags = m_sample->getNavMeshDrawFlags();
m_sample->setNavMeshDrawFlags(m_oldFlags & ~DU_DRAWNAVMESH_OFFMESHCONS);
}
} }
void OffMeshConnectionTool::reset() void OffMeshConnectionTool::reset()
@ -104,6 +112,8 @@ void OffMeshConnectionTool::handleClick(const float* p, bool shift)
{ {
geom->deleteOffMeshConnection(nearestIndex); geom->deleteOffMeshConnection(nearestIndex);
} }
// geom->updateOffMeshConnectionVisibility(m_sample->getNavMesh());
} }
else else
{ {
@ -117,6 +127,7 @@ void OffMeshConnectionTool::handleClick(const float* p, bool shift)
{ {
geom->addOffMeshConnection(m_hitPos, p, m_sample->getAgentRadius(), m_bidir ? 1 : 0); geom->addOffMeshConnection(m_hitPos, p, m_sample->getAgentRadius(), m_bidir ? 1 : 0);
m_hitPosSet = false; m_hitPosSet = false;
// geom->updateOffMeshConnectionVisibility(m_sample->getNavMesh());
} }
} }

View File

@ -82,7 +82,7 @@ void DebugDrawGL::end()
Sample::Sample() : Sample::Sample() :
m_geom(0), m_geom(0),
m_navMesh(0), m_navMesh(0),
m_navMeshDrawFlags(DU_DRAWNAVMESH_CLOSEDLIST), m_navMeshDrawFlags(DU_DRAWNAVMESH_CLOSEDLIST|DU_DRAWNAVMESH_OFFMESHCONS),
m_tool(0) m_tool(0)
{ {
resetCommonSettings(); resetCommonSettings();
@ -209,3 +209,11 @@ bool Sample::handleBuild()
{ {
return true; return true;
} }
/*
void Sample::handleNavMeshChanged()
{
if (m_geom)
m_geom->updateOffMeshConnectionVisibility(m_navMesh);
}
*/

View File

@ -197,16 +197,14 @@ void Sample_SoloMeshSimple::handleRender()
duDebugDrawTriMeshSlope(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(), duDebugDrawTriMeshSlope(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(),
m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(),
m_agentMaxSlope); m_agentMaxSlope);
if ((m_navMeshDrawFlags & DU_DRAWNAVMESH_OFFMESHCONS) == 0) m_geom->drawOffMeshConnections(&dd);
m_geom->drawOffMeshConnections(&dd);
} }
else if (m_drawMode != DRAWMODE_NAVMESH_TRANS) else if (m_drawMode != DRAWMODE_NAVMESH_TRANS)
{ {
// Draw mesh // Draw mesh
duDebugDrawTriMesh(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(), duDebugDrawTriMesh(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(),
m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), 0); m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), 0);
if ((m_navMeshDrawFlags & DU_DRAWNAVMESH_OFFMESHCONS) == 0) m_geom->drawOffMeshConnections(&dd);
m_geom->drawOffMeshConnections(&dd);
} }
glDisable(GL_FOG); glDisable(GL_FOG);
@ -312,8 +310,10 @@ void Sample_SoloMeshSimple::handleRenderOverlay(double* proj, double* model, int
void Sample_SoloMeshSimple::handleMeshChanged(class InputGeom* geom) void Sample_SoloMeshSimple::handleMeshChanged(class InputGeom* geom)
{ {
Sample::handleMeshChanged(geom); Sample::handleMeshChanged(geom);
delete m_navMesh; delete m_navMesh;
m_navMesh = 0; m_navMesh = 0;
if (m_tool) if (m_tool)
{ {
m_tool->reset(); m_tool->reset();
@ -638,8 +638,6 @@ bool Sample_SoloMeshSimple::handleBuild()
rcGetLog()->log(RC_LOG_PROGRESS, "TOTAL: %.1fms", rcGetDeltaTimeUsec(totStartTime, totEndTime)/1000.0f); rcGetLog()->log(RC_LOG_PROGRESS, "TOTAL: %.1fms", rcGetDeltaTimeUsec(totStartTime, totEndTime)/1000.0f);
} }
setNavMeshDrawFlags(DU_DRAWNAVMESH_OFFMESHCONS);
if (m_tool) if (m_tool)
m_tool->init(this); m_tool->init(this);

View File

@ -231,16 +231,14 @@ void Sample_SoloMeshTiled::handleRender()
duDebugDrawTriMeshSlope(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(), duDebugDrawTriMeshSlope(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(),
m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(),
m_agentMaxSlope); m_agentMaxSlope);
if ((m_navMeshDrawFlags & DU_DRAWNAVMESH_OFFMESHCONS) == 0) m_geom->drawOffMeshConnections(&dd);
m_geom->drawOffMeshConnections(&dd);
} }
else if (m_drawMode != DRAWMODE_NAVMESH_TRANS) else if (m_drawMode != DRAWMODE_NAVMESH_TRANS)
{ {
// Draw mesh // Draw mesh
duDebugDrawTriMesh(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(), duDebugDrawTriMesh(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(),
m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), 0); m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), 0);
if ((m_navMeshDrawFlags & DU_DRAWNAVMESH_OFFMESHCONS) == 0) m_geom->drawOffMeshConnections(&dd);
m_geom->drawOffMeshConnections(&dd);
} }
glDisable(GL_FOG); glDisable(GL_FOG);
@ -556,8 +554,13 @@ void Sample_SoloMeshTiled::handleRenderOverlay(double* proj, double* model, int*
void Sample_SoloMeshTiled::handleMeshChanged(class InputGeom* geom) void Sample_SoloMeshTiled::handleMeshChanged(class InputGeom* geom)
{ {
Sample::handleMeshChanged(geom); Sample::handleMeshChanged(geom);
delete m_navMesh;
m_navMesh = 0;
m_statTimePerTileSamples = 0; m_statTimePerTileSamples = 0;
m_statPolysPerTileSamples = 0; m_statPolysPerTileSamples = 0;
if (m_tool) if (m_tool)
{ {
m_tool->reset(); m_tool->reset();
@ -937,10 +940,10 @@ bool Sample_SoloMeshTiled::handleBuild()
params.detailVertsCount = m_dmesh->nverts; params.detailVertsCount = m_dmesh->nverts;
params.detailTris = m_dmesh->tris; params.detailTris = m_dmesh->tris;
params.detailTriCount = m_dmesh->ntris; params.detailTriCount = m_dmesh->ntris;
params.offMeshConVerts = 0; params.offMeshConVerts = m_geom->getOffMeshConnectionVerts();
params.offMeshConRad = 0; params.offMeshConRad = m_geom->getOffMeshConnectionRads();
params.offMeshConDir = 0; params.offMeshConDir = m_geom->getOffMeshConnectionDirs();
params.offMeshConCount = 0; params.offMeshConCount = m_geom->getOffMeshConnectionCount();
params.walkableHeight = m_agentHeight; params.walkableHeight = m_agentHeight;
params.walkableRadius = m_agentRadius; params.walkableRadius = m_agentRadius;
params.walkableClimb = m_agentMaxClimb; params.walkableClimb = m_agentMaxClimb;
@ -1013,8 +1016,6 @@ bool Sample_SoloMeshTiled::handleBuild()
rcGetLog()->log(RC_LOG_PROGRESS, "TOTAL: %.1fms", rcGetDeltaTimeUsec(totStartTime, totEndTime)/1000.0f); rcGetLog()->log(RC_LOG_PROGRESS, "TOTAL: %.1fms", rcGetDeltaTimeUsec(totStartTime, totEndTime)/1000.0f);
} }
setNavMeshDrawFlags(DU_DRAWNAVMESH_OFFMESHCONS);
if (m_tool) if (m_tool)
m_tool->init(this); m_tool->init(this);

View File

@ -311,8 +311,7 @@ void Sample_TileMesh::handleRender()
// Draw mesh // Draw mesh
duDebugDrawTriMesh(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(), duDebugDrawTriMesh(&dd, m_geom->getMesh()->getVerts(), m_geom->getMesh()->getVertCount(),
m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), 0); m_geom->getMesh()->getTris(), m_geom->getMesh()->getNormals(), m_geom->getMesh()->getTriCount(), 0);
if ((m_navMeshDrawFlags & DU_DRAWNAVMESH_OFFMESHCONS) == 0) m_geom->drawOffMeshConnections(&dd);
m_geom->drawOffMeshConnections(&dd);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
@ -363,9 +362,10 @@ void Sample_TileMesh::handleMeshChanged(class InputGeom* geom)
Sample::handleMeshChanged(geom); Sample::handleMeshChanged(geom);
cleanup(); cleanup();
delete m_navMesh; delete m_navMesh;
m_navMesh = 0; m_navMesh = 0;
if (m_tool) if (m_tool)
{ {
m_tool->reset(); m_tool->reset();
@ -404,8 +404,6 @@ bool Sample_TileMesh::handleBuild()
if (m_buildAll) if (m_buildAll)
buildAllTiles(); buildAllTiles();
setNavMeshDrawFlags(DU_DRAWNAVMESH_OFFMESHCONS);
if (m_tool) if (m_tool)
m_tool->init(this); m_tool->init(this);
@ -796,10 +794,10 @@ unsigned char* Sample_TileMesh::buildTileMesh(const float* bmin, const float* bm
params.detailVertsCount = m_dmesh->nverts; params.detailVertsCount = m_dmesh->nverts;
params.detailTris = m_dmesh->tris; params.detailTris = m_dmesh->tris;
params.detailTriCount = m_dmesh->ntris; params.detailTriCount = m_dmesh->ntris;
params.offMeshConVerts = 0; params.offMeshConVerts = m_geom->getOffMeshConnectionVerts();
params.offMeshConRad = 0; params.offMeshConRad = m_geom->getOffMeshConnectionRads();
params.offMeshConDir = 0; params.offMeshConDir = m_geom->getOffMeshConnectionDirs();
params.offMeshConCount = 0; params.offMeshConCount = m_geom->getOffMeshConnectionCount();
params.walkableHeight = m_agentHeight; params.walkableHeight = m_agentHeight;
params.walkableRadius = m_agentRadius; params.walkableRadius = m_agentRadius;
params.walkableClimb = m_agentMaxClimb; params.walkableClimb = m_agentMaxClimb;