diff --git a/src/app/rom.cc b/src/app/rom.cc index 769f17ca..c9f2b45d 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -22,11 +22,11 @@ namespace yaze { namespace app { -absl::Status ROM::OpenFromFile(const absl::string_view &filename) { +absl::Status ROM::LoadFromFile(const absl::string_view &filename) { std::ifstream file(filename.data(), std::ios::binary); if (!file.is_open()) { return absl::InternalError( - absl::StrCat("Could not open ROM file ", filename)); + absl::StrCat("Could not open ROM file: ", filename)); } size_ = std::filesystem::file_size(filename); rom_data_.resize(size_); @@ -37,10 +37,25 @@ absl::Status ROM::OpenFromFile(const absl::string_view &filename) { } file.close(); is_loaded_ = true; + memcpy(title, rom_data_.data() + 32704, 20); // copy ROM title return absl::OkStatus(); } -absl::Status ROM::LoadAllGraphicsDataV2() { +absl::Status ROM::LoadFromPointer(uchar *data, size_t length) { + if (data == nullptr) + return absl::InvalidArgumentError( + "Could not load ROM: parameter `data` is empty"); + + memcpy(rom_data_.data(), data, length); + return absl::OkStatus(); +} + +// 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 +absl::Status ROM::LoadAllGraphicsData() { Bytes sheet; for (int i = 0; i < core::NumberOfSheets; i++) { @@ -53,7 +68,7 @@ absl::Status ROM::LoadAllGraphicsDataV2() { } else { auto offset = GetGraphicsAddress(i); absl::StatusOr new_sheet = - DecompressV2(offset, core::UncompressedSheetSize); + Decompress(offset, core::UncompressedSheetSize); if (!new_sheet.ok()) { return new_sheet.status(); } else { @@ -66,16 +81,24 @@ absl::Status ROM::LoadAllGraphicsDataV2() { return converted_sheet.status(); } else { Bytes result = std::move(*converted_sheet); - graphics_bin_v2_[i] = + graphics_bin_[i] = gfx::Bitmap(core::kTilesheetWidth, core::kTilesheetHeight, core::kTilesheetDepth, result.data()); - graphics_bin_v2_.at(i).CreateTexture(renderer_); + graphics_bin_.at(i).CreateTexture(renderer_); } } return absl::OkStatus(); } -absl::StatusOr ROM::DecompressV2(int offset, int size, bool reversed) { +absl::StatusOr ROM::DecompressGraphics(int pos, int size) { + return Decompress(pos, size, false); +} + +absl::StatusOr ROM::DecompressOverworld(int pos, int size) { + return Decompress(pos, size, true); +} + +absl::StatusOr ROM::Decompress(int offset, int size, bool reversed) { Bytes buffer(size); uint length = 0; uint buffer_pos = 0; @@ -190,227 +213,15 @@ absl::StatusOr ROM::Convert3bppTo8bppSheet(Bytes sheet, int size) { return sheet_buffer_out; } -// ---------------------------------------------------------------------------- - -void ROM::Close() { - if (is_loaded_) { - delete[] current_rom_; - for (auto i = 0; i < num_sheets_; i++) { - delete[] decompressed_graphic_sheets_[i]; - delete[] converted_graphic_sheets_[i]; - } - } -} - -void ROM::SetupRenderer(std::shared_ptr renderer) { - renderer_ = renderer; -} - -// TODO: check if the rom has a header on load -void ROM::LoadFromFile(const std::string &path) { - std::ifstream file(path.c_str(), std::ios::binary); - if (!file.is_open()) { - std::cout << "Error: Could not open ROM file " << path << std::endl; - return; - } - size_ = std::filesystem::file_size(path.c_str()); - current_rom_ = new uchar[size_]; - for (uint i = 0; i < size_; i++) { - char byte_read_ = ' '; - file.read(&byte_read_, sizeof(char)); - current_rom_[i] = byte_read_; - } - file.close(); - SDL_memcpy(title, current_rom_ + 32704, 20); - is_loaded_ = true; -} - -void ROM::LoadFromPointer(uchar *data) { current_rom_ = data; } - -// 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 -void ROM::LoadAllGraphicsData() { - auto buffer = new uchar[346624]; - auto data = new uchar[2048]; - int buffer_pos = 0; - - for (int i = 0; i < core::NumberOfSheets; i++) { - // uncompressed sheets - if (i >= 115 && i <= 126) { - data = new uchar[core::Uncompressed3BPPSize]; - int startAddress = GetGraphicsAddress(i); - for (int j = 0; j < core::Uncompressed3BPPSize; j++) { - data[j] = current_rom_[j + startAddress]; - } - } else { - auto gfx_addr = GetGraphicsAddress(i); - data = Decompress(gfx_addr, core::UncompressedSheetSize); - } - - gfx::Bitmap tilesheet_bmp(core::kTilesheetWidth, core::kTilesheetHeight, - core::kTilesheetDepth, SNES3bppTo8bppSheet(data)); - tilesheet_bmp.CreateTexture(renderer_); - graphics_bin_[i] = tilesheet_bmp; - - for (int j = 0; j < sizeof(data); j++) { - buffer[j + buffer_pos] = data[j]; - } - - buffer_pos += sizeof(data); - } - - master_gfx_bin_ = buffer; -} - uint ROM::GetGraphicsAddress(uint8_t offset) const { uint snes_address = 0; uint pc_address = 0; - snes_address = (uint)((((current_rom_[0x4F80 + offset]) << 16) | - ((current_rom_[0x505F + offset]) << 8) | - ((current_rom_[0x513E + offset])))); + snes_address = (uint)((((rom_data_[0x4F80 + offset]) << 16) | + ((rom_data_[0x505F + offset]) << 8) | + ((rom_data_[0x513E + offset])))); pc_address = core::SnesToPc(snes_address); return pc_address; } -uchar *ROM::DecompressGraphics(int pos, int size) { - return Decompress(pos, size, false); -} - -uchar *ROM::DecompressOverworld(int pos, int size) { - return Decompress(pos, size, true); -} - -uchar *ROM::Decompress(int pos, int size, bool reversed) { - auto buffer = new uchar[size]; - uint length = 0; - uint buffer_pos = 0; - uchar cmd = 0; - - uchar databyte = current_rom_[pos]; - while (databyte != 0xFF) { // End of decompression - databyte = current_rom_[pos]; - - // Expanded Command - if ((databyte & 0xE0) == 0xE0) { - cmd = (uchar)((databyte >> 2) & 0x07); - length = - (ushort)(((current_rom_[pos] << 8) | current_rom_[pos + 1]) & 0x3FF); - pos += 2; // Advance 2 bytes in ROM - } else { // Normal Command - cmd = (uchar)((databyte >> 5) & 0x07); - length = (uchar)(databyte & 0x1F); - pos += 1; // Advance 1 byte in ROM - } - length += 1; // each commands is at least of size 1 even if index 00 - - switch (cmd) { - case kCommandDirectCopy: - for (int i = 0; i < length; i++) { - buffer[buffer_pos++] = current_rom_[pos++]; - } - // Do not advance in the ROM - break; - case kCommandByteFill: - for (int i = 0; i < length; i++) { - buffer[buffer_pos++] = current_rom_[pos]; - } - pos += 1; // Advance 1 byte in the ROM - break; - case kCommandWordFill: - for (int i = 0; i < length; i += 2) { - buffer[buffer_pos++] = current_rom_[pos]; - buffer[buffer_pos++] = current_rom_[pos + 1]; - } - pos += 2; // Advance 2 byte in the ROM - break; - case kCommandIncreasingFill: { - uchar inc_byte = current_rom_[pos]; - for (int i = 0; i < length; i++) { - buffer[buffer_pos++] = inc_byte++; - } - pos += 1; // Advance 1 byte in the ROM - } break; - case kCommandRepeatingBytes: { - ushort s1 = ((current_rom_[pos + 1] & 0xFF) << 8); - ushort s2 = ((current_rom_[pos] & 0xFF)); - // Reversed byte order for overworld maps - if (reversed) { - auto addr = (current_rom_[pos + 2]) | ((current_rom_[pos + 1]) << 8); - if (buffer_pos + length >= size) { - size *= 2; - buffer = new uchar[size]; - std::cout << "Reallocate buffer" << std::endl; - } - memcpy(buffer + buffer_pos, current_rom_ + pos, length); - pos += 2; - } else { - auto addr = (ushort)(s1 | s2); - for (int i = 0; i < length; i++) { - buffer[buffer_pos] = buffer[addr + i]; - buffer_pos++; - } - pos += 2; // Advance 2 bytes in the ROM - } - } break; - } - } - num_sheets_++; - decompressed_graphic_sheets_.push_back(buffer); - return buffer; -} - -// 128x32 -uchar *ROM::SNES3bppTo8bppSheet(uchar *buffer_in, int sheet_id, int size) { - // 8bpp sheet out - auto sheet_buffer_out = new uchar[size]; - int xx = 0; // positions where we are at on the sheet - int yy = 0; - int pos = 0; - int ypos = 0; - - if (sheet_id != 0) { - yy = sheet_id; - } - - // for each tiles - // 16 per line - for (int i = 0; i < 64; i++) { - // for each line - for (int y = 0; y < 8; y++) { - //[0] + [1] + [16] - for (int x = 0; x < 8; x++) { - auto b1 = ((buffer_in[(y * 2) + (24 * pos)] & (kGraphicsBitmap[x]))); - auto b2 = - (buffer_in[((y * 2) + (24 * pos)) + 1] & (kGraphicsBitmap[x])); - auto b3 = (buffer_in[(16 + y) + (24 * pos)] & (kGraphicsBitmap[x])); - unsigned char b = 0; - if (b1 != 0) { - b |= 1; - } - if (b2 != 0) { - b |= 2; - } - if (b3 != 0) { - b |= 4; - } - sheet_buffer_out[x + (xx) + (y * 128) + (yy * 1024)] = b; - } - } - pos++; - ypos++; - xx += 8; - if (ypos >= 16) { - yy++; - xx = 0; - ypos = 0; - } - } - converted_graphic_sheets_.push_back(sheet_buffer_out); - return sheet_buffer_out; -} - } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/rom.h b/src/app/rom.h index 29b4b122..399a1bc3 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -40,41 +40,34 @@ struct OWMapTiles { class ROM { public: - absl::Status OpenFromFile(const absl::string_view& filename); - absl::StatusOr DecompressV2(int offset, int size = 0x800, - bool reversed = false); - absl::StatusOr Convert3bppTo8bppSheet(Bytes sheet, int size = 0x1000); - absl::Status LoadAllGraphicsDataV2(); + absl::Status LoadFromFile(const absl::string_view& filename); + absl::Status LoadFromPointer(uchar* data, size_t length); + absl::Status LoadAllGraphicsData(); // absl::Status SaveOverworld(); - // absl::Status SaveDungeons(); - void Close(); - void SetupRenderer(std::shared_ptr renderer); - void LoadFromFile(const std::string& path); - void LoadFromPointer(uchar* data); - void LoadAllGraphicsData(); + absl::StatusOr DecompressGraphics(int pos, int size); + absl::StatusOr DecompressOverworld(int pos, int size); + absl::StatusOr Decompress(int offset, int size = 0x800, + bool reversed = false); + + absl::StatusOr Convert3bppTo8bppSheet(Bytes sheet, int size = 0x1000); uint GetGraphicsAddress(uint8_t id) const; - - uchar* DecompressGraphics(int pos, int size); - uchar* DecompressOverworld(int pos, int size); - uchar* Decompress(int pos, int size = 0x800, bool reversed = false); - - uchar* SNES3bppTo8bppSheet(uchar* buffer_in, int sheet_id = 0, - int size = 0x1000); - - auto data() { return rom_data_.data(); } - auto isLoaded() const { return is_loaded_; } auto GetSize() const { return size_; } auto GetTitle() const { return title; } - auto Renderer() { return renderer_; } auto GetGraphicsBin() const { return graphics_bin_; } - auto GetGraphicsBinV2() const { return graphics_bin_v2_; } auto GetMasterGraphicsBin() const { return master_gfx_bin_; } auto GetVRAM() const { return pseudo_vram_; } auto GetBytes() const { return rom_data_; } + auto data() { return rom_data_.data(); } + auto isLoaded() const { return is_loaded_; } + + auto Renderer() { return renderer_; } + void SetupRenderer(std::shared_ptr renderer) { + renderer_ = renderer; + } uchar& operator[](int i) { if (i > size_) { std::cout << "Index out of bounds" << std::endl; @@ -96,11 +89,8 @@ class ROM { gfx::pseudo_vram pseudo_vram_; Bytes rom_data_; - std::vector decompressed_graphic_sheets_; - std::vector converted_graphic_sheets_; std::shared_ptr renderer_; - std::unordered_map graphics_bin_; - absl::flat_hash_map graphics_bin_v2_; + absl::flat_hash_map graphics_bin_; }; } // namespace app