Close #16840: Add support for rectangular heightmaps

This commit is contained in:
Hielke Morsink 2022-07-28 22:24:37 +02:00 committed by GitHub
parent 43bc0b0cd9
commit 0392925450
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 35 additions and 28 deletions

View File

@ -3205,7 +3205,6 @@ STR_6047 :Smooth tiles
STR_6048 :Height map error
STR_6049 :Error reading PNG
STR_6050 :Error reading bitmap
STR_6051 :The width and height need to match
STR_6052 :The heightmap is too big, and will be cut off
STR_6053 :The heightmap cannot be normalised
STR_6054 :Only 24-bit bitmaps are supported

View File

@ -3,8 +3,9 @@
- Feature: [#13634] Add ability to sell merchandise in random colours.
- Feature: [#16662] Show a warning message when g2.dat is mismatched.
- Feature: [#17107] Ride operating settings can be set via text input.
- Improvement: [#15358] Park and scenario names can now contain up to 128 characters.
- Improvement: [#17575] You can now search for Authors in Object Selection.
- Improved: [#15358] Park and scenario names can now contain up to 128 characters.
- Improved: [#16840] Add support for rectangular heightmaps.
- Improved: [#17575] You can now search for Authors in Object Selection.
- Change: [#17319] Giant screenshots are now cropped to the horizontal view-clipping selection.
- Change: [#17499] Update error text when using vehicle incompatible with TD6 and add error when using incompatible track elements.
- Fix: [#7466] Coaster track not drawn at tunnel exit.

View File

@ -3342,7 +3342,7 @@ enum : uint16_t
STR_HEIGHT_MAP_ERROR = 6048,
STR_ERROR_READING_PNG = 6049,
STR_ERROR_READING_BITMAP = 6050,
STR_ERROR_WIDTH_AND_HEIGHT_DO_NOT_MATCH = 6051,
STR_ERROR_HEIHGT_MAP_TOO_BIG = 6052,
STR_ERROR_CANNOT_NORMALIZE = 6053,
STR_ERROR_24_BIT_BITMAP = 6054,

View File

@ -668,6 +668,15 @@ static void mapgen_simplex(mapgen_settings* settings)
#pragma region Heightmap
/**
* Return the tile coordinate that matches the given pixel of a heightmap
*/
static TileCoordsXY MapgenHeightmapCoordToTileCoordsXY(uint32_t x, uint32_t y)
{
// The height map does not include the empty tiles around the map, so we add 1.
return TileCoordsXY(static_cast<int32_t>(y + 1), static_cast<int32_t>(x + 1));
}
bool mapgen_load_heightmap(const utf8* path)
{
auto format = Imaging::GetImageFormatFromPath(path);
@ -680,23 +689,17 @@ bool mapgen_load_heightmap(const utf8* path)
try
{
auto image = Imaging::ReadFromFile(path, format);
if (image.Width != image.Height)
{
context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_WIDTH_AND_HEIGHT_DO_NOT_MATCH, {});
return false;
}
auto size = image.Width;
if (image.Width > MAXIMUM_MAP_SIZE_PRACTICAL)
auto width = std::min<uint32_t>(image.Width, MAXIMUM_MAP_SIZE_PRACTICAL);
auto height = std::min<uint32_t>(image.Height, MAXIMUM_MAP_SIZE_PRACTICAL);
if (width != image.Width || height != image.Height)
{
context_show_error(STR_HEIGHT_MAP_ERROR, STR_ERROR_HEIHGT_MAP_TOO_BIG, {});
size = std::min<uint32_t>(image.Height, MAXIMUM_MAP_SIZE_PRACTICAL);
}
// Allocate memory for the height map values, one byte pixel
_heightMapData.mono_bitmap.resize(size * size);
_heightMapData.width = size;
_heightMapData.height = size;
_heightMapData.mono_bitmap.resize(width * height);
_heightMapData.width = width;
_heightMapData.height = height;
// Copy average RGB value to mono bitmap
constexpr auto numChannels = 4;
@ -790,15 +793,16 @@ static void mapgen_smooth_heightmap(std::vector<uint8_t>& src, int32_t strength)
void mapgen_generate_from_heightmap(mapgen_settings* settings)
{
openrct2_assert(_heightMapData.width == _heightMapData.height, "Invalid height map size");
openrct2_assert(!_heightMapData.mono_bitmap.empty(), "No height map loaded");
openrct2_assert(settings->simplex_high != settings->simplex_low, "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;
auto maxSize = static_cast<int32_t>(_heightMapData.width + 2); // + 2 for the black tiles around the map
map_init({ maxSize, maxSize });
// Get technical map size, +2 for the black tiles around the map
auto maxWidth = static_cast<int32_t>(_heightMapData.width + 2);
auto maxHeight = static_cast<int32_t>(_heightMapData.height + 2);
map_init({ maxHeight, maxWidth });
if (settings->smooth_height_map)
{
@ -841,8 +845,8 @@ void mapgen_generate_from_heightmap(mapgen_settings* settings)
for (uint32_t x = 0; x < _heightMapData.width; x++)
{
// The x and y axis are flipped in the world, so this uses y for x and x for y.
auto* const surfaceElement = map_get_surface_element_at(
TileCoordsXY{ static_cast<int32_t>(y + 1), static_cast<int32_t>(x + 1) }.ToCoordsXY());
auto tileCoords = MapgenHeightmapCoordToTileCoordsXY(x, y);
auto* const surfaceElement = map_get_surface_element_at(tileCoords.ToCoordsXY());
if (surfaceElement == nullptr)
continue;
@ -871,11 +875,12 @@ void mapgen_generate_from_heightmap(mapgen_settings* settings)
while (true)
{
uint32_t numTilesChanged = 0;
for (uint32_t y = 1; y <= _heightMapData.height; y++)
for (uint32_t y = 0; y < _heightMapData.height; y++)
{
for (uint32_t x = 1; x <= _heightMapData.width; x++)
for (uint32_t x = 0; x < _heightMapData.width; x++)
{
numTilesChanged += tile_smooth(x, y);
auto tileCoords = MapgenHeightmapCoordToTileCoordsXY(x, y);
numTilesChanged += tile_smooth(tileCoords);
}
}

View File

@ -198,9 +198,9 @@ int32_t map_smooth(int32_t l, int32_t t, int32_t r, int32_t b)
* This does not change the base height, unless all corners have been raised.
* @returns 0 if no edits were made, 1 otherwise
*/
int32_t tile_smooth(int32_t x, int32_t y)
int32_t tile_smooth(const TileCoordsXY& tileCoords)
{
auto* const surfaceElement = map_get_surface_element_at(TileCoordsXY{ x, y }.ToCoordsXY());
auto* const surfaceElement = map_get_surface_element_at(tileCoords.ToCoordsXY());
if (surfaceElement == nullptr)
return 0;
@ -241,7 +241,8 @@ int32_t tile_smooth(int32_t x, int32_t y)
continue;
// Get neighbour height. If the element is not valid (outside of map) assume the same height
auto* neighbourSurfaceElement = map_get_surface_element_at(TileCoordsXY{ x + x_offset, y + y_offset }.ToCoordsXY());
auto* neighbourSurfaceElement = map_get_surface_element_at(
(tileCoords + TileCoordsXY{ x_offset, y_offset }).ToCoordsXY());
neighbourHeightOffset.baseheight[index] = neighbourSurfaceElement != nullptr ? neighbourSurfaceElement->base_height
: surfaceElement->base_height;

View File

@ -10,6 +10,7 @@
#pragma once
#include "../common.h"
#include "Location.hpp"
enum
{
@ -20,4 +21,4 @@ enum
};
int32_t map_smooth(int32_t l, int32_t t, int32_t r, int32_t b);
int32_t tile_smooth(int32_t x, int32_t y);
int32_t tile_smooth(const TileCoordsXY& tileCoords);