diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index 2f5f0995..a9f4f39b 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -160,14 +160,14 @@ void MasterEditor::DrawYazeMenu() { END_MENU_BAR() } -void MasterEditor::DrawFileMenu() const { +void MasterEditor::DrawFileMenu() { if (ImGui::BeginMenu("File")) { if (ImGui::MenuItem("Open", "Ctrl+O")) { ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Open ROM", ".sfc,.smc", "."); } - MENU_ITEM2("Save", "Ctrl+S") {} + MENU_ITEM2("Save", "Ctrl+S") { status_ = rom_.SaveToFile(true); } MENU_ITEM("Save As..") {} ImGui::Separator(); diff --git a/src/app/editor/master_editor.h b/src/app/editor/master_editor.h index 66712aee..42a208f0 100644 --- a/src/app/editor/master_editor.h +++ b/src/app/editor/master_editor.h @@ -38,7 +38,7 @@ class MasterEditor { void DrawInfoPopup(); void DrawYazeMenu(); - void DrawFileMenu() const; + void DrawFileMenu(); void DrawEditMenu(); void DrawViewMenu(); void DrawHelpMenu(); diff --git a/src/app/rom.cc b/src/app/rom.cc index 0b208c56..09a902c0 100644 --- a/src/app/rom.cc +++ b/src/app/rom.cc @@ -596,6 +596,8 @@ absl::StatusOr ROM::Load2bppGraphics() { return sheet; } +// ============================================================================ + // 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 @@ -692,60 +694,6 @@ absl::Status ROM::LoadFromBytes(const Bytes& data) { // ============================================================================ -absl::Status ROM::SaveToFile() { - std::fstream file(filename_.data(), std::ios::binary | std::ios::out); - if (!file.is_open()) { - return absl::InternalError( - absl::StrCat("Could not open ROM file: ", filename_)); - } - for (auto i = 0; i < size_; ++i) { - file << rom_data_[i]; - } - return absl::OkStatus(); -} - -// ============================================================================ - -gfx::SNESColor ROM::ReadColor(int offset) { - short color = toint16(offset); - gfx::snes_color new_color; - new_color.red = (color & 0x1F) * 8; - new_color.green = ((color >> 5) & 0x1F) * 8; - new_color.blue = ((color >> 10) & 0x1F) * 8; - gfx::SNESColor snes_color(new_color); - return snes_color; -} - -// ============================================================================ - -gfx::SNESPalette ROM::ReadPalette(int offset, int num_colors) { - int color_offset = 0; - std::vector colors(num_colors); - - while (color_offset < num_colors) { - short color = toint16(offset); - gfx::snes_color new_color; - new_color.red = (color & 0x1F) * 8; - new_color.green = ((color >> 5) & 0x1F) * 8; - new_color.blue = ((color >> 10) & 0x1F) * 8; - colors[color_offset].setSNES(new_color); - color_offset++; - offset += 2; - } - - gfx::SNESPalette palette(colors); - return palette; -} - -void ROM::Write(int addr, int value) { rom_data_[addr] = value; } - -void ROM::WriteShort(int addr, int value) { - rom_data_[addr] = (uchar)(value & 0xFF); - rom_data_[addr + 1] = (uchar)((value >> 8) & 0xFF); -} - -// ============================================================================ - void ROM::LoadAllPalettes() { // 35 colors each, 7x5 (0,2 on grid) for (int i = 0; i < 6; i++) { @@ -816,12 +764,11 @@ void ROM::LoadAllPalettes() { } } +// ============================================================================ + void ROM::SaveAllPalettes() { // Iterate through all palette_groups_ - for (auto& group : palette_groups_) { - const std::string& groupName = group.first; - auto& palettes = group.second; - + for (auto& [groupName, palettes] : palette_groups_) { // Iterate through all palettes in the group for (size_t i = 0; i < palettes.size(); ++i) { auto palette = palettes[i]; @@ -840,6 +787,97 @@ void ROM::SaveAllPalettes() { } } +// ============================================================================ + +absl::Status ROM::SaveToFile(bool backup) { + // Check if backup is enabled + if (backup) { + // Create a backup file with timestamp in its name + auto now = std::chrono::system_clock::now(); + auto now_c = std::chrono::system_clock::to_time_t(now); + std::string backup_filename = + absl::StrCat(filename_, "_backup_", std::ctime(&now_c)); + + // Remove newline character from ctime() + backup_filename.erase( + std::remove(backup_filename.begin(), backup_filename.end(), '\n'), + backup_filename.end()); + + // Replace spaces with underscores + std::replace(backup_filename.begin(), backup_filename.end(), ' ', '_'); + + // Now, copy the original file to the backup file + std::filesystem::copy(filename_, backup_filename, + std::filesystem::copy_options::overwrite_existing); + } + + // Run the other save functions + SaveAllPalettes(); + + std::fstream file(filename_.data(), std::ios::binary | std::ios::out); + if (!file.is_open()) { + return absl::InternalError( + absl::StrCat("Could not open ROM file: ", filename_)); + } + + // Save the data to the file + for (auto i = 0; i < size_; ++i) { + file << rom_data_[i]; + } + + // Check for write errors + if (!file.good()) { + return absl::InternalError( + absl::StrCat("Error while writing to ROM file: ", filename_)); + } + + return absl::OkStatus(); +} + +// ============================================================================ + +gfx::SNESColor ROM::ReadColor(int offset) { + short color = toint16(offset); + gfx::snes_color new_color; + new_color.red = (color & 0x1F) * 8; + new_color.green = ((color >> 5) & 0x1F) * 8; + new_color.blue = ((color >> 10) & 0x1F) * 8; + gfx::SNESColor snes_color(new_color); + return snes_color; +} + +// ============================================================================ + +gfx::SNESPalette ROM::ReadPalette(int offset, int num_colors) { + int color_offset = 0; + std::vector colors(num_colors); + + while (color_offset < num_colors) { + short color = toint16(offset); + gfx::snes_color new_color; + new_color.red = (color & 0x1F) * 8; + new_color.green = ((color >> 5) & 0x1F) * 8; + new_color.blue = ((color >> 10) & 0x1F) * 8; + colors[color_offset].setSNES(new_color); + color_offset++; + offset += 2; + } + + gfx::SNESPalette palette(colors); + return palette; +} + +// ============================================================================ + +void ROM::Write(int addr, int value) { rom_data_[addr] = value; } + +void ROM::WriteShort(int addr, int value) { + rom_data_[addr] = (uchar)(value & 0xFF); + rom_data_[addr + 1] = (uchar)((value >> 8) & 0xFF); +} + +// ============================================================================ + void ROM::WriteColor(uint32_t address, const gfx::SNESColor& color) { uint16_t bgr = ((color.snes >> 10) & 0x1F) | ((color.snes & 0x1F) << 10) | (color.snes & 0x7C00); @@ -849,6 +887,8 @@ void ROM::WriteColor(uint32_t address, const gfx::SNESColor& color) { rom_data_[address + 1] = static_cast((bgr >> 8) & 0xFF); } +// ============================================================================ + uint32_t ROM::GetPaletteAddress(const std::string& groupName, size_t paletteIndex, size_t colorIndex) const { // Retrieve the base address for the palette group diff --git a/src/app/rom.h b/src/app/rom.h index e83c4160..16148815 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -4,8 +4,11 @@ #include #include +#include +#include #include #include +#include #include #include #include @@ -126,21 +129,17 @@ class ROM { absl::StatusOr DecompressGraphics(int pos, int size); absl::StatusOr DecompressOverworld(int pos, int size); + // Load functions absl::StatusOr Load2bppGraphics(); - absl::Status LoadAllGraphicsData(); absl::Status LoadFromFile(const absl::string_view& filename); absl::Status LoadFromPointer(uchar* data, size_t length); absl::Status LoadFromBytes(const Bytes& data); void LoadAllPalettes(); + absl::Status SaveToFile(bool backup); void SaveAllPalettes(); - uint32_t GetPaletteAddress(const std::string& groupName, size_t paletteIndex, - size_t colorIndex) const; - - absl::Status SaveToFile(); - gfx::SNESColor ReadColor(int offset); gfx::SNESPalette ReadPalette(int offset, int num_colors); @@ -148,24 +147,29 @@ class ROM { void WriteShort(int addr, int value); void WriteColor(uint32_t address, const gfx::SNESColor& color); + uint32_t GetPaletteAddress(const std::string& groupName, size_t paletteIndex, + size_t colorIndex) const; + absl::Status ApplyAssembly(const absl::string_view& filename, size_t patch_size); absl::Status PatchOverworldMosaic(char mosaic_tiles[core::kNumOverworldMaps], int routine_offset); - auto GetTitle() const { return title; } gfx::BitmapTable GetGraphicsBin() const { return graphics_bin_; } auto GetGraphicsBuffer() const { return graphics_buffer_; } - auto GetPaletteGroup(std::string group) { return palette_groups_[group]; } + auto GetPaletteGroup(const std::string& group) { + return palette_groups_[group]; + } + auto GetTitle() const { return title; } void SetupRenderer(std::shared_ptr renderer) { renderer_ = renderer; } + auto size() const { return size_; } auto isLoaded() const { return is_loaded_; } auto begin() { return rom_data_.begin(); } auto end() { return rom_data_.end(); } auto data() { return rom_data_.data(); } auto char_data() { return reinterpret_cast(rom_data_.data()); } - auto size() const { return size_; } uchar& operator[](int i) { if (i > size_) {