13#include <unordered_map>
17#include "absl/container/flat_hash_map.h"
18#include "absl/status/status.h"
19#include "absl/status/statusor.h"
20#include "absl/strings/str_cat.h"
21#include "absl/strings/string_view.h"
39 uint32_t ptr2, uint32_t ptr3) {
41 data[ptr1 + addr], data[ptr2 + addr], data[ptr3 + addr]));
46 std::vector<uint8_t> sheet;
47 const uint8_t sheets[] = {113, 114, 218, 219, 220, 221};
49 for (
const auto& sheet_id : sheets) {
50 auto offset = GetGraphicsAddress(
data(), sheet_id,
57 for (
const auto& each_pixel : converted_sheet) {
58 sheet.push_back(each_pixel);
65 const uint32_t kLinkGfxOffset = 0x80000;
66 const uint16_t kLinkGfxLength = 0x800;
80 return absl::OkStatus();
84 std::vector<uint8_t> sheet;
88 if (i >= 115 && i <= 126) {
98 }
else if (i == 113 || i == 114 || i >= 218) {
139 return absl::OkStatus();
144 return absl::InvalidArgumentError(
145 "Could not load ROM: parameter `filename` is empty.");
147 std::string full_filename = std::filesystem::absolute(
filename).string();
151 std::ifstream file(
filename_, std::ios::binary);
152 if (!file.is_open()) {
153 return absl::NotFoundError(
154 absl::StrCat(
"Could not open ROM file: ",
filename_));
160 }
catch (
const std::filesystem::filesystem_error& e) {
162 file.seekg(0, std::ios::end);
164 return absl::InternalError(absl::StrCat(
165 "Could not get file size: ",
filename_,
" - ", e.what()));
167 size_ = file.tellg();
185 std::string resource_label_filename = absl::StrFormat(
"%s.labels",
filename);
188 return absl::OkStatus();
192 if (!
data || length == 0)
193 return absl::InvalidArgumentError(
194 "Could not load ROM: parameter `data` is empty.");
206 return absl::OkStatus();
211 constexpr size_t kBaseRomSize = 1048576;
212 constexpr size_t kHeaderSize = 0x200;
213 if (
size_ % kBaseRomSize == kHeaderSize) {
221 constexpr uint32_t kTitleStringOffset = 0x7FC0;
222 constexpr uint32_t kTitleStringLength = 20;
223 std::copy(
rom_data_.begin() + kTitleStringOffset,
224 rom_data_.begin() + kTitleStringOffset + kTitleStringLength,
226 if (
rom_data_[kTitleStringOffset + 0x19] == 0) {
238 size_ = kBaseRomSize * 2;
240 return absl::OkStatus();
245 return absl::InvalidArgumentError(
246 "Could not load ROM: parameter `data` is empty.");
251 return absl::OkStatus();
255 absl::Status non_firing_status;
257 return absl::InternalError(
"ROM data is empty.");
268 auto now = std::chrono::system_clock::now();
269 auto now_c = std::chrono::system_clock::to_time_t(now);
270 std::string backup_filename =
271 absl::StrCat(
filename,
"_backup_", std::ctime(&now_c));
274 backup_filename.erase(
275 std::remove(backup_filename.begin(), backup_filename.end(),
'\n'),
276 backup_filename.end());
279 std::replace(backup_filename.begin(), backup_filename.end(),
' ',
'_');
283 std::filesystem::copy(
filename_, backup_filename,
284 std::filesystem::copy_options::overwrite_existing);
285 }
catch (
const std::filesystem::filesystem_error& e) {
286 non_firing_status = absl::InternalError(absl::StrCat(
287 "Could not create backup file: ", backup_filename,
" - ", e.what()));
292 if (
flags()->kSaveAllPalettes) {
296 if (
flags()->kSaveGfxGroups) {
303 auto now = std::chrono::system_clock::now();
304 auto now_c = std::chrono::system_clock::to_time_t(now);
306 std::cout << filename_no_ext << std::endl;
307 filename = absl::StrCat(filename_no_ext,
"_", std::ctime(&now_c));
320 std::ofstream file(
filename.data(), std::ios::binary | std::ios::app);
323 file.open(
filename.data(), std::ios::binary);
325 return absl::InternalError(
326 absl::StrCat(
"Could not open or create ROM file: ",
filename));
333 static_cast<const char*
>(
static_cast<const void*
>(
rom_data_.data())),
335 }
catch (
const std::ofstream::failure& e) {
336 return absl::InternalError(absl::StrCat(
337 "Error while writing to ROM file: ",
filename,
" - ", e.what()));
342 return absl::InternalError(
343 absl::StrCat(
"Error while writing to ROM file: ",
filename));
346 if (!non_firing_status.ok()) {
347 return non_firing_status;
350 return absl::OkStatus();
355 for (
size_t j = 0; j < palette.
size(); ++j) {
364 return absl::OkStatus();
370 for (size_t i = 0; i < group.size(); ++i) {
372 SavePalette(i, group.name(), *group.mutable_palette(i)));
374 return absl::OkStatus();
377 return absl::OkStatus();
380absl::Status Rom::LoadGfxGroups() {
387 main_blockset_ptr = core::SnesToPc(main_blockset_ptr);
390 for (
int j = 0; j < 8; j++) {
391 main_blockset_ids[i][j] = rom_data_[main_blockset_ptr + (i * 8) + j];
396 for (
int j = 0; j < 4; j++) {
402 for (
int j = 0; j < 4; j++) {
403 spriteset_ids[i][j] =
404 rom_data_[version_constants().kSpriteBlocksetPointer + (i * 4) + j];
409 for (
int j = 0; j < 4; j++) {
410 paletteset_ids[i][j] =
411 rom_data_[version_constants().kDungeonPalettesGroups + (i * 4) + j];
415 return absl::OkStatus();
418absl::Status Rom::SaveGroupsToRom() {
420 main_blockset_ptr = core::SnesToPc(main_blockset_ptr);
423 for (
int j = 0; j < 8; j++) {
424 rom_data_[main_blockset_ptr + (i * 8) + j] = main_blockset_ids[i][j];
429 for (
int j = 0; j < 4; j++) {
435 for (
int j = 0; j < 4; j++) {
436 rom_data_[version_constants().kSpriteBlocksetPointer + (i * 4) + j] =
442 for (
int j = 0; j < 4; j++) {
443 rom_data_[version_constants().kDungeonPalettesGroups + (i * 4) + j] =
444 paletteset_ids[i][j];
448 return absl::OkStatus();
451std::shared_ptr<Rom> SharedRom::shared_rom_ =
nullptr;
VersionConstants version_constants() const
std::vector< uint8_t > rom_data_
absl::Status LoadGfxGroups()
absl::Status SaveToFile(bool backup, bool save_new=false, std::string filename="")
Saves the Rom data to a file.
absl::Status SaveAllPalettes()
Saves all palettes in the Rom.
std::array< gfx::Bitmap, kNumGfxSheets > graphics_sheets_
absl::Status SavePalette(int index, const std::string &group_name, gfx::SnesPalette &palette)
absl::Status LoadAllGraphicsData(bool defer_render=false)
This function iterates over all graphics sheets in the Rom and loads them into memory....
absl::StatusOr< std::vector< uint8_t > > Load2BppGraphics()
Loads 2bpp graphics from Rom data.
absl::Status LoadLinkGraphics()
Loads the players 4bpp graphics sheet from Rom data.
gfx::PaletteGroupMap palette_groups_
absl::Status WriteColor(uint32_t address, const gfx::SnesColor &color)
absl::Status SaveGroupsToRom()
absl::Status LoadFromFile(const std::string &filename, bool z3_load=true)
absl::Status LoadFromBytes(const std::vector< uint8_t > &data)
absl::StatusOr< std::vector< uint8_t > > ReadByteVector(uint32_t offset, uint32_t length)
std::vector< uint8_t > graphics_buffer_
core::ResourceLabelManager resource_label_manager_
absl::Status LoadFromPointer(uchar *data, size_t length, bool z3_load=true)
absl::Status LoadZelda3()
std::array< gfx::Bitmap, kNumLinkSheets > link_graphics_
static Renderer & GetInstance()
void RenderBitmap(gfx::Bitmap *bitmap)
Used to render a bitmap to the screen.
void set_modified(bool m)
Represents a palette of colors for the Super Nintendo Entertainment System (SNES).
#define RETURN_IF_ERROR(expression)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
int GetGraphicsAddress(const uchar *data, uint8_t addr, uint32_t ptr1, uint32_t ptr2, uint32_t ptr3)
int AddressFromBytes(uint8_t bank, uint8_t high, uint8_t low) noexcept
uint32_t SnesToPc(uint32_t addr) noexcept
absl::StatusOr< std::vector< uint8_t > > DecompressV2(const uchar *data, int offset, int size, int mode)
Decompresses a buffer of data using the LC_LZ2 algorithm.
uint32_t GetPaletteAddress(const std::string &group_name, size_t palette_index, size_t color_index)
constexpr int kTilesheetDepth
constexpr int kTilesheetWidth
std::vector< uint8_t > SnesTo8bppSheet(const std::vector< uint8_t > &sheet, int bpp)
absl::Status LoadAllPalettes(const std::vector< uint8_t > &rom_data, PaletteGroupMap &groups)
Loads all the palettes for the game.
constexpr int kTilesheetHeight
constexpr int kEntranceGfxGroup
constexpr uint32_t kNumRoomBlocksets
constexpr uint32_t kNumSpritesets
constexpr int Uncompressed3BPPSize
constexpr uint32_t kNumLinkSheets
constexpr uint32_t kNumGfxSheets
constexpr uint32_t kNumMainBlocksets
constexpr uint32_t kGfxGroupsPointer
constexpr uint32_t kNumPalettesets
bool LoadLabels(const std::string &filename)
PaletteGroup global_sprites
PaletteGroup dungeon_main
absl::Status for_each(Func &&func)
Represents a group of palettes.