From 898cb3ae3dde047a2eb2a171bb7258ce6cd017a5 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Thu, 26 Sep 2024 20:52:08 +0100 Subject: [PATCH] Screenshotting: Use `SDL_RWops` throughout Turns out `SDL_RWFromFP` isn't implemented in SDL for mingw. --- Source/capture.cpp | 9 +++++---- Source/utils/surface_to_pcx.cpp | 20 +++++++++++--------- Source/utils/surface_to_pcx.hpp | 3 ++- Source/utils/surface_to_png.cpp | 5 ++--- Source/utils/surface_to_png.hpp | 8 +++++++- 5 files changed, 27 insertions(+), 18 deletions(-) diff --git a/Source/capture.cpp b/Source/capture.cpp index 5f8863f57d7..856263d768c 100644 --- a/Source/capture.cpp +++ b/Source/capture.cpp @@ -34,7 +34,7 @@ namespace devilution { namespace { -FILE *CaptureFile(std::string *dstPath) +SDL_RWops *CaptureFile(std::string *dstPath) { const char *ext = #if DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PCX @@ -54,7 +54,7 @@ FILE *CaptureFile(std::string *dstPath) i++; *dstPath = StrCat(paths::PrefPath(), filename, "-", i, ext); } - return OpenFile(dstPath->c_str(), "wb"); + return SDL_RWFromFile(dstPath->c_str(), "wb"); } /** @@ -79,9 +79,10 @@ void CaptureScreen() std::string fileName; const uint32_t startTime = SDL_GetTicks(); - FILE *outStream = CaptureFile(&fileName); + SDL_RWops *outStream = CaptureFile(&fileName); if (outStream == nullptr) { - LogError("Failed to open {} for writing: {}", fileName, std::strerror(errno)); + LogError("Failed to open {} for writing: {}", fileName, SDL_GetError()); + SDL_ClearError(); return; } DrawAndBlit(); diff --git a/Source/utils/surface_to_pcx.cpp b/Source/utils/surface_to_pcx.cpp index b1bdc696fa1..efe44187297 100644 --- a/Source/utils/surface_to_pcx.cpp +++ b/Source/utils/surface_to_pcx.cpp @@ -15,13 +15,15 @@ namespace devilution { namespace { -tl::expected CheckedFWrite(const void *ptr, size_t size, FILE *out) +tl::expected CheckedFWrite(const void *ptr, size_t size, SDL_RWops *out) { - if (std::fwrite(ptr, size, 1, out) != 1) { - const char *errorMessage = std::strerror(errno); + if (SDL_RWwrite(out, ptr, size, 1) != 1) { + const char *errorMessage = SDL_GetError(); if (errorMessage == nullptr) errorMessage = ""; - return tl::make_unexpected(std::string("fwrite failed with: ").append(errorMessage)); + tl::expected result = tl::make_unexpected(std::string("write failed with: ").append(errorMessage)); + SDL_ClearError(); + return result; } return {}; } @@ -33,7 +35,7 @@ tl::expected CheckedFWrite(const void *ptr, size_t size, FILE * @param out File stream to write to * @return True on success */ -tl::expected WritePcxHeader(int16_t width, int16_t height, FILE *out) +tl::expected WritePcxHeader(int16_t width, int16_t height, SDL_RWops *out) { PCXHeader buffer; @@ -58,7 +60,7 @@ tl::expected WritePcxHeader(int16_t width, int16_t height, FI * @param out File stream for the PCX file. * @return True if successful, else false */ -tl::expected WritePcxPalette(SDL_Color *palette, FILE *out) +tl::expected WritePcxPalette(SDL_Color *palette, SDL_RWops *out) { uint8_t pcxPalette[1 + 256 * 3]; @@ -121,7 +123,7 @@ uint8_t *WritePcxLine(uint8_t *src, uint8_t *dst, int width) * @param out File stream for the PCX file. * @return True if successful, else false */ -tl::expected WritePcxPixels(const Surface &buf, FILE *out) +tl::expected WritePcxPixels(const Surface &buf, SDL_RWops *out) { const int width = buf.w(); const std::unique_ptr pBuffer { new uint8_t[static_cast(2 * width)] }; @@ -138,7 +140,7 @@ tl::expected WritePcxPixels(const Surface &buf, FILE *out) } // namespace tl::expected -WriteSurfaceToFilePcx(const Surface &buf, FILE *outStream) +WriteSurfaceToFilePcx(const Surface &buf, SDL_RWops *outStream) { tl::expected result = WritePcxHeader(buf.w(), buf.h(), outStream); if (!result.has_value()) return result; @@ -146,7 +148,7 @@ WriteSurfaceToFilePcx(const Surface &buf, FILE *outStream) if (!result.has_value()) return result; result = WritePcxPalette(buf.surface->format->palette->colors, outStream); if (!result.has_value()) return result; - std::fclose(outStream); + SDL_RWclose(outStream); return {}; } diff --git a/Source/utils/surface_to_pcx.hpp b/Source/utils/surface_to_pcx.hpp index 92968a050b7..bb82e0ac76c 100644 --- a/Source/utils/surface_to_pcx.hpp +++ b/Source/utils/surface_to_pcx.hpp @@ -1,6 +1,7 @@ #include #include +#include #include #include "engine/surface.hpp" @@ -8,6 +9,6 @@ namespace devilution { tl::expected -WriteSurfaceToFilePcx(const Surface &buf, FILE *outStream); +WriteSurfaceToFilePcx(const Surface &buf, SDL_RWops *outStream); } // namespace devilution diff --git a/Source/utils/surface_to_png.cpp b/Source/utils/surface_to_png.cpp index 7979443ddf5..e64abf246dd 100644 --- a/Source/utils/surface_to_png.cpp +++ b/Source/utils/surface_to_png.cpp @@ -13,10 +13,9 @@ namespace devilution { extern "C" int IMG_SavePNG_RW(SDL_Surface *surface, SDL_RWops *dst, int freedst); tl::expected -WriteSurfaceToFilePng(const Surface &buf, FILE *outStream) +WriteSurfaceToFilePng(const Surface &buf, SDL_RWops *dst) { - SDL_RWops *rwops = SDL_RWFromFP(outStream, /*autoclose=*/SDL_TRUE); - if (rwops == nullptr || IMG_SavePNG_RW(buf.surface, rwops, /*freedst=*/1) != 0) { + if (IMG_SavePNG_RW(buf.surface, dst, /*freedst=*/1) != 0) { tl::expected result = tl::make_unexpected(std::string(SDL_GetError())); SDL_ClearError(); return result; diff --git a/Source/utils/surface_to_png.hpp b/Source/utils/surface_to_png.hpp index bb442f5d546..eeeed4ea036 100644 --- a/Source/utils/surface_to_png.hpp +++ b/Source/utils/surface_to_png.hpp @@ -1,13 +1,19 @@ #include #include +#include #include #include "engine/surface.hpp" namespace devilution { +/** + * @brief Writes the given surface to `dst` as PNG. + * + * Takes ownership of `dst` and closes it when done. + */ tl::expected -WriteSurfaceToFilePng(const Surface &buf, FILE *outStream); +WriteSurfaceToFilePng(const Surface &buf, SDL_RWops *dst); } // namespace devilution