15#include "absl/status/status.h"
16#include "absl/strings/str_format.h"
17#include "imgui/imgui.h"
72 for (
auto& room :
rooms_) {
89 .display_name =
"Dungeon Controls",
90 .window_title =
" Dungeon Controls",
92 .category =
"Dungeon",
93 .shortcut_hint =
"Ctrl+Shift+D",
94 .visibility_flag =
nullptr,
97 .disabled_tooltip =
"Load a ROM to access dungeon controls"});
99 panel_manager->RegisterPanel(
101 .display_name =
"Room List",
102 .window_title =
" Room List",
104 .category =
"Dungeon",
105 .shortcut_hint =
"Ctrl+Shift+R",
106 .visibility_flag =
nullptr,
109 .disabled_tooltip =
"Load a ROM to browse dungeon rooms"});
111 panel_manager->RegisterPanel(
113 .display_name =
"Entrance List",
114 .window_title =
" Entrance List",
116 .category =
"Dungeon",
117 .shortcut_hint =
"Ctrl+Shift+E",
118 .visibility_flag =
nullptr,
121 .disabled_tooltip =
"Load a ROM to browse dungeon entrances"});
123 panel_manager->RegisterPanel(
124 {.card_id =
"dungeon.entrance_properties",
125 .display_name =
"Entrance Properties",
126 .window_title =
" Entrance Properties",
128 .category =
"Dungeon",
130 .visibility_flag =
nullptr,
133 .disabled_tooltip =
"Load a ROM to edit entrance properties"});
135 panel_manager->RegisterPanel(
137 .display_name =
"Room Matrix",
138 .window_title =
" Room Matrix",
140 .category =
"Dungeon",
141 .shortcut_hint =
"Ctrl+Shift+M",
142 .visibility_flag =
nullptr,
145 .disabled_tooltip =
"Load a ROM to view the room matrix"});
147 panel_manager->RegisterPanel(
149 .display_name =
"Room Graphics",
150 .window_title =
" Room Graphics",
152 .category =
"Dungeon",
153 .shortcut_hint =
"Ctrl+Shift+G",
154 .visibility_flag =
nullptr,
157 .disabled_tooltip =
"Load a ROM to view room graphics"});
159 panel_manager->RegisterPanel(
161 .display_name =
"Palette Editor",
162 .window_title =
" Palette Editor",
164 .category =
"Dungeon",
165 .shortcut_hint =
"Ctrl+Shift+P",
166 .visibility_flag =
nullptr,
169 .disabled_tooltip =
"Load a ROM to edit dungeon palettes"});
176 panel_manager->RegisterEditorPanel(std::make_unique<DungeonRoomSelectorPanel>(
179 panel_manager->RegisterEditorPanel(std::make_unique<DungeonEntranceListPanel>(
183 panel_manager->RegisterEditorPanel(std::make_unique<DungeonRoomMatrixPanel>(
187 panel_manager->RegisterEditorPanel(std::make_unique<DungeonEntrancesPanel>(
199 return absl::FailedPreconditionError(
"ROM not loaded");
204 if (!dim_table.IsLoaded()) {
211 return absl::FailedPreconditionError(
"GameData not available");
228 std::make_unique<emu::render::EmulatorRenderService>(
rom_);
231 LOG_ERROR(
"DungeonEditorV2",
"Failed to initialize render service: %s",
232 status.message().data());
246 auto graphics_panel = std::make_unique<DungeonRoomGraphicsPanel>(
260 auto object_editor = std::make_unique<ObjectEditorPanel>(
267 rooms_[current_room_id_].RenderRoomGraphics();
272 object_editor->SetRooms(&
rooms_);
303 auto minecart_panel = std::make_unique<MinecartTrackEditorPanel>();
306 std::move(minecart_panel));
330 if (room_id >= 0 && room_id < (
int)
rooms_.size()) {
331 rooms_[room_id].RenderRoomGraphics();
337 return absl::OkStatus();
349 if (loading_card.
Begin()) {
350 ImGui::TextColored(theme.text_secondary_gray,
"Loading dungeon data...");
352 "Independent editor cards will appear once ROM data is loaded.");
355 return absl::OkStatus();
360 if (ImGui::IsKeyPressed(ImGuiKey_Delete)) {
363 viewer->DeleteSelectedObjects();
371 return absl::OkStatus();
376 return absl::FailedPreconditionError(
"ROM not loaded");
382 LOG_ERROR(
"DungeonEditorV2",
"Failed to save palette changes: %s",
383 status.message().data());
386 LOG_INFO(
"DungeonEditorV2",
"Saved %zu modified colors to ROM",
390 for (
auto& room :
rooms_) {
391 auto status = room.SaveObjects();
393 LOG_ERROR(
"DungeonEditorV2",
"Failed to save room objects: %s",
394 status.message().data());
399 if (!sys_status.ok()) {
400 LOG_ERROR(
"DungeonEditorV2",
"Failed to save room system data: %s",
401 sys_status.message().data());
409 LOG_ERROR(
"DungeonEditorV2",
"DungeonEditorSystem save failed: %s",
410 status.message().data());
415 return absl::OkStatus();
421 std::string card_id = absl::StrFormat(
"dungeon.room_%d", room_id);
422 bool panel_visible =
true;
427 if (!panel_visible) {
439 std::string active_category =
444 if (active_category !=
"Dungeon" && !is_pinned) {
451 std::string base_name = absl::StrFormat(
454 std::string card_name_str = absl::StrFormat(
458 room_cards_[room_id] = std::make_shared<gui::PanelWindow>(
474 ImGui::SetNextWindowDockID(
room_dock_id_, ImGuiCond_FirstUseEver);
476 if (room_card->Begin(&open)) {
478 if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) {
500 if (room_id < 0 || room_id >= 0x128) {
501 ImGui::Text(
"Invalid room ID: %d", room_id);
505 auto& room =
rooms_[room_id];
507 if (!room.IsLoaded()) {
510 ImGui::TextColored(theme.text_error_red,
"Failed to load room: %s",
511 status.message().data());
517 if (!sys_status.ok()) {
518 LOG_ERROR(
"DungeonEditorV2",
"Failed to load system data: %s",
519 sys_status.message().data());
524 if (room.IsLoaded()) {
525 bool needs_render =
false;
530 if (room.blocks().empty()) {
531 room.LoadRoomGraphics(room.blockset);
533 LOG_DEBUG(
"[DungeonEditorV2]",
"Loaded room %d graphics from ROM",
542 if (room.GetTileObjects().empty()) {
545 LOG_DEBUG(
"[DungeonEditorV2]",
"Loaded room %d objects from ROM",
555 auto& bg1_bitmap = room.bg1_buffer().bitmap();
556 if (needs_render || !bg1_bitmap.is_active() || bg1_bitmap.width() == 0) {
557 room.RenderRoomGraphics();
558 LOG_DEBUG(
"[DungeonEditorV2]",
"Rendered room %d to bitmaps", room_id);
562 if (room.IsLoaded()) {
563 ImGui::TextColored(theme.text_success_green,
ICON_MD_CHECK " Loaded");
565 ImGui::TextColored(theme.text_error_red,
ICON_MD_PENDING " Not Loaded");
568 ImGui::TextDisabled(
"Objects: %zu", room.GetTileObjects().size());
574 viewer->DrawDungeonCanvas(room_id);
601 if (room_id >= 0 && room_id < (
int)
rooms_.size()) {
602 auto& room =
rooms_[room_id];
603 if (!room.IsLoaded()) {
607 if (room.IsLoaded()) {
616 auto dungeon_main_pal_group =
646 std::string card_id = absl::StrFormat(
"dungeon.room_%d", room_id);
661 std::string room_name = absl::StrFormat(
664 std::string base_card_id = absl::StrFormat(
"dungeon.room_%d", room_id);
667 {.card_id = base_card_id,
668 .display_name = room_name,
671 .category =
"Dungeon",
673 .visibility_flag =
nullptr,
674 .priority = 200 + room_id});
681 if (entrance_id < 0 || entrance_id >=
static_cast<int>(
entrances_.size())) {
724 LOG_ERROR(
"DungeonEditorV2",
"Cannot place object: Invalid room ID %d",
732 "Placing object ID=0x%02X at position (%d,%d) in room %03X", obj.
id_,
735 room.RenderRoomGraphics();
737 "Object placed and room re-rendered successfully");
743 if (new_room_id < 0 || new_room_id >=
static_cast<int>(
rooms_.size())) {
769 if (swap_index < 0) {
781 std::string old_card_id = absl::StrFormat(
"dungeon.room_%d", old_room_id);
792 std::string new_room_name = absl::StrFormat(
795 std::string new_card_id = absl::StrFormat(
"dungeon.room_%d", new_room_id);
798 {.card_id = new_card_id,
799 .display_name = new_room_name,
802 .category =
"Dungeon",
804 .visibility_flag =
nullptr,
805 .priority = 200 + new_room_id});
817 auto viewer = std::make_unique<DungeonCanvasViewer>(
rom_);
818 viewer->SetRooms(&
rooms_);
824 viewer->object_interaction().SetMutationHook(
827 viewer->object_interaction().SetCacheInvalidationCallback(
829 if (room_id >= 0 && room_id <
static_cast<int>(
rooms_.size())) {
830 rooms_[room_id].MarkObjectsDirty();
831 rooms_[room_id].RenderRoomGraphics();
835 viewer->object_interaction().SetObjectPlacedCallback(
841 viewer->SetRoomNavigationCallback([
this](
int target_room) {
842 if (target_room >= 0 && target_room <
static_cast<int>(
rooms_.size())) {
847 viewer->SetRoomSwapCallback([
this](
int old_room,
int new_room) {
851 viewer->SetShowSpritePanelCallback(
852 [
this]() {
ShowPanel(
"dungeon.sprite_editor"); });
853 viewer->SetShowItemPanelCallback(
854 [
this]() {
ShowPanel(
"dungeon.item_editor"); });
859 return it->second.get();
866 return absl::UnimplementedError(
"Undo not available");
873 return absl::UnimplementedError(
"Redo not available");
878 viewer->object_interaction().HandleCopySelected();
879 viewer->object_interaction().HandleDeleteSelected();
881 return absl::OkStatus();
886 viewer->object_interaction().HandleCopySelected();
888 return absl::OkStatus();
893 viewer->object_interaction().HandlePasteObjects();
895 return absl::OkStatus();
899 if (room_id < 0 || room_id >=
static_cast<int>(
rooms_.size()))
907 int room_id, std::vector<zelda3::RoomObject> snapshot) {
908 if (room_id < 0 || room_id >=
static_cast<int>(
rooms_.size())) {
909 return absl::InvalidArgumentError(
"Invalid room ID");
912 auto& room =
rooms_[room_id];
913 room.GetTileObjects() = std::move(snapshot);
914 room.RenderRoomGraphics();
915 return absl::OkStatus();
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
class MinecartTrackEditorPanel * minecart_track_editor_panel_
static constexpr const char * kControlPanelId
void SetAgentMode(bool enabled)
std::array< zelda3::Room, 0x128 > rooms_
uint64_t current_palette_group_id_
void add_room(int room_id)
class ItemEditorPanel * item_editor_panel_
std::unordered_map< int, std::vector< std::vector< zelda3::RoomObject > > > undo_history_
std::array< zelda3::RoomEntrance, 0x8C > entrances_
gfx::PaletteGroup current_palette_group_
void OnEntranceSelected(int entrance_id)
static constexpr const char * kEntranceListId
absl::Status Save() override
gfx::IRenderer * renderer_
class SpriteEditorPanel * sprite_editor_panel_
void FocusRoom(int room_id)
void HandleObjectPlaced(const zelda3::RoomObject &obj)
std::unique_ptr< ObjectEditorPanel > owned_object_editor_panel_
std::unique_ptr< zelda3::DungeonEditorSystem > dungeon_editor_system_
void PushUndoSnapshot(int room_id)
absl::Status Copy() override
void Initialize() override
void OnRoomSelected(int room_id, bool request_focus=true)
~DungeonEditorV2() override
DungeonRoomGraphicsPanel * room_graphics_panel_
ObjectEditorPanel * object_editor_panel_
void ProcessDeferredTextures()
gfx::SnesPalette current_palette_
ImVector< int > active_rooms_
absl::Status Cut() override
std::map< int, std::unique_ptr< DungeonCanvasViewer > > room_viewers_
gui::PaletteEditorWidget palette_editor_
void ShowPanel(const std::string &card_id)
absl::Status Paste() override
void SwapRoomInPanel(int old_room_id, int new_room_id)
void DrawRoomTab(int room_id)
void ProcessPendingSwap()
absl::Status RestoreFromSnapshot(int room_id, std::vector< zelda3::RoomObject > snapshot)
PendingSwap pending_swap_
static constexpr const char * kObjectToolsId
DungeonCanvasViewer * GetViewerForRoom(int room_id)
absl::Status Update() override
absl::Status Undo() override
ImGuiWindowClass room_window_class_
void SelectObject(int obj_id)
std::unique_ptr< emu::render::EmulatorRenderService > render_service_
DungeonRoomLoader room_loader_
std::unordered_map< int, std::vector< std::vector< zelda3::RoomObject > > > redo_history_
std::unordered_map< int, std::shared_ptr< gui::PanelWindow > > room_cards_
absl::Status Redo() override
static constexpr const char * kRoomGraphicsId
static constexpr const char * kRoomMatrixId
static constexpr const char * kRoomSelectorId
DungeonRoomSelector room_selector_
zelda3::GameData * game_data_
static constexpr const char * kPaletteEditorId
void ClearRedo(int room_id)
uint64_t current_palette_id_
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group)
Set the current palette group for graphics rendering.
absl::Status LoadRoomEntrances(std::array< zelda3::RoomEntrance, 0x8C > &entrances)
absl::Status LoadRoom(int room_id, zelda3::Room &room)
void set_entrances(std::array< zelda3::RoomEntrance, 0x8C > *entrances)
void SetRoomSelectedCallback(std::function< void(int)> callback)
void set_active_rooms(const ImVector< int > &rooms)
void set_rooms(std::array< zelda3::Room, 0x128 > *rooms)
zelda3::GameData * game_data() const
EditorDependencies dependencies_
std::string MakePanelTitle(const std::string &base_title) const
void SetCanvasViewer(DungeonCanvasViewer *viewer)
void SetProjectRoot(const std::string &root)
void SetCanvasViewer(DungeonCanvasViewer *viewer)
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group)
void SetGameData(zelda3::GameData *game_data)
void SelectObject(int obj_id)
void SetCurrentRoom(int room_id)
void SetAgentOptimizedLayout(bool enabled)
bool ShowPanel(size_t session_id, const std::string &base_card_id)
void RegisterPanel(size_t session_id, const PanelDescriptor &base_info)
std::string GetActiveCategory() const
bool IsPanelVisible(size_t session_id, const std::string &base_card_id) const
void UnregisterPanel(size_t session_id, const std::string &base_card_id)
bool IsPanelPinned(size_t session_id, const std::string &base_card_id) const
void RegisterEditorPanel(std::unique_ptr< EditorPanel > panel)
Register an EditorPanel instance for central drawing.
void SetCanvasViewer(DungeonCanvasViewer *viewer)
void ProcessTextureQueue(IRenderer *renderer)
Defines an abstract interface for all rendering operations.
void Initialize(zelda3::GameData *game_data)
Initialize the palette manager with GameData.
static PaletteManager & Get()
Get the singleton instance.
absl::Status SaveAllToRom()
Save ALL modified palettes to ROM.
Draggable, dockable panel for editor sub-windows.
bool Begin(bool *p_open=nullptr)
void SetDefaultSize(float width, float height)
static CustomObjectManager & Get()
void Initialize(const std::string &custom_objects_folder)
static ObjectDimensionTable & Get()
#define ICON_MD_GRID_VIEW
#define ICON_MD_DOOR_FRONT
#define LOG_DEBUG(category, format,...)
#define LOG_ERROR(category, format,...)
#define LOG_INFO(category, format,...)
#define ASSIGN_OR_RETURN(type_variable_name, expression)
const AgentUITheme & GetTheme()
Editors are the view controllers for the application.
absl::StatusOr< PaletteGroup > CreatePaletteGroupFromLargePalette(SnesPalette &palette, int num_colors)
Create a PaletteGroup by dividing a large palette into sub-palettes.
std::string GetRoomLabel(int id)
Convenience function to get a room label.
#define RETURN_IF_ERROR(expr)
project::YazeProject * project
PanelManager * panel_manager
PaletteGroup dungeon_main
std::string custom_objects_folder
gfx::PaletteGroupMap palette_groups