diff --git a/src/app/editor/dungeon_editor.cc b/src/app/editor/dungeon_editor.cc index 7c3c0d4b..d825d5c6 100644 --- a/src/app/editor/dungeon_editor.cc +++ b/src/app/editor/dungeon_editor.cc @@ -4,6 +4,7 @@ #include "app/core/common.h" #include "app/core/pipeline.h" +#include "app/gfx/snes_palette.h" #include "app/gui/canvas.h" #include "app/gui/icons.h" #include "app/gui/input.h" @@ -31,11 +32,34 @@ absl::Status DungeonEditor::Update() { rooms_[i].LoadRoomGraphics(); } } + graphics_bin_ = rom()->graphics_bin(); + full_palette_ = + rom()->GetPaletteGroup("dungeon_main")[current_palette_group_id_]; + current_palette_group_ = + gfx::CreatePaletteGroupFromLargePalette(full_palette_); is_loaded_ = true; } + if (refresh_graphics_) { + for (int block : rooms_[current_room_id_].blocks()) { + graphics_bin_[block].ApplyPalette( + current_palette_group_[current_palette_id_]); + rom()->UpdateBitmap(&graphics_bin_[block]); + } + refresh_graphics_ = false; + } + DrawToolset(); + if (palette_showing_) { + ImGui::Begin("Palette Editor", &palette_showing_, 0); + current_palette_ = + rom()->GetPaletteGroup("dungeon_main")[current_palette_group_id_]; + core::SelectablePalettePipeline(current_palette_id_, refresh_graphics_, + current_palette_); + ImGui::End(); + } + if (ImGui::BeginTable("#DungeonEditTable", 3, kDungeonTableFlags, ImVec2(0, 0))) { TableSetupColumn("Room Selector"); @@ -149,7 +173,7 @@ void DungeonEditor::DrawToolset() { ImGui::TableNextColumn(); if (ImGui::Button(ICON_MD_PALETTE)) { - // Open the palette module + palette_showing_ = !palette_showing_; } ImGui::EndTable(); @@ -159,7 +183,7 @@ void DungeonEditor::DrawToolset() { void DungeonEditor::DrawRoomSelector() { if (rom()->isLoaded()) { gui::InputHexWord("Room ID", ¤t_room_id_); - // gui::InputHexByte("Palette ID", &rooms_[current_room_id_].palette); + gui::InputHex("Palette ID", ¤t_palette_id_); if (ImGuiID child_id = ImGui::GetID((void*)(intptr_t)9); ImGui::BeginChild(child_id, ImGui::GetContentRegionAvail(), true, @@ -183,7 +207,7 @@ void DungeonEditor::DrawDungeonTabView() { if (ImGui::BeginTabBar("MyTabBar", kDungeonTabBarFlags)) { // TODO: Manage the room that is being added to the tab bar. - if (ImGui::TabItemButton("##tabitem", kDungeonTabFlags)) { + if (ImGui::TabItemButton("+", kDungeonTabFlags)) { active_rooms_.push_back(next_tab_id++); // Add new tab } @@ -249,14 +273,13 @@ void DungeonEditor::DrawRoomGraphics() { auto blocks = rooms_[current_room_id_].blocks(); int current_block = 0; for (int block : blocks) { - auto bitmap = rom()->graphics_bin()[block]; int offset = height * (current_block + 1); int top_left_y = room_gfx_canvas_.GetZeroPoint().y + 2; if (current_block >= 1) { top_left_y = room_gfx_canvas_.GetZeroPoint().y + height * current_block; } room_gfx_canvas_.GetDrawList()->AddImage( - (void*)bitmap.texture(), + (void*)graphics_bin_[block].texture(), ImVec2(room_gfx_canvas_.GetZeroPoint().x + 2, top_left_y), ImVec2(room_gfx_canvas_.GetZeroPoint().x + 0x100, room_gfx_canvas_.GetZeroPoint().y + offset)); diff --git a/src/app/editor/dungeon_editor.h b/src/app/editor/dungeon_editor.h index 4868fa35..a27181f0 100644 --- a/src/app/editor/dungeon_editor.h +++ b/src/app/editor/dungeon_editor.h @@ -5,6 +5,7 @@ #include "app/core/common.h" #include "app/core/editor.h" +#include "app/editor/modules/palette_editor.h" #include "app/gui/canvas.h" #include "app/gui/icons.h" #include "app/rom.h" @@ -50,22 +51,36 @@ class DungeonEditor : public Editor, void DrawTileSelector(); void DrawObjectRenderer(); - uint16_t current_room_id_ = 0; bool is_loaded_ = false; bool show_object_render_ = false; bool object_loaded_ = false; + bool palette_showing_ = false; + + bool refresh_graphics_ = false; + uint64_t current_palette_id_ = 0; + uint64_t current_palette_group_id_ = 0; + + uint16_t current_room_id_ = 0; gfx::Bitmap room_gfx_bmp_; + gfx::SNESPalette current_palette_; - ImVector active_rooms_; + gfx::SNESPalette full_palette_; + + gfx::PaletteGroup current_palette_group_; - std::vector rooms_; - zelda3::dungeon::DungeonObjectRenderer object_renderer_; gui::Canvas canvas_; gui::Canvas room_gfx_canvas_; gui::Canvas object_canvas_; + gfx::BitmapTable graphics_bin_; + + ImVector active_rooms_; + std::vector rooms_; std::vector room_graphics_; + zelda3::dungeon::DungeonObjectRenderer object_renderer_; + + PaletteEditor palette_editor_; enum BackgroundType { kNoBackground, diff --git a/src/app/editor/master_editor.cc b/src/app/editor/master_editor.cc index 9c425d47..6a971bd0 100644 --- a/src/app/editor/master_editor.cc +++ b/src/app/editor/master_editor.cc @@ -13,9 +13,9 @@ #include "app/editor/dungeon_editor.h" #include "app/editor/graphics_editor.h" #include "app/editor/modules/assembly_editor.h" -#include "app/editor/overworld_editor.h" #include "app/editor/modules/music_editor.h" #include "app/editor/modules/palette_editor.h" +#include "app/editor/overworld_editor.h" #include "app/editor/screen_editor.h" #include "app/editor/sprite_editor.h" #include "app/emu/emulator.h" @@ -40,7 +40,7 @@ constexpr ImGuiWindowFlags kMainEditorFlags = ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoTitleBar; void NewMasterFrame() { - const ImGuiIO &io = ImGui::GetIO(); + const ImGuiIO& io = ImGui::GetIO(); ImGui::NewFrame(); ImGui::SetNextWindowPos(gui::kZeroPos); ImVec2 dimensions(io.DisplaySize.x, io.DisplaySize.y); @@ -52,8 +52,8 @@ void NewMasterFrame() { } } -bool BeginCentered(const char *name) { - ImGuiIO const &io = ImGui::GetIO(); +bool BeginCentered(const char* name) { + ImGuiIO const& io = ImGui::GetIO(); ImVec2 pos(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f); ImGui::SetNextWindowPos(pos, ImGuiCond_Always, ImVec2(0.5f, 0.5f)); ImGuiWindowFlags flags = @@ -62,6 +62,53 @@ bool BeginCentered(const char *name) { return ImGui::Begin(name, nullptr, flags); } +class RecentFilesManager { + public: + RecentFilesManager(const std::string& filename) : filename_(filename) {} + + void AddFile(const std::string& filePath) { + // Add a file to the list, avoiding duplicates + auto it = std::find(recentFiles_.begin(), recentFiles_.end(), filePath); + if (it == recentFiles_.end()) { + recentFiles_.push_back(filePath); + } + } + + void Save() { + std::ofstream file(filename_); + if (!file.is_open()) { + return; // Handle the error appropriately + } + + for (const auto& filePath : recentFiles_) { + file << filePath << std::endl; + } + } + + void Load() { + std::ifstream file(filename_); + if (!file.is_open()) { + return; // Handle the error appropriately + } + + recentFiles_.clear(); + std::string line; + while (std::getline(file, line)) { + if (!line.empty()) { + recentFiles_.push_back(line); + } + } + } + + const std::vector& GetRecentFiles() const { + return recentFiles_; + } + + private: + std::string filename_; + std::vector recentFiles_; +}; + } // namespace void MasterEditor::SetupScreen(std::shared_ptr renderer) { @@ -81,10 +128,12 @@ void MasterEditor::UpdateScreen() { TAB_BAR("##TabBar") TAB_ITEM("Overworld") + current_editor_ = &overworld_editor_; status_ = overworld_editor_.Update(); END_TAB_ITEM() TAB_ITEM("Dungeon") + current_editor_ = &dungeon_editor_; status_ = dungeon_editor_.Update(); END_TAB_ITEM() @@ -92,20 +141,20 @@ void MasterEditor::UpdateScreen() { status_ = graphics_editor_.Update(); END_TAB_ITEM() - TAB_ITEM("Music") - music_editor_.Update(); - END_TAB_ITEM() - TAB_ITEM("Sprites") status_ = sprite_editor_.Update(); END_TAB_ITEM() + TAB_ITEM("Palettes") + status_ = palette_editor_.Update(); + END_TAB_ITEM() + TAB_ITEM("Screens") screen_editor_.Update(); END_TAB_ITEM() - TAB_ITEM("Palettes") - status_ = palette_editor_.Update(); + TAB_ITEM("Music") + music_editor_.Update(); END_TAB_ITEM() END_TAB_BAR() @@ -114,12 +163,22 @@ void MasterEditor::UpdateScreen() { } void MasterEditor::DrawFileDialog() { - core::FileDialogPipeline("ChooseFileDlgKey", ".sfc,.smc", std::nullopt, - [&]() { - std::string filePathName = - ImGuiFileDialog::Instance()->GetFilePathName(); - status_ = rom()->LoadFromFile(filePathName); - }); + core::FileDialogPipeline( + "ChooseFileDlgKey", ".sfc,.smc", std::nullopt, [&]() { + std::string filePathName = + ImGuiFileDialog::Instance()->GetFilePathName(); + status_ = rom()->LoadFromFile(filePathName); + static RecentFilesManager manager("recent_files.txt"); + + // Load existing recent files + manager.Load(); + + // Add a new file + manager.AddFile(filePathName); + + // Save the updated list + manager.Save(); + }); } void MasterEditor::DrawStatusPopup() { @@ -227,6 +286,21 @@ void MasterEditor::DrawFileMenu() { ".sfc,.smc", "."); } + if (ImGui::BeginMenu("Open Recent")) { + static RecentFilesManager manager("recent_files.txt"); + manager.Load(); + if (manager.GetRecentFiles().empty()) { + ImGui::MenuItem("No Recent Files", nullptr, false, false); + } else { + for (const auto& filePath : manager.GetRecentFiles()) { + if (ImGui::MenuItem(filePath.c_str())) { + status_ = rom()->LoadFromFile(filePath); + } + } + } + ImGui::EndMenu(); + } + MENU_ITEM2("Save", "Ctrl+S") { status_ = rom()->SaveToFile(backup_rom_); } MENU_ITEM("Save As..") { save_as_menu = true; } @@ -284,12 +358,12 @@ void MasterEditor::DrawFileMenu() { void MasterEditor::DrawEditMenu() { if (ImGui::BeginMenu("Edit")) { - MENU_ITEM2("Undo", "Ctrl+Z") { status_ = overworld_editor_.Undo(); } - MENU_ITEM2("Redo", "Ctrl+Y") { status_ = overworld_editor_.Redo(); } + MENU_ITEM2("Undo", "Ctrl+Z") { status_ = current_editor_->Undo(); } + MENU_ITEM2("Redo", "Ctrl+Y") { status_ = current_editor_->Redo(); } ImGui::Separator(); - MENU_ITEM2("Cut", "Ctrl+X") { status_ = overworld_editor_.Cut(); } - MENU_ITEM2("Copy", "Ctrl+C") { status_ = overworld_editor_.Copy(); } - MENU_ITEM2("Paste", "Ctrl+V") { status_ = overworld_editor_.Paste(); } + MENU_ITEM2("Cut", "Ctrl+X") { status_ = current_editor_->Cut(); } + MENU_ITEM2("Copy", "Ctrl+C") { status_ = current_editor_->Copy(); } + MENU_ITEM2("Paste", "Ctrl+V") { status_ = current_editor_->Paste(); } ImGui::Separator(); MENU_ITEM2("Find", "Ctrl+F") {} ImGui::Separator(); @@ -319,7 +393,7 @@ void MasterEditor::DrawViewMenu() { if (show_memory_editor) { static MemoryEditor mem_edit; - mem_edit.DrawWindow("Memory Editor", (void *)&(*rom()), rom()->size()); + mem_edit.DrawWindow("Memory Editor", (void*)&(*rom()), rom()->size()); } if (show_imgui_demo) { diff --git a/src/app/editor/master_editor.h b/src/app/editor/master_editor.h index 5a3223c8..8133ad14 100644 --- a/src/app/editor/master_editor.h +++ b/src/app/editor/master_editor.h @@ -15,8 +15,8 @@ #include "app/editor/graphics_editor.h" #include "app/editor/modules/assembly_editor.h" #include "app/editor/modules/music_editor.h" -#include "app/editor/overworld_editor.h" #include "app/editor/modules/palette_editor.h" +#include "app/editor/overworld_editor.h" #include "app/editor/screen_editor.h" #include "app/editor/sprite_editor.h" #include "app/emu/emulator.h" @@ -60,6 +60,8 @@ class MasterEditor : public SharedROM, public core::ExperimentFlags { std::shared_ptr sdl_renderer_; emu::Emulator emulator_; + Editor *current_editor_ = nullptr; + AssemblyEditor assembly_editor_; DungeonEditor dungeon_editor_; GraphicsEditor graphics_editor_; diff --git a/src/app/editor/modules/palette_editor.cc b/src/app/editor/modules/palette_editor.cc index 73f16be2..21e56dcd 100644 --- a/src/app/editor/modules/palette_editor.cc +++ b/src/app/editor/modules/palette_editor.cc @@ -98,9 +98,6 @@ absl::Status PaletteEditor::DrawPaletteGroup(int category) { const auto size = rom()->GetPaletteGroup(kPaletteGroupNames[category].data()).size(); auto palettes = rom()->GetPaletteGroup(kPaletteGroupNames[category].data()); - // if (static bool init = false; !init) { - // InitializeSavedPalette(palettes[0]); - // } static bool edit_color = false; for (int j = 0; j < size; j++) { ImGui::Text("%d", j); diff --git a/src/app/gfx/snes_palette.cc b/src/app/gfx/snes_palette.cc index dfc72862..293ca12c 100644 --- a/src/app/gfx/snes_palette.cc +++ b/src/app/gfx/snes_palette.cc @@ -262,6 +262,26 @@ PaletteGroup CreatePaletteGroupFromColFile( return toret; } +// Take a SNESPalette with N many colors and divide it into palettes of 8 colors +// each +PaletteGroup CreatePaletteGroupFromLargePalette(SNESPalette& palette) { + PaletteGroup toret; + + std::cout << "Palette size is " << palette.size() << std::endl; + + for (int i = 0; i < palette.size(); i += 8) { + SNESPalette new_palette; + if (i + 8 < palette.size()) { + for (int j = 0; j < 8; j++) { + new_palette.AddColor(palette[i + j]); + } + } + + toret.AddPalette(new_palette); + } + return toret; +} + } // namespace gfx } // namespace app } // namespace yaze \ No newline at end of file diff --git a/src/app/gfx/snes_palette.h b/src/app/gfx/snes_palette.h index 19c9c041..c0f1e783 100644 --- a/src/app/gfx/snes_palette.h +++ b/src/app/gfx/snes_palette.h @@ -261,6 +261,8 @@ struct PaletteGroup { PaletteGroup CreatePaletteGroupFromColFile(std::vector& colors); +PaletteGroup CreatePaletteGroupFromLargePalette(SNESPalette& palette); + } // namespace gfx } // namespace app } // namespace yaze diff --git a/src/app/rom.h b/src/app/rom.h index 83811348..a09f03fb 100644 --- a/src/app/rom.h +++ b/src/app/rom.h @@ -419,6 +419,10 @@ class ROM : public core::ExperimentFlags { gfx::BitmapTable graphics_bin() const { return graphics_bin_; } + gfx::Bitmap* mutable_graphics_sheet(int index) { + return &graphics_bin_.at(index); + } + auto title() const { return title_; } auto size() const { return size_; } auto begin() { return rom_data_.begin(); }