Skip to content

Commit

Permalink
Support loading of startup logos from RPG_RT.exe
Browse files Browse the repository at this point in the history
  • Loading branch information
Ghabry committed Nov 19, 2023
1 parent e834e88 commit 43dbe0b
Show file tree
Hide file tree
Showing 5 changed files with 121 additions and 15 deletions.
67 changes: 67 additions & 0 deletions src/exe_reader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,73 @@ std::vector<uint8_t> EXEReader::GetExFont() {
return {};
}

std::vector<std::vector<uint8_t>> EXEReader::GetLogos() {
corefile.clear();

if (!resource_ofs) {
return {};
}

std::vector<std::vector<uint8_t>> logos;

uint32_t resourcesIDEs = GetU16(resource_ofs + 0x0C);
if (resourcesIDEs == 1) {
uint32_t resourcesIDEbase = resource_ofs + 0x10;
if (ResNameCheck(exe_reader_roffset(resource_ofs, GetU32(resourcesIDEbase)), "XYZ")) {
uint32_t xyz_base = exe_reader_roffset(resource_ofs, GetU32(resourcesIDEbase + 4));
uint16_t xyz_logos = GetU16(xyz_base + 0x0C);
uint32_t xyz_logo_base = xyz_base + 0x10;

char current_logo = '1';
std::string res_name = "LOGOX";
while (xyz_logos > 0) {
res_name.back() = current_logo;

uint32_t name = GetU32(xyz_logo_base);
// Actually a name?
if (name & 0x80000000) {
name = exe_reader_roffset(resource_ofs, name);

if (ResNameCheck(name, res_name.c_str())) {
uint32_t dataent = GetU32(xyz_logo_base + 4);
if (dataent & 0x80000000) {
dataent = exe_reader_roffset(resource_ofs, dataent);
dataent = resource_ofs + GetU32(dataent + 0x14);
}
uint32_t filebase = (GetU32(dataent) - resource_rva) + resource_ofs;
uint32_t filesize = GetU32(dataent + 0x04);
Output::Debug("EXEReader: {} resource found (DE {:#x}; {:#x}; len {:#x})", res_name, dataent, filebase, filesize);
std::vector<uint8_t> logo;
logo.resize(filesize);

corefile.seekg(filebase, std::ios_base::beg);
corefile.read(reinterpret_cast<char*>(logo.data()), filesize);
if (logo.size() < 8 || strncmp(reinterpret_cast<char*>(logo.data()), "XYZ1", 4) != 0) {
Output::Debug("{}: Not a XYZ image", res_name);
return {};
}

if (corefile.gcount() != filesize) {
Output::Debug("{}: Error reading resource (read {}, expected {})", res_name, corefile.gcount(), filesize);
return {};
}
//auto crc = crc32(0, logo.data(), logo.size());
//Output::Debug("{} {:x}", res_name, crc);
logos.push_back(logo);
} else {
return logos;
}
}
xyz_logo_base += 8;
current_logo++;
xyz_logos--;
}
}
}

return logos;
}

const EXEReader::FileInfo& EXEReader::GetFileInfo() {
corefile.clear();

Expand Down
1 change: 1 addition & 0 deletions src/exe_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ class EXEReader {
// Extracts an EXFONT resource with BMP header if present
// and returns exfont buffer on success.
std::vector<uint8_t> GetExFont();
std::vector<std::vector<uint8_t>> GetLogos();

struct FileInfo {
uint64_t version = 0;
Expand Down
5 changes: 3 additions & 2 deletions src/scene_gamebrowser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,9 +219,10 @@ void Scene_GameBrowser::BootGame() {
game_loading = false;
load_window->SetVisible(false);

if (!FileFinder::FindImage("Logo", "LOGO1").empty()) {
auto logos = Scene_Logo::LoadLogos();
if (!logos.empty()) {
// Delegate to Scene_Logo when a startup graphic was found
Scene::Push(std::make_shared<Scene_Logo>(1));
Scene::Push(std::make_shared<Scene_Logo>(std::move(logos), 1));
return;
}

Expand Down
55 changes: 44 additions & 11 deletions src/scene_logo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include "scene_logo.h"
#include "async_handler.h"
#include "bitmap.h"
#include "exe_reader.h"
#include "filefinder.h"
#include "game_battle.h"
#include "input.h"
Expand All @@ -35,16 +36,21 @@
#include "text.h"
#include "version.h"
#include <ctime>
#include <memory>

Scene_Logo::Scene_Logo(unsigned current_logo_index) :
frame_counter(0), current_logo_index(current_logo_index) {
Scene_Logo::Scene_Logo() :
frame_counter(0) {
type = Scene::Logo;
skip_logos = Player::debug_flag || Game_Battle::battle_test.enabled;
}

if (current_logo_index > 0) {
detected_game = true;
}
Scene_Logo::Scene_Logo(std::vector<std::vector<uint8_t>> logos, unsigned current_logo_index) :
frame_counter(0), logos(std::move(logos)), current_logo_index(current_logo_index) {

skip_logos = Player::debug_flag || Game_Battle::battle_test.enabled;
type = Scene::Logo;

assert(current_logo_index > 0);
detected_game = true;
}

void Scene_Logo::Start() {
Expand All @@ -61,6 +67,8 @@ void Scene_Logo::vUpdate() {
// async delay for emscripten
return;
}

logos = LoadLogos();
}

++frame_counter;
Expand All @@ -86,8 +94,8 @@ void Scene_Logo::vUpdate() {
if (detected_game) {
if (!skip_logos) {
// Check for another logo
if (!FileFinder::FindImage("Logo", "LOGO" + std::to_string(current_logo_index + 1)).empty()) {
Scene::Push(std::make_shared<Scene_Logo>(current_logo_index + 1), true);
if (current_logo_index < logos.size()) {
Scene::Push(std::make_shared<Scene_Logo>(std::move(logos), current_logo_index + 1), true);
return;
}
}
Expand Down Expand Up @@ -162,9 +170,8 @@ BitmapRef Scene_Logo::LoadLogo() {
}
} else {
// Load external logos
// FIXME: Also get the LOGO1,LOGO2,LOGO3 from RPG_RT
auto logo_stream = FileFinder::OpenImage("Logo", "LOGO" + std::to_string(current_logo_index));
current_logo = Bitmap::Create(std::move(logo_stream), false);
const auto& logo_bytes = logos[current_logo_index - 1];
current_logo = Bitmap::Create(logo_bytes.data(), logo_bytes.size(), false);
}

return current_logo;
Expand Down Expand Up @@ -200,7 +207,33 @@ void Scene_Logo::DrawTextOnLogo(bool verbose) {
text_rect.x--;
text_rect.y--;
}
}

std::vector<std::vector<uint8_t>> Scene_Logo::LoadLogos() {
std::vector<std::vector<uint8_t>> logos;

for (int i = 1; i < 100; ++i) {
auto is = FileFinder::OpenImage("Logo", "LOGO" + std::to_string(i));
if (is) {
logos.push_back(Utils::ReadStream(is));
} else {
break;
}
}

#ifndef EMSCRIPTEN
if (logos.empty()) {
// Attempt reading Logos from RPG_RT.exe (not supported on Emscripten)
auto exeis = FileFinder::Game().OpenFile(EXE_NAME);

if (exeis) {
std::unique_ptr<EXEReader> exe_reader = std::make_unique<EXEReader>(std::move(exeis));
logos = exe_reader->GetLogos();
}
}
#endif

return logos;
}

void Scene_Logo::OnIndexReady(FileRequestResult*) {
Expand Down
8 changes: 6 additions & 2 deletions src/scene_logo.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ class Scene_Logo : public Scene {
/**
* Constructor.
*/
Scene_Logo(unsigned current_logo_index = 0);
Scene_Logo();
Scene_Logo(std::vector<std::vector<uint8_t>> logos, unsigned current_logo_index);

void Start() override;
void vUpdate() override;
Expand All @@ -46,11 +47,14 @@ class Scene_Logo : public Scene {
void DrawBackground(Bitmap& dst) override;
void DrawTextOnLogo(bool verbose);

static std::vector<std::vector<uint8_t>> LoadLogos();

private:
std::unique_ptr<Sprite> logo;
BitmapRef logo_img;
int frame_counter;
unsigned current_logo_index;
std::vector<std::vector<uint8_t>> logos;
unsigned current_logo_index = 0;
bool skip_logos = false;
bool detected_game = false;

Expand Down

0 comments on commit 43dbe0b

Please sign in to comment.