diff --git a/src/pathfinder/water_regions.cpp b/src/pathfinder/water_regions.cpp index 2b1a9842b2..47856f6fe8 100644 --- a/src/pathfinder/water_regions.cpp +++ b/src/pathfinder/water_regions.cpp @@ -19,7 +19,6 @@ #include "follow_track.hpp" #include "ship.h" -#include #include using TWaterRegionTraversabilityBits = uint16_t; @@ -68,6 +67,8 @@ struct WaterRegionTileIterator { } }; +using TWaterRegionPatchLabelArray = std::array; + /** * Represents a square section of the map of a fixed size. Within this square individual unconnected patches of water are * identified using a Connected Component Labeling (CCL) algorithm. Note that all information stored in this class applies @@ -79,12 +80,14 @@ class WaterRegion friend class WaterRegionReference; std::array edge_traversability_bits{}; + bool initialized = false; bool has_cross_region_aqueducts = false; TWaterRegionPatchLabel number_of_patches = 0; // 0 = no water, 1 = one single patch of water, etc... - std::array tile_patch_labels{}; - bool initialized = false; + std::unique_ptr tile_patch_labels; }; +static std::unique_ptr _spare_labels; + class WaterRegionReference { const uint32_t tile_x; const uint32_t tile_y; @@ -110,6 +113,14 @@ class WaterRegionReference { return (TileX(tile) - this->tile_x) + WATER_REGION_EDGE_LENGTH * (TileY(tile) - this->tile_y); } + inline bool HasNonMatchingPatchLabel(TWaterRegionPatchLabel expected_label) const + { + for (TWaterRegionPatchLabel label : *this->wr.tile_patch_labels) { + if (label != expected_label) return true; + } + return false; + } + public: WaterRegionReference(uint32_t region_x, uint32_t region_y, WaterRegion &wr) : tile_x(region_x * WATER_REGION_EDGE_LENGTH), tile_y(region_y * WATER_REGION_EDGE_LENGTH), wr(wr) @@ -150,7 +161,10 @@ public: TWaterRegionPatchLabel GetLabel(TileIndex tile) const { assert(this->ContainsTile(tile)); - return this->wr.tile_patch_labels[this->GetLocalIndex(tile)]; + if (this->wr.tile_patch_labels == nullptr) { + return this->NumberOfPatches() == 0 ? INVALID_WATER_REGION_PATCH : 1; + } + return (*this->wr.tile_patch_labels)[this->GetLocalIndex(tile)]; } /** @@ -161,7 +175,15 @@ public: { this->wr.has_cross_region_aqueducts = false; - this->wr.tile_patch_labels.fill(INVALID_WATER_REGION_PATCH); + if (this->wr.tile_patch_labels == nullptr) { + if (_spare_labels != nullptr) { + this->wr.tile_patch_labels = std::move(_spare_labels); + } else { + this->wr.tile_patch_labels = std::make_unique(); + } + } + + this->wr.tile_patch_labels->fill(INVALID_WATER_REGION_PATCH); TWaterRegionPatchLabel current_label = 1; TWaterRegionPatchLabel highest_assigned_label = 0; @@ -188,9 +210,10 @@ public: const TrackdirBits valid_dirs = TrackBitsToTrackdirBits(GetWaterTracks(tile)); if (valid_dirs == TRACKDIR_BIT_NONE) continue; - if (this->wr.tile_patch_labels[GetLocalIndex(tile)] != INVALID_WATER_REGION_PATCH) continue; + TWaterRegionPatchLabel &tile_patch = (*this->wr.tile_patch_labels)[GetLocalIndex(tile)]; + if (tile_patch != INVALID_WATER_REGION_PATCH) continue; - this->wr.tile_patch_labels[GetLocalIndex(tile)] = current_label; + tile_patch = current_label; highest_assigned_label = current_label; increase_label = true; @@ -218,6 +241,11 @@ public: if (GetWaterTracks(TileXY(top_x, top_y + i)) & TRACK_BIT_3WAY_NE) SetBit(this->wr.edge_traversability_bits[DIAGDIR_NE], i); // NE edge if (GetWaterTracks(TileXY(top_x + WATER_REGION_EDGE_LENGTH - 1, top_y + i)) & TRACK_BIT_3WAY_SW) SetBit(this->wr.edge_traversability_bits[DIAGDIR_SW], i); // SW edge } + + if (this->wr.number_of_patches == 0 || (this->wr.number_of_patches == 1 && !this->HasNonMatchingPatchLabel(1))) { + /* No need for patch storage: trivial cases */ + _spare_labels = std::move(this->wr.tile_patch_labels); + } } /** @@ -228,9 +256,9 @@ public: if (!this->wr.initialized) this->ForceUpdate(); } - inline uint32_t CountPatchLabelOccurence(TWaterRegionPatchLabel label) const + inline bool HasPatchStorage() const { - return std::count(this->wr.tile_patch_labels.begin(), this->wr.tile_patch_labels.end(), label); + return this->wr.tile_patch_labels != nullptr; } }; @@ -428,9 +456,7 @@ uint GetWaterRegionTileDebugColourIndex(TileIndex tile) case 1: { const WaterRegionReference wr = GetWaterRegionRef(tile); - if (!wr.IsInitialized()) return 0; - - if (wr.CountPatchLabelOccurence(1) == WATER_REGION_NUMBER_OF_TILES) return 2; + if (wr.HasPatchStorage()) return 2; return 0; }