Save ROM with modified palettes, backup system
This commit is contained in:
@@ -160,14 +160,14 @@ void MasterEditor::DrawYazeMenu() {
|
|||||||
END_MENU_BAR()
|
END_MENU_BAR()
|
||||||
}
|
}
|
||||||
|
|
||||||
void MasterEditor::DrawFileMenu() const {
|
void MasterEditor::DrawFileMenu() {
|
||||||
if (ImGui::BeginMenu("File")) {
|
if (ImGui::BeginMenu("File")) {
|
||||||
if (ImGui::MenuItem("Open", "Ctrl+O")) {
|
if (ImGui::MenuItem("Open", "Ctrl+O")) {
|
||||||
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Open ROM",
|
ImGuiFileDialog::Instance()->OpenDialog("ChooseFileDlgKey", "Open ROM",
|
||||||
".sfc,.smc", ".");
|
".sfc,.smc", ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
MENU_ITEM2("Save", "Ctrl+S") {}
|
MENU_ITEM2("Save", "Ctrl+S") { status_ = rom_.SaveToFile(true); }
|
||||||
MENU_ITEM("Save As..") {}
|
MENU_ITEM("Save As..") {}
|
||||||
|
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ class MasterEditor {
|
|||||||
void DrawInfoPopup();
|
void DrawInfoPopup();
|
||||||
|
|
||||||
void DrawYazeMenu();
|
void DrawYazeMenu();
|
||||||
void DrawFileMenu() const;
|
void DrawFileMenu();
|
||||||
void DrawEditMenu();
|
void DrawEditMenu();
|
||||||
void DrawViewMenu();
|
void DrawViewMenu();
|
||||||
void DrawHelpMenu();
|
void DrawHelpMenu();
|
||||||
|
|||||||
156
src/app/rom.cc
156
src/app/rom.cc
@@ -596,6 +596,8 @@ absl::StatusOr<Bytes> ROM::Load2bppGraphics() {
|
|||||||
return sheet;
|
return sheet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
// 0-112 -> compressed 3bpp bgr -> (decompressed each) 0x600 chars
|
// 0-112 -> compressed 3bpp bgr -> (decompressed each) 0x600 chars
|
||||||
// 113-114 -> compressed 2bpp -> (decompressed each) 0x800 chars
|
// 113-114 -> compressed 2bpp -> (decompressed each) 0x800 chars
|
||||||
// 115-126 -> uncompressed 3bpp sprites -> (each) 0x600 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<gfx::SNESColor> 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() {
|
void ROM::LoadAllPalettes() {
|
||||||
// 35 colors each, 7x5 (0,2 on grid)
|
// 35 colors each, 7x5 (0,2 on grid)
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
@@ -816,12 +764,11 @@ void ROM::LoadAllPalettes() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
void ROM::SaveAllPalettes() {
|
void ROM::SaveAllPalettes() {
|
||||||
// Iterate through all palette_groups_
|
// Iterate through all palette_groups_
|
||||||
for (auto& group : palette_groups_) {
|
for (auto& [groupName, palettes] : palette_groups_) {
|
||||||
const std::string& groupName = group.first;
|
|
||||||
auto& palettes = group.second;
|
|
||||||
|
|
||||||
// Iterate through all palettes in the group
|
// Iterate through all palettes in the group
|
||||||
for (size_t i = 0; i < palettes.size(); ++i) {
|
for (size_t i = 0; i < palettes.size(); ++i) {
|
||||||
auto palette = palettes[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<gfx::SNESColor> 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) {
|
void ROM::WriteColor(uint32_t address, const gfx::SNESColor& color) {
|
||||||
uint16_t bgr = ((color.snes >> 10) & 0x1F) | ((color.snes & 0x1F) << 10) |
|
uint16_t bgr = ((color.snes >> 10) & 0x1F) | ((color.snes & 0x1F) << 10) |
|
||||||
(color.snes & 0x7C00);
|
(color.snes & 0x7C00);
|
||||||
@@ -849,6 +887,8 @@ void ROM::WriteColor(uint32_t address, const gfx::SNESColor& color) {
|
|||||||
rom_data_[address + 1] = static_cast<uint8_t>((bgr >> 8) & 0xFF);
|
rom_data_[address + 1] = static_cast<uint8_t>((bgr >> 8) & 0xFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ============================================================================
|
||||||
|
|
||||||
uint32_t ROM::GetPaletteAddress(const std::string& groupName,
|
uint32_t ROM::GetPaletteAddress(const std::string& groupName,
|
||||||
size_t paletteIndex, size_t colorIndex) const {
|
size_t paletteIndex, size_t colorIndex) const {
|
||||||
// Retrieve the base address for the palette group
|
// Retrieve the base address for the palette group
|
||||||
|
|||||||
@@ -4,8 +4,11 @@
|
|||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <asar/src/asar/interface-lib.h>
|
#include <asar/src/asar/interface-lib.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <ctime>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -126,21 +129,17 @@ class ROM {
|
|||||||
absl::StatusOr<Bytes> DecompressGraphics(int pos, int size);
|
absl::StatusOr<Bytes> DecompressGraphics(int pos, int size);
|
||||||
absl::StatusOr<Bytes> DecompressOverworld(int pos, int size);
|
absl::StatusOr<Bytes> DecompressOverworld(int pos, int size);
|
||||||
|
|
||||||
|
// Load functions
|
||||||
absl::StatusOr<Bytes> Load2bppGraphics();
|
absl::StatusOr<Bytes> Load2bppGraphics();
|
||||||
|
|
||||||
absl::Status LoadAllGraphicsData();
|
absl::Status LoadAllGraphicsData();
|
||||||
absl::Status LoadFromFile(const absl::string_view& filename);
|
absl::Status LoadFromFile(const absl::string_view& filename);
|
||||||
absl::Status LoadFromPointer(uchar* data, size_t length);
|
absl::Status LoadFromPointer(uchar* data, size_t length);
|
||||||
absl::Status LoadFromBytes(const Bytes& data);
|
absl::Status LoadFromBytes(const Bytes& data);
|
||||||
void LoadAllPalettes();
|
void LoadAllPalettes();
|
||||||
|
|
||||||
|
absl::Status SaveToFile(bool backup);
|
||||||
void SaveAllPalettes();
|
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::SNESColor ReadColor(int offset);
|
||||||
gfx::SNESPalette ReadPalette(int offset, int num_colors);
|
gfx::SNESPalette ReadPalette(int offset, int num_colors);
|
||||||
|
|
||||||
@@ -148,24 +147,29 @@ class ROM {
|
|||||||
void WriteShort(int addr, int value);
|
void WriteShort(int addr, int value);
|
||||||
void WriteColor(uint32_t address, const gfx::SNESColor& color);
|
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,
|
absl::Status ApplyAssembly(const absl::string_view& filename,
|
||||||
size_t patch_size);
|
size_t patch_size);
|
||||||
absl::Status PatchOverworldMosaic(char mosaic_tiles[core::kNumOverworldMaps],
|
absl::Status PatchOverworldMosaic(char mosaic_tiles[core::kNumOverworldMaps],
|
||||||
int routine_offset);
|
int routine_offset);
|
||||||
|
|
||||||
auto GetTitle() const { return title; }
|
|
||||||
gfx::BitmapTable GetGraphicsBin() const { return graphics_bin_; }
|
gfx::BitmapTable GetGraphicsBin() const { return graphics_bin_; }
|
||||||
auto GetGraphicsBuffer() const { return graphics_buffer_; }
|
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<SDL_Renderer> renderer) {
|
void SetupRenderer(std::shared_ptr<SDL_Renderer> renderer) {
|
||||||
renderer_ = renderer;
|
renderer_ = renderer;
|
||||||
}
|
}
|
||||||
|
auto size() const { return size_; }
|
||||||
auto isLoaded() const { return is_loaded_; }
|
auto isLoaded() const { return is_loaded_; }
|
||||||
auto begin() { return rom_data_.begin(); }
|
auto begin() { return rom_data_.begin(); }
|
||||||
auto end() { return rom_data_.end(); }
|
auto end() { return rom_data_.end(); }
|
||||||
auto data() { return rom_data_.data(); }
|
auto data() { return rom_data_.data(); }
|
||||||
auto char_data() { return reinterpret_cast<char*>(rom_data_.data()); }
|
auto char_data() { return reinterpret_cast<char*>(rom_data_.data()); }
|
||||||
auto size() const { return size_; }
|
|
||||||
|
|
||||||
uchar& operator[](int i) {
|
uchar& operator[](int i) {
|
||||||
if (i > size_) {
|
if (i > size_) {
|
||||||
|
|||||||
Reference in New Issue
Block a user