diff --git a/src/openrct2/world/map_generator/HeightMap.hpp b/src/openrct2/world/map_generator/HeightMap.hpp index 1ff4e86189..93723b9a72 100644 --- a/src/openrct2/world/map_generator/HeightMap.hpp +++ b/src/openrct2/world/map_generator/HeightMap.hpp @@ -24,17 +24,17 @@ namespace OpenRCT2::World::MapGenerator std::vector _height; public: - const uint16_t width; - const uint16_t height; + uint16_t width{}; + uint16_t height{}; - HeightMap(int32_t tagetWidth, int32_t targetHeight) - : _height(tagetWidth * targetHeight) - , width(tagetWidth) + HeightMap(int32_t targetWidth, int32_t targetHeight) + : _height(targetWidth * targetHeight) + , width(targetWidth) , height(targetHeight) { } - HeightMap(const HeightMap& heightMap) = default; + HeightMap() = default; uint8_t& operator[](TileCoordsXY pos) { @@ -48,6 +48,11 @@ namespace OpenRCT2::World::MapGenerator return _height[pos.y * width + pos.x]; } + void clear() + { + _height.clear(); + } + uint8_t* data() { return _height.data(); @@ -58,6 +63,11 @@ namespace OpenRCT2::World::MapGenerator return _height.data(); } + bool empty() const + { + return _height.empty(); + } + size_t size() const { return _height.size(); diff --git a/src/openrct2/world/map_generator/PngTerrainGenerator.cpp b/src/openrct2/world/map_generator/PngTerrainGenerator.cpp index 31cd3096b2..75e2d26fb7 100644 --- a/src/openrct2/world/map_generator/PngTerrainGenerator.cpp +++ b/src/openrct2/world/map_generator/PngTerrainGenerator.cpp @@ -17,6 +17,7 @@ #include "../../localisation/StringIds.h" #include "../Map.h" #include "../tile_element/SurfaceElement.h" +#include "HeightMap.hpp" #include "MapGen.h" #include "MapHelpers.h" #include "SurfaceSelection.h" @@ -25,12 +26,7 @@ namespace OpenRCT2::World::MapGenerator { - static struct - { - uint32_t width = 0; - uint32_t height = 0; - std::vector mono_bitmap; - } _heightMapData; + static HeightMap _heightMapData{}; /** * Return the tile coordinate that matches the given pixel of a heightmap @@ -61,9 +57,7 @@ namespace OpenRCT2::World::MapGenerator } // Allocate memory for the height map values, one byte pixel - _heightMapData.mono_bitmap.resize(width * height); - _heightMapData.width = width; - _heightMapData.height = height; + _heightMapData = HeightMap(width, height); // Copy average RGB value to mono bitmap constexpr auto numChannels = 4; @@ -76,7 +70,7 @@ namespace OpenRCT2::World::MapGenerator const auto red = pixels[x * numChannels + y * pitch]; const auto green = pixels[x * numChannels + y * pitch + 1]; const auto blue = pixels[x * numChannels + y * pitch + 2]; - _heightMapData.mono_bitmap[x + y * _heightMapData.width] = (red + green + blue) / 3; + _heightMapData[TileCoordsXY(x, y)] = (red + green + blue) / 3; } } return true; @@ -104,25 +98,23 @@ namespace OpenRCT2::World::MapGenerator */ void UnloadHeightmapImage() { - _heightMapData.mono_bitmap.clear(); - _heightMapData.width = 0; - _heightMapData.height = 0; + _heightMapData.clear(); } /** * Applies box blur to the surface N times */ - static void SmoothHeightmap(std::vector& src, int32_t strength) + static void SmoothHeightmap(HeightMap& src, int32_t strength) { // Create buffer to store one channel - std::vector dest(src.size()); + HeightMap temp{ src.width, src.height }; for (int32_t i = 0; i < strength; i++) { // Calculate box blur value to all pixels of the surface - for (uint32_t y = 0; y < _heightMapData.height; y++) + for (auto y = 0; y < temp.height; y++) { - for (uint32_t x = 0; x < _heightMapData.width; x++) + for (auto x = 0; x < temp.width; x++) { uint32_t heightSum = 0; @@ -133,23 +125,23 @@ namespace OpenRCT2::World::MapGenerator { // Clamp x and y so they stay within the image // This assumes the height map is not tiled, and increases the weight of the edges - const int32_t readX = std::clamp(x + offsetX, 0, _heightMapData.width - 1); - const int32_t readY = std::clamp(y + offsetY, 0, _heightMapData.height - 1); - heightSum += src[readX + readY * _heightMapData.width]; + const auto readX = std::clamp(x + offsetX, 0, temp.width - 1); + const auto readY = std::clamp(y + offsetY, 0, temp.height - 1); + heightSum += src[{ readX, readY }]; } } // Take average - dest[x + y * _heightMapData.width] = heightSum / 9; + temp[{ x, y }] = heightSum / 9; } } - // Now apply the blur to the source pixels - for (uint32_t y = 0; y < _heightMapData.height; y++) + // Now copy the blur to the source pixels + for (auto y = 0; y < temp.height; y++) { - for (uint32_t x = 0; x < _heightMapData.width; x++) + for (auto x = 0; x < temp.width; x++) { - src[x + y * _heightMapData.width] = dest[x + y * _heightMapData.width]; + src[{ x, y }] = temp[{ x, y }]; } } } @@ -157,15 +149,15 @@ namespace OpenRCT2::World::MapGenerator void GenerateFromHeightmapImage(Settings* settings) { - Guard::Assert(!_heightMapData.mono_bitmap.empty(), "No height map loaded"); + Guard::Assert(!_heightMapData.empty(), "No height map loaded"); Guard::Assert(settings->heightmapHigh != settings->heightmapLow, "Low and high setting cannot be the same"); // Make a copy of the original height map that we can edit - auto dest = _heightMapData.mono_bitmap; + HeightMap dest = _heightMapData; // Get technical map size, +2 for the black tiles around the map - auto maxWidth = static_cast(_heightMapData.width + 2); - auto maxHeight = static_cast(_heightMapData.height + 2); + auto maxWidth = static_cast(dest.width + 2); + auto maxHeight = static_cast(dest.height + 2); MapInit({ maxHeight, maxWidth }); if (settings->smooth_height_map) @@ -180,12 +172,12 @@ namespace OpenRCT2::World::MapGenerator { // Get highest and lowest pixel value maxValue = 0; - minValue = 0xff; - for (uint32_t y = 0; y < _heightMapData.height; y++) + minValue = 255; + for (auto y = 0; y < dest.height; y++) { - for (uint32_t x = 0; x < _heightMapData.width; x++) + for (auto x = 0; x < dest.width; x++) { - uint8_t value = dest[x + y * _heightMapData.width]; + uint8_t value = dest[{ x, y }]; maxValue = std::max(maxValue, value); minValue = std::min(minValue, value); } @@ -207,9 +199,9 @@ namespace OpenRCT2::World::MapGenerator const uint8_t rangeIn = maxValue - minValue; const uint8_t rangeOut = (settings->heightmapHigh - settings->heightmapLow) * 2; - for (uint32_t y = 0; y < _heightMapData.height; y++) + for (auto y = 0; y < dest.height; y++) { - for (uint32_t x = 0; x < _heightMapData.width; x++) + for (auto x = 0; x < dest.width; x++) { // The x and y axis are flipped in the world, so this uses y for x and x for y. auto tileCoords = HeightmapCoordToTileCoordsXY(x, y); @@ -218,7 +210,7 @@ namespace OpenRCT2::World::MapGenerator continue; // Read value from bitmap, and convert its range - uint8_t value = dest[x + y * _heightMapData.width]; + uint8_t value = dest[{ x, y }]; value = static_cast(static_cast(value - minValue) / rangeIn * rangeOut) + (settings->heightmapLow * 2); surfaceElement->BaseHeight = value; @@ -247,9 +239,9 @@ namespace OpenRCT2::World::MapGenerator while (true) { uint32_t numTilesChanged = 0; - for (uint32_t y = 0; y < _heightMapData.height; y++) + for (auto y = 0; y < dest.height; y++) { - for (uint32_t x = 0; x < _heightMapData.width; x++) + for (auto x = 0; x < dest.width; x++) { auto tileCoords = HeightmapCoordToTileCoordsXY(x, y); numTilesChanged += TileSmooth(tileCoords);