yaze 0.3.2
Link to the Past ROM Editor
 
Loading...
Searching...
No Matches
dungeon_canvas_viewer.h
Go to the documentation of this file.
1#ifndef YAZE_APP_EDITOR_DUNGEON_DUNGEON_CANVAS_VIEWER_H
2#define YAZE_APP_EDITOR_DUNGEON_DUNGEON_CANVAS_VIEWER_H
3
4#include <array>
5#include <cstdint>
6#include <functional>
7#include <map>
8#include <optional>
9#include <string>
10#include <unordered_map>
11#include <vector>
12
13#include "app/editor/editor.h"
18#include "core/project.h"
21#include "dungeon_room_store.h"
22#include "imgui/imgui.h"
23#include "rom/rom.h"
25#include "zelda3/dungeon/room.h"
27#include "zelda3/game_data.h"
28
29namespace yaze {
30namespace editor {
31
32class MinecartTrackEditorPanel;
33class DungeonCanvasViewerTestPeer;
34
35enum class DungeonConnectedLinkType : uint8_t {
36 Door,
39};
40
42 int from_room_id = -1;
43 int to_room_id = -1;
46 // Provenance fields populated by CollectDungeonConnectedRoomLinkDiagnostics
47 // for hover tooltips and issue reports. Defaults represent "not applicable".
48 int slot_index = -1; // Staircase slot 0..3, -1 otherwise.
49 int16_t object_id = -1; // Placed staircase tile-object id, -1 otherwise.
50 int door_index = -1; // Index in room.GetDoors() for Door links.
52};
53
54// Discriminator for staircase configuration anomalies surfaced through
55// CollectDungeonConnectedRoomLinkDiagnostics. Each kind explains a different
56// failure mode the runtime silently ignores.
57enum class DungeonStaircaseIssueKind : uint8_t {
58 // Header destination is non-zero but no placed interroom-stair object
59 // consumes that slot. Runtime never traverses the link.
61 // Placed interroom-stair object exists but the matched header slot is 0
62 // (unset) or out of range — the runtime would jump to an invalid room.
64 // Placed interroom-stair object beyond the 4 header slots. The runtime
65 // can only consume four; extras can never be reached.
67};
68
69// Captures one anomaly found while resolving a room's staircase connectivity.
70// Field meaning depends on `kind`; defaults represent "not applicable".
72 int from_room_id = -1;
74 int slot_index = -1; // 0..3 for UnusedHeader/MissingDestination.
75 int header_room_id = -1; // Header destination value (raw, may be invalid).
76 int16_t object_id = -1; // Placed object id (MissingDestination/Extra).
77};
78
80 std::vector<DungeonConnectedRoomLink> links;
81 std::vector<DungeonStaircaseIssue> staircase_issues;
82};
83
92
93inline constexpr std::array<const char*, 6> kDungeonIssueCategoryLabels = {{
94 "Palette mismatch",
95 "Object draw mismatch",
96 "Door render mismatch",
97 "Entity mismatch",
98 "Overlay or collision mismatch",
99 "General room render mismatch",
100}};
101
103 return static_cast<int>(category);
104}
105
106inline const char* GetIssueCategoryLabel(int index) {
107 if (index < 0 ||
108 index >= static_cast<int>(kDungeonIssueCategoryLabels.size())) {
109 return kDungeonIssueCategoryLabels.back();
110 }
111 return kDungeonIssueCategoryLabels[static_cast<size_t>(index)];
112}
113
115 const DungeonObjectInteraction& object_interaction) {
116 if (!object_interaction.GetSelectedObjectIndices().empty()) {
118 }
119 if (object_interaction.HasEntitySelection()) {
120 switch (object_interaction.GetSelectedEntity().type) {
121 case EntityType::Door:
124 case EntityType::Item:
126 default:
127 break;
128 }
129 }
131}
132
133std::vector<DungeonConnectedRoomLink> CollectDungeonConnectedRoomLinks(
134 int room_id, const zelda3::Room& room,
135 const std::function<bool(int, zelda3::DoorDirection)>& has_reciprocal_door);
136
137// Returns the same set of links as CollectDungeonConnectedRoomLinks plus any
138// stale staircase header slots — i.e. header destinations with no placed
139// interroom-stair object consuming them. Provenance fields on each returned
140// link are populated for tooltip/issue-report surfacing.
141DungeonConnectedRoomLinkDiagnostics CollectDungeonConnectedRoomLinkDiagnostics(
142 int room_id, const zelda3::Room& room,
143 const std::function<bool(int, zelda3::DoorDirection)>& has_reciprocal_door);
144
145// Renders a single connectivity link as a one-line human-readable description
146// for tooltips and issue reports. Caller decides separator/heading.
148 const DungeonConnectedRoomLink& link);
149
150// Renders a staircase issue entry as a one-line warning for tooltips and
151// issue reports.
153 const DungeonStaircaseIssue& issue);
154
155// Returns the room id adjacent to `room_id` in the given direction, or -1 if
156// no such neighbor exists (out of the 16x16 room matrix).
157inline int NeighborRoomId(int room_id, zelda3::DoorDirection dir) {
158 if (room_id < 0 || room_id >= zelda3::kNumberOfRooms) {
159 return -1;
160 }
161
162 constexpr int kCols = 16;
163 const int row = room_id / kCols;
164 const int col = room_id % kCols;
165
166 int candidate = -1;
167 switch (dir) {
169 candidate = row > 0 ? room_id - kCols : -1;
170 break;
172 candidate = room_id + kCols;
173 break;
175 candidate = col > 0 ? room_id - 1 : -1;
176 break;
178 candidate = col < kCols - 1 ? room_id + 1 : -1;
179 break;
180 }
181
182 return (candidate >= 0 && candidate < zelda3::kNumberOfRooms) ? candidate
183 : -1;
184}
185
186// Returns the opposite cardinal direction (N<->S, E<->W).
201
206 Manual, // Use ObjectDrawer routines
207 Emulator, // Use SNES emulator
208 Hybrid // Emulator with manual fallback
209};
210
212 public:
213 explicit DungeonCanvasViewer(Rom* rom = nullptr)
217 [this](int target_room, std::optional<size_t> target_door_index,
218 int target_tile_x, int target_tile_y) {
219 NavigateToRoom(target_room);
220 if (target_tile_x >= 0 && target_tile_y >= 0) {
221 ScrollToTile(target_tile_x, target_tile_y);
222 TriggerCanvasPingRect(target_tile_x * 8, target_tile_y * 8, 24, 24);
223 } else {
225 }
226 if (target_door_index.has_value()) {
228 *target_door_index);
229 }
230 });
231 }
232
233 void DrawDungeonCanvas(int room_id);
234 std::optional<int> DrawConnectedRoomMatrix(int center_room_id);
235 void DrawConnectedToolbarControls(int center_room_id);
236 void Draw(int room_id);
237 void TriggerChangePing();
238 void TriggerCanvasPingRect(int pixel_x, int pixel_y, int pixel_w,
239 int pixel_h);
241 const std::vector<zelda3::RoomObject>& previous_objects,
242 const std::vector<zelda3::RoomObject>& next_objects);
243
244 // Unscaled content size of the connected-room graph centered on
245 // `center_room_id`. Used by the workbench to reserve scroll space for the
246 // body child before DrawConnectedRoomMatrix runs, so the matrix doesn't need
247 // to open its own BeginChild scroll wrapper.
248 ImVec2 GetConnectedContentSize(int center_room_id);
249 // Clamped connected-canvas zoom scale that matches the one used by
250 // DrawConnectedRoomMatrix when it next runs.
251 float ConnectedCanvasScale() const;
252 void SetConnectedControlsInline(bool inline_controls) {
253 connected_controls_inline_ = inline_controls;
254 }
255
263 EditorContext context() const { return {rom_, game_data_}; }
270 Rom* rom() const { return rom_; }
273 void SetRenderer(gfx::IRenderer* renderer) { renderer_ = renderer; }
274
275 // Room data access
281 // Rebind ROM-backed context without replacing this viewer. This preserves
282 // panel aliases into viewer state while discarding selections and caches
283 // that may refer to data decoded from the previous ROM bytes.
285 DungeonRoomStore* rooms, int room_id);
286 DungeonRoomStore* rooms() const { return rooms_; }
287 bool HasRooms() const { return rooms_ != nullptr; }
288
289 // Best-effort "current room" context for auxiliary panels that are driven by
290 // whichever room the viewer is currently drawing.
291 int current_room_id() const { return current_room_id_; }
292
293 // Workbench/Inspector integration.
294 void SetCompactHeaderMode(bool compact) { compact_header_mode_ = compact; }
296 void SetRoomDetailsExpanded(bool expanded) { show_room_details_ = expanded; }
297
298 // Used by overworld editor when double-clicking entrances
299 void set_active_rooms(const ImVector<int>& rooms) { active_rooms_ = rooms; }
301
302 // Palette access
305 }
306 void SetCurrentPaletteId(uint64_t id) { current_palette_id_ = id; }
308 bool force_refresh = false) {
309 bool palette_changed = current_palette_group_.name() != group.name() ||
310 current_palette_group_.size() != group.size();
311 for (int i = 0; !palette_changed && i < static_cast<int>(group.size());
312 ++i) {
313 palette_changed =
315 }
316 if (!palette_changed && !force_refresh) {
317 return;
318 }
319
321 object_interaction_.SetCurrentPaletteGroup(group, force_refresh);
322 }
323 void SetEntranceRenderContext(int entrance_id, uint8_t entrance_blockset) {
324 current_entrance_id_ = entrance_id;
325 current_entrance_blockset_ = entrance_blockset;
326 }
334 }
335 void SetRoomNavigationCallback(std::function<void(int)> callback) {
336 room_navigation_callback_ = std::move(callback);
337 }
338 // Callback to swap the current room in-place (for arrow navigation)
339 void SetRoomSwapCallback(std::function<void(int, int)> callback) {
340 room_swap_callback_ = std::move(callback);
341 }
342
343 bool CanNavigateRooms() const {
344 return room_swap_callback_ != nullptr ||
345 room_navigation_callback_ != nullptr;
346 }
347
348 // Navigate to another dungeon room using the same semantics as the header
349 // arrow buttons:
350 // - If a swap callback exists (workbench mode), swap in-place.
351 // - Otherwise, use the navigation callback (opens/switches room view).
352 void NavigateToRoom(int target_room) {
353 if (target_room < 0 || target_room >= zelda3::kNumberOfRooms) {
354 return;
355 }
358 } else if (room_navigation_callback_) {
359 room_navigation_callback_(target_room);
360 }
361 }
362 void SetShowObjectPanelCallback(std::function<void()> callback) {
363 show_object_panel_callback_ = std::move(callback);
364 }
365 void SetShowSpritePanelCallback(std::function<void()> callback) {
366 show_sprite_panel_callback_ = std::move(callback);
367 }
368 void SetShowItemPanelCallback(std::function<void()> callback) {
369 show_item_panel_callback_ = std::move(callback);
370 }
371 void SetShowRoomListCallback(std::function<void()> callback) {
372 show_room_list_callback_ = std::move(callback);
373 }
374 void SetShowRoomMatrixCallback(std::function<void()> callback) {
375 show_room_matrix_callback_ = std::move(callback);
376 }
377 void SetShowEntranceListCallback(std::function<void()> callback) {
378 show_entrance_list_callback_ = std::move(callback);
379 }
380
387
390 }
392
393 // Overlay toggles (used by settings panels / workbench UI).
417 }
424
425 bool show_grid() const { return show_grid_; }
426 void set_show_grid(bool show) { show_grid_ = show; }
427 int custom_grid_size() const { return custom_grid_size_; }
428 void set_custom_grid_size(int size) {
429 custom_grid_size_ = size > 0 ? size : 1;
430 }
432 void set_show_object_bounds(bool show) { show_object_bounds_ = show; }
436 }
440 void set_show_texture_debug(bool show) { show_texture_debug_ = show; }
441 bool show_layer_info() const { return show_layer_info_; }
442 void set_show_layer_info(bool show) { show_layer_info_ = show; }
451
452 // Mutable pointer accessors for OverlayManagerPanel binding.
453 bool* mutable_show_grid() { return &show_grid_; }
475 void SetShowRoomGraphicsCallback(std::function<void()> callback) {
476 show_room_graphics_callback_ = std::move(callback);
477 }
478 void SetShowDoorEditorCallback(std::function<void()> callback) {
479 show_door_editor_callback_ = std::move(callback);
480 }
481 void SetShowDungeonSettingsCallback(std::function<void()> callback) {
482 show_dungeon_settings_callback_ = std::move(callback);
483 }
484 void SetSaveRoomCallback(std::function<void(int)> callback) {
485 save_room_callback_ = std::move(callback);
486 }
488 std::function<void(int, const zelda3::RoomObject&)> callback) {
489 edit_graphics_callback_ = std::move(callback);
490 }
492 std::function<void(int, const zelda3::RoomObject&)> callback) {
493 edit_object_tiles_callback_ = std::move(callback);
494 }
498 void SetPinned(bool pinned) { is_pinned_ = pinned; }
499 void SetPinCallback(std::function<void(bool)> callback) {
500 pin_callback_ = std::move(callback);
501 }
503 const project::YazeProject* project() const { return project_; }
504
505 // Canvas access
507 const gui::Canvas& canvas() const { return canvas_; }
508
509 // Object interaction access
511
515
516 // Enable/disable object interaction mode
517 void SetObjectInteractionEnabled(bool enabled) {
519 }
523
524 // Make the room header controls non-interactive while still allowing canvas
525 // pan/zoom (useful for split/compare views).
526 void SetHeaderReadOnly(bool read_only) { header_read_only_ = read_only; }
527 bool header_read_only() const { return header_read_only_; }
528
529 // Hide the header chrome entirely (useful for stitched/split layouts where a
530 // parent container provides its own metadata/controls).
531 void SetHeaderVisible(bool visible) { header_visible_ = visible; }
532 bool header_visible() const { return header_visible_; }
539
540 // Set and get the object render mode
545
546 // Layer visibility controls (per-room) using RoomLayerManager
547 void SetLayerVisible(int room_id, zelda3::LayerType layer, bool visible) {
548 GetRoomLayerManager(room_id).SetLayerVisible(layer, visible);
549 }
550 bool IsLayerVisible(int room_id, zelda3::LayerType layer) const {
551 auto it = room_layer_managers_.find(room_id);
552 return it != room_layer_managers_.end() ? it->second.IsLayerVisible(layer)
553 : true;
554 }
555
556 // Legacy compatibility - BG1 visibility (combines layout + objects)
557 void SetBG1Visible(int room_id, bool visible) {
558 auto& mgr = GetRoomLayerManager(room_id);
559 mgr.SetLayerVisible(zelda3::LayerType::BG1_Layout, visible);
560 mgr.SetLayerVisible(zelda3::LayerType::BG1_Objects, visible);
561 }
562 void SetBG2Visible(int room_id, bool visible) {
563 auto& mgr = GetRoomLayerManager(room_id);
564 mgr.SetLayerVisible(zelda3::LayerType::BG2_Layout, visible);
565 mgr.SetLayerVisible(zelda3::LayerType::BG2_Objects, visible);
566 }
567 bool IsBG1Visible(int room_id) const {
568 auto it = room_layer_managers_.find(room_id);
569 if (it == room_layer_managers_.end())
570 return true;
571 return it->second.IsLayerVisible(zelda3::LayerType::BG1_Layout) ||
572 it->second.IsLayerVisible(zelda3::LayerType::BG1_Objects);
573 }
574 bool IsBG2Visible(int room_id) const {
575 auto it = room_layer_managers_.find(room_id);
576 if (it == room_layer_managers_.end())
577 return true;
578 return it->second.IsLayerVisible(zelda3::LayerType::BG2_Layout) ||
579 it->second.IsLayerVisible(zelda3::LayerType::BG2_Objects);
580 }
581
582 // Layer blend mode controls
583 void SetLayerBlendMode(int room_id, zelda3::LayerType layer,
585 GetRoomLayerManager(room_id).SetLayerBlendMode(layer, mode);
586 }
588 zelda3::LayerType layer) const {
589 auto it = room_layer_managers_.find(room_id);
590 return it != room_layer_managers_.end()
591 ? it->second.GetLayerBlendMode(layer)
593 }
594
595 // Per-object translucency
596 void SetObjectTranslucent(int room_id, size_t object_index, bool translucent,
597 uint8_t alpha = 128) {
598 GetRoomLayerManager(room_id).SetObjectTranslucency(object_index,
599 translucent, alpha);
600 }
601
602 // Layer manager access
604 return room_layer_managers_[room_id];
605 }
607 static zelda3::RoomLayerManager default_manager;
608 auto it = room_layer_managers_.find(room_id);
609 return it != room_layer_managers_.end() ? it->second : default_manager;
610 }
611
612 // Legacy BG2 layer type (mapped to blend mode)
613 void SetBG2LayerType(int room_id, int type) {
614 auto& mgr = GetRoomLayerManager(room_id);
616 switch (type) {
617 case 0:
619 break;
620 case 1:
622 break;
623 case 2:
625 break;
626 case 3:
628 break;
629 case 4:
631 break;
632 default:
634 break;
635 }
636 mgr.SetLayerBlendMode(zelda3::LayerType::BG2_Layout, mode);
637 mgr.SetLayerBlendMode(zelda3::LayerType::BG2_Objects, mode);
638 }
639 int GetBG2LayerType(int room_id) const {
641 switch (mode) {
643 return 0;
645 return 1;
647 return 2;
649 return 3;
651 return 4;
652 }
653 return 0;
654 }
655
656 // Set the object to be placed
658 // Pass palette group first so ghost preview can render correctly
661 }
664 false);
665 }
666
667 // Scroll the canvas to center on the given tile coordinates.
668 // The pending target is consumed by Draw() on the next frame.
669 void ScrollToTile(int tile_x, int tile_y) {
670 pending_scroll_target_ = {tile_x, tile_y};
671 }
673 return pending_scroll_target_.has_value();
674 }
675 std::optional<std::pair<int, int>> GetPendingScrollTarget() const {
677 }
678
679 // Object manipulation
681
682 // Entity visibility controls
683 void SetSpritesVisible(bool visible) {
685 }
687 void SetPotItemsVisible(bool visible) {
689 }
691
694 int col = 0;
695 int row = 0;
696 bool placed = false;
697 bool connected_to_start = false;
698 };
699
700 std::array<bool, zelda3::kNumberOfRooms> room_mask{};
701 std::array<RoomPlacement, zelda3::kNumberOfRooms> room_positions{};
702 std::array<std::string, zelda3::kNumberOfRooms> room_floor_labels{};
703 std::vector<std::string> floor_order;
704 std::vector<DungeonConnectedRoomLink> links;
705 // Staircase configuration anomalies aggregated across the whole
706 // connected component. Order is "first-encountered during BFS".
707 std::vector<DungeonStaircaseIssue> staircase_issues;
708 // Resolved links whose destination room falls outside the project's
709 // current dungeon registry scope (only populated when scoping is active).
710 // The runtime would still traverse these; the matrix omits the target
711 // rooms by default but surfaces the link as a diagnostic so the user can
712 // see "current dungeon connects out to room X via staircase".
713 std::vector<DungeonConnectedRoomLink> out_of_scope_links;
714 // True when BFS is restricted to a project-registry dungeon group.
716 int room_count = 0;
718 int min_col = 0;
719 int max_col = 0;
720 int min_row = 0;
721 int max_row = 0;
722 };
723
724 private:
726 friend class
728 friend class
730 friend class
732 friend class
734
736 int x = 0;
737 int y = 0;
738 int w = 0;
739 int h = 0;
740 };
741
743 const zelda3::RoomObject& object, int canvas_x,
744 int canvas_y);
745 void DrawRoomHeader(zelda3::Room& room, int room_id);
746 void DrawRoomNavigation(int room_id);
747 void DrawRoomPropertyTable(zelda3::Room& room, int room_id);
748 void DrawRecentRoomBreadcrumbs(int room_id);
749 void DrawLayerControls(zelda3::Room& room, int room_id);
750 void DrawCompactLayerToggles(int room_id);
751 void PopulateCanvasContextMenu(int room_id);
752 void AddInteractionContextMenuItems(int room_id);
753 void AddLoadedRoomContextMenuItems(int room_id);
755 std::vector<gui::CanvasMenuItem> BuildSelectionContextMenuItems(int room_id);
756 std::optional<zelda3::RoomObject> GetObjectUnderContextCursor(int room_id);
759 std::optional<gui::CanvasMenuItem> BuildOpenContextMenu();
764 std::string BuildRoomMetadataSummary(const zelda3::Room& room,
765 int room_id) const;
766 std::string BuildDrawIssueReport(const zelda3::Room& room, int room_id) const;
767 std::string BuildSelectionIssueReport(const zelda3::Room& room,
768 int room_id) const;
769 void OpenIssueReportPopup(const std::string& title,
770 const std::string& summary,
771 const std::string& kind_label,
772 const std::string& diagnostics, int room_id,
773 int default_category_index);
774 absl::Status PrepareIssueReportPopup(const std::string& title,
775 const std::string& summary,
776 const std::string& kind_label,
777 const std::string& diagnostics,
778 int room_id, int default_category_index);
779 std::string BuildIssueReportClipboardText() const;
780 absl::Status CaptureIssueReportScreenshot();
781 absl::Status AppendIssueReportToLog();
782 absl::Status EnsureIssueReportPersisted();
785 void SetIssueReportPopupStatus(std::string message, bool is_error);
787 void DrawIssueReportStatusMessage() const;
788 void RenderSprites(const gui::CanvasRuntime& rt, const zelda3::Room& room);
789 void RenderPotItems(const gui::CanvasRuntime& rt, const zelda3::Room& room);
791 const zelda3::Room& room);
792
793 // Touch interaction: long-press context menu for entities
795 const zelda3::Room& room);
796
797 // Visualization
799 const zelda3::Room& room);
802 GetCollisionOverlayCache(int room_id);
803
804 // Draw semi-transparent overlay on stored value 1 / BG2 overlay objects when
805 // mask mode is active.
807 const zelda3::Room& room);
808 void DrawPersistentDebugWindows(int room_id);
809 void DrawRoomDebugWindow(zelda3::Room& room, int room_id);
810 void DrawTextureDebugWindow(zelda3::Room& room, int room_id);
811 void DrawLayerInfoWindow(int room_id);
813 int room_id);
814 void DrawCoordinateOverlayHud(int room_id);
815 bool ValidateRoomCanvasRequest(int room_id);
819 void RefreshActiveRoomCanvasState(zelda3::Room& room, int room_id);
821 void SyncCanvasCaptureRegion(const gui::CanvasRuntime& canvas_rt);
822 void ConsumePendingCanvasScroll(const gui::CanvasRuntime& canvas_rt);
823 void DrawHeaderHiddenMetadataHud(int room_id);
824 void PrepareRoomStateForCanvas(zelda3::Room& room, int room_id);
825 void DrawRoomCanvasContent(const gui::CanvasRuntime& canvas_rt,
826 zelda3::Room& room, int room_id);
827 void HandleRoomCanvasDropTargets(zelda3::Room& room, int room_id);
828 void DrawChangePingOverlay(const gui::CanvasRuntime& canvas_rt,
829 const zelda3::Room& room);
830 void RecordVisitedRoom(int room_id);
831
832 // Room graphics management
833 // Load: Read from ROM, Render: Process pixels, Draw: Display on canvas
834 absl::Status LoadAndRenderRoomGraphics(int room_id);
839 int ApplyConnectedStaircaseIssueAutoFixes(int center_room_id);
840 bool DrawRoomBackgroundLayers(int room_id); // Draw room buffers to canvas
841
842 Rom* rom_ = nullptr;
844 gui::Canvas canvas_{"##DungeonCanvas", ImVec2(0x200, 0x200)};
845 gui::Canvas connected_canvas_{"##DungeonConnectedCanvas",
846 ImVec2(0x200, 0x200)};
847 // ObjectRenderer removed - use ObjectDrawer for rendering (production system)
849
850 // Touch gesture handler for long-press context menus on touch devices
852
853 // Scroll target
854 std::optional<std::pair<int, int>> pending_scroll_target_;
855
856 // Room data
859 std::vector<int> recently_visited_rooms_;
862 // Used by overworld editor for double-click entrance → open dungeon room
863 ImVector<int> active_rooms_;
872 // Last-frame visibility of the connected-mode side panel (overview /
873 // preview). Used to apply hysteresis when the viewport width crosses the
874 // panel's min-size threshold, so dragging the pane splitter past the
875 // threshold doesn't cause a sudden ~220 px horizontal snap.
878 ImVec2 connected_controls_custom_position_value_ = ImVec2(0.0f, 0.0f);
883
884 // Object interaction state
886
887 // Per-room layer managers (4-way visibility, blend modes, per-object translucency)
888 std::map<int, zelda3::RoomLayerManager> room_layer_managers_;
889
890 // Palette data
894 std::function<void(int)> room_navigation_callback_;
895 std::function<void(int, int)>
896 room_swap_callback_; // (old_room_id, new_room_id)
897 std::function<void()> show_object_panel_callback_;
898 std::function<void()> show_sprite_panel_callback_;
899 std::function<void()> show_item_panel_callback_;
900 std::function<void()> show_room_list_callback_;
901 std::function<void()> show_room_matrix_callback_;
902 std::function<void()> show_entrance_list_callback_;
903 std::function<void()> show_room_graphics_callback_;
904 std::function<void()> show_door_editor_callback_;
905 std::function<void()> show_dungeon_settings_callback_;
906 std::function<void(int)> save_room_callback_;
907 std::function<void(int, const zelda3::RoomObject&)> edit_graphics_callback_;
910 bool is_pinned_ = false;
911 std::function<void(bool)> pin_callback_;
913
923 bool show_room_details_ = false;
925 bool header_read_only_ = false;
926 bool header_visible_ = true;
928
930 std::vector<uint16_t> track_tile_order_;
931 std::vector<uint16_t> switch_tile_order_;
933 std::unordered_map<int, DungeonRenderingHelpers::CollisionOverlayCache>
935 std::bitset<256> minecart_sprite_ids_{};
936
937 // Object rendering cache
945 std::vector<ObjectRenderCache> object_render_cache_;
946 uint64_t last_palette_hash_ = 0;
947
948 // Debug state flags
952 bool show_layer_info_ = false;
953 bool show_grid_ = false; // Grid off by default for dungeon editor
955 false; // Show camera coordinates on hover (toggle via Debug menu)
956 int layout_override_ = -1; // -1 for no override
959 ObjectRenderMode::Emulator; // Default to emulator rendering
960
961 // Object outline filtering toggles
963 bool show_type1_objects = true; // Standard objects (0x00-0xFF)
964 bool show_type2_objects = true; // Extended objects (0x100-0x1FF)
965 bool show_type3_objects = true; // Special objects (0xF00-0xFFF)
966 bool show_layer0_objects = true; // Primary / upper layer (BG1)
967 bool show_layer1_objects = true; // BG2 overlay / lower layer (BG2)
968 bool show_layer2_objects = true; // BG1 overlay room stream
969 };
971
972 // Entity overlay visibility toggles
974 bool show_sprites = true; // Show sprite entities
975 bool show_pot_items = true; // Show pot item entities
976 bool show_chests = true; // Show chest entities (future)
977 };
979
981
982 // Previous room state for change detection (per-viewer)
985 int prev_layout_ = -1;
987
996 std::string issue_report_popup_id_ = "##DungeonIssueReportPopup";
1008 std::vector<ChangePingRect> change_ping_rects_;
1010 std::function<void(int, const zelda3::RoomObject&)>
1012};
1013
1014} // namespace editor
1015} // namespace yaze
1016
1017#endif
The Rom class is used to load, save, and modify Rom data. This is a generic SNES ROM container and do...
Definition rom.h:28
std::optional< zelda3::RoomObject > GetObjectUnderContextCursor(int room_id)
gui::CanvasMenuItem BuildLayerVisibilityContextMenu(int room_id)
void HandleRoomCanvasDropTargets(zelda3::Room &room, int room_id)
bool RoomHasNonExitDoorInDirection(int room_id, zelda3::DoorDirection dir)
const zelda3::RoomLayerManager & GetRoomLayerManager(int room_id) const
void DrawChangePingOverlay(const gui::CanvasRuntime &canvas_rt, const zelda3::Room &room)
void SetShowEntranceListCallback(std::function< void()> callback)
void RefreshActiveRoomCanvasState(zelda3::Room &room, int room_id)
gui::CanvasMenuItem BuildRoomContextMenu(int room_id)
gui::CanvasMenuItem BuildDebugContextMenu(int room_id)
friend class DungeonEditorPaletteRefreshTest_CachedRoomRefreshesThroughViewerCompositePreparation_Test
std::optional< std::pair< int, int > > pending_scroll_target_
void SetLayerBlendMode(int room_id, zelda3::LayerType layer, zelda3::LayerBlendMode mode)
void SyncCanvasCaptureRegion(const gui::CanvasRuntime &canvas_rt)
std::vector< gui::CanvasMenuItem > BuildSelectionContextMenuItems(int room_id)
void SetEditorSystem(zelda3::DungeonEditorSystem *system)
int ApplyConnectedStaircaseIssueAutoFixes(int center_room_id)
void RenderPotItems(const gui::CanvasRuntime &rt, const zelda3::Room &room)
std::optional< int > DrawConnectedRoomMatrix(int center_room_id)
absl::Status LoadAndRenderRoomGraphics(int room_id)
friend class DungeonEditorPaletteRefreshTest_DungeonMainNotificationSkipsUnrelatedCachedViewerWork_Test
void SetMinecartTrackPanel(MinecartTrackEditorPanel *panel)
void SetObjectTranslucent(int room_id, size_t object_index, bool translucent, uint8_t alpha=128)
void SetShowItemPanelCallback(std::function< void()> callback)
std::function< void()> show_door_editor_callback_
void SetShowRoomGraphicsCallback(std::function< void()> callback)
void SetConnectedControlsInline(bool inline_controls)
std::function< void(int, const zelda3::RoomObject &) edit_object_tiles_callback_)
void SetProject(const project::YazeProject *project)
std::function< void(int, const zelda3::RoomObject &) edit_graphics_callback_)
const DungeonRenderingHelpers::CollisionOverlayCache & GetCollisionOverlayCache(int room_id)
void SetIssueReportPopupStatus(std::string message, bool is_error)
void set_active_rooms(const ImVector< int > &rooms)
void SetRenderer(gfx::IRenderer *renderer)
void SetEditGraphicsCallback(std::function< void(int, const zelda3::RoomObject &)> callback)
void SetBG2LayerType(int room_id, int type)
friend class DungeonEditorPaletteRefreshTest_CachedPanelPaletteRefreshSurvivesWorkbenchModeAndPreservesRoomPalette_Test
std::function< void()> show_entrance_list_callback_
void DrawTextureDebugWindow(zelda3::Room &room, int room_id)
zelda3::Room * EnsureRoomLoadedForConnectedView(int room_id)
void SetShowRoomListCallback(std::function< void()> callback)
ConnectedRoomGraphData connected_graph_cache_
zelda3::Room * PrepareActiveRoomForCanvasFrame(int room_id)
void RefreshRomBackedState(Rom *rom, zelda3::GameData *game_data, DungeonRoomStore *rooms, int room_id)
DungeonObjectInteraction object_interaction_
void SetObjectRenderMode(ObjectRenderMode mode)
void PrepareRoomStateForCanvas(zelda3::Room &room, int room_id)
void OpenIssueReportPopup(const std::string &title, const std::string &summary, const std::string &kind_label, const std::string &diagnostics, int room_id, int default_category_index)
void DrawRoomCanvasContent(const gui::CanvasRuntime &canvas_rt, zelda3::Room &room, int room_id)
DungeonObjectInteraction & object_interaction()
void DrawRoomDebugWindow(zelda3::Room &room, int room_id)
ConnectedRoomGraphData BuildConnectedRoomGraph(int start_room_id)
friend class DungeonEditorPaletteRefreshTest_CachedCompositePreparationPreservesTargetEntranceContext_Test
std::string BuildRoomMetadataSummary(const zelda3::Room &room, int room_id) const
std::function< void()> show_room_list_callback_
void TriggerCanvasPingRect(int pixel_x, int pixel_y, int pixel_w, int pixel_h)
void SetShowRoomMatrixCallback(std::function< void()> callback)
const project::YazeProject * project_
void SetRoomNavigationCallback(std::function< void(int)> callback)
gui::CanvasMenuItem BuildReportContextMenu(int room_id)
void SetShowSpritePanelCallback(std::function< void()> callback)
void SetPreviewObject(const zelda3::RoomObject &object)
std::function< void()> show_object_panel_callback_
std::function< void(bool)> pin_callback_
std::optional< std::pair< int, int > > GetPendingScrollTarget() const
void SetBG1Visible(int room_id, bool visible)
void SetBG2Visible(int room_id, bool visible)
bool IsLayerVisible(int room_id, zelda3::LayerType layer) const
std::unordered_map< int, DungeonRenderingHelpers::CollisionOverlayCache > collision_overlay_cache_
void DrawLayerControls(zelda3::Room &room, int room_id)
void SetShowObjectPanelCallback(std::function< void()> callback)
void RenderSprites(const gui::CanvasRuntime &rt, const zelda3::Room &room)
gfx::Bitmap * PrepareRoomCompositeBitmap(int room_id)
zelda3::RoomLayerManager & GetRoomLayerManager(int room_id)
ObjectRenderMode GetObjectRenderMode() const
void DrawMaskHighlights(const gui::CanvasRuntime &rt, const zelda3::Room &room)
void TriggerObjectChangePing(const std::vector< zelda3::RoomObject > &previous_objects, const std::vector< zelda3::RoomObject > &next_objects)
gui::CanvasFrameOptions BuildRoomCanvasFrameOptions() const
std::string BuildDrawIssueReport(const zelda3::Room &room, int room_id) const
void SetEntranceRenderContext(int entrance_id, uint8_t entrance_blockset)
absl::Status PrepareIssueReportPopup(const std::string &title, const std::string &summary, const std::string &kind_label, const std::string &diagnostics, int room_id, int default_category_index)
std::function< void()> show_dungeon_settings_callback_
void SetRoomSwapCallback(std::function< void(int, int)> callback)
const project::YazeProject * project() const
void SetEditObjectTilesCallback(std::function< void(int, const zelda3::RoomObject &)> callback)
std::function< void()> show_room_matrix_callback_
void ScrollToTile(int tile_x, int tile_y)
zelda3::LayerBlendMode GetLayerBlendMode(int room_id, zelda3::LayerType layer) const
std::function< void()> show_room_graphics_callback_
void ConsumePendingCanvasScroll(const gui::CanvasRuntime &canvas_rt)
void SetSaveRoomCallback(std::function< void(int)> callback)
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group, bool force_refresh=false)
void DrawRoomHeader(zelda3::Room &room, int room_id)
std::function< void(int)> room_navigation_callback_
void RenderEntityOverlay(const gui::CanvasRuntime &rt, const zelda3::Room &room)
std::function< void()> show_item_panel_callback_
std::map< int, zelda3::RoomLayerManager > room_layer_managers_
std::vector< ObjectRenderCache > object_render_cache_
void DisplayObjectInfo(const gui::CanvasRuntime &rt, const zelda3::RoomObject &object, int canvas_x, int canvas_y)
std::function< void()> show_sprite_panel_callback_
std::function< void(int, int)> room_swap_callback_
DungeonRenderingHelpers::TrackCollisionConfig track_collision_config_
void SetLayerVisible(int room_id, zelda3::LayerType layer, bool visible)
void DrawObjectPositionOutlines(const gui::CanvasRuntime &rt, const zelda3::Room &room)
std::optional< gui::CanvasMenuItem > BuildOpenContextMenu()
void DrawRoomPropertyTable(zelda3::Room &room, int room_id)
void HandleTouchLongPressContextMenu(const gui::CanvasRuntime &rt, const zelda3::Room &room)
void SetShowDungeonSettingsCallback(std::function< void()> callback)
void SetRooms(DungeonRoomStore *rooms)
MinecartTrackEditorPanel * minecart_track_panel_
std::vector< ChangePingRect > change_ping_rects_
void DrawRoomCanvasOverlays(const gui::CanvasRuntime &rt, zelda3::Room &room, int room_id)
std::string BuildSelectionIssueReport(const zelda3::Room &room, int room_id) const
gui::CanvasMenuItem BuildCopyExportContextMenu(int room_id)
void SetGameData(zelda3::GameData *game_data)
void SetShowDoorEditorCallback(std::function< void()> callback)
void SetPinCallback(std::function< void(bool)> callback)
std::function< void(int)> save_room_callback_
Handles object selection, placement, and interaction within the dungeon canvas.
void SetDoorPairNavigationCallback(std::function< void(int, std::optional< size_t >, int, int)> callback)
void SetEditorSystem(zelda3::DungeonEditorSystem *system)
std::vector< size_t > GetSelectedObjectIndices() const
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group, bool force_refresh=false)
void SelectEntity(EntityType type, size_t index)
void SetPreviewObject(const zelda3::RoomObject &object, bool loaded)
Represents a bitmap image optimized for SNES ROM hacking.
Definition bitmap.h:67
Defines an abstract interface for all rendering operations.
Definition irenderer.h:60
Handles touch input integration for Canvas.
Modern, robust canvas for drawing and manipulating graphics.
Definition canvas.h:64
RoomLayerManager - Manages layer visibility and compositing.
void SetLayerBlendMode(LayerType layer, LayerBlendMode mode)
void SetLayerVisible(LayerType layer, bool visible)
void SetObjectTranslucency(size_t object_index, bool translucent, uint8_t alpha=128)
std::string FormatDungeonConnectedLinkDescription(const DungeonConnectedRoomLink &link)
int NeighborRoomId(int room_id, zelda3::DoorDirection dir)
DungeonConnectedRoomLinkDiagnostics CollectDungeonConnectedRoomLinkDiagnostics(int room_id, const zelda3::Room &room, const std::function< bool(int, zelda3::DoorDirection)> &has_reciprocal_door)
const char * GetIssueCategoryLabel(int index)
constexpr std::array< const char *, 6 > kDungeonIssueCategoryLabels
zelda3::DoorDirection OppositeDir(zelda3::DoorDirection dir)
DungeonIssueCategory GetDefaultSelectionIssueCategory(const DungeonObjectInteraction &object_interaction)
ObjectRenderMode
Handles the main dungeon canvas rendering and interaction.
constexpr int ToIssueCategoryIndex(DungeonIssueCategory category)
std::vector< DungeonConnectedRoomLink > CollectDungeonConnectedRoomLinks(int room_id, const zelda3::Room &room, const std::function< bool(int, zelda3::DoorDirection)> &has_reciprocal_door)
std::string FormatDungeonStaircaseIssueDescription(const DungeonStaircaseIssue &issue)
DoorType
Door types from ALTTP.
Definition door_types.h:33
@ NormalDoor
Normal door (upper layer)
LayerBlendMode
Layer blend modes for compositing.
LayerType
Layer types for the 4-way visibility system.
constexpr int kNumberOfRooms
DoorDirection
Door direction on room walls.
Definition door_types.h:18
@ South
Bottom wall (horizontal door, 4x3 tiles)
@ North
Top wall (horizontal door, 4x3 tiles)
@ East
Right wall (vertical door, 3x4 tiles)
@ West
Left wall (vertical door, 3x4 tiles)
std::array< RoomPlacement, zelda3::kNumberOfRooms > room_positions
std::array< std::string, zelda3::kNumberOfRooms > room_floor_labels
std::vector< DungeonConnectedRoomLink > links
std::vector< DungeonStaircaseIssue > staircase_issues
Lightweight view into the essential runtime context (Rom + GameData)
Definition editor.h:72
zelda3::GameData * game_data
Definition editor.h:74
Represents a group of palettes.
const SnesPalette & palette_ref(int i) const
Declarative menu item definition.
Definition canvas_menu.h:64
Modern project structure with comprehensive settings consolidation.
Definition project.h:172