From 9604ce3724dd83db4212ee9c8d8be1e9208baba0 Mon Sep 17 00:00:00 2001 From: scawful Date: Sun, 14 Apr 2024 11:57:59 -0500 Subject: [PATCH] Refactor ROM class --- src/app/rom.cc | 14 ++-- src/app/rom.h | 180 ++++++++++++++++++++++++------------------------- 2 files changed, 98 insertions(+), 96 deletions(-) diff --git a/src/app/rom.cc b/src/app/rom.cc index e390c1bb..929f7b42 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -220,7 +220,8 @@ absl::Status ROM::LoadLinkGraphics() { auto link_sheet_8bpp = gfx::SnesTo8bppSheet(link_sheet_3bpp, /*bpp=*/3); link_graphics_[i].Create(core::kTilesheetWidth, core::kTilesheetHeight, core::kTilesheetDepth, link_sheet_8bpp); - RETURN_IF_ERROR(link_graphics_[i].ApplyPaletteWithTransparent(link_palette_, 0)); + RETURN_IF_ERROR( + link_graphics_[i].ApplyPaletteWithTransparent(link_palette_, 0)); RenderBitmap(&link_graphics_[i]); } @@ -228,6 +229,7 @@ absl::Status ROM::LoadLinkGraphics() { } absl::Status ROM::LoadAllGraphicsData() { + constexpr uint32_t kNumGfxSheets = 223; Bytes sheet; bool bpp3 = false; @@ -255,11 +257,11 @@ absl::Status ROM::LoadAllGraphicsData() { core::kTilesheetDepth); if (i > 115) { // Apply sprites palette - graphics_manager_[i]->ApplyPaletteWithTransparent( - palette_groups_["global_sprites"][0], 0); + RETURN_IF_ERROR(graphics_manager_[i]->ApplyPaletteWithTransparent( + palette_groups_["global_sprites"][0], 0)); } else { - graphics_manager_[i]->ApplyPaletteWithTransparent( - palette_groups_["dungeon_main"][0], 0); + RETURN_IF_ERROR(graphics_manager_[i]->ApplyPaletteWithTransparent( + palette_groups_["dungeon_main"][0], 0)); } graphics_manager_[i]->CreateTexture(renderer_); } @@ -341,6 +343,8 @@ absl::Status ROM::LoadFromFile(const absl::string_view& filename, // Load Zelda 3 specific data if requested if (z3_load) { // Copy ROM title + constexpr uint32_t kTitleStringOffset = 0x7FC0; + constexpr uint32_t kTitleStringLength = 20; memcpy(title_, rom_data_.data() + kTitleStringOffset, kTitleStringLength); if (rom_data_[kTitleStringOffset + 0x19] == 0) { version_ = Z3_Version::JP; diff --git a/src/app/rom.h b/src/app/rom.h index b5a0b562..45c0a91e 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -44,13 +44,15 @@ using PaletteGroupMap = std::unordered_map; // Define an enum class for the different versions of the game enum class Z3_Version { - US = 1, - JP = 2, - SD = 3, - RANDO = 4, + US = 1, // US version + JP = 2, // JP version + SD = 3, // Super Donkey Proto (Experimental) + RANDO = 4, // Randomizer (Unimplemented) }; -// Define a struct to hold the version-specific constants +/** + * @brief A struct to hold version constants for each version of the game. + */ struct VersionConstants { uint32_t kGfxAnimatedPointer; uint32_t kOverworldGfxGroups1; @@ -72,7 +74,9 @@ struct VersionConstants { uint32_t kDungeonPalettesGroups; }; -// Define a map to hold the version constants for each version +/** + * @brief A map of version constants for each version of the game. + */ static const std::map kVersionConstantsMap = { {Z3_Version::US, { @@ -117,91 +121,16 @@ static const std::map kVersionConstantsMap = { 0x67DD0, // kDungeonPalettesGroups }}}; -// Define some constants used throughout the ROM class -constexpr uint32_t kOverworldGraphicsPos1 = 0x4F80; -constexpr uint32_t kOverworldGraphicsPos2 = 0x505F; -constexpr uint32_t kOverworldGraphicsPos3 = 0x513E; -constexpr uint32_t kTile32Num = 4432; -constexpr uint32_t kTitleStringOffset = 0x7FC0; -constexpr uint32_t kTitleStringLength = 20; -constexpr uint32_t kNumGfxSheets = 223; constexpr uint32_t kNormalGfxSpaceStart = 0x87000; constexpr uint32_t kNormalGfxSpaceEnd = 0xC4200; -constexpr uint32_t kLinkSpriteLocation = 0x80000; constexpr uint32_t kFontSpriteLocation = 0x70000; -constexpr uint32_t gfx_groups_pointer = 0x6237; - -struct WriteAction { - int address; - std::variant, - gfx::SnesColor, std::vector> - value; -}; +constexpr uint32_t kGfxGroupsPointer = 0x6237; /** * @brief The ROM class is used to load, save, and modify ROM data. */ class ROM : public core::ExperimentFlags { public: - template - absl::Status RunTransaction(Args... args) { - absl::Status status; - // Fold expression to apply the Write function on each argument - ((status = WriteHelper(args)), ...); - return status; - } - - absl::Status WriteHelper(const WriteAction& action) { - if (std::holds_alternative(action.value)) { - return Write(action.address, std::get(action.value)); - } else if (std::holds_alternative(action.value) || - std::holds_alternative(action.value)) { - return WriteShort(action.address, std::get(action.value)); - } else if (std::holds_alternative>(action.value)) { - return WriteVector(action.address, - std::get>(action.value)); - } else if (std::holds_alternative(action.value)) { - return WriteColor(action.address, std::get(action.value)); - } else if (std::holds_alternative>( - action.value)) { - return absl::UnimplementedError( - "WriteHelper: std::vector"); - } - auto error_message = absl::StrFormat("Invalid write argument type: %s", - typeid(action.value).name()); - throw std::runtime_error(error_message); - return absl::InvalidArgumentError(error_message); - } - - template - absl::Status ReadTransaction(T& var, int address, Args&&... args) { - absl::Status status = ReadHelper(var, address); - if (!status.ok()) { - return status; - } - - if constexpr (sizeof...(args) > 0) { - status = ReadTransaction(std::forward(args)...); - } - - return status; - } - - template - absl::Status ReadHelper(T& var, int address) { - if constexpr (std::is_same_v) { - ASSIGN_OR_RETURN(auto result, ReadByte(address)); - var = result; - } else if constexpr (std::is_same_v) { - ASSIGN_OR_RETURN(auto result, ReadWord(address)); - var = result; - } else if constexpr (std::is_same_v>) { - ASSIGN_OR_RETURN(auto result, ReadByteVector(address, var.size())); - var = result; - } - return absl::OkStatus(); - } - /** * @brief Loads 2bpp graphics from ROM data. * @@ -225,11 +154,14 @@ class ROM : public core::ExperimentFlags { * data is converted to 8 BPP and stored in a bitmap. * * The graphics sheets are divided into the following ranges: - * 0-112 -> compressed 3bpp bgr -> (decompressed each) 0x600 chars - * 113-114 -> compressed 2bpp -> (decompressed each) 0x800 chars - * 115-126 -> uncompressed 3bpp sprites -> (each) 0x600 chars - * 127-217 -> compressed 3bpp sprites -> (decompressed each) 0x600 chars - * 218-222 -> compressed 2bpp -> (decompressed each) 0x800 chars + * + * | Range | Compression Type | Decompressed Size | Number of Chars | + * |---------|------------------|------------------|-----------------| + * | 0-112 | Compressed 3bpp BGR | 0x600 chars | Decompressed each | + * | 113-114 | Compressed 2bpp | 0x800 chars | Decompressed each | + * | 115-126 | Uncompressed 3bpp sprites | 0x600 chars | Each | + * | 127-217 | Compressed 3bpp sprites | 0x600 chars | Decompressed each | + * | 218-222 | Compressed 2bpp | 0x800 chars | Decompressed each | * */ absl::Status LoadAllGraphicsData(); @@ -468,6 +400,28 @@ class ROM : public core::ExperimentFlags { return WriteShort(address, bgr); } + template + absl::Status WriteTransaction(Args... args) { + absl::Status status; + // Fold expression to apply the Write function on each argument + ((status = WriteHelper(args)), ...); + return status; + } + + template + absl::Status ReadTransaction(T& var, int address, Args&&... args) { + absl::Status status = ReadHelper(var, address); + if (!status.ok()) { + return status; + } + + if constexpr (sizeof...(args) > 0) { + status = ReadTransaction(std::forward(args)...); + } + + return status; + } + void Expand(int size) { rom_data_.resize(size); size_ = size; @@ -596,8 +550,8 @@ class ROM : public core::ExperimentFlags { spriteset_ids.resize(144, std::vector(4)); paletteset_ids.resize(72, std::vector(4)); - int gfxPointer = (rom_data_[gfx_groups_pointer + 1] << 8) + - rom_data_[gfx_groups_pointer]; + int gfxPointer = + (rom_data_[kGfxGroupsPointer + 1] << 8) + rom_data_[kGfxGroupsPointer]; gfxPointer = core::SnesToPc(gfxPointer); for (int i = 0; i < 37; i++) { @@ -629,8 +583,8 @@ class ROM : public core::ExperimentFlags { } bool SaveGroupsToROM() { - int gfxPointer = (rom_data_[gfx_groups_pointer + 1] << 8) + - rom_data_[gfx_groups_pointer]; + int gfxPointer = + (rom_data_[kGfxGroupsPointer + 1] << 8) + rom_data_[kGfxGroupsPointer]; gfxPointer = core::SnesToPc(gfxPointer); for (int i = 0; i < 37; i++) { @@ -666,6 +620,50 @@ class ROM : public core::ExperimentFlags { auto resource_label() { return &resource_label_manager_; } private: + struct WriteAction { + int address; + std::variant, + gfx::SnesColor, std::vector> + value; + }; + + absl::Status WriteHelper(const WriteAction& action) { + if (std::holds_alternative(action.value)) { + return Write(action.address, std::get(action.value)); + } else if (std::holds_alternative(action.value) || + std::holds_alternative(action.value)) { + return WriteShort(action.address, std::get(action.value)); + } else if (std::holds_alternative>(action.value)) { + return WriteVector(action.address, + std::get>(action.value)); + } else if (std::holds_alternative(action.value)) { + return WriteColor(action.address, std::get(action.value)); + } else if (std::holds_alternative>( + action.value)) { + return absl::UnimplementedError( + "WriteHelper: std::vector"); + } + auto error_message = absl::StrFormat("Invalid write argument type: %s", + typeid(action.value).name()); + throw std::runtime_error(error_message); + return absl::InvalidArgumentError(error_message); + } + + template + absl::Status ReadHelper(T& var, int address) { + if constexpr (std::is_same_v) { + ASSIGN_OR_RETURN(auto result, ReadByte(address)); + var = result; + } else if constexpr (std::is_same_v) { + ASSIGN_OR_RETURN(auto result, ReadWord(address)); + var = result; + } else if constexpr (std::is_same_v>) { + ASSIGN_OR_RETURN(auto result, ReadByteVector(address, var.size())); + var = result; + } + return absl::OkStatus(); + } + long size_ = 0; bool is_loaded_ = false; bool has_header_ = false;