23#include "table/strings.h"
41static const uint MAX_HEIGHTMAP_SIZE_PIXELS = 256 << 20;
47static_assert(MAX_HEIGHTMAP_SIZE_PIXELS < UINT32_MAX / 8);
60 return (uint64_t)width * height <= MAX_HEIGHTMAP_SIZE_PIXELS &&
69static inline uint8_t
RGBToGreyscale(uint8_t red, uint8_t green, uint8_t blue)
73 return ((red * 19595) + (green * 38470) + (blue * 7471)) / 65536;
85 uint8_t gray_palette[256];
86 png_bytep *row_pointers =
nullptr;
87 bool has_palette = png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE;
88 uint channels = png_get_channels(png_ptr, info_ptr);
97 png_get_PLTE(png_ptr, info_ptr, &palette, &palette_size);
98 for (i = 0; i < palette_size && (palette_size != 16 || all_gray); i++) {
99 all_gray &= palette[i].red == palette[i].green && palette[i].red == palette[i].blue;
100 gray_palette[i] =
RGBToGreyscale(palette[i].red, palette[i].green, palette[i].blue);
109 if (palette_size == 16 && !all_gray) {
110 for (i = 0; i < palette_size; i++) {
111 gray_palette[i] = 256 * i / palette_size;
116 row_pointers = png_get_rows(png_ptr, info_ptr);
119 for (x = 0; x < png_get_image_width(png_ptr, info_ptr); x++) {
120 for (y = 0; y < png_get_image_height(png_ptr, info_ptr); y++) {
121 uint8_t *pixel = &map[y * png_get_image_width(png_ptr, info_ptr) + x];
122 uint x_offset = x * channels;
125 *pixel = gray_palette[row_pointers[y][x_offset]];
126 }
else if (channels == 3) {
128 row_pointers[y][x_offset + 1], row_pointers[y][x_offset + 2]);
130 *pixel = row_pointers[y][x_offset];
141static bool ReadHeightmapPNG(std::string_view filename, uint *x, uint *y, std::vector<uint8_t> *map)
143 png_structp png_ptr =
nullptr;
144 png_infop info_ptr =
nullptr;
147 if (!fp.has_value()) {
152 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
153 if (png_ptr ==
nullptr) {
158 info_ptr = png_create_info_struct(png_ptr);
159 if (info_ptr ==
nullptr || setjmp(png_jmpbuf(png_ptr))) {
161 png_destroy_read_struct(&png_ptr, &info_ptr,
nullptr);
165 png_init_io(png_ptr, *fp);
169 png_set_packing(png_ptr);
170 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_PACKING | PNG_TRANSFORM_STRIP_ALPHA | PNG_TRANSFORM_STRIP_16,
nullptr);
174 if ((png_get_channels(png_ptr, info_ptr) != 1) && (png_get_channels(png_ptr, info_ptr) != 3) && (png_get_bit_depth(png_ptr, info_ptr) != 8)) {
176 png_destroy_read_struct(&png_ptr, &info_ptr,
nullptr);
180 uint width = png_get_image_width(png_ptr, info_ptr);
181 uint height = png_get_image_height(png_ptr, info_ptr);
185 png_destroy_read_struct(&png_ptr, &info_ptr,
nullptr);
189 if (map !=
nullptr) {
190 map->resize(
static_cast<size_t>(width) * height);
197 png_destroy_read_struct(&png_ptr, &info_ptr,
nullptr);
209 uint8_t gray_palette[256];
211 if (!data.palette.empty()) {
212 bool all_gray =
true;
216 all_gray &= data.palette[i].r == data.palette[i].g && data.palette[i].r == data.palette[i].b;
217 gray_palette[i] =
RGBToGreyscale(data.palette[i].r, data.palette[i].g, data.palette[i].b);
237 gray_palette[1] = 16;
242 for (uint y = 0; y < info.
height; y++) {
243 uint8_t *pixel = &map[y *
static_cast<size_t>(info.
width)];
244 const uint8_t *bitmap = &data.bitmap[y *
static_cast<size_t>(info.
width) * (info.
bpp == 24 ? 3 : 1)];
246 for (uint x = 0; x < info.
width; x++) {
247 if (info.
bpp != 24) {
248 *pixel++ = gray_palette[*bitmap++];
262static bool ReadHeightmapBMP(std::string_view filename, uint *x, uint *y, std::vector<uint8_t> *map)
265 if (!f.has_value()) {
274 if (!BmpReadHeader(file, info, data)) {
284 if (map !=
nullptr) {
285 if (!BmpReadBitmap(file, info, data)) {
290 map->resize(
static_cast<size_t>(info.width) * info.height);
310 const uint num_div = 16384;
316 uint row_pad = 0, col_pad = 0;
318 uint img_row, img_col;
323 default: NOT_REACHED();
334 if ((img_width * num_div) / img_height > ((width * num_div) / height)) {
336 img_scale = (width * num_div) / img_width;
337 row_pad = (1 + height - ((img_height * img_scale) / num_div)) / 2;
340 img_scale = (height * num_div) / img_height;
341 col_pad = (1 + width - ((img_width * img_scale) / num_div)) / 2;
350 for (row = 0; row < height; row++) {
351 for (col = 0; col < width; col++) {
353 default: NOT_REACHED();
366 img_row = (((row - row_pad) * num_div) / img_scale);
368 default: NOT_REACHED();
370 img_col = (((width - 1 - col - col_pad) * num_div) / img_scale);
373 img_col = (((col - col_pad) * num_div) / img_scale);
377 assert(img_row < img_height);
378 assert(img_col < img_width);
380 uint heightmap_height = map[img_row * img_width + img_col];
382 if (heightmap_height > 0) {
407 uint8_t current_height;
415 for (row = 0; (uint)row < height; row++) {
416 for (col = 0; (uint)col < width; col++) {
430 if (
TileHeight(tile) >= (uint)current_height + 2) {
443 for (row = height - 1; row >= 0; row--) {
444 for (col = width - 1; col >= 0; col--) {
446 if ((uint)col != width - 1) {
451 if ((uint)row != height - 1) {
459 if (
TileHeight(tile) >= (uint)current_height + 2) {
520 std::vector<uint8_t> map;
545 for (uint row = edge_distance; row <
Map::SizeY() - edge_distance; row++) {
546 for (uint col = edge_distance; col <
Map::SizeX() - edge_distance; col++) {
Read and write support for bmps.
A file from which bytes, words and double words are read in (potentially) a random order.
Map accessors for 'clear' tiles.
void MakeClear(Tile t, ClearGround g, uint density)
Make a clear tile.
Functions related to errors.
@ WL_ERROR
Errors (eg. saving/loading failed)
void ShowErrorMessage(EncodedString &&summary_msg, int x, int y, CommandCost &cc)
Display an error message in a window.
std::optional< FileHandle > FioFOpenFile(std::string_view filename, std::string_view mode, Subdirectory subdir, size_t *filesize)
Opens a OpenTTD file somewhere in a personal or global directory.
Functions for Standard In/Out file operations.
DetailedFileType
Kinds of files in each AbstractFileType.
@ DFT_HEIGHTMAP_BMP
BMP file.
@ DFT_HEIGHTMAP_PNG
PNG file.
@ HEIGHTMAP_DIR
Subdirectory of scenario for heightmaps.
Declarations for savegames operations.
Functions related to the gfx engine.
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
static const uint MAX_HEIGHTMAP_SIDE_LENGTH_IN_PIXELS
Maximum number of pixels for one dimension of a heightmap image.
static bool ReadHeightmapBMP(std::string_view filename, uint *x, uint *y, std::vector< uint8_t > *map)
Reads the heightmap and/or size of the heightmap from a BMP file.
bool GetHeightmapDimensions(DetailedFileType dft, std::string_view filename, uint *x, uint *y)
Get the dimensions of a heightmap.
static bool ReadHeightmapPNG(std::string_view filename, uint *x, uint *y, std::vector< uint8_t > *map)
Reads the heightmap and/or size of the heightmap from a PNG file.
void FlatEmptyWorld(uint8_t tile_height)
Make an empty world where all tiles are of height 'tile_height'.
static void GreyscaleToMapHeights(uint img_width, uint img_height, std::span< const uint8_t > map)
Converts a given greyscale map to something that fits in OTTD map system and create a map of that dat...
static void ReadHeightmapPNGImageData(std::span< uint8_t > map, png_structp png_ptr, png_infop info_ptr)
The PNG Heightmap loader.
static bool ReadHeightMap(DetailedFileType dft, std::string_view filename, uint *x, uint *y, std::vector< uint8_t > *map)
Reads the heightmap with the correct file reader.
bool LoadHeightmap(DetailedFileType dft, std::string_view filename)
Load a heightmap from file and change the map in its current dimensions to a landscape representing t...
static uint8_t RGBToGreyscale(uint8_t red, uint8_t green, uint8_t blue)
Convert RGB colours to Greyscale using 29.9% Red, 58.7% Green, 11.4% Blue (average luminosity formula...
static bool IsValidHeightmapDimension(size_t width, size_t height)
Check whether the loaded dimension of the heightmap image are considered valid enough to attempt to l...
void FixSlopes()
This function takes care of the fact that land in OpenTTD can never differ more than 1 in height.
static void ReadHeightmapBMPImageData(std::span< uint8_t > map, const BmpInfo &info, const BmpData &data)
The BMP Heightmap loader.
Functions related to creating heightmaps from files.
@ HM_CLOCKWISE
Rotate the map clockwise 45 degrees.
@ HM_COUNTER_CLOCKWISE
Rotate the map counter clockwise 45 degrees.
bool IsMapSurroundedByWater()
Check if all tiles on the map edge should be considered water borders.
Functions related to OTTD's landscape.
uint DistanceFromEdge(TileIndex tile)
Param the minimum distance to an edge.
static debug_inline TileIndex TileXY(uint x, uint y)
Returns the TileIndex of a coordinate.
static const uint MAX_MAP_SIZE
Maximal map size = 4096.
uint32_t RandomRange(uint32_t limit, const std::source_location location=std::source_location::current())
Pick a random number between 0 and limit - 1, inclusive.
A number of safeguards to prevent using unsafe methods.
Functions/types related to saving and loading games.
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition of base types and functions in a cross-platform compatible way.
EncodedString GetEncodedString(StringID str)
Encode a string with no parameters into an encoded string.
Functions related to OTTD's strings.
uint32_t height
bitmap height
uint32_t width
bitmap width
uint32_t palette_size
number of colours in palette
uint16_t bpp
bits per pixel
bool freeform_edges
allow terraforming the tiles at the map edges
uint8_t map_height_limit
the maximum allowed heightlevel
uint8_t heightmap_rotation
rotation director for the heightmap
uint8_t heightmap_height
highest mountain for heightmap (towards what it scales)
ConstructionSettings construction
construction of things in-game
GameCreationSettings game_creation
settings used during the creation of a game (map)
static uint SizeY()
Get the size of the map along the Y.
static debug_inline uint SizeX()
Get the size of the map along the X.
bool IsInnerTile(Tile tile)
Check if a tile is within the map (not a border)
void SetTileHeight(Tile tile, uint height)
Sets the height of a tile.
static debug_inline uint TileHeight(Tile tile)
Returns the height of a tile.
static constexpr uint MAX_TILE_HEIGHT
Maximum allowed tile height.
Map accessors for void tiles.
void MakeVoid(Tile t)
Make a nice void tile ;)