void World::GenerateAccessibleTileSurface(EUnitType parUnitType) { if (unitTypeToAccessibleSurface.count(parUnitType) > 0) SDL_FreeSurface(unitTypeToAccessibleSurface[parUnitType]); unitTypeToAccessibleSurface[parUnitType] = SDL_CreateRGBSurface(SDL_HWSURFACE, width_ * BUILD_TILE_SIZE, height_ * BUILD_TILE_SIZE, screen->format->BitsPerPixel, screen->format->Rmask, screen->format->Gmask, screen->format->Bmask, screen->format->Amask); assert(unitTypeToAccessibleSurface[parUnitType]); SDL_Rect dst = { 0, 0, BUILD_TILE_SIZE, BUILD_TILE_SIZE }; int2 unitDimension(unitTypeToUnitDesc[parUnitType].width, unitTypeToUnitDesc[parUnitType].height); for (size_t x = 0; x < width_; ++x) for (size_t y = 0; y < height_; ++y) { if (!IsBuildTileAccessible(BuildTile(x, y), unitDimension)) { dst.x = x * BUILD_TILE_SIZE; dst.y = y * BUILD_TILE_SIZE; SDL_FillRect(unitTypeToAccessibleSurface[parUnitType], &dst, 0x00ff0000); } else { SDL_Rect buildTileRect = { x * BUILD_TILE_SIZE, y * BUILD_TILE_SIZE, BUILD_TILE_SIZE, BUILD_TILE_SIZE}; SDL_FillRect(unitTypeToAccessibleSurface[parUnitType], &buildTileRect, ((x + y) % 2) ? 0x000000ff : 0x00ffffff); } } }
bool NavigationMesh::Build(const BoundingBox& boundingBox) { PROFILE(BuildPartialNavigationMesh); if (!node_) return false; if (!navMesh_) { LOGERROR("Navigation mesh must first be built fully before it can be partially rebuilt"); return false; } if (!node_->GetWorldScale().Equals(Vector3::ONE)) LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended"); BoundingBox localSpaceBox = boundingBox.Transformed(node_->GetWorldTransform().Inverse()); float tileEdgeLength = (float)tileSize_ * cellSize_; Vector<NavigationGeometryInfo> geometryList; CollectGeometries(geometryList); int sx = Clamp((int)((localSpaceBox.min_.x_ - boundingBox_.min_.x_) / tileEdgeLength), 0, numTilesX_ - 1); int sz = Clamp((int)((localSpaceBox.min_.z_ - boundingBox_.min_.z_) / tileEdgeLength), 0, numTilesZ_ - 1); int ex = Clamp((int)((localSpaceBox.max_.x_ - boundingBox_.min_.x_) / tileEdgeLength), 0, numTilesX_ - 1); int ez = Clamp((int)((localSpaceBox.max_.z_ - boundingBox_.min_.z_) / tileEdgeLength), 0, numTilesZ_ - 1); unsigned numTiles = 0; for (int z = sz; z <= ez; ++z) { for (int x = sx; x <= ex; ++x) { if (BuildTile(geometryList, x, z)) ++numTiles; } } LOGDEBUG("Rebuilt " + String(numTiles) + " tiles of the navigation mesh"); return true; }
bool NavigationMesh::Build() { PROFILE(BuildNavigationMesh); // Release existing navigation data and zero the bounding box ReleaseNavigationMesh(); if (!node_) return false; if (!node_->GetWorldScale().Equals(Vector3::ONE)) LOGWARNING("Navigation mesh root node has scaling. Agent parameters may not work as intended"); Vector<NavigationGeometryInfo> geometryList; CollectGeometries(geometryList); if (geometryList.Empty()) return true; // Nothing to do // Build the combined bounding box for (unsigned i = 0; i < geometryList.Size(); ++i) boundingBox_.Merge(geometryList[i].boundingBox_); // Expand bounding box by padding boundingBox_.min_ -= padding_; boundingBox_.max_ += padding_; { PROFILE(BuildNavigationMesh); // Calculate number of tiles int gridW = 0, gridH = 0; float tileEdgeLength = (float)tileSize_ * cellSize_; rcCalcGridSize(&boundingBox_.min_.x_, &boundingBox_.max_.x_, cellSize_, &gridW, &gridH); numTilesX_ = (gridW + tileSize_ - 1) / tileSize_; numTilesZ_ = (gridH + tileSize_ - 1) / tileSize_; // Calculate max. number of tiles and polygons, 22 bits available to identify both tile & polygon within tile unsigned maxTiles = NextPowerOfTwo(numTilesX_ * numTilesZ_); unsigned tileBits = 0; unsigned temp = maxTiles; while (temp > 1) { temp >>= 1; ++tileBits; } unsigned maxPolys = 1 << (22 - tileBits); dtNavMeshParams params; rcVcopy(params.orig, &boundingBox_.min_.x_); params.tileWidth = tileEdgeLength; params.tileHeight = tileEdgeLength; params.maxTiles = maxTiles; params.maxPolys = maxPolys; navMesh_ = dtAllocNavMesh(); if (!navMesh_) { LOGERROR("Could not allocate navigation mesh"); return false; } if (dtStatusFailed(navMesh_->init(¶ms))) { LOGERROR("Could not initialize navigation mesh"); ReleaseNavigationMesh(); return false; } // Build each tile unsigned numTiles = 0; for (int z = 0; z < numTilesZ_; ++z) { for (int x = 0; x < numTilesX_; ++x) { if (BuildTile(geometryList, x, z)) ++numTiles; } } LOGDEBUG("Built navigation mesh with " + String(numTiles) + " tiles"); return true; } }