dtMeshTile* dtNavMesh::getNeighbourTileAt(int x, int y, int side) const { switch (side) { case 0: x++; break; case 1: x++; y++; break; case 2: y++; break; case 3: x--; y++; break; case 4: x--; break; case 5: x--; y--; break; case 6: y--; break; case 7: x++; y--; break; }; // Find tile based on hash. int h = computeTileHash(x, y, m_tileLutMask); dtMeshTile* tile = m_posLookup[h]; while (tile) { if (tile->header && tile->header->x == x && tile->header->y == y) return tile; tile = tile->next; } return 0; }
const dtMeshTile* dtNavMesh::getTileAt(int x, int y) const { if ((x < -100000 || x > 100000) || (y < -100000 || y > 100000)) return 0; // Find tile based on hash. int h = computeTileHash(x,y,m_tileLutMask); access ((char*)(m_posLookup+h),F_OK); if (errno==14) return 0; dtMeshTile* tile = m_posLookup[h]; while (tile) { if (sizeof(*tile)!=sizeof(dtMeshTile)) return 0; if (sizeof(*tile->header)!=sizeof(dtMeshHeader)) return 0; access ((char*)tile,F_OK); if (errno==14) return 0; access ((char*)tile->header,F_OK); if (errno==14) return 0; if (tile->header && tile->header->x == x && tile->header->y == y) return tile; tile = tile->next; } return 0; }
dtTileRef dtNavMesh::getTileRefAt(int x, int y) 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) return getTileRef(tile); tile = tile->next; } return 0; }
dtStatus dtTileCache::addTile(unsigned char* data, const int dataSize, unsigned char flags, dtCompressedTileRef* result) { // Make sure the data is in right format. dtTileCacheLayerHeader* header = (dtTileCacheLayerHeader*)data; if (header->magic != DT_TILECACHE_MAGIC) return DT_FAILURE | DT_WRONG_MAGIC; if (header->version != DT_TILECACHE_VERSION) return DT_FAILURE | DT_WRONG_VERSION; // Make sure the location is free. if (getTileAt(header->tx, header->ty, header->tlayer)) return DT_FAILURE; // Allocate a tile. dtCompressedTile* tile = 0; if (m_nextFreeTile) { tile = m_nextFreeTile; m_nextFreeTile = tile->next; tile->next = 0; } // 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->tx, header->ty, m_tileLutMask); tile->next = m_posLookup[h]; m_posLookup[h] = tile; // Init tile. const int headerSize = dtAlign4(sizeof(dtTileCacheLayerHeader)); tile->header = (dtTileCacheLayerHeader*)data; tile->data = data; tile->dataSize = dataSize; tile->compressed = tile->data + headerSize; tile->compressedSize = tile->dataSize - headerSize; tile->flags = flags; if (result) *result = getTileRef(tile); return DT_SUCCESS; }
const dtMeshTile* dtNavMesh::getTileAt(const int x, const int y, const int layer) const { // Find tile based on hash. int h = computeTileHash(x,y,m_tileLutMask); dtMeshTile* tile = m_posLookup[h]; while (tile) { if (tile->header && tile->header->x == x && tile->header->y == y && tile->header->layer == layer) { return tile; } tile = tile->next; } return 0; }
dtCompressedTile* dtTileCache::getTileAt(const int tx, const int ty, const int tlayer) { // Find tile based on hash. int h = computeTileHash(tx,ty,m_tileLutMask); dtCompressedTile* tile = m_posLookup[h]; while (tile) { if (tile->header && tile->header->tx == tx && tile->header->ty == ty && tile->header->tlayer == tlayer) { return tile; } tile = tile->next; } return 0; }
/// @par /// /// This function will not fail if the tiles array is too small to hold the /// entire result set. It will simply fill the array to capacity. int dtNavMesh::getTilesAt(const int x, const int y, dtMeshTile const** tiles, const int maxTiles) const { int n = 0; // Find tile based on hash. int h = computeTileHash(x,y,m_tileLutMask); dtMeshTile* tile = m_posLookup[h]; while (tile) { if (tile->header && tile->header->x == x && tile->header->y == y) { if (n < maxTiles) tiles[n++] = tile; } tile = tile->next; } return n; }
int dtTileCache::getTilesAt(const int tx, const int ty, dtCompressedTileRef* tiles, const int maxTiles) const { int n = 0; // Find tile based on hash. int h = computeTileHash(tx,ty,m_tileLutMask); dtCompressedTile* tile = m_posLookup[h]; while (tile) { if (tile->header && tile->header->tx == tx && tile->header->ty == ty) { if (n < maxTiles) tiles[n++] = getTileRef(tile); } tile = tile->next; } return n; }
/// @par /// /// The add operation will fail if the data is in the wrong format, the allocated tile /// space is full, or there is a tile already at the specified reference. /// /// The lastRef parameter is used to restore a tile with the same tile /// reference it had previously used. In this case the #dtPolyRef's for the /// tile will be restored to the same values they were before the tile was /// removed. /// /// @see dtCreateNavMeshData, #removeTile dtStatus dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef, dtTileRef* result) { // Make sure the data is in right format. dtMeshHeader* header = (dtMeshHeader*)data; if (header->magic != DT_NAVMESH_MAGIC) return DT_FAILURE | DT_WRONG_MAGIC; if (header->version != DT_NAVMESH_VERSION) return DT_FAILURE | DT_WRONG_VERSION; // Make sure the location is free. if (getTileAt(header->x, header->y, header->layer)) return DT_FAILURE; // Allocate a tile. dtMeshTile* tile = 0; if (!lastRef) { if (m_nextFree) { tile = m_nextFree; m_nextFree = tile->next; tile->next = 0; } } else { // Try to relocate the tile to specific index with same salt. int tileIndex = (int)decodePolyIdTile((dtPolyRef)lastRef); if (tileIndex >= m_maxTiles) return DT_FAILURE | DT_OUT_OF_MEMORY; // Try to find the specific tile id from the free list. dtMeshTile* target = &m_tiles[tileIndex]; dtMeshTile* prev = 0; tile = m_nextFree; while (tile && tile != target) { prev = tile; tile = tile->next; } // Could not find the correct location. if (tile != target) return DT_FAILURE | DT_OUT_OF_MEMORY; // Remove from freelist if (!prev) m_nextFree = tile->next; else prev->next = tile->next; // Restore salt. tile->salt = decodePolyIdSalt((dtPolyRef)lastRef); } // 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); unsigned char* d = data + headerSize; tile->verts = (float*)d; d += vertsSize; tile->polys = (dtPoly*)d; d += polysSize; tile->links = (dtLink*)d; d += linksSize; tile->detailMeshes = (dtPolyDetail*)d; d += detailMeshesSize; tile->detailVerts = (float*)d; d += detailVertsSize; tile->detailTris = (unsigned char*)d; d += detailTrisSize; tile->bvTree = (dtBVNode*)d; d += bvtreeSize; tile->offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize; // If there are no items in the bvtree, reset the tree pointer. if (!bvtreeSize) tile->bvTree = 0; // Build links freelist tile->linksFreeList = 0; tile->links[header->maxLinkCount-1].next = DT_NULL_LINK; for (int i = 0; i < header->maxLinkCount-1; ++i) tile->links[i].next = i+1; // Init tile. tile->header = header; tile->data = data; tile->dataSize = dataSize; tile->flags = flags; connectIntLinks(tile); baseOffMeshLinks(tile); // Create connections with neighbour tiles. static const int MAX_NEIS = 32; dtMeshTile* neis[MAX_NEIS]; int nneis; // Connect with layers in current tile. nneis = getTilesAt(header->x, header->y, neis, MAX_NEIS); for (int j = 0; j < nneis; ++j) { if (neis[j] != tile) { connectExtLinks(tile, neis[j], -1); connectExtLinks(neis[j], tile, -1); } connectExtOffMeshLinks(tile, neis[j], -1); connectExtOffMeshLinks(neis[j], tile, -1); } // Connect with neighbour tiles. for (int i = 0; i < 8; ++i) { nneis = getNeighbourTilesAt(header->x, header->y, i, neis, MAX_NEIS); for (int j = 0; j < nneis; ++j) { connectExtLinks(tile, neis[j], i); connectExtLinks(neis[j], tile, dtOppositeTile(i)); connectExtOffMeshLinks(tile, neis[j], i); connectExtOffMeshLinks(neis[j], tile, dtOppositeTile(i)); } } if (result) *result = getTileRef(tile); return DT_SUCCESS; }
/// @par /// /// This function returns the data for the tile so that, if desired, /// it can be added back to the navigation mesh at a later point. /// /// @see #addTile dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSize) { if (!ref) return DT_FAILURE | DT_INVALID_PARAM; unsigned int tileIndex = decodePolyIdTile((dtPolyRef)ref); unsigned int tileSalt = decodePolyIdSalt((dtPolyRef)ref); if ((int)tileIndex >= m_maxTiles) return DT_FAILURE | DT_INVALID_PARAM; dtMeshTile* tile = &m_tiles[tileIndex]; if (tile->salt != tileSalt) return DT_FAILURE | DT_INVALID_PARAM; // Remove tile from hash lookup. int h = computeTileHash(tile->header->x,tile->header->y,m_tileLutMask); dtMeshTile* prev = 0; dtMeshTile* cur = m_posLookup[h]; while (cur) { if (cur == tile) { if (prev) prev->next = cur->next; else m_posLookup[h] = cur->next; break; } prev = cur; cur = cur->next; } // Remove connections to neighbour tiles. // Create connections with neighbour tiles. static const int MAX_NEIS = 32; dtMeshTile* neis[MAX_NEIS]; int nneis; // Connect with layers in current tile. nneis = getTilesAt(tile->header->x, tile->header->y, neis, MAX_NEIS); for (int j = 0; j < nneis; ++j) { if (neis[j] == tile) continue; unconnectExtLinks(neis[j], tile); } // Connect with neighbour tiles. for (int i = 0; i < 8; ++i) { nneis = getNeighbourTilesAt(tile->header->x, tile->header->y, i, neis, MAX_NEIS); for (int j = 0; j < nneis; ++j) unconnectExtLinks(neis[j], tile); } // Reset tile. if (tile->flags & DT_TILE_FREE_DATA) { // Owns data dtFree(tile->data); tile->data = 0; tile->dataSize = 0; if (data) *data = 0; if (dataSize) *dataSize = 0; } else { if (data) *data = tile->data; if (dataSize) *dataSize = tile->dataSize; } tile->header = 0; tile->flags = 0; tile->linksFreeList = 0; tile->polys = 0; tile->verts = 0; tile->links = 0; tile->detailMeshes = 0; tile->detailVerts = 0; tile->detailTris = 0; tile->bvTree = 0; tile->offMeshCons = 0; // Update salt, salt should never be zero. tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1); if (tile->salt == 0) tile->salt++; // Add to free list. tile->next = m_nextFree; m_nextFree = tile; return DT_SUCCESS; }
dtStatus dtNavMesh::removeTile(dtTileRef ref, unsigned char** data, int* dataSize) { if (!ref) return DT_FAILURE; unsigned int tileIndex = decodePolyIdTile((dtPolyRef)ref); unsigned int tileSalt = decodePolyIdSalt((dtPolyRef)ref); if ((int)tileIndex >= m_maxTiles) return DT_FAILURE; dtMeshTile* tile = &m_tiles[tileIndex]; if (tile->salt != tileSalt) return DT_FAILURE; // Remove tile from hash lookup. int h = computeTileHash(tile->header->x,tile->header->y,m_tileLutMask); dtMeshTile* prev = 0; dtMeshTile* cur = m_posLookup[h]; while (cur) { if (cur == tile) { if (prev) prev->next = cur->next; else m_posLookup[h] = cur->next; break; } prev = cur; cur = cur->next; } // Remove connections to neighbour tiles. for (int i = 0; i < 8; ++i) { dtMeshTile* nei = getNeighbourTileAt(tile->header->x,tile->header->y,i); if (!nei) continue; unconnectExtLinks(nei, dtOppositeTile(i)); } // Reset tile. if (tile->flags & DT_TILE_FREE_DATA) { // Owns data free(tile->data); tile->data = 0; tile->dataSize = 0; if (data) *data = 0; if (dataSize) *dataSize = 0; } else { if (data) *data = tile->data; if (dataSize) *dataSize = tile->dataSize; } tile->header = 0; tile->flags = 0; tile->linksFreeList = 0; tile->polys = 0; tile->verts = 0; tile->links = 0; tile->detailMeshes = 0; tile->detailVerts = 0; tile->detailTris = 0; tile->bvTree = 0; tile->offMeshCons = 0; // Update salt, salt should never be zero. tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1); if (tile->salt == 0) tile->salt++; // Add to free list. tile->next = m_nextFree; m_nextFree = tile; return DT_SUCCESS; }
dtStatus dtTileCache::removeTile(dtCompressedTileRef ref, unsigned char** data, int* dataSize) { if (!ref) return DT_FAILURE | DT_INVALID_PARAM; unsigned int tileIndex = decodeTileIdTile(ref); unsigned int tileSalt = decodeTileIdSalt(ref); if ((int)tileIndex >= m_params.maxTiles) return DT_FAILURE | DT_INVALID_PARAM; dtCompressedTile* tile = &m_tiles[tileIndex]; if (tile->salt != tileSalt) return DT_FAILURE | DT_INVALID_PARAM; // Remove tile from hash lookup. const int h = computeTileHash(tile->header->tx,tile->header->ty,m_tileLutMask); dtCompressedTile* prev = 0; dtCompressedTile* cur = m_posLookup[h]; while (cur) { if (cur == tile) { if (prev) prev->next = cur->next; else m_posLookup[h] = cur->next; break; } prev = cur; cur = cur->next; } // Reset tile. if (tile->flags & DT_COMPRESSEDTILE_FREE_DATA) { // Owns data dtFree(tile->data); tile->data = 0; tile->dataSize = 0; if (data) *data = 0; if (dataSize) *dataSize = 0; } else { if (data) *data = tile->data; if (dataSize) *dataSize = tile->dataSize; } tile->header = 0; tile->data = 0; tile->dataSize = 0; tile->compressed = 0; tile->compressedSize = 0; tile->flags = 0; // Update salt, salt should never be zero. tile->salt = (tile->salt+1) & ((1<<m_saltBits)-1); if (tile->salt == 0) tile->salt++; // Add to free list. tile->next = m_nextFreeTile; m_nextFreeTile = tile; return DT_SUCCESS; }
dtTileRef dtNavMesh::addTile(unsigned char* data, int dataSize, int flags, dtTileRef lastRef) { // Make sure the data is in right format. dtMeshHeader* header = (dtMeshHeader*)data; if (header->magic != DT_NAVMESH_MAGIC) return 0; if (header->version != DT_NAVMESH_VERSION) return 0; // Make sure the location is free. if (getTileAt(header->x, header->y)) return 0; // Allocate a tile. dtMeshTile* tile = 0; if (!lastRef) { if (m_nextFree) { tile = m_nextFree; m_nextFree = tile->next; tile->next = 0; } } else { // TODO: Better error reporting! // Try to relocate the tile to specific index with same salt. int tileIndex = (int)decodePolyIdTile((dtPolyRef)lastRef); if (tileIndex >= m_maxTiles) return 0; // Try to find the specific tile id from the free list. dtMeshTile* target = &m_tiles[tileIndex]; dtMeshTile* prev = 0; tile = m_nextFree; while (tile && tile != target) { prev = tile; tile = tile->next; } // Could not find the correct location. if (tile != target) return 0; // Remove from freelist if (!prev) m_nextFree = tile->next; else prev->next = tile->next; // Restore salt. tile->salt = decodePolyIdSalt((dtPolyRef)lastRef); } // Make sure we could allocate a tile. if (!tile) return 0; // 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); unsigned char* d = data + headerSize; tile->verts = (float*)d; d += vertsSize; tile->polys = (dtPoly*)d; d += polysSize; tile->links = (dtLink*)d; d += linksSize; tile->detailMeshes = (dtPolyDetail*)d; d += detailMeshesSize; tile->detailVerts = (float*)d; d += detailVertsSize; tile->detailTris = (unsigned char*)d; d += detailTrisSize; tile->bvTree = (dtBVNode*)d; d += bvtreeSize; tile->offMeshCons = (dtOffMeshConnection*)d; d += offMeshLinksSize; // 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; // Init tile. tile->header = header; tile->data = data; tile->dataSize = dataSize; tile->flags = flags; connectIntLinks(tile); connectIntOffMeshLinks(tile); // Create connections connections. for (int i = 0; i < 8; ++i) { dtMeshTile* nei = getNeighbourTileAt(header->x, header->y, i); if (nei) { connectExtLinks(tile, nei, i); connectExtLinks(nei, tile, opposite(i)); connectExtOffMeshLinks(tile, nei, i); connectExtOffMeshLinks(nei, tile, opposite(i)); } } return getTileRef(tile); }