Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2025-05-14 18:41:13 +05:00
994 changed files with 38753 additions and 34512 deletions
+59 -90
View File
@@ -38,8 +38,6 @@ static const char * const SCREENSHOT_NAME = "screenshot"; ///< Default filename
static const char * const HEIGHTMAP_NAME = "heightmap"; ///< Default filename of a saved heightmap.
std::string _screenshot_format_name; ///< Extension of the current screenshot format (corresponds with #_cur_screenshot_format).
uint _num_screenshot_formats; ///< Number of available screenshot formats.
uint _cur_screenshot_format; ///< Index of the currently selected screenshot format in #_screenshot_formats.
static std::string _screenshot_name; ///< Filename of the screenshot file.
std::string _full_screenshot_path; ///< Pathname of the screenshot file.
uint _heightmap_highest_peak; ///< When saving a heightmap, this contains the highest peak on the map.
@@ -73,7 +71,7 @@ struct ScreenshotFormat {
ScreenshotHandlerProc *proc; ///< Function for writing the screenshot.
};
#define MKCOLOUR(x) TO_LE32X(x)
#define MKCOLOUR(x) TO_LE32(x)
/*************************************************
**** SCREENSHOT CODE FOR WINDOWS BITMAP (.BMP)
@@ -99,7 +97,7 @@ static_assert(sizeof(BitmapInfoHeader) == 40);
/** Format of palette data in BMP header */
struct RgbQuad {
byte blue, green, red, reserved;
uint8_t blue, green, red, reserved;
};
static_assert(sizeof(RgbQuad) == 4);
@@ -126,8 +124,9 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
default: return false;
}
FILE *f = fopen(name, "wb");
if (f == nullptr) return false;
auto of = FileHandle::Open(name, "wb");
if (!of.has_value()) return false;
auto &f = *of;
/* Each scanline must be aligned on a 32bit boundary */
uint bytewidth = Align(w * bpp, 4); // bytes per line in file
@@ -158,7 +157,6 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
/* Write file header and info header */
if (fwrite(&bfh, sizeof(bfh), 1, f) != 1 || fwrite(&bih, sizeof(bih), 1, f) != 1) {
fclose(f);
return false;
}
@@ -173,7 +171,6 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
}
/* Write the palette */
if (fwrite(rq, sizeof(rq), 1, f) != 1) {
fclose(f);
return false;
}
}
@@ -181,8 +178,8 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
/* Try to use 64k of memory, store between 16 and 128 lines */
uint maxlines = Clamp(65536 / (w * pixelformat / 8), 16, 128); // number of lines per iteration
uint8_t *buff = MallocT<uint8_t>(maxlines * w * pixelformat / 8); // buffer which is rendered to
uint8_t *line = CallocT<uint8_t>(bytewidth); // one line, stored to file
std::vector<uint8_t> buff(maxlines * w * pixelformat / 8); // buffer which is rendered to
std::vector<uint8_t> line(bytewidth); // one line, stored to file
/* Start at the bottom, since bitmaps are stored bottom up */
do {
@@ -190,18 +187,18 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
h -= n;
/* Render the pixels */
callb(userdata, buff, h, w, n);
callb(userdata, buff.data(), h, w, n);
/* Write each line */
while (n-- != 0) {
if (pixelformat == 8) {
/* Move to 'line', leave last few pixels in line zeroed */
memcpy(line, buff + n * w, w);
memcpy(line.data(), buff.data() + n * w, w);
} else {
/* Convert from 'native' 32bpp to BMP-like 24bpp.
* Works for both big and little endian machines */
Colour *src = ((Colour *)buff) + n * w;
byte *dst = line;
Colour *src = ((Colour *)buff.data()) + n * w;
uint8_t *dst = line.data();
for (uint i = 0; i < w; i++) {
dst[i * 3 ] = src[i].b;
dst[i * 3 + 1] = src[i].g;
@@ -209,18 +206,12 @@ static bool MakeBMPImage(const char *name, ScreenshotCallback *callb, void *user
}
}
/* Write to file */
if (fwrite(line, bytewidth, 1, f) != 1) {
free(line);
free(buff);
fclose(f);
if (fwrite(line.data(), bytewidth, 1, f) != 1) {
return false;
}
}
} while (h != 0);
free(line);
free(buff);
fclose(f);
return true;
}
@@ -265,7 +256,6 @@ static void PNGAPI png_my_warning(png_structp png_ptr, png_const_charp message)
static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
{
png_color rq[256];
FILE *f;
uint i, y, n;
uint maxlines;
uint bpp = pixelformat / 8;
@@ -275,26 +265,24 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
/* only implemented for 8bit and 32bit images so far. */
if (pixelformat != 8 && pixelformat != 32) return false;
f = fopen(name, "wb");
if (f == nullptr) return false;
auto of = FileHandle::Open(name, "wb");
if (!of.has_value()) return false;
auto &f = *of;
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, const_cast<char *>(name), png_my_error, png_my_warning);
if (png_ptr == nullptr) {
fclose(f);
return false;
}
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == nullptr) {
png_destroy_write_struct(&png_ptr, (png_infopp)nullptr);
fclose(f);
return false;
}
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(f);
return false;
}
@@ -362,19 +350,19 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
sig_bit.gray = 8;
png_set_sBIT(png_ptr, info_ptr, &sig_bit);
#if TTD_ENDIAN == TTD_LITTLE_ENDIAN
png_set_bgr(png_ptr);
png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
#else
png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
#endif /* TTD_ENDIAN == TTD_LITTLE_ENDIAN */
if constexpr (std::endian::native == std::endian::little) {
png_set_bgr(png_ptr);
png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
} else {
png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE);
}
}
/* use by default 64k temp memory */
maxlines = Clamp(65536 / w, 16, 128);
/* now generate the bitmap bits */
void *buff = CallocT<uint8_t>(static_cast<size_t>(w) * maxlines * bpp); // by default generate 128 lines at a time.
std::vector<uint8_t> buff(static_cast<size_t>(w) * maxlines * bpp); // by default generate 128 lines at a time.
y = 0;
do {
@@ -382,20 +370,18 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
n = std::min(h - y, maxlines);
/* render the pixels into the buffer */
callb(userdata, buff, y, w, n);
callb(userdata, buff.data(), y, w, n);
y += n;
/* write them to png */
for (i = 0; i != n; i++) {
png_write_row(png_ptr, (png_bytep)buff + i * w * bpp);
png_write_row(png_ptr, (png_bytep)buff.data() + i * w * bpp);
}
} while (y != h);
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(buff);
fclose(f);
return true;
}
#endif /* WITH_PNG */
@@ -407,21 +393,21 @@ static bool MakePNGImage(const char *name, ScreenshotCallback *callb, void *user
/** Definition of a PCX file header. */
struct PcxHeader {
byte manufacturer;
byte version;
byte rle;
byte bpp;
uint8_t manufacturer;
uint8_t version;
uint8_t rle;
uint8_t bpp;
uint32_t unused;
uint16_t xmax, ymax;
uint16_t hdpi, vdpi;
byte pal_small[16 * 3];
byte reserved;
byte planes;
uint8_t pal_small[16 * 3];
uint8_t reserved;
uint8_t planes;
uint16_t pitch;
uint16_t cpal;
uint16_t width;
uint16_t height;
byte filler[54];
uint8_t filler[54];
};
static_assert(sizeof(PcxHeader) == 128);
@@ -439,7 +425,6 @@ static_assert(sizeof(PcxHeader) == 128);
*/
static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *userdata, uint w, uint h, int pixelformat, const Colour *palette)
{
FILE *f;
uint maxlines;
uint y;
PcxHeader pcx;
@@ -451,8 +436,9 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
}
if (pixelformat != 8 || w == 0) return false;
f = fopen(name, "wb");
if (f == nullptr) return false;
auto of = FileHandle::Open(name, "wb");
if (!of.has_value()) return false;
auto &f = *of;
memset(&pcx, 0, sizeof(pcx));
@@ -473,7 +459,6 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
/* write pcx header */
if (fwrite(&pcx, sizeof(pcx), 1, f) != 1) {
fclose(f);
return false;
}
@@ -481,7 +466,7 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
maxlines = Clamp(65536 / w, 16, 128);
/* now generate the bitmap bits */
uint8_t *buff = CallocT<uint8_t>(static_cast<size_t>(w) * maxlines); // by default generate 128 lines at a time.
std::vector<uint8_t> buff(static_cast<size_t>(w) * maxlines); // by default generate 128 lines at a time.
y = 0;
do {
@@ -490,13 +475,13 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
uint i;
/* render the pixels into the buffer */
callb(userdata, buff, y, w, n);
callb(userdata, buff.data(), y, w, n);
y += n;
/* write them to pcx */
for (i = 0; i != n; i++) {
const uint8_t *bufp = buff + i * w;
byte runchar = bufp[0];
const uint8_t *bufp = buff.data() + i * w;
uint8_t runchar = bufp[0];
uint runcount = 1;
uint j;
@@ -507,14 +492,10 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
if (ch != runchar || runcount >= 0x3f) {
if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
if (fputc(0xC0 | runcount, f) == EOF) {
free(buff);
fclose(f);
return false;
}
}
if (fputc(runchar, f) == EOF) {
free(buff);
fclose(f);
return false;
}
runcount = 0;
@@ -526,29 +507,22 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
/* write remaining bytes.. */
if (runcount > 1 || (runchar & 0xC0) == 0xC0) {
if (fputc(0xC0 | runcount, f) == EOF) {
free(buff);
fclose(f);
return false;
}
}
if (fputc(runchar, f) == EOF) {
free(buff);
fclose(f);
return false;
}
}
} while (y != h);
free(buff);
/* write 8-bit colour palette */
if (fputc(12, f) == EOF) {
fclose(f);
return false;
}
/* Palette is word-aligned, copy it to a temporary byte array */
byte tmp[256 * 3];
uint8_t tmp[256 * 3];
for (uint i = 0; i < 256; i++) {
tmp[i * 3 + 0] = palette[i].r;
@@ -557,8 +531,6 @@ static bool MakePCXImage(const char *name, ScreenshotCallback *callb, void *user
}
success = fwrite(tmp, sizeof(tmp), 1, f) == 1;
fclose(f);
return success;
}
@@ -575,24 +547,26 @@ static const ScreenshotFormat _screenshot_formats[] = {
{"pcx", &MakePCXImage},
};
/* The currently loaded screenshot format. Set to a valid value as it might be used in early crash logs, when InitializeScreenshotFormats has not been called yet. */
static const ScreenshotFormat *_cur_screenshot_format = std::begin(_screenshot_formats);
/** Get filename extension of current screenshot file format. */
const char *GetCurrentScreenshotExtension()
{
return _screenshot_formats[_cur_screenshot_format].extension;
return _cur_screenshot_format->extension;
}
/** Initialize screenshot format information on startup, with #_screenshot_format_name filled from the loadsave code. */
void InitializeScreenshotFormats()
{
uint j = 0;
for (uint i = 0; i < lengthof(_screenshot_formats); i++) {
if (_screenshot_format_name.compare(_screenshot_formats[i].extension) == 0) {
j = i;
break;
for (auto &format : _screenshot_formats) {
if (_screenshot_format_name == format.extension) {
_cur_screenshot_format = &format;
return;
}
}
_cur_screenshot_format = j;
_num_screenshot_formats = lengthof(_screenshot_formats);
_cur_screenshot_format = std::begin(_screenshot_formats);
}
/**
@@ -706,8 +680,7 @@ static const char *MakeScreenshotName(const char *default_fn, const char *ext, b
/** Make a screenshot of the current screen. */
static bool MakeSmallScreenshot(bool crashlog)
{
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension, crashlog), CurrentScreenCallback, nullptr, _screen.width, _screen.height,
return _cur_screenshot_format->proc(MakeScreenshotName(SCREENSHOT_NAME, _cur_screenshot_format->extension, crashlog), CurrentScreenCallback, nullptr, _screen.width, _screen.height,
BlitterFactory::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette);
}
@@ -805,8 +778,7 @@ static bool MakeLargeWorldScreenshot(ScreenshotType t, uint32_t width = 0, uint3
Viewport vp;
SetupScreenshotViewport(t, &vp, width, height);
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), LargeWorldCallback, &vp, vp.width, vp.height,
return _cur_screenshot_format->proc(MakeScreenshotName(SCREENSHOT_NAME, _cur_screenshot_format->extension), LargeWorldCallback, &vp, vp.width, vp.height,
BlitterFactory::GetCurrentBlitter()->GetScreenDepth(), _cur_palette.palette);
}
@@ -819,14 +791,14 @@ static bool MakeLargeWorldScreenshot(ScreenshotType t, uint32_t width = 0, uint3
*/
static void HeightmapCallback(void *, void *buffer, uint y, uint, uint n)
{
byte *buf = (byte *)buffer;
uint8_t *buf = (uint8_t *)buffer;
while (n > 0) {
TileIndex ti = TileXY(Map::MaxX(), y);
for (uint x = Map::MaxX(); true; x--) {
*buf = 256 * TileHeight(ti) / (1 + _heightmap_highest_peak);
buf++;
if (x == 0) break;
ti = TILE_ADDXY(ti, -1, 0);
ti = TileAddXY(ti, -1, 0);
}
y++;
n--;
@@ -848,13 +820,12 @@ bool MakeHeightmapScreenshot(const char *filename)
}
_heightmap_highest_peak = 0;
for (TileIndex tile = 0; tile < Map::Size(); tile++) {
for (const auto tile : Map::Iterate()) {
uint h = TileHeight(tile);
_heightmap_highest_peak = std::max(h, _heightmap_highest_peak);
}
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
return sf->proc(filename, HeightmapCallback, nullptr, Map::SizeX(), Map::SizeY(), 8, palette);
return _cur_screenshot_format->proc(filename, HeightmapCallback, nullptr, Map::SizeX(), Map::SizeY(), 8, palette);
}
static ScreenshotType _confirmed_screenshot_type; ///< Screenshot type the current query is about to confirm.
@@ -938,8 +909,7 @@ static bool RealMakeScreenshot(ScreenshotType t, std::string name, uint32_t widt
break;
case SC_HEIGHTMAP: {
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
ret = MakeHeightmapScreenshot(MakeScreenshotName(HEIGHTMAP_NAME, sf->extension));
ret = MakeHeightmapScreenshot(MakeScreenshotName(HEIGHTMAP_NAME, _cur_screenshot_format->extension));
break;
}
@@ -1003,7 +973,7 @@ static void MinimapScreenCallback(void *, void *buf, uint y, uint pitch, uint n)
uint col = (Map::SizeX() - 1) - (i % pitch);
TileIndex tile = TileXY(col, row);
byte val = GetSmallMapOwnerPixels(tile, GetTileType(tile), IncludeHeightmap::Never) & 0xFF;
uint8_t val = GetSmallMapOwnerPixels(tile, GetTileType(tile), IncludeHeightmap::Never) & 0xFF;
uint32_t colour_buf = 0;
colour_buf = (_cur_palette.palette[val].b << 0);
@@ -1020,6 +990,5 @@ static void MinimapScreenCallback(void *, void *buf, uint y, uint pitch, uint n)
*/
bool MakeMinimapWorldScreenshot()
{
const ScreenshotFormat *sf = _screenshot_formats + _cur_screenshot_format;
return sf->proc(MakeScreenshotName(SCREENSHOT_NAME, sf->extension), MinimapScreenCallback, nullptr, Map::SizeX(), Map::SizeY(), 32, _cur_palette.palette);
return _cur_screenshot_format->proc(MakeScreenshotName(SCREENSHOT_NAME, _cur_screenshot_format->extension), MinimapScreenCallback, nullptr, Map::SizeX(), Map::SizeY(), 32, _cur_palette.palette);
}