mirror of
https://github.com/ENSL/NS.git
synced 2025-04-20 16:30:56 +00:00
Implement new off-mesh connection system
This commit is contained in:
parent
97b87089f6
commit
12fb10f998
13 changed files with 912 additions and 925 deletions
|
@ -134,7 +134,6 @@ inline void freeLink(dtMeshTile* tile, unsigned int link)
|
|||
tile->linksFreeList = link;
|
||||
}
|
||||
|
||||
|
||||
dtNavMesh* dtAllocNavMesh()
|
||||
{
|
||||
void* mem = dtAlloc(sizeof(dtNavMesh), DT_ALLOC_PERM);
|
||||
|
@ -284,7 +283,7 @@ dtStatus dtNavMesh::init(unsigned char* data, const int dataSize, const int flag
|
|||
if (dtStatusFailed(status))
|
||||
return status;
|
||||
|
||||
return addTile(data, dataSize, flags, 0, 0, false);
|
||||
return addTile(data, dataSize, flags, 0, 0);
|
||||
}
|
||||
|
||||
/// @par
|
||||
|
@ -350,6 +349,169 @@ int dtNavMesh::findConnectingPolys(const float* va, const float* vb,
|
|||
return n;
|
||||
}
|
||||
|
||||
void dtNavMesh::LinkOffMeshConnectionToTiles(dtOffMeshConnection* con)
|
||||
{
|
||||
con->FromTileX = -1;
|
||||
con->FromTileY = -1;
|
||||
con->FromTileLayer = -1;
|
||||
|
||||
con->ToTileX = -1;
|
||||
con->ToTileY = -1;
|
||||
con->ToTileLayer = -1;
|
||||
|
||||
const float ext[3] = { con->rad, 18.0f, con->rad };
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
dtVsub(bmin, &con->pos[0], ext);
|
||||
dtVadd(bmax, &con->pos[0], ext);
|
||||
|
||||
// Find tiles the query touches.
|
||||
int minx, miny, maxx, maxy;
|
||||
this->calcTileLoc(bmin, &minx, &miny);
|
||||
this->calcTileLoc(bmax, &maxx, &maxy);
|
||||
|
||||
static const int MAX_NEIS = 32;
|
||||
dtMeshTile* neis[MAX_NEIS];
|
||||
|
||||
float NearestDist = FLT_MAX;
|
||||
|
||||
float nearestPt[3];
|
||||
|
||||
for (int y = miny; y <= maxy; ++y)
|
||||
{
|
||||
for (int x = minx; x <= maxx; ++x)
|
||||
{
|
||||
const int nneis = this->getTilesAt(x, y, neis, MAX_NEIS);
|
||||
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
dtMeshTile* tile = neis[j];
|
||||
|
||||
dtPolyRef NearestPoly = findNearestPolyInTile(tile, &con->pos[0], ext, nearestPt);
|
||||
|
||||
if (NearestPoly)
|
||||
{
|
||||
float thisDist = dtVdistSqr(nearestPt, &con->pos[0]);
|
||||
|
||||
if (thisDist < NearestDist)
|
||||
{
|
||||
thisDist = NearestDist;
|
||||
con->FromTileX = tile->header->x;
|
||||
con->FromTileY = tile->header->y;
|
||||
con->FromTileLayer = tile->header->layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NearestDist = FLT_MAX;
|
||||
|
||||
dtVsub(bmin, &con->pos[3], ext);
|
||||
dtVadd(bmax, &con->pos[3], ext);
|
||||
|
||||
this->calcTileLoc(bmin, &minx, &miny);
|
||||
this->calcTileLoc(bmax, &maxx, &maxy);
|
||||
|
||||
|
||||
for (int y = miny; y <= maxy; ++y)
|
||||
{
|
||||
for (int x = minx; x <= maxx; ++x)
|
||||
{
|
||||
const int nneis = this->getTilesAt(x, y, neis, MAX_NEIS);
|
||||
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
dtMeshTile* tile = neis[j];
|
||||
|
||||
dtPolyRef NearestPoly = findNearestPolyInTile(tile, &con->pos[3], ext, nearestPt);
|
||||
|
||||
if (NearestPoly)
|
||||
{
|
||||
float thisDist = dtVdistSqr(nearestPt, &con->pos[3]);
|
||||
|
||||
if (thisDist < NearestDist)
|
||||
{
|
||||
thisDist = NearestDist;
|
||||
con->ToTileX = tile->header->x;
|
||||
con->ToTileY = tile->header->y;
|
||||
con->ToTileLayer = tile->header->layer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dtNavMesh::unconnectOffMeshLink(dtOffMeshConnection* con)
|
||||
{
|
||||
if (!con || con->FromTileX < 0 || con->ToTileX < 0)
|
||||
return;
|
||||
|
||||
dtMeshTile* tile = getTileAt(con->FromTileX, con->FromTileY, con->FromTileLayer);
|
||||
dtMeshTile* target = this->getTileAt(con->ToTileX, con->ToTileY, con->ToTileLayer);
|
||||
|
||||
if (!tile || !target) return;
|
||||
|
||||
const unsigned int targetNum = decodePolyIdTile(getTileRef(target));
|
||||
|
||||
for (int i = 0; i < tile->header->polyCount; ++i)
|
||||
{
|
||||
dtPoly* poly = &tile->polys[i];
|
||||
unsigned int j = poly->firstLink;
|
||||
unsigned int pj = DT_NULL_LINK;
|
||||
while (j != DT_NULL_LINK)
|
||||
{
|
||||
if (decodePolyIdTile(tile->links[j].ref) == targetNum && tile->links[j].OffMeshID == con->userId)
|
||||
{
|
||||
// Remove link.
|
||||
unsigned int nj = tile->links[j].next;
|
||||
if (pj == DT_NULL_LINK)
|
||||
poly->firstLink = nj;
|
||||
else
|
||||
tile->links[pj].next = nj;
|
||||
freeLink(tile, j);
|
||||
j = nj;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Advance
|
||||
pj = j;
|
||||
j = tile->links[j].next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unsigned int sourceNum = decodePolyIdTile(getTileRef(tile));
|
||||
|
||||
for (int i = 0; i < target->header->polyCount; ++i)
|
||||
{
|
||||
dtPoly* poly = &target->polys[i];
|
||||
unsigned int j = poly->firstLink;
|
||||
unsigned int pj = DT_NULL_LINK;
|
||||
while (j != DT_NULL_LINK)
|
||||
{
|
||||
if (decodePolyIdTile(target->links[j].ref) == sourceNum && target->links[j].OffMeshID == con->userId)
|
||||
{
|
||||
// Remove link.
|
||||
unsigned int nj = target->links[j].next;
|
||||
if (pj == DT_NULL_LINK)
|
||||
poly->firstLink = nj;
|
||||
else
|
||||
target->links[pj].next = nj;
|
||||
freeLink(target, j);
|
||||
j = nj;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Advance
|
||||
pj = j;
|
||||
j = target->links[j].next;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dtNavMesh::unconnectLinks(dtMeshTile* tile, dtMeshTile* target)
|
||||
{
|
||||
if (!tile || !target) return;
|
||||
|
@ -451,76 +613,6 @@ void dtNavMesh::connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side)
|
|||
}
|
||||
}
|
||||
|
||||
void dtNavMesh::connectDistantExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side)
|
||||
{
|
||||
if (!tile) return;
|
||||
|
||||
// Connect off-mesh links.
|
||||
// We are interested on links which land from target tile to this tile.
|
||||
const unsigned char oppositeSide = (side == -1) ? 0xff : (unsigned char)dtOppositeTile(side);
|
||||
|
||||
for (int i = 0; i < target->header->offMeshConCount; ++i)
|
||||
{
|
||||
dtOffMeshConnection* targetCon = &target->offMeshCons[i];
|
||||
|
||||
dtPoly* targetPoly = &target->polys[targetCon->poly];
|
||||
// Skip off-mesh connections which start location could not be connected at all.
|
||||
if (targetPoly->firstLink == DT_NULL_LINK)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
const float halfExtents[3] = { targetCon->rad, target->header->walkableClimb, targetCon->rad };
|
||||
|
||||
// Find polygon to connect to.
|
||||
const float* p = &targetCon->pos[3];
|
||||
float nearestPt[3];
|
||||
dtPolyRef ref = findNearestPolyInTile(tile, p, halfExtents, nearestPt);
|
||||
if (!ref)
|
||||
continue;
|
||||
// findNearestPoly may return too optimistic results, further check to make sure.
|
||||
if (dtSqr(nearestPt[0] - p[0]) + dtSqr(nearestPt[2] - p[2]) > dtSqr(targetCon->rad))
|
||||
continue;
|
||||
// Make sure the location is on current mesh.
|
||||
float* v = &target->verts[targetPoly->verts[1] * 3];
|
||||
dtVcopy(v, nearestPt);
|
||||
|
||||
// Link off-mesh connection to target poly.
|
||||
unsigned int idx = allocLink(target);
|
||||
if (idx != DT_NULL_LINK)
|
||||
{
|
||||
dtLink* link = &target->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.
|
||||
if (targetCon->flags & DT_OFFMESH_CON_BIDIR)
|
||||
{
|
||||
unsigned int tidx = allocLink(tile);
|
||||
if (tidx != DT_NULL_LINK)
|
||||
{
|
||||
const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref);
|
||||
dtPoly* landPoly = &tile->polys[landPolyIdx];
|
||||
dtLink* link = &tile->links[tidx];
|
||||
link->ref = getPolyRefBase(target) | (dtPolyRef)(targetCon->poly);
|
||||
link->edge = 0xff;
|
||||
link->side = (unsigned char)(side == -1 ? 0xff : side);
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = landPoly->firstLink;
|
||||
landPoly->firstLink = tidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side)
|
||||
{
|
||||
if (!tile) return;
|
||||
|
@ -531,7 +623,7 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int
|
|||
|
||||
for (int i = 0; i < target->header->offMeshConCount; ++i)
|
||||
{
|
||||
dtOffMeshConnection* targetCon = &target->offMeshCons[i];
|
||||
dtOffMeshConnection* targetCon = target->offMeshCons[i];
|
||||
if (targetCon->side != oppositeSide)
|
||||
continue;
|
||||
|
||||
|
@ -541,7 +633,6 @@ void dtNavMesh::connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int
|
|||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
const float halfExtents[3] = { targetCon->rad, target->header->walkableClimb, targetCon->rad };
|
||||
|
||||
|
@ -631,6 +722,67 @@ void dtNavMesh::connectIntLinks(dtMeshTile* tile)
|
|||
}
|
||||
}
|
||||
|
||||
void dtNavMesh::baseOffMeshLinks(dtOffMeshConnection* con)
|
||||
{
|
||||
if (!con) return;
|
||||
|
||||
dtMeshTile* tile = getTileAt(con->FromTileX, con->FromTileY, con->FromTileLayer);
|
||||
|
||||
if (!tile) { return; }
|
||||
|
||||
dtPolyRef base = getPolyRefBase(tile);
|
||||
|
||||
dtPoly* poly = &tile->polys[con->poly];
|
||||
|
||||
const float halfExtents[3] = { con->rad, tile->header->walkableClimb, con->rad };
|
||||
|
||||
// Find polygon to connect to.
|
||||
const float* p = &con->pos[0]; // First vertex
|
||||
float nearestPt[3];
|
||||
dtPolyRef ref = findNearestPolyInTile(tile, p, halfExtents, nearestPt);
|
||||
if (!ref) return;
|
||||
// findNearestPoly may return too optimistic results, further check to make sure.
|
||||
if (dtSqr(nearestPt[0] - p[0]) + dtSqr(nearestPt[2] - p[2]) > dtSqr(con->rad))
|
||||
return;
|
||||
// Make sure the location is on current mesh.
|
||||
float* v = &tile->verts[poly->verts[0] * 3];
|
||||
dtVcopy(v, nearestPt);
|
||||
|
||||
// Link off-mesh connection to target poly.
|
||||
unsigned int idx = allocLink(tile);
|
||||
if (idx != DT_NULL_LINK)
|
||||
{
|
||||
dtLink* link = &tile->links[idx];
|
||||
link->OffMeshID = -1;
|
||||
link->ref = ref;
|
||||
link->edge = (unsigned char)0;
|
||||
link->side = 0xff;
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = poly->firstLink;
|
||||
poly->firstLink = idx;
|
||||
}
|
||||
|
||||
// Start end-point is always connect back to off-mesh connection.
|
||||
unsigned int tidx = allocLink(tile);
|
||||
if (tidx != DT_NULL_LINK)
|
||||
{
|
||||
const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref);
|
||||
dtPoly* landPoly = &tile->polys[landPolyIdx];
|
||||
dtLink* link = &tile->links[tidx];
|
||||
link->OffMeshID = -1;
|
||||
link->ref = base | (dtPolyRef)(con->poly);
|
||||
link->edge = 0xff;
|
||||
link->side = 0xff;
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = landPoly->firstLink;
|
||||
landPoly->firstLink = tidx;
|
||||
}
|
||||
|
||||
con->bBased = true;
|
||||
}
|
||||
|
||||
void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile)
|
||||
{
|
||||
if (!tile) return;
|
||||
|
@ -640,7 +792,7 @@ void dtNavMesh::baseOffMeshLinks(dtMeshTile* tile)
|
|||
// Base off-mesh connection start points.
|
||||
for (int i = 0; i < tile->header->offMeshConCount; ++i)
|
||||
{
|
||||
dtOffMeshConnection* con = &tile->offMeshCons[i];
|
||||
dtOffMeshConnection* con = tile->offMeshCons[i];
|
||||
dtPoly* poly = &tile->polys[con->poly];
|
||||
|
||||
const float halfExtents[3] = { con->rad, tile->header->walkableClimb, con->rad };
|
||||
|
@ -943,7 +1095,7 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co
|
|||
if (p->getType() == DT_POLYTYPE_OFFMESH_CONNECTION)
|
||||
continue;
|
||||
// Calc polygon bounds.
|
||||
const float* v = &tile->verts[p->verts[0]*3];
|
||||
const float* v = &tile->verts[p->verts[0] * 3];
|
||||
dtVcopy(bmin, v);
|
||||
dtVcopy(bmax, v);
|
||||
for (int j = 1; j < p->vertCount; ++j)
|
||||
|
@ -979,7 +1131,7 @@ int dtNavMesh::queryPolygonsInTile(const dtMeshTile* tile, const float* qmin, co
|
|||
///
|
||||
/// @see dtCreateNavMeshData, #removeTile
|
||||
dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
||||
dtTileRef lastRef, dtTileRef* result, bool bMarkOffMeshDirty)
|
||||
dtTileRef lastRef, dtTileRef* result)
|
||||
{
|
||||
// Make sure the data is in right format.
|
||||
dtMeshHeader* header = (dtMeshHeader*)data;
|
||||
|
@ -994,11 +1146,11 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
if (m_polyBits < dtIlog2(dtNextPow2((unsigned int)header->polyCount)))
|
||||
return DT_FAILURE | DT_INVALID_PARAM;
|
||||
#endif
|
||||
|
||||
|
||||
// Make sure the location is free.
|
||||
if (getTileAt(header->x, header->y, header->layer))
|
||||
return DT_FAILURE | DT_ALREADY_OCCUPIED;
|
||||
|
||||
|
||||
// Allocate a tile.
|
||||
dtMeshTile* tile = 0;
|
||||
if (!lastRef)
|
||||
|
@ -1041,23 +1193,22 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
// Make sure we could allocate a tile.
|
||||
if (!tile)
|
||||
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||
|
||||
|
||||
// Insert tile into the position lut.
|
||||
int h = computeTileHash(header->x, header->y, m_tileLutMask);
|
||||
tile->next = m_posLookup[h];
|
||||
m_posLookup[h] = tile;
|
||||
|
||||
|
||||
// Patch header pointers.
|
||||
const int headerSize = dtAlign4(sizeof(dtMeshHeader));
|
||||
const int vertsSize = dtAlign4(sizeof(float)*3*header->vertCount);
|
||||
const int polysSize = dtAlign4(sizeof(dtPoly)*header->polyCount);
|
||||
const int linksSize = dtAlign4(sizeof(dtLink)*(header->maxLinkCount));
|
||||
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*header->detailMeshCount);
|
||||
const int detailVertsSize = dtAlign4(sizeof(float)*3*header->detailVertCount);
|
||||
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*header->detailTriCount);
|
||||
const int bvtreeSize = dtAlign4(sizeof(dtBVNode)*header->bvNodeCount);
|
||||
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection)*header->offMeshConCount);
|
||||
const int receivingOffMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection) * header->receivingOffMeshConCount);
|
||||
const int vertsSize = dtAlign4(sizeof(float) * 3 * header->vertCount);
|
||||
const int polysSize = dtAlign4(sizeof(dtPoly) * header->polyCount);
|
||||
const int linksSize = dtAlign4(sizeof(dtLink) * (header->maxLinkCount));
|
||||
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail) * header->detailMeshCount);
|
||||
const int detailVertsSize = dtAlign4(sizeof(float) * 3 * header->detailVertCount);
|
||||
const int detailTrisSize = dtAlign4(sizeof(unsigned char) * 4 * header->detailTriCount);
|
||||
const int bvtreeSize = dtAlign4(sizeof(dtBVNode) * header->bvNodeCount);
|
||||
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection) * header->offMeshConCount);
|
||||
|
||||
unsigned char* d = data + headerSize;
|
||||
tile->verts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||
|
@ -1067,9 +1218,7 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
tile->detailVerts = dtGetThenAdvanceBufferPointer<float>(d, detailVertsSize);
|
||||
tile->detailTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
tile->bvTree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvtreeSize);
|
||||
tile->offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshLinksSize);
|
||||
tile->receivingOffMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, receivingOffMeshLinksSize);
|
||||
|
||||
tile->offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection*>(d, offMeshLinksSize);
|
||||
|
||||
// If there are no items in the bvtree, reset the tree pointer.
|
||||
if (!bvtreeSize)
|
||||
|
@ -1077,9 +1226,9 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
|
||||
// Build links freelist
|
||||
tile->linksFreeList = 0;
|
||||
tile->links[header->maxLinkCount-1].next = DT_NULL_LINK;
|
||||
for (int i = 0; i < header->maxLinkCount-1; ++i)
|
||||
tile->links[i].next = i+1;
|
||||
tile->links[header->maxLinkCount - 1].next = DT_NULL_LINK;
|
||||
for (int i = 0; i < header->maxLinkCount - 1; ++i)
|
||||
tile->links[i].next = i + 1;
|
||||
|
||||
// Init tile.
|
||||
tile->header = header;
|
||||
|
@ -1089,25 +1238,28 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
|
||||
connectIntLinks(tile);
|
||||
|
||||
// Base off-mesh connections to their starting polygons and connect connections inside the tile.
|
||||
baseOffMeshLinks(tile);
|
||||
for (int i = 0; i < tile->header->offMeshConCount; i++)
|
||||
{
|
||||
baseOffMeshLinks(tile->offMeshCons[i]);
|
||||
}
|
||||
|
||||
// Create connections with neighbour tiles.
|
||||
static const int MAX_NEIS = 32;
|
||||
dtMeshTile* neis[MAX_NEIS];
|
||||
int nneis;
|
||||
|
||||
|
||||
|
||||
// Connect with layers in current tile.
|
||||
nneis = getTilesAt(header->x, header->y, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
if (neis[j] == tile)
|
||||
continue;
|
||||
|
||||
|
||||
connectExtLinks(tile, neis[j], -1);
|
||||
connectExtLinks(neis[j], tile, -1);
|
||||
}
|
||||
|
||||
|
||||
// Connect with neighbour tiles.
|
||||
for (int i = 0; i < 8; ++i)
|
||||
{
|
||||
|
@ -1119,115 +1271,101 @@ dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags,
|
|||
}
|
||||
}
|
||||
|
||||
GlobalOffMeshLinks(tile);
|
||||
|
||||
if (bMarkOffMeshDirty)
|
||||
{
|
||||
for (int i = 0; i < tile->header->receivingOffMeshConCount; i++)
|
||||
{
|
||||
dtOffMeshConnection* targetCon = &tile->receivingOffMeshCons[i];
|
||||
|
||||
m_PendingOffMeshs[m_NumPendingConnections++] = targetCon;
|
||||
}
|
||||
}
|
||||
|
||||
if (result)
|
||||
*result = getTileRef(tile);
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
void dtNavMesh::GlobalOffMeshLinks(dtMeshTile* target)
|
||||
void dtNavMesh::GlobalOffMeshLinks(dtOffMeshConnection* con)
|
||||
{
|
||||
if (!target)
|
||||
if (!con)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < target->header->offMeshConCount; ++i)
|
||||
dtMeshTile* tile = getTileAt(con->FromTileX, con->FromTileY, con->FromTileLayer);
|
||||
|
||||
if (!tile) { return; }
|
||||
|
||||
dtPoly* targetPoly = &tile->polys[con->poly];
|
||||
// Skip off-mesh connections which start location could not be connected at all.
|
||||
if (targetPoly->firstLink == DT_NULL_LINK)
|
||||
return;
|
||||
|
||||
dtMeshTile* TargetTile = this->getTileAt(con->ToTileX, con->ToTileY, con->ToTileLayer);
|
||||
|
||||
if (!TargetTile) { return; }
|
||||
|
||||
const float ext[3] = { con->rad, tile->header->walkableClimb, con->rad };
|
||||
|
||||
// Find polygon to connect to.
|
||||
const float* p = &con->pos[3];
|
||||
float nearestPt[3];
|
||||
dtPolyRef ref = findNearestPolyInTile(TargetTile, p, ext, nearestPt);
|
||||
if (!ref)
|
||||
return;
|
||||
// findNearestPoly may return too optimistic results, further check to make sure.
|
||||
if (dtSqr(nearestPt[0] - p[0]) + dtSqr(nearestPt[2] - p[2]) > dtSqr(con->rad))
|
||||
return;
|
||||
// Make sure the location is on current mesh.
|
||||
float* v = &tile->verts[targetPoly->verts[1] * 3];
|
||||
dtVcopy(v, nearestPt);
|
||||
|
||||
// Link off-mesh connection to target poly.
|
||||
unsigned int idx = allocLink(tile);
|
||||
if (idx != DT_NULL_LINK)
|
||||
{
|
||||
dtOffMeshConnection* targetCon = &target->offMeshCons[i];
|
||||
dtLink* link = &tile->links[idx];
|
||||
link->ref = ref;
|
||||
link->edge = (unsigned char)1;
|
||||
link->side = (unsigned char)0xff;
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = targetPoly->firstLink;
|
||||
link->OffMeshID = con->userId;
|
||||
targetPoly->firstLink = idx;
|
||||
}
|
||||
|
||||
dtPoly* targetPoly = &target->polys[targetCon->poly];
|
||||
// Skip off-mesh connections which start location could not be connected at all.
|
||||
if (targetPoly->firstLink == DT_NULL_LINK)
|
||||
continue;
|
||||
|
||||
const float ext[3] = { targetCon->rad, target->header->walkableClimb, targetCon->rad };
|
||||
|
||||
|
||||
float bmin[3], bmax[3];
|
||||
dtVsub(bmin, &targetCon->pos[3], ext);
|
||||
dtVadd(bmax, &targetCon->pos[3], ext);
|
||||
|
||||
// Find tiles the query touches.
|
||||
int minx, miny, maxx, maxy;
|
||||
this->calcTileLoc(bmin, &minx, &miny);
|
||||
this->calcTileLoc(bmax, &maxx, &maxy);
|
||||
|
||||
static const int MAX_NEIS = 32;
|
||||
dtMeshTile* neis[MAX_NEIS];
|
||||
|
||||
for (int y = miny; y <= maxy; ++y)
|
||||
// Link target poly to off-mesh connection.
|
||||
if (con->bBiDir)
|
||||
{
|
||||
unsigned int tidx = allocLink(TargetTile);
|
||||
if (tidx != DT_NULL_LINK)
|
||||
{
|
||||
for (int x = minx; x <= maxx; ++x)
|
||||
{
|
||||
const int nneis = this->getTilesAt(x, y, neis, MAX_NEIS);
|
||||
for (int j = 0; j < nneis; ++j)
|
||||
{
|
||||
auto tile = neis[j];
|
||||
|
||||
|
||||
// Find polygon to connect to.
|
||||
const float* p = &targetCon->pos[3];
|
||||
float nearestPt[3];
|
||||
dtPolyRef ref = findNearestPolyInTile(tile, p, ext, nearestPt);
|
||||
if (!ref)
|
||||
continue;
|
||||
// findNearestPoly may return too optimistic results, further check to make sure.
|
||||
if (dtSqr(nearestPt[0] - p[0]) + dtSqr(nearestPt[2] - p[2]) > dtSqr(targetCon->rad))
|
||||
continue;
|
||||
// Make sure the location is on current mesh.
|
||||
float* v = &target->verts[targetPoly->verts[1] * 3];
|
||||
dtVcopy(v, nearestPt);
|
||||
|
||||
// Link off-mesh connection to target poly.
|
||||
unsigned int idx = allocLink(target);
|
||||
if (idx != DT_NULL_LINK)
|
||||
{
|
||||
dtLink* link = &target->links[idx];
|
||||
link->ref = ref;
|
||||
link->edge = (unsigned char)1;
|
||||
link->side = (unsigned char)0xff;
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = targetPoly->firstLink;
|
||||
targetPoly->firstLink = idx;
|
||||
}
|
||||
|
||||
// Link target poly to off-mesh connection.
|
||||
if (targetCon->flags & DT_OFFMESH_CON_BIDIR)
|
||||
{
|
||||
unsigned int tidx = allocLink(tile);
|
||||
if (tidx != DT_NULL_LINK)
|
||||
{
|
||||
const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref);
|
||||
dtPoly* landPoly = &tile->polys[landPolyIdx];
|
||||
dtLink* link = &tile->links[tidx];
|
||||
link->ref = getPolyRefBase(target) | (dtPolyRef)(targetCon->poly);
|
||||
link->edge = (unsigned char)0xff;
|
||||
link->side = (unsigned char)(0xff);
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = landPoly->firstLink;
|
||||
landPoly->firstLink = tidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const unsigned short landPolyIdx = (unsigned short)decodePolyIdPoly(ref);
|
||||
dtPoly* landPoly = &TargetTile->polys[landPolyIdx];
|
||||
dtLink* link = &TargetTile->links[tidx];
|
||||
link->ref = getPolyRefBase(tile) | (dtPolyRef)(con->poly);
|
||||
link->edge = (unsigned char)0xff;
|
||||
link->side = (unsigned char)(0xff);
|
||||
link->bmin = link->bmax = 0;
|
||||
// Add to linked list.
|
||||
link->next = landPoly->firstLink;
|
||||
link->OffMeshID = con->userId;
|
||||
landPoly->firstLink = tidx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer) const
|
||||
const dtMeshTile* dtNavMesh::getTileAtConst(const int x, const int y, const int layer) const
|
||||
{
|
||||
// Find tile based on hash.
|
||||
int h = computeTileHash(x, y, m_tileLutMask);
|
||||
dtMeshTile* tile = m_posLookup[h];
|
||||
while (tile)
|
||||
{
|
||||
if (tile->header &&
|
||||
tile->header->x == x &&
|
||||
tile->header->y == y &&
|
||||
tile->header->layer == layer)
|
||||
{
|
||||
return tile;
|
||||
}
|
||||
tile = tile->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer)
|
||||
{
|
||||
// Find tile based on hash.
|
||||
int h = computeTileHash(x,y,m_tileLutMask);
|
||||
|
@ -1693,7 +1831,7 @@ const dtOffMeshConnection* dtNavMesh::getOffMeshConnectionByRef(dtPolyRef ref) c
|
|||
|
||||
const unsigned int idx = ip - tile->header->offMeshBase;
|
||||
dtAssert(idx < (unsigned int)tile->header->offMeshConCount);
|
||||
return &tile->offMeshCons[idx];
|
||||
return tile->offMeshCons[idx];
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -289,109 +289,69 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
return false;
|
||||
|
||||
const int nvp = params->nvp;
|
||||
|
||||
|
||||
// Classify off-mesh connection points. We store only the connections
|
||||
// whose start point is inside the tile.
|
||||
unsigned char* offMeshConClass = 0;
|
||||
int storedOffMeshConCount = 0;
|
||||
int receiveOffMeshConCount = 0;
|
||||
int offMeshConLinkCount = 0;
|
||||
|
||||
if (params->offMeshConCount > 0)
|
||||
|
||||
if (params->NumOffMeshConnections > 0)
|
||||
{
|
||||
offMeshConClass = (unsigned char*)dtAlloc(sizeof(unsigned char) * params->offMeshConCount * 2, DT_ALLOC_TEMP);
|
||||
offMeshConClass = (unsigned char*)dtAlloc(sizeof(unsigned char)*params->offMeshConCount*2, DT_ALLOC_TEMP);
|
||||
if (!offMeshConClass)
|
||||
return false;
|
||||
|
||||
// Find tight heigh bounds, used for culling out off-mesh start locations.
|
||||
float hmin = FLT_MAX;
|
||||
float hmax = -FLT_MAX;
|
||||
|
||||
if (params->detailVerts && params->detailVertsCount)
|
||||
for (int i = 0; i < params->NumOffMeshConnections; i++)
|
||||
{
|
||||
for (int i = 0; i < params->detailVertsCount; ++i)
|
||||
{
|
||||
const float h = params->detailVerts[i * 3 + 1];
|
||||
hmin = dtMin(hmin, h);
|
||||
hmax = dtMax(hmax, h);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < params->vertCount; ++i)
|
||||
{
|
||||
const unsigned short* iv = ¶ms->verts[i * 3];
|
||||
const float h = params->bmin[1] + iv[1] * params->ch;
|
||||
hmin = dtMin(hmin, h);
|
||||
hmax = dtMax(hmax, h);
|
||||
}
|
||||
}
|
||||
hmin -= params->walkableClimb;
|
||||
hmax += params->walkableClimb;
|
||||
float bmin[3], bmax[3];
|
||||
dtVcopy(bmin, params->bmin);
|
||||
dtVcopy(bmax, params->bmax);
|
||||
bmin[1] = hmin;
|
||||
bmax[1] = hmax;
|
||||
dtOffMeshConnection* con = ¶ms->GlobalOffMeshConnections[i];
|
||||
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
{
|
||||
const float* p0 = ¶ms->offMeshConVerts[(i * 2 + 0) * 3];
|
||||
const float* p1 = ¶ms->offMeshConVerts[(i * 2 + 1) * 3];
|
||||
offMeshConClass[i * 2 + 0] = classifyOffMeshPoint(p0, bmin, bmax);
|
||||
offMeshConClass[i * 2 + 1] = classifyOffMeshPoint(p1, bmin, bmax);
|
||||
if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; }
|
||||
|
||||
// Zero out off-mesh start positions which are not even potentially touching the mesh.
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
bool bOriginates = (con->FromTileX == params->tileX && con->FromTileY == params->tileY && con->FromTileLayer == params->tileLayer);
|
||||
bool bTargets = (con->ToTileX == params->tileX && con->ToTileY == params->tileY && con->ToTileLayer == params->tileLayer);
|
||||
|
||||
if (bOriginates)
|
||||
{
|
||||
if (p0[1] < bmin[1] || p0[1] > bmax[1])
|
||||
offMeshConClass[i * 2 + 0] = 0;
|
||||
}
|
||||
|
||||
// Cound how many links should be allocated for off-mesh connections.
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
con->state = DT_OFFMESH_DIRTY;
|
||||
offMeshConLinkCount++;
|
||||
if (offMeshConClass[i * 2 + 1] == 0xff)
|
||||
offMeshConLinkCount++;
|
||||
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
{
|
||||
storedOffMeshConCount++;
|
||||
}
|
||||
else if (offMeshConClass[i * 2 + 1] == 0xff)
|
||||
{
|
||||
receiveOffMeshConCount++;
|
||||
}
|
||||
|
||||
if (bTargets)
|
||||
{
|
||||
con->state = DT_OFFMESH_DIRTY;
|
||||
offMeshConLinkCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Off-mesh connectionss are stored as polygons, adjust values.
|
||||
const int totPolyCount = params->polyCount + storedOffMeshConCount;
|
||||
const int totVertCount = params->vertCount + storedOffMeshConCount * 2;
|
||||
|
||||
const int totVertCount = params->vertCount + storedOffMeshConCount*2;
|
||||
|
||||
// Find portal edges which are at tile borders.
|
||||
int edgeCount = 0;
|
||||
int portalCount = 0;
|
||||
for (int i = 0; i < params->polyCount; ++i)
|
||||
{
|
||||
const unsigned short* p = ¶ms->polys[i * 2 * nvp];
|
||||
const unsigned short* p = ¶ms->polys[i*2*nvp];
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == MESH_NULL_IDX) break;
|
||||
edgeCount++;
|
||||
|
||||
if (p[nvp + j] & 0x8000)
|
||||
|
||||
if (p[nvp+j] & 0x8000)
|
||||
{
|
||||
unsigned short dir = p[nvp + j] & 0xf;
|
||||
unsigned short dir = p[nvp+j] & 0xf;
|
||||
if (dir != 0xf)
|
||||
portalCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int maxLinkCount = edgeCount + portalCount * 2 + offMeshConLinkCount * 2;
|
||||
|
||||
const int maxLinkCount = edgeCount + portalCount*2 + offMeshConLinkCount*2;
|
||||
|
||||
// Find unique detail vertices.
|
||||
int uniqueDetailVertCount = 0;
|
||||
int detailTriCount = 0;
|
||||
|
@ -401,8 +361,8 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
detailTriCount = params->detailTriCount;
|
||||
for (int i = 0; i < params->polyCount; ++i)
|
||||
{
|
||||
const unsigned short* p = ¶ms->polys[i * nvp * 2];
|
||||
int ndv = params->detailMeshes[i * 4 + 1];
|
||||
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
||||
int ndv = params->detailMeshes[i*4+1];
|
||||
int nv = 0;
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
|
@ -420,41 +380,40 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
detailTriCount = 0;
|
||||
for (int i = 0; i < params->polyCount; ++i)
|
||||
{
|
||||
const unsigned short* p = ¶ms->polys[i * nvp * 2];
|
||||
const unsigned short* p = ¶ms->polys[i*nvp*2];
|
||||
int nv = 0;
|
||||
for (int j = 0; j < nvp; ++j)
|
||||
{
|
||||
if (p[j] == MESH_NULL_IDX) break;
|
||||
nv++;
|
||||
}
|
||||
detailTriCount += nv - 2;
|
||||
detailTriCount += nv-2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Calculate data size
|
||||
const int headerSize = dtAlign4(sizeof(dtMeshHeader));
|
||||
const int vertsSize = dtAlign4(sizeof(float) * 3 * totVertCount);
|
||||
const int polysSize = dtAlign4(sizeof(dtPoly) * totPolyCount);
|
||||
const int linksSize = dtAlign4(sizeof(dtLink) * maxLinkCount);
|
||||
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail) * params->polyCount);
|
||||
const int detailVertsSize = dtAlign4(sizeof(float) * 3 * uniqueDetailVertCount);
|
||||
const int detailTrisSize = dtAlign4(sizeof(unsigned char) * 4 * detailTriCount);
|
||||
const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode) * params->polyCount * 2) : 0;
|
||||
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection) * storedOffMeshConCount);
|
||||
const int receiveOffMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection) * receiveOffMeshConCount);
|
||||
|
||||
const int vertsSize = dtAlign4(sizeof(float)*3*totVertCount);
|
||||
const int polysSize = dtAlign4(sizeof(dtPoly)*totPolyCount);
|
||||
const int linksSize = dtAlign4(sizeof(dtLink)*maxLinkCount);
|
||||
const int detailMeshesSize = dtAlign4(sizeof(dtPolyDetail)*params->polyCount);
|
||||
const int detailVertsSize = dtAlign4(sizeof(float)*3*uniqueDetailVertCount);
|
||||
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*detailTriCount);
|
||||
const int bvTreeSize = params->buildBvTree ? dtAlign4(sizeof(dtBVNode)*params->polyCount*2) : 0;
|
||||
const int offMeshConsSize = dtAlign4(sizeof(dtOffMeshConnection*)*storedOffMeshConCount);
|
||||
|
||||
const int dataSize = headerSize + vertsSize + polysSize + linksSize +
|
||||
detailMeshesSize + detailVertsSize + detailTrisSize +
|
||||
bvTreeSize + offMeshConsSize + receiveOffMeshConsSize;
|
||||
|
||||
unsigned char* data = (unsigned char*)dtAlloc(sizeof(unsigned char) * dataSize, DT_ALLOC_PERM);
|
||||
detailMeshesSize + detailVertsSize + detailTrisSize +
|
||||
bvTreeSize + offMeshConsSize;
|
||||
|
||||
unsigned char* data = (unsigned char*)dtAlloc(sizeof(unsigned char)*dataSize, DT_ALLOC_PERM);
|
||||
if (!data)
|
||||
{
|
||||
dtFree(offMeshConClass);
|
||||
return false;
|
||||
}
|
||||
memset(data, 0, dataSize);
|
||||
|
||||
|
||||
unsigned char* d = data;
|
||||
|
||||
dtMeshHeader* header = dtGetThenAdvanceBufferPointer<dtMeshHeader>(d, headerSize);
|
||||
|
@ -465,10 +424,9 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
float* navDVerts = dtGetThenAdvanceBufferPointer<float>(d, detailVertsSize);
|
||||
unsigned char* navDTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
dtBVNode* navBvtree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvTreeSize);
|
||||
dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshConsSize);
|
||||
dtOffMeshConnection* receivingOffMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, receiveOffMeshConsSize);
|
||||
|
||||
|
||||
dtOffMeshConnection** offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection*>(d, offMeshConsSize);
|
||||
|
||||
|
||||
// Store header
|
||||
header->magic = DT_NAVMESH_MAGIC;
|
||||
header->version = DT_NAVMESH_VERSION;
|
||||
|
@ -489,38 +447,41 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
header->walkableHeight = params->walkableHeight;
|
||||
header->walkableRadius = params->walkableRadius;
|
||||
header->walkableClimb = params->walkableClimb;
|
||||
header->offMeshConCount = storedOffMeshConCount;
|
||||
header->receivingOffMeshConCount = receiveOffMeshConCount;
|
||||
header->bvNodeCount = params->buildBvTree ? params->polyCount * 2 : 0;
|
||||
|
||||
header->offMeshConCount = offMeshConLinkCount;
|
||||
header->bvNodeCount = params->buildBvTree ? params->polyCount*2 : 0;
|
||||
|
||||
const int offMeshVertsBase = params->vertCount;
|
||||
const int offMeshPolyBase = params->polyCount;
|
||||
|
||||
|
||||
// Store vertices
|
||||
// Mesh vertices
|
||||
for (int i = 0; i < params->vertCount; ++i)
|
||||
{
|
||||
const unsigned short* iv = ¶ms->verts[i * 3];
|
||||
float* v = &navVerts[i * 3];
|
||||
const unsigned short* iv = ¶ms->verts[i*3];
|
||||
float* v = &navVerts[i*3];
|
||||
v[0] = params->bmin[0] + iv[0] * params->cs;
|
||||
v[1] = params->bmin[1] + iv[1] * params->ch;
|
||||
v[2] = params->bmin[2] + iv[2] * params->cs;
|
||||
}
|
||||
// Off-mesh link vertices.
|
||||
int n = 0;
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
for (int i = 0; i < params->NumOffMeshConnections; i++)
|
||||
{
|
||||
dtOffMeshConnection* con = ¶ms->GlobalOffMeshConnections[i];
|
||||
|
||||
if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; }
|
||||
|
||||
// Only store connections which start from this tile.
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
if (con->FromTileX == params->tileX && con->FromTileY == params->tileY && con->FromTileLayer == params->tileLayer)
|
||||
{
|
||||
const float* linkv = ¶ms->offMeshConVerts[i * 2 * 3];
|
||||
float* v = &navVerts[(offMeshVertsBase + n * 2) * 3];
|
||||
const float* linkv = &con->pos[0];
|
||||
float* v = &navVerts[(offMeshVertsBase + n*2)*3];
|
||||
dtVcopy(&v[0], &linkv[0]);
|
||||
dtVcopy(&v[3], &linkv[3]);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Store polygons
|
||||
// Mesh polys
|
||||
const unsigned short* src = params->polys;
|
||||
|
@ -535,10 +496,10 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
{
|
||||
if (src[j] == MESH_NULL_IDX) break;
|
||||
p->verts[j] = src[j];
|
||||
if (src[nvp + j] & 0x8000)
|
||||
if (src[nvp+j] & 0x8000)
|
||||
{
|
||||
// Border or portal edge.
|
||||
unsigned short dir = src[nvp + j] & 0xf;
|
||||
unsigned short dir = src[nvp+j] & 0xf;
|
||||
if (dir == 0xf) // Border
|
||||
p->neis[j] = 0;
|
||||
else if (dir == 0) // Portal x-
|
||||
|
@ -553,26 +514,30 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
else
|
||||
{
|
||||
// Normal connection
|
||||
p->neis[j] = src[nvp + j] + 1;
|
||||
p->neis[j] = src[nvp+j]+1;
|
||||
}
|
||||
|
||||
p->vertCount++;
|
||||
}
|
||||
src += nvp * 2;
|
||||
src += nvp*2;
|
||||
}
|
||||
// Off-mesh connection vertices.
|
||||
n = 0;
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
for (int i = 0; i < params->NumOffMeshConnections; i++)
|
||||
{
|
||||
dtOffMeshConnection* con = ¶ms->GlobalOffMeshConnections[i];
|
||||
|
||||
if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; }
|
||||
|
||||
// Only store connections which start from this tile.
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
if (con->FromTileX == params->tileX && con->FromTileY == params->tileY && con->FromTileLayer == params->tileLayer)
|
||||
{
|
||||
dtPoly* p = &navPolys[offMeshPolyBase + n];
|
||||
dtPoly* p = &navPolys[offMeshPolyBase+n];
|
||||
p->vertCount = 2;
|
||||
p->verts[0] = (unsigned short)(offMeshVertsBase + n * 2 + 0);
|
||||
p->verts[1] = (unsigned short)(offMeshVertsBase + n * 2 + 1);
|
||||
p->flags = params->offMeshConFlags[i];
|
||||
p->setArea(params->offMeshConAreas[i]);
|
||||
p->verts[0] = (unsigned short)(offMeshVertsBase + n*2+0);
|
||||
p->verts[1] = (unsigned short)(offMeshVertsBase + n*2+1);
|
||||
p->flags = con->flags;
|
||||
p->setArea(con->area);
|
||||
p->setType(DT_POLYTYPE_OFFMESH_CONNECTION);
|
||||
n++;
|
||||
}
|
||||
|
@ -587,22 +552,22 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
for (int i = 0; i < params->polyCount; ++i)
|
||||
{
|
||||
dtPolyDetail& dtl = navDMeshes[i];
|
||||
const int vb = (int)params->detailMeshes[i * 4 + 0];
|
||||
const int ndv = (int)params->detailMeshes[i * 4 + 1];
|
||||
const int vb = (int)params->detailMeshes[i*4+0];
|
||||
const int ndv = (int)params->detailMeshes[i*4+1];
|
||||
const int nv = navPolys[i].vertCount;
|
||||
dtl.vertBase = (unsigned int)vbase;
|
||||
dtl.vertCount = (unsigned char)(ndv - nv);
|
||||
dtl.triBase = (unsigned int)params->detailMeshes[i * 4 + 2];
|
||||
dtl.triCount = (unsigned char)params->detailMeshes[i * 4 + 3];
|
||||
dtl.vertCount = (unsigned char)(ndv-nv);
|
||||
dtl.triBase = (unsigned int)params->detailMeshes[i*4+2];
|
||||
dtl.triCount = (unsigned char)params->detailMeshes[i*4+3];
|
||||
// Copy vertices except the first 'nv' verts which are equal to nav poly verts.
|
||||
if (ndv - nv)
|
||||
if (ndv-nv)
|
||||
{
|
||||
memcpy(&navDVerts[vbase * 3], ¶ms->detailVerts[(vb + nv) * 3], sizeof(float) * 3 * (ndv - nv));
|
||||
vbase += (unsigned short)(ndv - nv);
|
||||
memcpy(&navDVerts[vbase*3], ¶ms->detailVerts[(vb+nv)*3], sizeof(float)*3*(ndv-nv));
|
||||
vbase += (unsigned short)(ndv-nv);
|
||||
}
|
||||
}
|
||||
// Store triangles.
|
||||
memcpy(navDTris, params->detailTris, sizeof(unsigned char) * 4 * params->detailTriCount);
|
||||
memcpy(navDTris, params->detailTris, sizeof(unsigned char)*4*params->detailTriCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -615,18 +580,18 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
dtl.vertBase = 0;
|
||||
dtl.vertCount = 0;
|
||||
dtl.triBase = (unsigned int)tbase;
|
||||
dtl.triCount = (unsigned char)(nv - 2);
|
||||
dtl.triCount = (unsigned char)(nv-2);
|
||||
// Triangulate polygon (local indices).
|
||||
for (int j = 2; j < nv; ++j)
|
||||
{
|
||||
unsigned char* t = &navDTris[tbase * 4];
|
||||
unsigned char* t = &navDTris[tbase*4];
|
||||
t[0] = 0;
|
||||
t[1] = (unsigned char)(j - 1);
|
||||
t[1] = (unsigned char)(j-1);
|
||||
t[2] = (unsigned char)j;
|
||||
// Bit for each edge that belongs to poly boundary.
|
||||
t[3] = (1 << 2);
|
||||
if (j == 2) t[3] |= (1 << 0);
|
||||
if (j == nv - 1) t[3] |= (1 << 4);
|
||||
t[3] = (1<<2);
|
||||
if (j == 2) t[3] |= (1<<0);
|
||||
if (j == nv-1) t[3] |= (1<<4);
|
||||
tbase++;
|
||||
}
|
||||
}
|
||||
|
@ -635,63 +600,34 @@ bool dtCreateNavMeshData(dtNavMeshCreateParams* params, unsigned char** outData,
|
|||
// Store and create BVtree.
|
||||
if (params->buildBvTree)
|
||||
{
|
||||
createBVTree(params, navBvtree, 2 * params->polyCount);
|
||||
createBVTree(params, navBvtree, 2*params->polyCount);
|
||||
}
|
||||
|
||||
// Store Off-Mesh connections.
|
||||
n = 0;
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
for (int i = 0; i < params->NumOffMeshConnections; i++)
|
||||
{
|
||||
dtOffMeshConnection* con = ¶ms->GlobalOffMeshConnections[i];
|
||||
|
||||
if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; }
|
||||
|
||||
// Only store connections which start from this tile.
|
||||
if (offMeshConClass[i * 2 + 0] == 0xff)
|
||||
if (con->FromTileX == params->tileX && con->FromTileY == params->tileY && con->FromTileLayer == params->tileLayer)
|
||||
{
|
||||
dtOffMeshConnection* con = &offMeshCons[n];
|
||||
con->poly = (unsigned short)(offMeshPolyBase + n);
|
||||
// Copy connection end-points.
|
||||
const float* endPts = ¶ms->offMeshConVerts[i * 2 * 3];
|
||||
dtVcopy(&con->pos[0], &endPts[0]);
|
||||
dtVcopy(&con->pos[3], &endPts[3]);
|
||||
con->rad = params->offMeshConRad[i];
|
||||
con->flags = params->offMeshConDir[i] ? DT_OFFMESH_CON_BIDIR : 0;
|
||||
con->side = offMeshConClass[i * 2 + 1];
|
||||
if (params->offMeshConUserID)
|
||||
con->userId = params->offMeshConUserID[i];
|
||||
|
||||
offMeshCons[n] = con;
|
||||
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
n = 0;
|
||||
for (int i = 0; i < params->offMeshConCount; ++i)
|
||||
{
|
||||
// Only store connections which start from this tile.
|
||||
if (offMeshConClass[i * 2 + 0] != 0xff && offMeshConClass[i * 2 + 1] == 0xff)
|
||||
{
|
||||
dtOffMeshConnection* con = &receivingOffMeshCons[n];
|
||||
con->poly = (unsigned short)(offMeshPolyBase + n);
|
||||
// Copy connection end-points.
|
||||
const float* endPts = ¶ms->offMeshConVerts[i * 2 * 3];
|
||||
dtVcopy(&con->pos[0], &endPts[0]);
|
||||
dtVcopy(&con->pos[3], &endPts[3]);
|
||||
con->rad = params->offMeshConRad[i];
|
||||
con->flags = params->offMeshConDir[i] ? DT_OFFMESH_CON_BIDIR : 0;
|
||||
con->side = offMeshConClass[i * 2 + 0];
|
||||
if (params->offMeshConUserID)
|
||||
con->userId = params->offMeshConUserID[i];
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
if (header->offMeshConCount > 0)
|
||||
{
|
||||
int thing = 0;
|
||||
dtIgnoreUnused(thing);
|
||||
}
|
||||
|
||||
header->offMeshConCount = n;
|
||||
|
||||
dtFree(offMeshConClass);
|
||||
|
||||
|
||||
*outData = data;
|
||||
*outDataSize = dataSize;
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -724,7 +660,6 @@ bool dtNavMeshHeaderSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||
dtSwapEndian(&header->detailTriCount);
|
||||
dtSwapEndian(&header->bvNodeCount);
|
||||
dtSwapEndian(&header->offMeshConCount);
|
||||
dtSwapEndian(&header->receivingOffMeshConCount);
|
||||
dtSwapEndian(&header->offMeshBase);
|
||||
dtSwapEndian(&header->walkableHeight);
|
||||
dtSwapEndian(&header->walkableRadius);
|
||||
|
@ -767,7 +702,6 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||
const int detailTrisSize = dtAlign4(sizeof(unsigned char)*4*header->detailTriCount);
|
||||
const int bvtreeSize = dtAlign4(sizeof(dtBVNode)*header->bvNodeCount);
|
||||
const int offMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection)*header->offMeshConCount);
|
||||
const int receiveOffMeshLinksSize = dtAlign4(sizeof(dtOffMeshConnection) * header->receivingOffMeshConCount);
|
||||
|
||||
unsigned char* d = data + headerSize;
|
||||
float* verts = dtGetThenAdvanceBufferPointer<float>(d, vertsSize);
|
||||
|
@ -780,7 +714,6 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||
//unsigned char* detailTris = dtGetThenAdvanceBufferPointer<unsigned char>(d, detailTrisSize);
|
||||
dtBVNode* bvTree = dtGetThenAdvanceBufferPointer<dtBVNode>(d, bvtreeSize);
|
||||
dtOffMeshConnection* offMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, offMeshLinksSize);
|
||||
dtOffMeshConnection* receivingOffMeshCons = dtGetThenAdvanceBufferPointer<dtOffMeshConnection>(d, receiveOffMeshLinksSize);
|
||||
|
||||
// Vertices
|
||||
for (int i = 0; i < header->vertCount*3; ++i)
|
||||
|
@ -838,16 +771,6 @@ bool dtNavMeshDataSwapEndian(unsigned char* data, const int /*dataSize*/)
|
|||
dtSwapEndian(&con->rad);
|
||||
dtSwapEndian(&con->poly);
|
||||
}
|
||||
|
||||
// Receiving Off-mesh Connections.
|
||||
for (int i = 0; i < header->receivingOffMeshConCount; ++i)
|
||||
{
|
||||
dtOffMeshConnection* con = &receivingOffMeshCons[i];
|
||||
for (int j = 0; j < 6; ++j)
|
||||
dtSwapEndian(&con->pos[j]);
|
||||
dtSwapEndian(&con->rad);
|
||||
dtSwapEndian(&con->poly);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -347,7 +347,7 @@ dtStatus dtNavMeshQuery::findRandomPointAroundCircleIgnoreReachability(dtPolyRef
|
|||
int thisTileXIndex = StartTileX + tileX;
|
||||
int thisTileYIndex = StartTileY + tileY;
|
||||
|
||||
const dtMeshTile* t = m_nav->getTileAt(thisTileXIndex, thisTileYIndex, layer);
|
||||
const dtMeshTile* t = m_nav->getTileAtConst(thisTileXIndex, thisTileYIndex, layer);
|
||||
|
||||
if (!t || !t->header) continue;
|
||||
|
||||
|
|
|
@ -74,10 +74,12 @@ dtTileCache::dtTileCache() :
|
|||
m_obstacles(0),
|
||||
m_nextFreeObstacle(0),
|
||||
m_nreqs(0),
|
||||
m_nOffMeshReqs(0),
|
||||
m_nupdate(0)
|
||||
{
|
||||
memset(&m_params, 0, sizeof(m_params));
|
||||
memset(m_reqs, 0, sizeof(ObstacleRequest) * MAX_REQUESTS);
|
||||
memset(m_OffMeshReqs, 0, sizeof(OffMeshRequest) * MAX_REQUESTS);
|
||||
}
|
||||
|
||||
dtTileCache::~dtTileCache()
|
||||
|
@ -92,11 +94,14 @@ dtTileCache::~dtTileCache()
|
|||
}
|
||||
dtFree(m_obstacles);
|
||||
m_obstacles = 0;
|
||||
dtFree(m_offMeshConnections);
|
||||
m_offMeshConnections = 0;
|
||||
dtFree(m_posLookup);
|
||||
m_posLookup = 0;
|
||||
dtFree(m_tiles);
|
||||
m_tiles = 0;
|
||||
m_nreqs = 0;
|
||||
m_nOffMeshReqs = 0;
|
||||
m_nupdate = 0;
|
||||
}
|
||||
|
||||
|
@ -138,6 +143,19 @@ dtStatus dtTileCache::init(const dtTileCacheParams* params,
|
|||
m_obstacles[i].next = m_nextFreeObstacle;
|
||||
m_nextFreeObstacle = &m_obstacles[i];
|
||||
}
|
||||
|
||||
// Alloc space for off-mesh connections.
|
||||
m_offMeshConnections = (dtOffMeshConnection*)dtAlloc(sizeof(dtOffMeshConnection) * m_params.maxOffMeshConnections, DT_ALLOC_PERM);
|
||||
if (!m_offMeshConnections)
|
||||
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||
memset(m_offMeshConnections, 0, sizeof(dtOffMeshConnection) * m_params.maxOffMeshConnections);
|
||||
m_nextFreeOffMeshConnection = 0;
|
||||
for (int i = m_params.maxOffMeshConnections - 1; i >= 0; --i)
|
||||
{
|
||||
m_offMeshConnections[i].salt = 1;
|
||||
m_offMeshConnections[i].next = m_nextFreeOffMeshConnection;
|
||||
m_nextFreeOffMeshConnection = &m_offMeshConnections[i];
|
||||
}
|
||||
|
||||
// Init tiles
|
||||
m_tileLutSize = dtNextPow2(m_params.maxTiles/4);
|
||||
|
@ -225,6 +243,13 @@ dtObstacleRef dtTileCache::getObstacleRef(const dtTileCacheObstacle* ob) const
|
|||
return encodeObstacleId(ob->salt, idx);
|
||||
}
|
||||
|
||||
dtOffMeshConnectionRef dtTileCache::getOffMeshRef(const dtOffMeshConnection* con) const
|
||||
{
|
||||
if (!con) return 0;
|
||||
const unsigned int idx = (unsigned int)(con - m_offMeshConnections);
|
||||
return encodeObstacleId(con->salt, idx);
|
||||
}
|
||||
|
||||
const dtTileCacheObstacle* dtTileCache::getObstacleByRef(dtObstacleRef ref)
|
||||
{
|
||||
if (!ref)
|
||||
|
@ -239,6 +264,20 @@ const dtTileCacheObstacle* dtTileCache::getObstacleByRef(dtObstacleRef ref)
|
|||
return ob;
|
||||
}
|
||||
|
||||
dtOffMeshConnection* dtTileCache::getOffMeshConnectionByRef(dtOffMeshConnectionRef ref)
|
||||
{
|
||||
if (!ref)
|
||||
return 0;
|
||||
unsigned int idx = decodeOffMeshIdCon(ref);
|
||||
if ((int)idx >= m_params.maxOffMeshConnections)
|
||||
return 0;
|
||||
dtOffMeshConnection* con = &m_offMeshConnections[idx];
|
||||
unsigned int salt = decodeOffMeshIdSalt(ref);
|
||||
if (con->salt != salt)
|
||||
return 0;
|
||||
return con;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::addTile(unsigned char* data, const int dataSize, unsigned char flags, dtCompressedTileRef* result)
|
||||
{
|
||||
// Make sure the data is in right format.
|
||||
|
@ -350,6 +389,42 @@ dtStatus dtTileCache::removeTile(dtCompressedTileRef ref, unsigned char** data,
|
|||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::addOffMeshConnection(const float* spos, const float* epos, const float radius, const unsigned char area, const unsigned short flags, const bool bBiDirectional, dtOffMeshConnectionRef* result)
|
||||
{
|
||||
if (m_nOffMeshReqs >= MAX_REQUESTS)
|
||||
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||
|
||||
dtOffMeshConnection* con = 0;
|
||||
if (m_nextFreeOffMeshConnection)
|
||||
{
|
||||
con = m_nextFreeOffMeshConnection;
|
||||
m_nextFreeOffMeshConnection = con->next;
|
||||
con->next = 0;
|
||||
}
|
||||
if (!con)
|
||||
return DT_FAILURE | DT_OUT_OF_MEMORY;
|
||||
|
||||
unsigned short salt = con->salt;
|
||||
memset(con, 0, sizeof(dtOffMeshConnection));
|
||||
con->salt = salt;
|
||||
con->state = DT_OFFMESH_NEW;
|
||||
dtVcopy(&con->pos[0], spos);
|
||||
dtVcopy(&con->pos[3], epos);
|
||||
con->rad = radius;
|
||||
con->area = area;
|
||||
con->flags = flags;
|
||||
con->bBiDir = bBiDirectional;
|
||||
|
||||
OffMeshRequest* req = &m_OffMeshReqs[m_nOffMeshReqs++];
|
||||
memset(req, 0, sizeof(OffMeshRequest));
|
||||
req->action = REQUEST_OFFMESH_ADD;
|
||||
req->ref = getOffMeshRef(con);
|
||||
|
||||
if (result)
|
||||
*result = req->ref;
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::addObstacle(const float* pos, const float radius, const float height, const int area, dtObstacleRef* result)
|
||||
{
|
||||
|
@ -387,7 +462,7 @@ dtStatus dtTileCache::addObstacle(const float* pos, const float radius, const fl
|
|||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, const int area, dtObstacleRef* result)
|
||||
dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result)
|
||||
{
|
||||
if (m_nreqs >= MAX_REQUESTS)
|
||||
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||
|
@ -409,7 +484,6 @@ dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, const
|
|||
ob->type = DT_OBSTACLE_BOX;
|
||||
dtVcopy(ob->box.bmin, bmin);
|
||||
dtVcopy(ob->box.bmax, bmax);
|
||||
ob->box.area = area;
|
||||
|
||||
ObstacleRequest* req = &m_reqs[m_nreqs++];
|
||||
memset(req, 0, sizeof(ObstacleRequest));
|
||||
|
@ -422,7 +496,7 @@ dtStatus dtTileCache::addBoxObstacle(const float* bmin, const float* bmax, const
|
|||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, const int area, dtObstacleRef* result)
|
||||
dtStatus dtTileCache::addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, dtObstacleRef* result)
|
||||
{
|
||||
if (m_nreqs >= MAX_REQUESTS)
|
||||
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||
|
@ -449,7 +523,6 @@ dtStatus dtTileCache::addBoxObstacle(const float* center, const float* halfExten
|
|||
float sinhalf = sinf(-0.5f*yRadians);
|
||||
ob->orientedBox.rotAux[0] = coshalf*sinhalf;
|
||||
ob->orientedBox.rotAux[1] = coshalf*coshalf - 0.5f;
|
||||
ob->orientedBox.area = area;
|
||||
|
||||
ObstacleRequest* req = &m_reqs[m_nreqs++];
|
||||
memset(req, 0, sizeof(ObstacleRequest));
|
||||
|
@ -477,6 +550,22 @@ dtStatus dtTileCache::removeObstacle(const dtObstacleRef ref)
|
|||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::removeOffMeshConnection(const dtOffMeshConnectionRef ref)
|
||||
{
|
||||
if (!ref)
|
||||
return DT_SUCCESS;
|
||||
|
||||
if (m_nOffMeshReqs >= MAX_REQUESTS)
|
||||
return DT_FAILURE | DT_BUFFER_TOO_SMALL;
|
||||
|
||||
OffMeshRequest* req = &m_OffMeshReqs[m_nOffMeshReqs++];
|
||||
memset(req, 0, sizeof(OffMeshRequest));
|
||||
req->action = REQUEST_OFFMESH_REMOVE;
|
||||
req->ref = ref;
|
||||
|
||||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::queryTiles(const float* bmin, const float* bmax,
|
||||
dtCompressedTileRef* results, int* resultCount, const int maxResults) const
|
||||
{
|
||||
|
@ -519,7 +608,7 @@ dtStatus dtTileCache::queryTiles(const float* bmin, const float* bmax,
|
|||
}
|
||||
|
||||
dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
||||
bool* upToDate)
|
||||
bool* upToDate)
|
||||
{
|
||||
if (m_nupdate == 0)
|
||||
{
|
||||
|
@ -527,7 +616,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
for (int i = 0; i < m_nreqs; ++i)
|
||||
{
|
||||
ObstacleRequest* req = &m_reqs[i];
|
||||
|
||||
|
||||
unsigned int idx = decodeObstacleIdObstacle(req->ref);
|
||||
if ((int)idx >= m_params.maxObstacles)
|
||||
continue;
|
||||
|
@ -535,7 +624,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
unsigned int salt = decodeObstacleIdSalt(req->ref);
|
||||
if (ob->salt != salt)
|
||||
continue;
|
||||
|
||||
|
||||
if (req->action == REQUEST_ADD)
|
||||
{
|
||||
// Find touched tiles.
|
||||
|
@ -574,20 +663,104 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
m_nreqs = 0;
|
||||
|
||||
for (int i = 0; i < m_nOffMeshReqs; ++i)
|
||||
{
|
||||
OffMeshRequest* req = &m_OffMeshReqs[i];
|
||||
|
||||
unsigned int idx = decodeOffMeshIdCon(req->ref);
|
||||
if ((int)idx >= m_params.maxOffMeshConnections)
|
||||
continue;
|
||||
dtOffMeshConnection* con = &m_offMeshConnections[idx];
|
||||
unsigned int salt = decodeOffMeshIdSalt(req->ref);
|
||||
if (con->salt != salt)
|
||||
continue;
|
||||
|
||||
if (req->action == REQUEST_OFFMESH_ADD)
|
||||
{
|
||||
con->state = DT_OFFMESH_DIRTY;
|
||||
|
||||
// Find touched tiles.
|
||||
float bmin[3], bmax[3];
|
||||
float ext[3] = { con->rad, 18.0f, con->rad };
|
||||
|
||||
dtVsub(bmin, &con->pos[0], ext);
|
||||
dtVadd(bmax, &con->pos[0], ext);
|
||||
|
||||
int ntouched = 0;
|
||||
dtCompressedTileRef touched[DT_MAX_TOUCHED_TILES];
|
||||
dtCompressedTileRef StartTileRef = 0;
|
||||
dtCompressedTileRef EndTileRef = 0;
|
||||
|
||||
queryTiles(bmin, bmax, touched, &ntouched, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
if (ntouched > 0)
|
||||
{
|
||||
StartTileRef = touched[0];
|
||||
}
|
||||
|
||||
dtVsub(bmin, &con->pos[3], ext);
|
||||
dtVadd(bmax, &con->pos[3], ext);
|
||||
|
||||
queryTiles(bmin, bmax, touched, &ntouched, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
if (ntouched > 0)
|
||||
{
|
||||
EndTileRef = touched[0];
|
||||
}
|
||||
|
||||
if (!StartTileRef || !EndTileRef) { continue; }
|
||||
|
||||
const dtCompressedTile* StartTile = getTileByRef(StartTileRef);
|
||||
const dtCompressedTile* EndTile = getTileByRef(EndTileRef);
|
||||
|
||||
con->FromTileX = StartTile->header->tx;
|
||||
con->FromTileY = StartTile->header->ty;
|
||||
con->FromTileLayer = StartTile->header->tlayer;
|
||||
|
||||
con->ToTileX = EndTile->header->tx;
|
||||
con->ToTileY = EndTile->header->ty;
|
||||
con->ToTileLayer = EndTile->header->tlayer;
|
||||
|
||||
if (m_nupdate < MAX_UPDATE)
|
||||
{
|
||||
if (!contains(m_update, m_nupdate, StartTileRef))
|
||||
m_update[m_nupdate++] = StartTileRef;
|
||||
}
|
||||
}
|
||||
else if (req->action == REQUEST_OFFMESH_REMOVE)
|
||||
{
|
||||
// Prepare to remove obstacle.
|
||||
con->state = DT_OFFMESH_REMOVING;
|
||||
// Add tiles to update list.
|
||||
|
||||
navmesh->unconnectOffMeshLink(con);
|
||||
|
||||
if (m_nupdate < MAX_UPDATE)
|
||||
{
|
||||
dtCompressedTile* Tile = getTileAt(con->FromTileX, con->FromTileY, con->FromTileLayer);
|
||||
dtCompressedTileRef TileRef = getTileRef(Tile);
|
||||
|
||||
if (!contains(m_update, m_nupdate, TileRef))
|
||||
m_update[m_nupdate++] = TileRef;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_nOffMeshReqs = 0;
|
||||
}
|
||||
|
||||
|
||||
dtStatus status = DT_SUCCESS;
|
||||
// Process updates
|
||||
if (m_nupdate)
|
||||
{
|
||||
// Build mesh
|
||||
const dtCompressedTileRef ref = m_update[0];
|
||||
status = buildNavMeshTile(ref, navmesh, true);
|
||||
status = buildNavMeshTile(ref, navmesh);
|
||||
m_nupdate--;
|
||||
if (m_nupdate > 0)
|
||||
memmove(m_update, m_update+1, m_nupdate*sizeof(dtCompressedTileRef));
|
||||
memmove(m_update, m_update + 1, m_nupdate * sizeof(dtCompressedTileRef));
|
||||
|
||||
// Update obstacle states.
|
||||
for (int i = 0; i < m_params.maxObstacles; ++i)
|
||||
|
@ -600,12 +773,12 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
{
|
||||
if (ob->pending[j] == ref)
|
||||
{
|
||||
ob->pending[j] = ob->pending[(int)ob->npending-1];
|
||||
ob->pending[j] = ob->pending[(int)ob->npending - 1];
|
||||
ob->npending--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// If all pending tiles processed, change state.
|
||||
if (ob->npending == 0)
|
||||
{
|
||||
|
@ -617,7 +790,7 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
{
|
||||
ob->state = DT_OBSTACLE_EMPTY;
|
||||
// Update salt, salt should never be zero.
|
||||
ob->salt = (ob->salt+1) & ((1<<16)-1);
|
||||
ob->salt = (ob->salt + 1) & ((1 << 16) - 1);
|
||||
if (ob->salt == 0)
|
||||
ob->salt++;
|
||||
// Return obstacle to free list.
|
||||
|
@ -627,74 +800,49 @@ dtStatus dtTileCache::update(const float /*dt*/, dtNavMesh* navmesh,
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (navmesh->GetNumPendingOffMeshConnections() > 0)
|
||||
if (m_nupdate == 0)
|
||||
{
|
||||
|
||||
for (int i = 0; i < navmesh->GetNumPendingOffMeshConnections(); i++)
|
||||
for (int i = 0; i < m_params.maxOffMeshConnections; ++i)
|
||||
{
|
||||
int NumTiles = 0;
|
||||
dtOffMeshConnection* con = &m_offMeshConnections[i];
|
||||
|
||||
float* connspos = &navmesh->GetPendingConnection(i)->pos[0];
|
||||
float* connepos = &navmesh->GetPendingConnection(i)->pos[3];
|
||||
|
||||
float ext[3] = { 10.0f, 10.0f, 10.0f };
|
||||
|
||||
float searchsposMin[3];
|
||||
float searchsposMax[3];
|
||||
|
||||
float searcheposMin[3];
|
||||
float searcheposMax[3];
|
||||
|
||||
dtVsub(searchsposMin, connspos, ext);
|
||||
dtVadd(searchsposMax, connspos, ext);
|
||||
|
||||
dtVsub(searcheposMin, connepos, ext);
|
||||
dtVadd(searcheposMax, connepos, ext);
|
||||
|
||||
dtCompressedTileRef AffectedTiles[DT_MAX_TOUCHED_TILES];
|
||||
|
||||
|
||||
queryTiles(searcheposMin, searcheposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
if (con->state == DT_OFFMESH_DIRTY)
|
||||
{
|
||||
const dtCompressedTile* Tile = getTileByRef(AffectedTiles[i]);
|
||||
|
||||
buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, navmesh, false);
|
||||
navmesh->unconnectOffMeshLink(con);
|
||||
navmesh->GlobalOffMeshLinks(con);
|
||||
con->state = DT_OFFMESH_CLEAN;
|
||||
}
|
||||
|
||||
queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
if (con->state == DT_OFFMESH_REMOVING)
|
||||
{
|
||||
const dtCompressedTile* Tile = getTileByRef(AffectedTiles[i]);
|
||||
|
||||
buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, navmesh, false);
|
||||
con->state = DT_OFFMESH_EMPTY;
|
||||
con->salt = (con->salt + 1) & ((1 << 16) - 1);
|
||||
if (con->salt == 0)
|
||||
con->salt++;
|
||||
con->next = m_nextFreeOffMeshConnection;
|
||||
m_nextFreeOffMeshConnection = con;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
navmesh->ClearPendingOffMeshConnections();
|
||||
}
|
||||
|
||||
if (upToDate)
|
||||
*upToDate = m_nupdate == 0 && m_nreqs == 0;
|
||||
*upToDate = m_nupdate == 0 && m_nreqs == 0 && m_nOffMeshReqs == 0;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* navmesh, bool bMarkOffMeshDirty)
|
||||
dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh* navmesh)
|
||||
{
|
||||
const int MAX_TILES = 32;
|
||||
dtCompressedTileRef tiles[MAX_TILES];
|
||||
const int ntiles = getTilesAt(tx,ty,tiles,MAX_TILES);
|
||||
|
||||
|
||||
for (int i = 0; i < ntiles; ++i)
|
||||
{
|
||||
dtStatus status = buildNavMeshTile(tiles[i], navmesh, bMarkOffMeshDirty);
|
||||
dtStatus status = buildNavMeshTile(tiles[i], navmesh);
|
||||
if (dtStatusFailed(status))
|
||||
return status;
|
||||
}
|
||||
|
@ -702,7 +850,7 @@ dtStatus dtTileCache::buildNavMeshTilesAt(const int tx, const int ty, dtNavMesh*
|
|||
return DT_SUCCESS;
|
||||
}
|
||||
|
||||
dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh, bool bMarkOffMeshDirty)
|
||||
dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh* navmesh)
|
||||
{
|
||||
dtAssert(m_talloc);
|
||||
dtAssert(m_tcomp);
|
||||
|
@ -720,7 +868,7 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
|
|||
NavMeshTileBuildContext bc(m_talloc);
|
||||
const int walkableClimbVx = (int)(m_params.walkableClimb / m_params.ch);
|
||||
dtStatus status;
|
||||
|
||||
|
||||
// Decompress tile layer data.
|
||||
status = dtDecompressTileCacheLayer(m_talloc, m_tcomp, tile->data, tile->dataSize, &bc.layer);
|
||||
if (dtStatusFailed(status))
|
||||
|
@ -805,6 +953,9 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
|
|||
{
|
||||
m_tmproc->process(¶ms, bc.lmesh->areas, bc.lmesh->flags);
|
||||
}
|
||||
|
||||
params.GlobalOffMeshConnections = m_offMeshConnections;
|
||||
params.NumOffMeshConnections = getOffMeshCount();
|
||||
|
||||
unsigned char* navData = 0;
|
||||
int navDataSize = 0;
|
||||
|
@ -817,8 +968,9 @@ dtStatus dtTileCache::buildNavMeshTile(const dtCompressedTileRef ref, dtNavMesh*
|
|||
// Add new tile, or leave the location empty.
|
||||
if (navData)
|
||||
{
|
||||
// Let the navmesh own the data.
|
||||
status = navmesh->addTile(navData,navDataSize,DT_TILE_FREE_DATA,0,0, bMarkOffMeshDirty);
|
||||
status = navmesh->addTile(navData,navDataSize,DT_TILE_FREE_DATA,0,0);
|
||||
|
||||
|
||||
if (dtStatusFailed(status))
|
||||
{
|
||||
dtFree(navData);
|
||||
|
|
|
@ -149,6 +149,14 @@ enum dtPolyTypes
|
|||
DT_POLYTYPE_OFFMESH_CONNECTION = 1,
|
||||
};
|
||||
|
||||
enum OffMeshState
|
||||
{
|
||||
DT_OFFMESH_EMPTY,
|
||||
DT_OFFMESH_NEW,
|
||||
DT_OFFMESH_DIRTY,
|
||||
DT_OFFMESH_CLEAN,
|
||||
DT_OFFMESH_REMOVING,
|
||||
};
|
||||
|
||||
/// Defines a polygon within a dtMeshTile object.
|
||||
/// @ingroup detour
|
||||
|
@ -183,6 +191,8 @@ struct dtPoly
|
|||
/// Gets the user defined area id.
|
||||
inline unsigned char getArea() const { return areaAndtype & 0x3f; }
|
||||
|
||||
inline unsigned short getFlags() const { return flags; }
|
||||
|
||||
/// Gets the polygon type. (See: #dtPolyTypes)
|
||||
inline unsigned char getType() const { return areaAndtype >> 6; }
|
||||
};
|
||||
|
@ -207,6 +217,7 @@ struct dtLink
|
|||
unsigned char side; ///< If a boundary link, defines on which side the link is.
|
||||
unsigned char bmin; ///< If a boundary link, defines the minimum sub-edge area.
|
||||
unsigned char bmax; ///< If a boundary link, defines the maximum sub-edge area.
|
||||
int OffMeshID = -1; ///< If an off-mesh connection, this will be the UserID of the connection that made this link
|
||||
};
|
||||
|
||||
/// Bounding volume node.
|
||||
|
@ -224,24 +235,45 @@ struct dtBVNode
|
|||
struct dtOffMeshConnection
|
||||
{
|
||||
/// The endpoints of the connection. [(ax, ay, az, bx, by, bz)]
|
||||
float pos[6];
|
||||
float pos[6] = { 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
|
||||
/// The radius of the endpoints. [Limit: >= 0]
|
||||
float rad;
|
||||
float rad = 0.0f;
|
||||
|
||||
/// The polygon reference of the connection within the tile.
|
||||
unsigned short poly;
|
||||
unsigned short poly = 0;
|
||||
|
||||
/// Link flags.
|
||||
/// @note These are not the connection's user defined flags. Those are assigned via the
|
||||
/// connection's dtPoly definition. These are link flags used for internal purposes.
|
||||
unsigned char flags;
|
||||
unsigned short flags = 0;
|
||||
unsigned char area = 0;
|
||||
|
||||
/// End point side.
|
||||
unsigned char side;
|
||||
unsigned char side = 0;
|
||||
|
||||
bool bBiDir = false;
|
||||
|
||||
/// The id of the offmesh connection. (User assigned when the navigation mesh is built.)
|
||||
unsigned int userId;
|
||||
unsigned int userId = 0;
|
||||
|
||||
int FromTileX = -1;
|
||||
int FromTileY = -1;
|
||||
int FromTileLayer = -1;
|
||||
|
||||
int ToTileX = -1;
|
||||
int ToTileY = -1;
|
||||
int ToTileLayer = -1;
|
||||
|
||||
bool bPendingDelete = false; // This off-mesh needs to be removed completely
|
||||
bool bDirty = false; // This off-mesh connection has had its from or to tile rebuilt recently so the links need to be re-established
|
||||
bool bBased = false; // This off-mesh connection has had its links based in the source tile
|
||||
|
||||
dtOffMeshConnection* next = nullptr;
|
||||
OffMeshState state = DT_OFFMESH_EMPTY;
|
||||
|
||||
unsigned short salt;
|
||||
|
||||
};
|
||||
|
||||
/// Provides high level information related to a dtMeshTile object.
|
||||
|
@ -265,7 +297,7 @@ struct dtMeshHeader
|
|||
int detailTriCount; ///< The number of triangles in the detail mesh.
|
||||
int bvNodeCount; ///< The number of bounding volume nodes. (Zero if bounding volumes are disabled.)
|
||||
int offMeshConCount; ///< The number of off-mesh connections.
|
||||
int receivingOffMeshConCount;
|
||||
|
||||
int offMeshBase; ///< The index of the first polygon which is an off-mesh connection.
|
||||
float walkableHeight; ///< The height of the agents using the tile.
|
||||
float walkableRadius; ///< The radius of the agents using the tile.
|
||||
|
@ -301,9 +333,8 @@ struct dtMeshTile
|
|||
/// (Will be null if bounding volumes are disabled.)
|
||||
dtBVNode* bvTree;
|
||||
|
||||
dtOffMeshConnection* offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||
dtOffMeshConnection* receivingOffMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||
|
||||
dtOffMeshConnection** offMeshCons; ///< The tile off-mesh connections. [Size: dtMeshHeader::offMeshConCount]
|
||||
|
||||
unsigned char* data; ///< The tile data. (Not directly accessed under normal situations.)
|
||||
int dataSize; ///< Size of the tile data.
|
||||
int flags; ///< Tile flags. (See: #dtTileFlags)
|
||||
|
@ -369,7 +400,7 @@ public:
|
|||
/// @param[in] lastRef The desired reference for the tile. (When reloading a tile.) [opt] [Default: 0]
|
||||
/// @param[out] result The tile reference. (If the tile was succesfully added.) [opt]
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result, bool bMarkOffMeshDirty);
|
||||
dtStatus addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result);
|
||||
|
||||
/// Removes the specified tile from the navigation mesh.
|
||||
/// @param[in] ref The reference of the tile to remove.
|
||||
|
@ -378,6 +409,13 @@ public:
|
|||
/// @return The status flags for the operation.
|
||||
dtStatus removeTile(dtTileRef ref, unsigned char** data, int* dataSize);
|
||||
|
||||
void GlobalOffMeshLinks(dtOffMeshConnection* con);
|
||||
|
||||
void baseOffMeshLinks(dtOffMeshConnection* Connection);
|
||||
|
||||
void LinkOffMeshConnectionToTiles(dtOffMeshConnection* con);
|
||||
void unconnectOffMeshLink(dtOffMeshConnection* con);
|
||||
|
||||
/// @}
|
||||
|
||||
/// @{
|
||||
|
@ -394,7 +432,9 @@ public:
|
|||
/// @param[in] y The tile's y-location. (x, y, layer)
|
||||
/// @param[in] layer The tile's layer. (x, y, layer)
|
||||
/// @return The tile, or null if the tile does not exist.
|
||||
const dtMeshTile* getTileAt(const int x, const int y, const int layer) const;
|
||||
dtMeshTile* getTileAt(const int x, const int y, const int layer);
|
||||
|
||||
const dtMeshTile* getTileAtConst(const int x, const int y, const int layer) const;
|
||||
|
||||
/// Gets all tiles at the specified grid location. (All layers.)
|
||||
/// @param[in] x The tile's x-location. (x, y)
|
||||
|
@ -467,10 +507,6 @@ public:
|
|||
/// @param[in] ref The polygon reference of the off-mesh connection.
|
||||
/// @return The specified off-mesh connection, or null if the polygon reference is not valid.
|
||||
const dtOffMeshConnection* getOffMeshConnectionByRef(dtPolyRef ref) const;
|
||||
|
||||
int GetNumPendingOffMeshConnections() { return m_NumPendingConnections; }
|
||||
void ClearPendingOffMeshConnections() { m_NumPendingConnections = 0; }
|
||||
dtOffMeshConnection* GetPendingConnection(int index) { return m_PendingOffMeshs[index]; }
|
||||
|
||||
/// @}
|
||||
|
||||
|
@ -520,8 +556,6 @@ public:
|
|||
/// @param[in] maxDataSize The size of the state within the data buffer.
|
||||
/// @return The status flags for the operation.
|
||||
dtStatus restoreTileState(dtMeshTile* tile, const unsigned char* data, const int maxDataSize);
|
||||
|
||||
void GlobalOffMeshLinks(dtMeshTile* target);
|
||||
|
||||
/// @}
|
||||
|
||||
|
@ -642,11 +676,12 @@ private:
|
|||
/// Builds internal polygons links for a tile.
|
||||
void baseOffMeshLinks(dtMeshTile* tile);
|
||||
|
||||
|
||||
|
||||
/// Builds external polygon links for a tile.
|
||||
void connectExtLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||
/// Builds external polygon links for a tile.
|
||||
void connectExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||
void connectDistantExtOffMeshLinks(dtMeshTile* tile, dtMeshTile* target, int side);
|
||||
/// Removes external links at specified side.
|
||||
void unconnectLinks(dtMeshTile* tile, dtMeshTile* target);
|
||||
|
||||
|
@ -670,10 +705,7 @@ private:
|
|||
int m_maxTiles; ///< Max number of tiles.
|
||||
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
||||
int m_tileLutMask; ///< Tile hash lookup mask.
|
||||
|
||||
dtOffMeshConnection* m_PendingOffMeshs[1024];
|
||||
int m_NumPendingConnections = 0;
|
||||
|
||||
|
||||
dtMeshTile** m_posLookup; ///< Tile hash lookup.
|
||||
dtMeshTile* m_nextFree; ///< Freelist of tiles.
|
||||
dtMeshTile* m_tiles; ///< List of tiles.
|
||||
|
|
|
@ -20,6 +20,9 @@
|
|||
#define DETOURNAVMESHBUILDER_H
|
||||
|
||||
#include "DetourAlloc.h"
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
/// Represents the source data used to build an navigation mesh tile.
|
||||
/// @ingroup detour
|
||||
|
@ -102,6 +105,9 @@ struct dtNavMeshCreateParams
|
|||
/// @note The BVTree is not normally needed for layered navigation meshes.
|
||||
bool buildBvTree;
|
||||
|
||||
dtOffMeshConnection* GlobalOffMeshConnections;
|
||||
int NumOffMeshConnections;
|
||||
|
||||
};
|
||||
|
||||
/// Builds navigation mesh tile data from the provided tile creation data.
|
||||
|
|
|
@ -2,10 +2,12 @@
|
|||
#define DETOURTILECACHE_H
|
||||
|
||||
#include "DetourStatus.h"
|
||||
#include "DetourNavMesh.h"
|
||||
|
||||
|
||||
#include <vector>
|
||||
|
||||
typedef unsigned int dtObstacleRef;
|
||||
typedef unsigned int dtOffMeshConnectionRef;
|
||||
|
||||
typedef unsigned int dtCompressedTileRef;
|
||||
|
||||
|
@ -96,6 +98,7 @@ struct dtTileCacheParams
|
|||
float maxSimplificationError;
|
||||
int maxTiles;
|
||||
int maxObstacles;
|
||||
int maxOffMeshConnections;
|
||||
};
|
||||
|
||||
struct dtTileCacheMeshProcess
|
||||
|
@ -104,6 +107,8 @@ struct dtTileCacheMeshProcess
|
|||
|
||||
virtual void process(struct dtNavMeshCreateParams* params,
|
||||
unsigned char* polyAreas, unsigned short* polyFlags) = 0;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -122,12 +127,16 @@ public:
|
|||
inline int getTileCount() const { return m_params.maxTiles; }
|
||||
inline const dtCompressedTile* getTile(const int i) const { return &m_tiles[i]; }
|
||||
|
||||
inline int getOffMeshCount() const { return m_params.maxOffMeshConnections; }
|
||||
inline int getObstacleCount() const { return m_params.maxObstacles; }
|
||||
inline const dtTileCacheObstacle* getObstacle(const int i) const { return &m_obstacles[i]; }
|
||||
inline const dtOffMeshConnection* getOffMeshConnection(const int i) const { return &m_offMeshConnections[i]; }
|
||||
|
||||
const dtTileCacheObstacle* getObstacleByRef(dtObstacleRef ref);
|
||||
dtOffMeshConnection* getOffMeshConnectionByRef(dtOffMeshConnectionRef ref);
|
||||
|
||||
dtObstacleRef getObstacleRef(const dtTileCacheObstacle* obmin) const;
|
||||
dtOffMeshConnectionRef getOffMeshRef(const dtOffMeshConnection* con) const;
|
||||
|
||||
dtStatus init(const dtTileCacheParams* params,
|
||||
struct dtTileCacheAlloc* talloc,
|
||||
|
@ -147,13 +156,16 @@ public:
|
|||
// Cylinder obstacle.
|
||||
dtStatus addObstacle(const float* pos, const float radius, const float height, const int area, dtObstacleRef* result);
|
||||
|
||||
dtStatus addOffMeshConnection(const float* spos, const float* epos, const float radius, const unsigned char area, const unsigned short flags, const bool bBiDirectional, dtOffMeshConnectionRef* result);
|
||||
|
||||
// Aabb obstacle.
|
||||
dtStatus addBoxObstacle(const float* bmin, const float* bmax, const int area, dtObstacleRef* result);
|
||||
dtStatus addBoxObstacle(const float* bmin, const float* bmax, dtObstacleRef* result);
|
||||
|
||||
// Box obstacle: can be rotated in Y.
|
||||
dtStatus addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, const int area, dtObstacleRef* result);
|
||||
dtStatus addBoxObstacle(const float* center, const float* halfExtents, const float yRadians, dtObstacleRef* result);
|
||||
|
||||
dtStatus removeObstacle(const dtObstacleRef ref);
|
||||
dtStatus removeOffMeshConnection(const dtOffMeshConnectionRef ref);
|
||||
|
||||
dtStatus queryTiles(const float* bmin, const float* bmax,
|
||||
dtCompressedTileRef* results, int* resultCount, const int maxResults) const;
|
||||
|
@ -166,9 +178,9 @@ public:
|
|||
/// otherwise another call will continue processing obstacle requests and tile rebuilds.
|
||||
dtStatus update(const float dt, class dtNavMesh* navmesh, bool* upToDate = 0);
|
||||
|
||||
dtStatus buildNavMeshTilesAt(const int tx, const int ty, class dtNavMesh* navmesh, bool bMarkOffMeshDirty);
|
||||
|
||||
dtStatus buildNavMeshTile(const dtCompressedTileRef ref, class dtNavMesh* navmesh, bool bMarkOffMeshDirty);
|
||||
dtStatus buildNavMeshTilesAt(const int tx, const int ty, class dtNavMesh* navmesh);
|
||||
|
||||
dtStatus buildNavMeshTile(const dtCompressedTileRef ref, class dtNavMesh* navmesh);
|
||||
|
||||
void calcTightTileBounds(const struct dtTileCacheLayerHeader* header, float* bmin, float* bmax) const;
|
||||
|
||||
|
@ -200,6 +212,12 @@ public:
|
|||
{
|
||||
return ((dtObstacleRef)salt << 16) | (dtObstacleRef)it;
|
||||
}
|
||||
|
||||
/// Encodes an obstacle id.
|
||||
inline dtOffMeshConnectionRef encodeOffMeshId(unsigned int salt, unsigned int it) const
|
||||
{
|
||||
return ((dtOffMeshConnectionRef)salt << 16) | (dtOffMeshConnectionRef)it;
|
||||
}
|
||||
|
||||
/// Decodes an obstacle salt.
|
||||
inline unsigned int decodeObstacleIdSalt(dtObstacleRef ref) const
|
||||
|
@ -207,6 +225,12 @@ public:
|
|||
const dtObstacleRef saltMask = ((dtObstacleRef)1<<16)-1;
|
||||
return (unsigned int)((ref >> 16) & saltMask);
|
||||
}
|
||||
|
||||
inline unsigned int decodeOffMeshIdSalt(dtOffMeshConnectionRef ref) const
|
||||
{
|
||||
const dtOffMeshConnectionRef saltMask = ((dtOffMeshConnectionRef)1 << 16) - 1;
|
||||
return (unsigned int)((ref >> 16) & saltMask);
|
||||
}
|
||||
|
||||
/// Decodes an obstacle id.
|
||||
inline unsigned int decodeObstacleIdObstacle(dtObstacleRef ref) const
|
||||
|
@ -214,6 +238,12 @@ public:
|
|||
const dtObstacleRef tileMask = ((dtObstacleRef)1<<16)-1;
|
||||
return (unsigned int)(ref & tileMask);
|
||||
}
|
||||
|
||||
inline unsigned int decodeOffMeshIdCon(dtOffMeshConnectionRef ref) const
|
||||
{
|
||||
const dtOffMeshConnectionRef tileMask = ((dtOffMeshConnectionRef)1 << 16) - 1;
|
||||
return (unsigned int)(ref & tileMask);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
@ -226,12 +256,25 @@ private:
|
|||
REQUEST_ADD,
|
||||
REQUEST_REMOVE,
|
||||
};
|
||||
|
||||
enum OffMeshRequestAction
|
||||
{
|
||||
REQUEST_OFFMESH_ADD,
|
||||
REQUEST_OFFMESH_REFRESH,
|
||||
REQUEST_OFFMESH_REMOVE
|
||||
};
|
||||
|
||||
struct ObstacleRequest
|
||||
{
|
||||
int action;
|
||||
dtObstacleRef ref;
|
||||
};
|
||||
|
||||
struct OffMeshRequest
|
||||
{
|
||||
int action;
|
||||
dtOffMeshConnectionRef ref;
|
||||
};
|
||||
|
||||
int m_tileLutSize; ///< Tile hash lookup size (must be pot).
|
||||
int m_tileLutMask; ///< Tile hash lookup mask.
|
||||
|
@ -251,10 +294,16 @@ private:
|
|||
|
||||
dtTileCacheObstacle* m_obstacles;
|
||||
dtTileCacheObstacle* m_nextFreeObstacle;
|
||||
|
||||
dtOffMeshConnection* m_offMeshConnections;
|
||||
dtOffMeshConnection* m_nextFreeOffMeshConnection;
|
||||
|
||||
static const int MAX_REQUESTS = 64;
|
||||
static const int MAX_REQUESTS = 256;
|
||||
ObstacleRequest m_reqs[MAX_REQUESTS];
|
||||
int m_nreqs;
|
||||
|
||||
OffMeshRequest m_OffMeshReqs[MAX_REQUESTS];
|
||||
int m_nOffMeshReqs;
|
||||
|
||||
static const int MAX_UPDATE = 64;
|
||||
dtCompressedTileRef m_update[MAX_UPDATE];
|
||||
|
|
|
@ -35,6 +35,7 @@ static const unsigned char DT_TILECACHE_TEAM2STRUCTURE_AREA = 6;
|
|||
static const unsigned char DT_TILECACHE_WELD_AREA = 7;
|
||||
static const unsigned char DT_TILECACHE_DOOR_AREA = 8;
|
||||
static const unsigned char DT_TILECACHE_WALKABLE_AREA = 63;
|
||||
|
||||
static const unsigned short DT_TILECACHE_NULL_IDX = 0xffff;
|
||||
|
||||
struct dtTileCacheLayerHeader
|
||||
|
|
|
@ -171,7 +171,7 @@ typedef enum _STRUCTUREPURPOSE
|
|||
|
||||
typedef struct _OFF_MESH_CONN
|
||||
{
|
||||
int MeshConnectionIndex = -1;
|
||||
unsigned int ConnectionRefs[2];
|
||||
unsigned short ConnectionFlags = 0;
|
||||
Vector FromLocation = g_vecZero;
|
||||
Vector ToLocation = g_vecZero;
|
||||
|
|
|
@ -72,23 +72,7 @@ struct TileCacheSetExportHeader
|
|||
|
||||
int NumOffMeshCons;
|
||||
|
||||
int OffMeshConVertsOffset;
|
||||
int OffMeshConVertsLength;
|
||||
|
||||
int OffMeshConRadsOffset;
|
||||
int OffMeshConRadsLength;
|
||||
|
||||
int OffMeshConDirsOffset;
|
||||
int OffMeshConDirsLength;
|
||||
|
||||
int OffMeshConAreasOffset;
|
||||
int OffMeshConAreasLength;
|
||||
|
||||
int OffMeshConFlagsOffset;
|
||||
int OffMeshConFlagsLength;
|
||||
|
||||
int OffMeshConUserIDsOffset;
|
||||
int OffMeshConUserIDsLength;
|
||||
int OffMeshConsOffset;
|
||||
};
|
||||
|
||||
struct TileCacheTileHeader
|
||||
|
@ -187,21 +171,6 @@ struct LinearAllocator : public dtTileCacheAlloc
|
|||
|
||||
struct MeshProcess : public dtTileCacheMeshProcess
|
||||
{
|
||||
int NumOffMeshConns = 0;
|
||||
float OffMeshVerts[MAX_OFFMESH_CONNS * 6];
|
||||
float OffMeshRads[MAX_OFFMESH_CONNS];
|
||||
unsigned char OffMeshDirs[MAX_OFFMESH_CONNS];
|
||||
unsigned char OffMeshAreas[MAX_OFFMESH_CONNS];
|
||||
unsigned short OffMeshFlags[MAX_OFFMESH_CONNS];
|
||||
unsigned int OffMeshIDs[MAX_OFFMESH_CONNS];
|
||||
|
||||
bool bNavDataDirty = false;
|
||||
|
||||
OffMeshConnectionDef ConnectionDefinitions[MAX_OFFMESH_CONNS];
|
||||
|
||||
vector<OffMeshConnectionDef> OffMeshConnections;
|
||||
|
||||
unsigned int NextUserID = 0;
|
||||
|
||||
inline MeshProcess()
|
||||
{}
|
||||
|
@ -211,197 +180,6 @@ struct MeshProcess : public dtTileCacheMeshProcess
|
|||
|
||||
}
|
||||
|
||||
void AddOffMeshConnectionDef(Vector Start, Vector End, unsigned char area, unsigned short flag, bool bBiDirectional, AvHAIOffMeshConnection* ConnectionRef)
|
||||
{
|
||||
OffMeshConnectionDef NewDefinition;
|
||||
NewDefinition.Area = area;
|
||||
NewDefinition.bBiDir = bBiDirectional;
|
||||
NewDefinition.spos[0] = Start.x;
|
||||
NewDefinition.spos[1] = Start.z;
|
||||
NewDefinition.spos[2] = -Start.y;
|
||||
NewDefinition.epos[0] = End.x;
|
||||
NewDefinition.epos[1] = End.z;
|
||||
NewDefinition.epos[2] = -End.y;
|
||||
NewDefinition.Flag = flag;
|
||||
NewDefinition.Rad = 18.0f;
|
||||
NewDefinition.UserID = NextUserID;
|
||||
NewDefinition.bDirty = true;
|
||||
|
||||
if (ConnectionRef)
|
||||
{
|
||||
ConnectionRef->MeshConnectionIndex = NextUserID;
|
||||
}
|
||||
|
||||
NextUserID++;
|
||||
|
||||
OffMeshConnections.push_back(NewDefinition);
|
||||
|
||||
bNavDataDirty = true;
|
||||
};
|
||||
|
||||
void RemoveOffMeshConnectionDef(int UserID)
|
||||
{
|
||||
for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++)
|
||||
{
|
||||
if (it->UserID == UserID)
|
||||
{
|
||||
it->bDirty = true;
|
||||
it->bPendingDelete = true;
|
||||
}
|
||||
}
|
||||
|
||||
bNavDataDirty = true;
|
||||
}
|
||||
|
||||
void PurgeDeletedConnections()
|
||||
{
|
||||
for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end();)
|
||||
{
|
||||
if (it->bPendingDelete)
|
||||
{
|
||||
it = OffMeshConnections.erase(it);
|
||||
}
|
||||
else
|
||||
{
|
||||
it++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateOffMeshData()
|
||||
{
|
||||
int CurrIndex = 0;
|
||||
int VertIndex = 0;
|
||||
|
||||
for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++)
|
||||
{
|
||||
if (!it->bPendingDelete)
|
||||
{
|
||||
OffMeshVerts[VertIndex++] = it->spos[0];
|
||||
OffMeshVerts[VertIndex++] = it->spos[1];
|
||||
OffMeshVerts[VertIndex++] = it->spos[2];
|
||||
OffMeshVerts[VertIndex++] = it->epos[0];
|
||||
OffMeshVerts[VertIndex++] = it->epos[1];
|
||||
OffMeshVerts[VertIndex++] = it->epos[2];
|
||||
|
||||
OffMeshRads[CurrIndex] = it->Rad;
|
||||
OffMeshDirs[CurrIndex] = it->bBiDir;
|
||||
OffMeshAreas[CurrIndex] = it->Area;
|
||||
OffMeshFlags[CurrIndex] = it->Flag;
|
||||
OffMeshIDs[CurrIndex] = it->UserID;
|
||||
|
||||
CurrIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
NumOffMeshConns = CurrIndex;
|
||||
|
||||
bNavDataDirty = false;
|
||||
}
|
||||
|
||||
void PopulateOffMeshConnectionVector()
|
||||
{
|
||||
OffMeshConnections.clear();
|
||||
|
||||
for (int i = 0; i < NumOffMeshConns; i++)
|
||||
{
|
||||
float* v = &OffMeshVerts[i*3*2];
|
||||
Vector StartPos = Vector(v[0], -v[2], v[1]);
|
||||
Vector EndPos = Vector(v[3], -v[5], v[4]);
|
||||
AddOffMeshConnectionDef(StartPos, EndPos, OffMeshAreas[i], OffMeshFlags[i], OffMeshDirs[i], nullptr);
|
||||
}
|
||||
|
||||
bNavDataDirty = false;
|
||||
}
|
||||
|
||||
void GetOffMeshConnectionPoints(int UserID, Vector& OutStartLoc, Vector& OutEndLoc)
|
||||
{
|
||||
OutStartLoc = ZERO_VECTOR;
|
||||
OutEndLoc = ZERO_VECTOR;
|
||||
|
||||
for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++)
|
||||
{
|
||||
if (it->UserID == UserID)
|
||||
{
|
||||
OutStartLoc.x = it->spos[0];
|
||||
OutStartLoc.y = -it->spos[2];
|
||||
OutStartLoc.z = it->spos[1];
|
||||
|
||||
OutEndLoc.x = it->epos[0];
|
||||
OutEndLoc.y = -it->epos[2];
|
||||
OutEndLoc.z = it->epos[1];
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vector<OffMeshConnectionDef> GetOffMeshConnections()
|
||||
{
|
||||
return OffMeshConnections;
|
||||
}
|
||||
|
||||
void MarkOffMeshConnectionsClean()
|
||||
{
|
||||
for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++)
|
||||
{
|
||||
it->bDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
vector<OffMeshConnectionDef*> GetDirtyOffMeshConnections()
|
||||
{
|
||||
vector<OffMeshConnectionDef*> Result;
|
||||
|
||||
for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++)
|
||||
{
|
||||
if (it->bDirty || it->bPendingDelete)
|
||||
{
|
||||
Result.push_back(&(*it));
|
||||
}
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void DrawAllConnections(float DrawTime)
|
||||
{
|
||||
Vector StartLine = ZERO_VECTOR;
|
||||
Vector EndLine = ZERO_VECTOR;
|
||||
|
||||
for (auto it = OffMeshConnections.begin(); it != OffMeshConnections.end(); it++)
|
||||
{
|
||||
Vector StartLine = Vector(it->spos[0], -it->spos[2], it->spos[1]);
|
||||
Vector EndLine = Vector(it->epos[0], -it->epos[2], it->epos[1]);
|
||||
|
||||
switch (it->Flag)
|
||||
{
|
||||
case SAMPLE_POLYFLAGS_WALK:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 255, 255);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_JUMP:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 255, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_WALLCLIMB:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 255, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_FALL:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 0, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_LADDER:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 0, 255);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_TEAM1PHASEGATE:
|
||||
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 128, 128);
|
||||
break;
|
||||
default:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 255, 255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
virtual void process(struct dtNavMeshCreateParams* params,
|
||||
unsigned char* polyAreas, unsigned short* polyFlags)
|
||||
{
|
||||
|
@ -455,32 +233,48 @@ struct MeshProcess : public dtTileCacheMeshProcess
|
|||
}
|
||||
}
|
||||
|
||||
if (bNavDataDirty)
|
||||
{
|
||||
UpdateOffMeshData();
|
||||
}
|
||||
|
||||
params->offMeshConAreas = OffMeshAreas;
|
||||
params->offMeshConCount = NumOffMeshConns;
|
||||
params->offMeshConDir = OffMeshDirs;
|
||||
params->offMeshConFlags = OffMeshFlags;
|
||||
params->offMeshConRad = OffMeshRads;
|
||||
params->offMeshConUserID = OffMeshIDs;
|
||||
params->offMeshConVerts = OffMeshVerts;
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
void AIDEBUG_DrawOffMeshConnections(float DrawTime)
|
||||
{
|
||||
if (NavMeshes[0].tileCache)
|
||||
if (NavMeshes[REGULAR_NAV_MESH].tileCache)
|
||||
{
|
||||
MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[0].tileCache->getMeshProcess();
|
||||
|
||||
if (m_tmproc)
|
||||
for (int i = 0; i < NavMeshes[REGULAR_NAV_MESH].tileCache->getOffMeshCount(); i++)
|
||||
{
|
||||
m_tmproc->DrawAllConnections(DrawTime);
|
||||
const dtOffMeshConnection* con = NavMeshes[REGULAR_NAV_MESH].tileCache->getOffMeshConnection(i);
|
||||
|
||||
if (con->state == DT_OFFMESH_EMPTY || con->state == DT_OFFMESH_REMOVING) { continue; }
|
||||
|
||||
Vector StartLine = Vector(con->pos[0], -con->pos[2], con->pos[1]);
|
||||
Vector EndLine = Vector(con->pos[3], -con->pos[5], con->pos[4]);
|
||||
switch (con->flags)
|
||||
{
|
||||
case SAMPLE_POLYFLAGS_WALK:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 255, 255);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_JUMP:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 255, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_WALLCLIMB:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 255, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_FALL:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 0, 0);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_LADDER:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 0, 255);
|
||||
break;
|
||||
case SAMPLE_POLYFLAGS_TEAM1PHASEGATE:
|
||||
case SAMPLE_POLYFLAGS_TEAM2PHASEGATE:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 255, 128, 128);
|
||||
break;
|
||||
default:
|
||||
UTIL_DrawLine(INDEXENT(1), StartLine, EndLine, DrawTime, 0, 255, 255);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -494,40 +288,7 @@ void UTIL_UpdateTileCache()
|
|||
{
|
||||
NavMeshes[i].tileCache->update(0.0f, NavMeshes[i].navMesh, &bUpToDate);
|
||||
}
|
||||
}
|
||||
|
||||
if (bUpToDate)
|
||||
{
|
||||
if (NavMeshes[0].tileCache)
|
||||
{
|
||||
MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[0].tileCache->getMeshProcess();
|
||||
|
||||
if (m_tmproc)
|
||||
{
|
||||
vector<OffMeshConnectionDef*> DirtyOffMeshConnections = m_tmproc->GetDirtyOffMeshConnections();
|
||||
|
||||
Vector StartPos, EndPos;
|
||||
|
||||
if (DirtyOffMeshConnections.size() > 0)
|
||||
{
|
||||
m_tmproc->bNavDataDirty = true;
|
||||
}
|
||||
|
||||
for (auto it = DirtyOffMeshConnections.begin(); it != DirtyOffMeshConnections.end(); it++)
|
||||
{
|
||||
m_tmproc->GetOffMeshConnectionPoints((*it)->UserID, StartPos, EndPos);
|
||||
|
||||
UTIL_OnOffMeshConnectionModified(StartPos, EndPos);
|
||||
|
||||
(*it)->bDirty = false;
|
||||
}
|
||||
|
||||
m_tmproc->PurgeDeletedConnections();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDistanceFromWall)
|
||||
|
@ -923,35 +684,12 @@ bool LoadNavMesh(const char* mapname)
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
int CurrFilePos = ftell(savedFile);
|
||||
|
||||
LinearAllocator* m_talloc = new LinearAllocator(32000);
|
||||
FastLZCompressor* m_tcomp = new FastLZCompressor;
|
||||
MeshProcess* m_tmproc = new MeshProcess;
|
||||
|
||||
m_tmproc->NumOffMeshConns = header.NumOffMeshCons;
|
||||
|
||||
fseek(savedFile, header.OffMeshConAreasOffset, SEEK_SET);
|
||||
size_t ReadResult = fread(m_tmproc->OffMeshAreas, header.OffMeshConAreasLength, 1, savedFile);
|
||||
|
||||
fseek(savedFile, header.OffMeshConDirsOffset, SEEK_SET);
|
||||
ReadResult = fread(m_tmproc->OffMeshDirs, header.OffMeshConDirsLength, 1, savedFile);
|
||||
|
||||
fseek(savedFile, header.OffMeshConFlagsOffset, SEEK_SET);
|
||||
ReadResult = fread(m_tmproc->OffMeshFlags, header.OffMeshConFlagsLength, 1, savedFile);
|
||||
|
||||
fseek(savedFile, header.OffMeshConRadsOffset, SEEK_SET);
|
||||
ReadResult = fread(m_tmproc->OffMeshRads, header.OffMeshConRadsLength, 1, savedFile);
|
||||
|
||||
fseek(savedFile, header.OffMeshConUserIDsOffset, SEEK_SET);
|
||||
ReadResult = fread(m_tmproc->OffMeshIDs, header.OffMeshConUserIDsLength, 1, savedFile);
|
||||
|
||||
fseek(savedFile, header.OffMeshConVertsOffset, SEEK_SET);
|
||||
ReadResult = fread(m_tmproc->OffMeshVerts, header.OffMeshConVertsLength, 1, savedFile);
|
||||
|
||||
m_tmproc->PopulateOffMeshConnectionVector();
|
||||
|
||||
// TODO: Need to pass all off mesh connection verts, areas, flags etc as arrays to m_tmproc. Needs to be exported from recast as such
|
||||
|
||||
status = NavMeshes[REGULAR_NAV_MESH].tileCache->init(&header.regularCacheParams, m_talloc, m_tcomp, m_tmproc);
|
||||
|
@ -1020,7 +758,7 @@ bool LoadNavMesh(const char* mapname)
|
|||
}
|
||||
|
||||
if (tile)
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[REGULAR_NAV_MESH].navMesh, false);
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[REGULAR_NAV_MESH].navMesh);
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.numOnosTiles; ++i)
|
||||
|
@ -1059,7 +797,7 @@ bool LoadNavMesh(const char* mapname)
|
|||
}
|
||||
|
||||
if (tile)
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[ONOS_NAV_MESH].navMesh, false);
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[ONOS_NAV_MESH].navMesh);
|
||||
}
|
||||
|
||||
for (int i = 0; i < header.numBuildingTiles; ++i)
|
||||
|
@ -1098,7 +836,21 @@ bool LoadNavMesh(const char* mapname)
|
|||
}
|
||||
|
||||
if (tile)
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[BUILDING_NAV_MESH].navMesh, false);
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTile(tile, NavMeshes[BUILDING_NAV_MESH].navMesh);
|
||||
}
|
||||
|
||||
fseek(savedFile, header.OffMeshConsOffset, SEEK_SET);
|
||||
|
||||
for (int i = 0; i < header.NumOffMeshCons; i++)
|
||||
{
|
||||
dtOffMeshConnection def;
|
||||
|
||||
fread(&def, sizeof(dtOffMeshConnection), 1, savedFile);
|
||||
|
||||
for (int ii = 0; ii < BUILDING_NAV_MESH; ii++)
|
||||
{
|
||||
NavMeshes[ii].tileCache->addOffMeshConnection(&def.pos[0], &def.pos[3], def.rad, def.area, def.flags, def.bBiDir, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(savedFile);
|
||||
|
@ -1136,31 +888,21 @@ bool LoadNavMesh(const char* mapname)
|
|||
return false;
|
||||
}
|
||||
|
||||
UTIL_RefreshOffMeshConnections();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void UTIL_RefreshOffMeshConnections()
|
||||
void OnOffMeshConnectionAdded(dtOffMeshConnection* NewConnection)
|
||||
{
|
||||
MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[0].tileCache->getMeshProcess();
|
||||
|
||||
if (!m_tmproc) { return; }
|
||||
|
||||
vector<OffMeshConnectionDef> Connections = m_tmproc->GetOffMeshConnections();
|
||||
|
||||
for (auto it = Connections.begin(); it != Connections.end(); it++)
|
||||
for (int i = 0; i <= BUILDING_NAV_MESH; i++)
|
||||
{
|
||||
if (it->bPendingDelete) { continue; }
|
||||
if (NavMeshes[i].navMesh && NavMeshes[i].tileCache)
|
||||
{
|
||||
NavMeshes[i].navMesh->LinkOffMeshConnectionToTiles(NewConnection);
|
||||
|
||||
Vector StartLoc, EndLoc;
|
||||
|
||||
m_tmproc->GetOffMeshConnectionPoints(it->UserID, StartLoc, EndLoc);
|
||||
|
||||
UTIL_OnOffMeshConnectionModified(StartLoc, EndLoc);
|
||||
dtCompressedTile* ModifiedTile = NavMeshes[i].tileCache->getTileAt(NewConnection->FromTileX, NewConnection->FromTileY, NewConnection->FromTileLayer);
|
||||
NavMeshes[i].tileCache->buildNavMeshTile(NavMeshes[i].tileCache->getTileRef(ModifiedTile), NavMeshes[i].navMesh);
|
||||
}
|
||||
}
|
||||
|
||||
m_tmproc->MarkOffMeshConnectionsClean();
|
||||
}
|
||||
|
||||
void UTIL_PopulateBaseNavProfiles()
|
||||
|
@ -7347,7 +7089,7 @@ nav_door* UTIL_GetNavDoorByEdict(const edict_t* DoorEdict)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned short flags, bool bBiDirectional, AvHAIOffMeshConnection* NewConnectionDef)
|
||||
void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned short flags, bool bBiDirectional, AvHAIOffMeshConnection* RemoveConnectionDef)
|
||||
{
|
||||
Vector ConnStart, ConnEnd;
|
||||
|
||||
|
@ -7360,132 +7102,29 @@ void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char are
|
|||
|
||||
ConnEnd = (hit.flFraction < 1.0f) ? hit.vecEndPos : EndLoc;
|
||||
|
||||
if (NavMeshes[REGULAR_NAV_MESH].tileCache)
|
||||
{
|
||||
NewConnectionDef->MeshConnectionIndex = -1;
|
||||
MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[REGULAR_NAV_MESH].tileCache->getMeshProcess();
|
||||
ConnStart = Vector(ConnStart.x, ConnStart.z, -ConnStart.y);
|
||||
ConnEnd = Vector(ConnEnd.x, ConnEnd.z, -ConnEnd.y);
|
||||
|
||||
if (m_tmproc)
|
||||
{
|
||||
m_tmproc->AddOffMeshConnectionDef(ConnStart, ConnEnd, area, flags, bBiDirectional, NewConnectionDef);
|
||||
}
|
||||
for (int i = 0; i < BUILDING_NAV_MESH; i++)
|
||||
{
|
||||
dtOffMeshConnectionRef ref = 0;
|
||||
|
||||
NavMeshes[i].tileCache->addOffMeshConnection(ConnStart, ConnEnd, 18.0f, area, flags, bBiDirectional, &ref);
|
||||
|
||||
RemoveConnectionDef->ConnectionRefs[i] = (unsigned int)ref;
|
||||
}
|
||||
}
|
||||
|
||||
void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* NewConnectionDef)
|
||||
void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* RemoveConnectionDef)
|
||||
{
|
||||
if (NewConnectionDef->MeshConnectionIndex < 0) { return; }
|
||||
|
||||
Vector StartLoc, EndLoc;
|
||||
|
||||
if (NavMeshes[REGULAR_NAV_MESH].tileCache)
|
||||
for (int i = 0; i < BUILDING_NAV_MESH; i++)
|
||||
{
|
||||
MeshProcess* m_tmproc = (MeshProcess*)NavMeshes[REGULAR_NAV_MESH].tileCache->getMeshProcess();
|
||||
dtOffMeshConnectionRef ref = 0;
|
||||
|
||||
if (m_tmproc)
|
||||
{
|
||||
m_tmproc->RemoveOffMeshConnectionDef(NewConnectionDef->MeshConnectionIndex);
|
||||
}
|
||||
NavMeshes[i].tileCache->removeOffMeshConnection(RemoveConnectionDef->ConnectionRefs[i]);
|
||||
|
||||
RemoveConnectionDef->ConnectionRefs[i] = 0;
|
||||
}
|
||||
|
||||
NewConnectionDef->MeshConnectionIndex = -1;
|
||||
|
||||
}
|
||||
|
||||
void UTIL_OnOffMeshConnectionModified(Vector StartLoc, Vector EndLoc)
|
||||
{
|
||||
float ext[3] = { 50.0f, 50.0f, 50.0f };
|
||||
|
||||
float spos[3] = { StartLoc.x, StartLoc.z, -StartLoc.y };
|
||||
float epos[3] = { EndLoc.x, EndLoc.z, -EndLoc.y };
|
||||
|
||||
float searchsposMin[3];
|
||||
float searchsposMax[3];
|
||||
|
||||
float searcheposMin[3];
|
||||
float searcheposMax[3];
|
||||
|
||||
dtVsub(searchsposMin, spos, ext);
|
||||
dtVadd(searchsposMax, spos, ext);
|
||||
|
||||
dtVsub(searcheposMin, epos, ext);
|
||||
dtVadd(searcheposMax, epos, ext);
|
||||
|
||||
int NumTiles = 0;
|
||||
dtCompressedTileRef AffectedTiles[DT_MAX_TOUCHED_TILES];
|
||||
|
||||
if (NavMeshes[REGULAR_NAV_MESH].tileCache && NavMeshes[REGULAR_NAV_MESH].navMesh)
|
||||
{
|
||||
NumTiles = 0;
|
||||
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->queryTiles(searcheposMin, searcheposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[REGULAR_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[REGULAR_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[REGULAR_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[REGULAR_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[REGULAR_NAV_MESH].navMesh, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (NavMeshes[ONOS_NAV_MESH].tileCache && NavMeshes[ONOS_NAV_MESH].navMesh)
|
||||
{
|
||||
NumTiles = 0;
|
||||
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->queryTiles(searcheposMin, searcheposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[ONOS_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[ONOS_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[ONOS_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[ONOS_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[ONOS_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (NavMeshes[BUILDING_NAV_MESH].tileCache && NavMeshes[BUILDING_NAV_MESH].navMesh)
|
||||
{
|
||||
NumTiles = 0;
|
||||
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->queryTiles(searcheposMin, searcheposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[BUILDING_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[BUILDING_NAV_MESH].navMesh, false);
|
||||
}
|
||||
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->queryTiles(searchsposMin, searchsposMax, AffectedTiles, &NumTiles, DT_MAX_TOUCHED_TILES);
|
||||
|
||||
for (int i = 0; i < NumTiles; i++)
|
||||
{
|
||||
const dtCompressedTile* Tile = NavMeshes[BUILDING_NAV_MESH].tileCache->getTileByRef(AffectedTiles[i]);
|
||||
|
||||
NavMeshes[BUILDING_NAV_MESH].tileCache->buildNavMeshTilesAt(Tile->header->tx, Tile->header->ty, NavMeshes[BUILDING_NAV_MESH].navMesh, false);
|
||||
}
|
||||
}
|
||||
|
||||
bNavMeshModified = true;
|
||||
}
|
||||
|
||||
const nav_profile GetBaseNavProfile(const int index)
|
||||
|
|
|
@ -292,9 +292,8 @@ void UTIL_RemoveTemporaryObstacle(unsigned int ObstacleRef);
|
|||
|
||||
void UTIL_RemoveTemporaryObstacles(unsigned int* ObstacleRefs);
|
||||
|
||||
void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned short flags, bool bBiDirectional, AvHAIOffMeshConnection* NewConnectionDef);
|
||||
void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* NewConnectionDef);
|
||||
void UTIL_OnOffMeshConnectionModified(Vector StartLoc, Vector EndLoc);
|
||||
void UTIL_AddOffMeshConnection(Vector StartLoc, Vector EndLoc, unsigned char area, unsigned short flags, bool bBiDirectional, AvHAIOffMeshConnection* RemoveConnectionDef);
|
||||
void UTIL_RemoveOffMeshConnections(AvHAIOffMeshConnection* RemoveConnectionDef);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -465,7 +464,7 @@ Vector UTIL_AdjustPointAwayFromNavWall(const Vector Location, const float MaxDis
|
|||
|
||||
void UTIL_PopulateBaseNavProfiles();
|
||||
|
||||
void UTIL_RefreshOffMeshConnections();
|
||||
void OnOffMeshConnectionAdded(dtOffMeshConnection* NewConnection);
|
||||
|
||||
#endif // BOT_NAVIGATION_H
|
||||
|
||||
|
|
|
@ -1567,7 +1567,7 @@ void AITAC_OnStructureCompleted(AvHAIBuildableStructure* NewStructure)
|
|||
NewConnection.ToLocation = OtherPhaseGate->Location;
|
||||
NewConnection.ConnectionFlags = NewFlag;
|
||||
NewConnection.TargetObject = OtherPhaseGate->edict;
|
||||
NewConnection.MeshConnectionIndex = -1;
|
||||
memset(&NewConnection.ConnectionRefs[0], 0, sizeof(NewConnection.ConnectionRefs));
|
||||
|
||||
UTIL_AddOffMeshConnection(NewStructure->Location, OtherPhaseGate->Location, SAMPLE_POLYAREA_GROUND, NewFlag, true, &NewConnection);
|
||||
|
||||
|
|
|
@ -1420,6 +1420,36 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
|
|||
|
||||
theSuccess = true;
|
||||
}
|
||||
else if (FStrEq(pcmd, "refreshoffmesh"))
|
||||
{
|
||||
theSuccess = true;
|
||||
}
|
||||
else if (FStrEq(pcmd, "evolvelerk"))
|
||||
{
|
||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAllAIPlayers();
|
||||
|
||||
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
|
||||
{
|
||||
AvHAIPlayer* thisBot = (*it);
|
||||
|
||||
AITASK_SetEvolveTask(thisBot, &thisBot->PrimaryBotTask, thisBot->Edict->v.origin, ALIEN_LIFEFORM_THREE, true);
|
||||
}
|
||||
|
||||
theSuccess = true;
|
||||
}
|
||||
else if (FStrEq(pcmd, "evolvegorge"))
|
||||
{
|
||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAllAIPlayers();
|
||||
|
||||
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
|
||||
{
|
||||
AvHAIPlayer* thisBot = (*it);
|
||||
|
||||
AITASK_SetEvolveTask(thisBot, &thisBot->PrimaryBotTask, thisBot->Edict->v.origin, ALIEN_LIFEFORM_TWO, true);
|
||||
}
|
||||
|
||||
theSuccess = true;
|
||||
}
|
||||
else if (FStrEq(pcmd, "tracedoor"))
|
||||
{
|
||||
Vector TraceStart = GetPlayerEyePosition(theAvHPlayer->edict()); // origin + pev->view_ofs
|
||||
|
@ -1435,6 +1465,14 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
|
|||
|
||||
if (Door)
|
||||
{
|
||||
for (auto it = Door->TriggerEnts.begin(); it != Door->TriggerEnts.end(); it++)
|
||||
{
|
||||
const char* ButtonTarget = STRING(it->Edict->v.target);
|
||||
const char* DoorTargetName = STRING(Door->DoorEdict->v.targetname);
|
||||
|
||||
bool bThing = true;
|
||||
}
|
||||
|
||||
DoorTrigger* Trigger = UTIL_GetNearestDoorTrigger(theAvHPlayer->pev->origin, Door, nullptr);
|
||||
|
||||
if (Trigger)
|
||||
|
@ -1448,11 +1486,11 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
|
|||
}
|
||||
else if (FStrEq(pcmd, "cometome"))
|
||||
{
|
||||
for (int i = 0; i < AIMGR_GetNumAIPlayers(); i++)
|
||||
{
|
||||
AvHAIPlayer* thisBot = AIMGR_GetAIPlayerAtIndex(i);
|
||||
vector<AvHAIPlayer*> AIPlayers = AIMGR_GetAllAIPlayers();
|
||||
|
||||
if (thisBot)
|
||||
for (auto it = AIPlayers.begin(); it != AIPlayers.end(); it++)
|
||||
{
|
||||
AvHAIPlayer* thisBot = (*it);
|
||||
{
|
||||
AITASK_SetMoveTask(thisBot, &thisBot->PrimaryBotTask, theAvHPlayer->pev->origin, true);
|
||||
}
|
||||
|
@ -1460,15 +1498,25 @@ BOOL AvHGamerules::ClientCommand( CBasePlayer *pPlayer, const char *pcmd )
|
|||
|
||||
theSuccess = true;
|
||||
}
|
||||
else if (FStrEq(pcmd, "aiteamstarts"))
|
||||
else if (FStrEq(pcmd, "testpointadjust"))
|
||||
{
|
||||
Vector TeamOneLoc = AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamANumber());
|
||||
Vector NewLoc = AdjustPointForPathfinding(theAvHPlayer->pev->origin);
|
||||
|
||||
UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, TeamOneLoc, 10.0f, 0, 0, 255);
|
||||
if (!vIsZero(NewLoc))
|
||||
{
|
||||
UTIL_DrawLine(INDEXENT(1), theAvHPlayer->pev->origin, NewLoc, 10.0f);
|
||||
}
|
||||
|
||||
Vector TeamTwoLoc = AITAC_GetTeamStartingLocation(GetGameRules()->GetTeamBNumber());
|
||||
theSuccess = true;
|
||||
}
|
||||
else if (FStrEq(pcmd, "testflightpath"))
|
||||
{
|
||||
vector<bot_path_node> path;
|
||||
path.clear();
|
||||
|
||||
UTIL_DrawLine(INDEXENT(1), INDEXENT(1)->v.origin, TeamTwoLoc, 10.0f, 0, 128, 0);
|
||||
FindFlightPathToPoint(GetBaseNavProfile(ALL_NAV_PROFILE), AITAC_GetTeamStartingLocation(TEAM_ONE) + Vector(0.0f, 0.0f, 50.0f), theAvHPlayer->pev->origin, path, 100.0f);
|
||||
|
||||
AIDEBUG_DrawPath(path, 20.0f);
|
||||
|
||||
theSuccess = true;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue