mirror of https://github.com/OpenRCT2/OpenRCT2.git
Close #16840: Add support for rectangular heightmaps
This commit is contained in:
parent
43bc0b0cd9
commit
0392925450
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue