void dtProximityGrid::addItem(const unsigned short id, const float minx, const float miny, const float maxx, const float maxy) { const int iminx = (int)dtMathFloorf(minx * m_invCellSize); const int iminy = (int)dtMathFloorf(miny * m_invCellSize); const int imaxx = (int)dtMathFloorf(maxx * m_invCellSize); const int imaxy = (int)dtMathFloorf(maxy * m_invCellSize); m_bounds[0] = dtMin(m_bounds[0], iminx); m_bounds[1] = dtMin(m_bounds[1], iminy); m_bounds[2] = dtMax(m_bounds[2], imaxx); m_bounds[3] = dtMax(m_bounds[3], imaxy); for (int y = iminy; y <= imaxy; ++y) { for (int x = iminx; x <= imaxx; ++x) { if (m_poolHead < m_poolSize) { const int h = hashPos2(x, y, m_bucketsSize); const unsigned short idx = (unsigned short)m_poolHead; m_poolHead++; Item& item = m_pool[idx]; item.x = (short)x; item.y = (short)y; item.id = id; item.next = m_buckets[h]; m_buckets[h] = idx; } } } }
void dtNavMesh::queryTiles(const float bmin[3], const float bmax[3], dtTileCallback callback, void * userdata) const { const int tx0 = (int)dtMathFloorf((bmin[0]-m_params.orig[0]) / m_tileWidth); const int tx1 = (int)dtMathFloorf((bmax[0]-m_params.orig[0]) / m_tileWidth); const int ty0 = (int)dtMathFloorf((bmin[2]-m_params.orig[2]) / m_tileHeight); const int ty1 = (int)dtMathFloorf((bmax[2]-m_params.orig[2]) / m_tileHeight); for (int ty = ty0; ty <= ty1; ++ty) { for (int tx = tx0; tx <= tx1; ++tx) { enum { MaxTiles = 32 }; const dtMeshTile * tmpTiles[ MaxTiles ]; const int ntiles = getTilesAt(tx,ty,tmpTiles,MaxTiles); for (int i = 0; i < ntiles; ++i) { if (dtOverlapBounds(bmin,bmax, tmpTiles[ i ]->header->bmin, tmpTiles[ i ]->header->bmax)) { callback( tmpTiles[i], userdata ); } } } } }
int dtProximityGrid::queryItems(const float minx, const float miny, const float maxx, const float maxy, unsigned short* ids, const int maxIds) const { const int iminx = (int)dtMathFloorf(minx * m_invCellSize); const int iminy = (int)dtMathFloorf(miny * m_invCellSize); const int imaxx = (int)dtMathFloorf(maxx * m_invCellSize); const int imaxy = (int)dtMathFloorf(maxy * m_invCellSize); int n = 0; for (int y = iminy; y <= imaxy; ++y) { for (int x = iminx; x <= imaxx; ++x) { const int h = hashPos2(x, y, m_bucketsSize); unsigned short idx = m_buckets[h]; while (idx != 0xffff) { Item& item = m_pool[idx]; if ((int)item.x == x && (int)item.y == y) { // Check if the id exists already. const unsigned short* end = ids + n; unsigned short* i = ids; while (i != end && *i != item.id) ++i; // Item not found, add it. if (i == end) { if (n >= maxIds) return n; ids[n++] = item.id; } } idx = item.next; } } } return n; }
dtStatus dtTileCache::queryTiles(const float* bmin, const float* bmax, dtCompressedTileRef* results, int* resultCount, const int maxResults) const { const int MAX_TILES = 32; dtCompressedTileRef tiles[MAX_TILES]; int n = 0; const float tw = m_params.width * m_params.cs; const float th = m_params.height * m_params.cs; const int tx0 = (int)dtMathFloorf((bmin[0]-m_params.orig[0]) / tw); const int tx1 = (int)dtMathFloorf((bmax[0]-m_params.orig[0]) / tw); const int ty0 = (int)dtMathFloorf((bmin[2]-m_params.orig[2]) / th); const int ty1 = (int)dtMathFloorf((bmax[2]-m_params.orig[2]) / th); for (int ty = ty0; ty <= ty1; ++ty) { for (int tx = tx0; tx <= tx1; ++tx) { const int ntiles = getTilesAt(tx,ty,tiles,MAX_TILES); for (int i = 0; i < ntiles; ++i) { const dtCompressedTile* tile = &m_tiles[decodeTileIdTile(tiles[i])]; float tbmin[3], tbmax[3]; calcTightTileBounds(tile->header, tbmin, tbmax); if (dtOverlapBounds(bmin,bmax, tbmin,tbmax)) { if (n < maxResults) results[n++] = tiles[i]; } } } } *resultCount = n; return DT_SUCCESS; }
static int createBVTree(const unsigned short* verts, const int /*nverts*/, const unsigned short* polys, const int npolys, const int nvp, const float cs, const float ch, const int /*nnodes*/, dtBVNode* nodes) { // Build tree BVItem* items = (BVItem*)dtAlloc(sizeof(BVItem)*npolys, DT_ALLOC_TEMP); for (int i = 0; i < npolys; i++) { BVItem& it = items[i]; it.i = i; // Calc polygon bounds. const unsigned short* p = &polys[i*nvp*2]; it.bmin[0] = it.bmax[0] = verts[p[0]*3+0]; it.bmin[1] = it.bmax[1] = verts[p[0]*3+1]; it.bmin[2] = it.bmax[2] = verts[p[0]*3+2]; for (int j = 1; j < nvp; ++j) { if (p[j] == MESH_NULL_IDX) break; unsigned short x = verts[p[j]*3+0]; unsigned short y = verts[p[j]*3+1]; unsigned short z = verts[p[j]*3+2]; if (x < it.bmin[0]) it.bmin[0] = x; if (y < it.bmin[1]) it.bmin[1] = y; if (z < it.bmin[2]) it.bmin[2] = z; if (x > it.bmax[0]) it.bmax[0] = x; if (y > it.bmax[1]) it.bmax[1] = y; if (z > it.bmax[2]) it.bmax[2] = z; } // Remap y it.bmin[1] = (unsigned short)dtMathFloorf((float)it.bmin[1]*ch/cs); it.bmax[1] = (unsigned short)dtMathCeilf((float)it.bmax[1]*ch/cs); } int curNode = 0; subdivide(items, npolys, 0, npolys, curNode, nodes); dtFree(items); return curNode; }
//----------------------------------------------------------------------------- // Purpose: Partial rebuild. Destroys tiles at bounds touching the mesh and // rebuilds those tiles. //----------------------------------------------------------------------------- bool CRecastMesh::RebuildPartial( CMapMesh *pMapMesh, const Vector &vMins, const Vector &vMaxs ) { double fStartTime = Plat_FloatTime(); BuildContext ctx; dtStatus status; const dtTileCacheParams &tcparams = *m_tileCache->getParams(); float bmin[3]; float bmax[3]; bmin[0] = vMins.x; bmin[1] = vMins.z; bmin[2] = vMins.y; bmax[0] = vMaxs.x; bmax[1] = vMaxs.z; bmax[2] = vMaxs.y; const float tw = tcparams.width * tcparams.cs; const float th = tcparams.height * tcparams.cs; const int tx0 = (int)dtMathFloorf((bmin[0]-tcparams.orig[0]) / tw); const int tx1 = (int)dtMathFloorf((bmax[0]-tcparams.orig[0]) / tw); const int ty0 = (int)dtMathFloorf((bmin[2]-tcparams.orig[2]) / th); const int ty1 = (int)dtMathFloorf((bmax[2]-tcparams.orig[2]) / th); TileCacheData tiles[MAX_LAYERS]; int ntiles; dtCompressedTileRef results[128]; for (int ty = ty0; ty <= ty1; ++ty) { for (int tx = tx0; tx <= tx1; ++tx) { int nCount = m_tileCache->getTilesAt( tx, ty, results, 128 ); for( int i = 0; i < nCount; i++ ) { unsigned char* data; int dataSize; m_tileCache->removeTile( results[i], &data, &dataSize ); } memset(tiles, 0, sizeof(tiles)); ntiles = rasterizeTileLayers(&ctx, pMapMesh, tx, ty, m_cfg, tiles, MAX_LAYERS); for (int i = 0; i < ntiles; ++i) { TileCacheData* tile = &tiles[i]; status = m_tileCache->addTile(tile->data, tile->dataSize, DT_COMPRESSEDTILE_FREE_DATA, 0); if (dtStatusFailed(status)) { dtFree(tile->data); tile->data = 0; continue; } } } } // Build initial meshes for (int ty = ty0; ty <= ty1; ++ty) { for (int tx = tx0; tx <= tx1; ++tx) { m_tileCache->buildNavMeshTilesAt(tx,ty, m_navMesh); } } if( recast_build_partial_debug.GetBool() ) DevMsg( "CRecastMesh: Generated partial mesh update %s in %f seconds\n", m_Name.Get(), Plat_FloatTime() - fStartTime ); return true; }