Merge pull request #20 from rwjuk/g1attempt

Implement load_g1()
This commit is contained in:
Ted John 2018-01-25 17:49:03 +00:00 committed by GitHub
commit d7689098d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 144 additions and 2 deletions

View File

@ -1,22 +1,121 @@
#include "gfx.h"
#include "../environment.h"
#include "../interop/interop.hpp"
#include "../ui.h"
#include <algorithm>
#include <fstream>
#include <iostream>
#include <memory>
using namespace openloco::interop;
namespace openloco::gfx
{
loco_global<drawpixelinfo_t, 0x0050B884> _screen_dpi;
namespace g1_expected_count
{
constexpr uint32_t disc = 0x101A; // And GOG
constexpr uint32_t steam = 0x0F38;
}
static loco_global<drawpixelinfo_t, 0x0050B884> _screen_dpi;
static loco_global_array<g1_element, g1_expected_count::disc, 0x9E2424> _g1Elements;
static std::unique_ptr<std::byte[]> _g1Buffer;
drawpixelinfo_t& screen_dpi()
{
return _screen_dpi;
}
static std::vector<g1_element> convert_elements(const std::vector<g1_element32_t>& elements32)
{
auto elements = std::vector<g1_element>();
elements.reserve(elements32.size());
std::transform(
elements32.begin(),
elements32.end(),
std::back_inserter(elements),
[](g1_element32_t src) { return g1_element(src); });
return elements;
}
template<typename T1, typename T2, typename T3>
std::basic_istream<T1, T2>& read_data(std::basic_istream<T1, T2>& stream, T3* dst, size_t count)
{
return stream.read((char*)dst, count * sizeof(T3));
}
template<typename T1, typename T2, typename T3>
std::basic_istream<T1, T2>& read_data(std::basic_istream<T1, T2>& stream, T3& dst)
{
return read_data(stream, &dst, 1);
}
// 0x0044733C
void load_g1()
{
call(0x0044733C);
auto g1Path = environment::get_path(environment::path_id::g1);
std::ifstream stream(g1Path, std::ios::in | std::ios::binary);
if (!stream)
{
throw std::runtime_error("Opening g1 file failed.");
}
g1_header_t header;
if (!read_data(stream, header))
{
throw std::runtime_error("Reading g1 file header failed.");
}
if (header.num_entries != g1_expected_count::disc)
{
std::cout << "G1 element count doesn't match expected value: ";
std::cout << "Expected " << g1_expected_count::disc << "; Got " << header.num_entries << std::endl;
if (header.num_entries == g1_expected_count::steam)
{
std::cout << "Got Steam G1.DAT variant, will fix elements automatically." << std::endl;
}
}
// Read element headers
auto elements32 = std::vector<g1_element32_t>(header.num_entries);
if (!read_data(stream, elements32.data(), header.num_entries))
{
throw std::runtime_error("Reading g1 element headers failed.");
}
auto elements = convert_elements(elements32);
// Read element data
auto elementData = std::make_unique<std::byte[]>(header.total_size);
if (!read_data(stream, elementData.get(), header.total_size))
{
throw std::runtime_error("Reading g1 elements failed.");
}
stream.close();
// The steam G1.DAT is missing two localised tutorial icons, and a smaller font variant
// This code copies the closest variants into their place, and moves other elements accordingly
if (header.num_entries == g1_expected_count::steam)
{
elements.resize(g1_expected_count::disc);
// Extra two tutorial images
std::copy_n(&elements[3549], header.num_entries - 3549, &elements[3551]);
std::copy_n(&elements[3551], 1, &elements[3549]);
std::copy_n(&elements[3551], 1, &elements[3550]);
// Extra font variant
std::copy_n(&elements[1788], 223, &elements[3898]);
}
// Adjust memory offsets
for (auto& element : elements)
{
element.offset += (uintptr_t)elementData.get();
}
_g1Buffer = std::move(elementData);
std::copy(elements.begin(), elements.end(), _g1Elements.get());
}
// 0x00447485

View File

@ -19,6 +19,49 @@ namespace openloco::gfx
uint16_t zoom_level; // 0x0E
};
drawpixelinfo_t& screen_dpi();
struct g1_header_t
{
uint32_t num_entries;
uint32_t total_size;
};
struct g1_element32_t
{
uint32_t offset; // 0x00
int16_t width; // 0x04
int16_t height; // 0x06
int16_t x_offset; // 0x08
int16_t y_offset; // 0x0A
uint16_t flags; // 0x0C
int16_t unused; // 0x0E
};
// A version that can be 64-bit when ready...
struct g1_element
{
uint8_t* offset = nullptr;
int16_t width = 0;
int16_t height = 0;
int16_t x_offset = 0;
int16_t y_offset = 0;
uint16_t flags = 0;
int16_t unused = 0;
g1_element() = default;
g1_element(const g1_element32_t& src)
: offset((uint8_t*)src.offset)
, width(src.width)
, height(src.height)
, x_offset(src.x_offset)
, y_offset(src.y_offset)
, flags(src.flags)
, unused(src.unused)
{
}
};
#pragma pack(pop)
drawpixelinfo_t& screen_dpi();