14#include "absl/status/status.h"
15#include "absl/status/statusor.h"
16#include "absl/strings/str_cat.h"
17#include "absl/strings/string_view.h"
33 uint32_t ptr2, uint32_t ptr3) {
35 data[ptr1 + addr], data[ptr2 + addr], data[ptr3 + addr]));
40 std::vector<uint8_t> sheet;
41 const uint8_t sheets[] = {113, 114, 218, 219, 220, 221};
43 for (
const auto &sheet_id : sheets) {
44 auto offset = GetGraphicsAddress(
data(), sheet_id,
51 for (
const auto &each_pixel : converted_sheet) {
52 sheet.push_back(each_pixel);
59 const uint32_t kLinkGfxOffset = 0x80000;
60 const uint16_t kLinkGfxLength = 0x800;
74 return absl::OkStatus();
78 std::vector<uint8_t> sheet;
82 if (i >= 115 && i <= 126) {
92 }
else if (i == 113 || i == 114 || i >= 218) {
133 return absl::OkStatus();
141 std::vector<uint8_t> final_data;
142 bool compressed =
true;
143 if (i >= 115 && i <= 126) {
146 }
else if (i == 113 || i == 114 || i >= 218) {
161 std::copy(final_data.begin(), final_data.end(),
165 return absl::OkStatus();
170 return absl::InvalidArgumentError(
171 "Could not load ROM: parameter `filename` is empty.");
173 std::string full_filename = std::filesystem::absolute(
filename).string();
176 std::ifstream file(
filename_, std::ios::binary);
177 if (!file.is_open()) {
178 return absl::NotFoundError(
179 absl::StrCat(
"Could not open ROM file: ",
filename_));
185 }
catch (
const std::filesystem::filesystem_error &e) {
187 file.seekg(0, std::ios::end);
189 return absl::InternalError(absl::StrCat(
190 "Could not get file size: ",
filename_,
" - ", e.what()));
192 size_ = file.tellg();
208 std::string resource_label_filename = absl::StrFormat(
"%s.labels",
filename);
210 return absl::OkStatus();
214 if (!
data || length == 0)
215 return absl::InvalidArgumentError(
216 "Could not load ROM: parameter `data` is empty.");
228 return absl::OkStatus();
233 constexpr size_t kBaseRomSize = 1048576;
234 constexpr size_t kHeaderSize = 0x200;
235 if (
size_ % kBaseRomSize == kHeaderSize) {
243 constexpr uint32_t kTitleStringOffset = 0x7FC0;
244 constexpr uint32_t kTitleStringLength = 20;
245 std::copy(
rom_data_.begin() + kTitleStringOffset,
246 rom_data_.begin() + kTitleStringOffset + kTitleStringLength,
248 if (
rom_data_[kTitleStringOffset + 0x19] == 0) {
261 size_ = kBaseRomSize * 2;
263 return absl::OkStatus();
268 return absl::InvalidArgumentError(
269 "Could not load ROM: parameter `data` is empty.");
274 return absl::OkStatus();
278 absl::Status non_firing_status;
280 return absl::InternalError(
"ROM data is empty.");
291 auto now = std::chrono::system_clock::now();
292 auto now_c = std::chrono::system_clock::to_time_t(now);
293 std::string backup_filename =
294 absl::StrCat(
filename,
"_backup_", std::ctime(&now_c));
297 backup_filename.erase(
298 std::remove(backup_filename.begin(), backup_filename.end(),
'\n'),
299 backup_filename.end());
302 std::replace(backup_filename.begin(), backup_filename.end(),
' ',
'_');
306 std::filesystem::copy(
filename_, backup_filename,
307 std::filesystem::copy_options::overwrite_existing);
308 }
catch (
const std::filesystem::filesystem_error &e) {
309 non_firing_status = absl::InternalError(absl::StrCat(
310 "Could not create backup file: ", backup_filename,
" - ", e.what()));
322 auto now = std::chrono::system_clock::now();
323 auto now_c = std::chrono::system_clock::to_time_t(now);
325 std::cout << filename_no_ext << std::endl;
326 filename = absl::StrCat(filename_no_ext,
"_", std::ctime(&now_c));
339 std::ofstream file(
filename.data(), std::ios::binary | std::ios::app);
342 file.open(
filename.data(), std::ios::binary);
344 return absl::InternalError(
345 absl::StrCat(
"Could not open or create ROM file: ",
filename));
352 static_cast<const char *
>(
static_cast<const void *
>(
rom_data_.data())),
354 }
catch (
const std::ofstream::failure &e) {
355 return absl::InternalError(absl::StrCat(
356 "Error while writing to ROM file: ",
filename,
" - ", e.what()));
361 return absl::InternalError(
362 absl::StrCat(
"Error while writing to ROM file: ",
filename));
365 if (!non_firing_status.ok()) {
366 return non_firing_status;
369 return absl::OkStatus();
374 for (
size_t j = 0; j < palette.
size(); ++j) {
383 return absl::OkStatus();
389 for (size_t i = 0; i < group.size(); ++i) {
391 SavePalette(i, group.name(), *group.mutable_palette(i)));
393 return absl::OkStatus();
396 return absl::OkStatus();
399absl::Status Rom::LoadGfxGroups() {
401 main_blockset_ptr = core::SnesToPc(main_blockset_ptr);
404 for (
int j = 0; j < 8; j++) {
405 main_blockset_ids[i][j] = rom_data_[main_blockset_ptr + (i * 8) + j];
410 for (
int j = 0; j < 4; j++) {
416 for (
int j = 0; j < 4; j++) {
417 spriteset_ids[i][j] =
418 rom_data_[version_constants().kSpriteBlocksetPointer + (i * 4) + j];
423 for (
int j = 0; j < 4; j++) {
424 paletteset_ids[i][j] =
425 rom_data_[version_constants().kDungeonPalettesGroups + (i * 4) + j];
429 return absl::OkStatus();
432absl::Status Rom::SaveGroupsToRom() {
434 main_blockset_ptr = core::SnesToPc(main_blockset_ptr);
437 for (
int j = 0; j < 8; j++) {
438 rom_data_[main_blockset_ptr + (i * 8) + j] = main_blockset_ids[i][j];
443 for (
int j = 0; j < 4; j++) {
449 for (
int j = 0; j < 4; j++) {
450 rom_data_[version_constants().kSpriteBlocksetPointer + (i * 4) + j] =
456 for (
int j = 0; j < 4; j++) {
457 rom_data_[version_constants().kDungeonPalettesGroups + (i * 4) + j] =
458 paletteset_ids[i][j];
462 return absl::OkStatus();
465std::shared_ptr<Rom> SharedRom::shared_rom_ =
nullptr;
VersionConstants version_constants() const
std::vector< uint8_t > rom_data_
absl::Status LoadGfxGroups()
absl::Status SaveAllGraphicsData()
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.
ResourceLabelManager resource_label_manager_
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_
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 > > CompressV2(const uchar *data, const int start, const int length, int mode, bool check)
Compresses a buffer of data using the LC_LZ2 algorithm.
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
std::vector< uint8_t > SnesTo8bppSheet(const std::vector< uint8_t > &sheet, int bpp, int num_sheets)
constexpr int kTilesheetWidth
absl::Status LoadAllPalettes(const std::vector< uint8_t > &rom_data, PaletteGroupMap &groups)
Loads all the palettes for the game.
std::vector< uint8_t > ConvertBpp(const std::vector< uint8_t > &tiles, uint32_t from_bpp, uint32_t to_bpp)
constexpr int kTilesheetHeight
constexpr uint32_t kNumRoomBlocksets
constexpr uint32_t kNumSpritesets
constexpr int Uncompressed3BPPSize
constexpr uint32_t kNumLinkSheets
constexpr uint32_t kNumGfxSheets
constexpr uint32_t kEntranceGfxGroup
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.