Use libpng to export screenshots.
This commit is contained in:
parent
a546219adf
commit
69067879c4
|
@ -185,6 +185,8 @@ endif()
|
|||
|
||||
find_package(SDL2_mixer REQUIRED)
|
||||
|
||||
find_package(PNG REQUIRED)
|
||||
|
||||
# The hint provided here is targetting Arch Linux, a distro of choice for many contributors
|
||||
if ("${CMAKE_SYSTEM_NAME}" MATCHES "(Free|Net|Open|DragonFly)BSD")
|
||||
find_package(yaml-cpp REQUIRED)
|
||||
|
@ -221,6 +223,8 @@ endif ()
|
|||
|
||||
target_link_libraries(${PROJECT} ${SDL2_LIBRARIES} ${SDL2_MIXER_LIBRARIES})
|
||||
target_link_libraries(${PROJECT} yaml-cpp ${YAML_CPP_LIBRARIES})
|
||||
target_link_libraries(${PROJECT} ${PNG_LIBRARIES})
|
||||
|
||||
|
||||
if (NOT MINGW)
|
||||
add_dependencies(${PROJECT} segfiles)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include "../intro.h"
|
||||
#include "../localisation/string_ids.h"
|
||||
#include "../openloco.h"
|
||||
#include "../platform/platform.h"
|
||||
#include "../things/thingmgr.h"
|
||||
#include "../tutorial.h"
|
||||
#include "../ui.h"
|
||||
|
@ -15,6 +16,7 @@
|
|||
#include "ShortcutManager.h"
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <png.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef NOMINMAX
|
||||
|
@ -49,6 +51,7 @@ namespace openloco::input
|
|||
static loco_global<int8_t, 0x00508F16> _screenshotCountdown;
|
||||
static loco_global<uint8_t, 0x00508F18> _keyModifier;
|
||||
static loco_global<ui::WindowType, 0x005233B6> _modalWindowType;
|
||||
static loco_global<char[16], 0x0112C826> _commonFormatArgs;
|
||||
static std::string _cheatBuffer; // 0x0011364A5
|
||||
static loco_global<uint8_t[256], 0x01140740> _keyboardState;
|
||||
static loco_global<uint8_t, 0x011364A4> _11364A4;
|
||||
|
@ -417,23 +420,97 @@ namespace openloco::input
|
|||
input::set_flag(input_flags::viewport_scrolling);
|
||||
}
|
||||
|
||||
static void PngWriteData(png_structp png_ptr, png_bytep data, png_size_t length)
|
||||
{
|
||||
auto ostream = static_cast<std::ostream*>(png_get_io_ptr(png_ptr));
|
||||
ostream->write((const char*)data, length);
|
||||
}
|
||||
|
||||
static void PngFlush(png_structp png_ptr)
|
||||
{
|
||||
auto ostream = static_cast<std::ostream*>(png_get_io_ptr(png_ptr));
|
||||
ostream->flush();
|
||||
}
|
||||
|
||||
// 0x00452667
|
||||
static int16_t saveScreenshot()
|
||||
{
|
||||
registers regs;
|
||||
|
||||
auto result = call(0x00452667, regs);
|
||||
bool cf = (result & (1 << 8)) != 0;
|
||||
|
||||
if (cf)
|
||||
void* buffer = malloc(0x10000);
|
||||
if (buffer == nullptr)
|
||||
{
|
||||
throw std::runtime_error("Failed to save screenshot");
|
||||
throw std::runtime_error("Failed to allocate memory");
|
||||
}
|
||||
|
||||
return regs.ax;
|
||||
}
|
||||
auto basePath = platform::get_user_directory();
|
||||
char suffixStr[256] = { 0 };
|
||||
fs::path path;
|
||||
for (int16_t suffix = 1; suffix <= std::numeric_limits<int16_t>().max(); suffix++)
|
||||
{
|
||||
stringmgr::format_string(suffixStr, 107, &suffix);
|
||||
if (!fs::exists(basePath / suffixStr))
|
||||
{
|
||||
path = basePath / suffixStr;
|
||||
path.replace_extension("png");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static loco_global<char[16], 0x0112C826> _commonFormatArgs;
|
||||
if (path.empty())
|
||||
{
|
||||
throw std::runtime_error("Failed finding filename");
|
||||
}
|
||||
|
||||
std::fstream outputStream(path.c_str(), std::ios::out | std::ios::binary);
|
||||
|
||||
static loco_global<uint8_t[256][4], 0x0113ED20> _113ED20;
|
||||
|
||||
auto png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
|
||||
if (png_ptr == nullptr)
|
||||
throw std::runtime_error("png_create_write_struct failed.");
|
||||
|
||||
png_set_write_fn(png_ptr, &outputStream, PngWriteData, PngFlush);
|
||||
|
||||
// Set error handler
|
||||
if (setjmp(png_jmpbuf(png_ptr)))
|
||||
{
|
||||
throw std::runtime_error("PNG ERROR");
|
||||
}
|
||||
|
||||
auto info_ptr = png_create_info_struct(png_ptr);
|
||||
if (info_ptr == nullptr)
|
||||
throw std::runtime_error("png_create_info_struct failed.");
|
||||
|
||||
auto palette = (png_colorp)png_malloc(png_ptr, 246 * sizeof(png_color));
|
||||
if (palette == nullptr)
|
||||
throw std::runtime_error("png_malloc failed.");
|
||||
|
||||
for (size_t i = 0; i < 246; i++)
|
||||
{
|
||||
palette[i].blue = _113ED20[i][0];
|
||||
palette[i].green = _113ED20[i][1];
|
||||
palette[i].red = _113ED20[i][2];
|
||||
}
|
||||
png_set_PLTE(png_ptr, info_ptr, palette, 246);
|
||||
auto& dpi = gfx::screen_dpi();
|
||||
|
||||
png_byte transparentIndex = 0;
|
||||
png_set_tRNS(png_ptr, info_ptr, &transparentIndex, 1, nullptr);
|
||||
png_set_IHDR(png_ptr, info_ptr, dpi.width, dpi.height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||
png_write_info(png_ptr, info_ptr);
|
||||
|
||||
uint8_t* data = dpi.bits;
|
||||
for (int y = 0; y < dpi.height; y++)
|
||||
{
|
||||
png_write_row(png_ptr, data);
|
||||
data += dpi.pitch + dpi.width;
|
||||
}
|
||||
|
||||
png_write_end(png_ptr, nullptr);
|
||||
png_free(png_ptr, palette);
|
||||
png_destroy_write_struct(&png_ptr, nullptr);
|
||||
|
||||
return suffix;
|
||||
}
|
||||
|
||||
// 0x004BE92A
|
||||
void handle_keyboard()
|
||||
|
|
Loading…
Reference in New Issue