Use libpng to export screenshots.

This commit is contained in:
Marijn van der Werf 2019-05-19 14:41:11 +02:00 committed by Aaron van Geffen
parent a546219adf
commit 69067879c4
2 changed files with 91 additions and 10 deletions

View File

@ -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)

View File

@ -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()