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; }
309 }
310 void SetEntranceRenderContext(int entrance_id, uint8_t entrance_blockset) {
311 current_entrance_id_ = entrance_id;
312 current_entrance_blockset_ = entrance_blockset;
313 }
321 }
322 void SetRoomNavigationCallback(std::function<void(int)> callback) {
323 room_navigation_callback_ = std::move(callback);
324 }
325 // Callback to swap the current room in-place (for arrow navigation)
326 void SetRoomSwapCallback(std::function<void(int, int)> callback) {
327 room_swap_callback_ = std::move(callback);
328 }
329
330 bool CanNavigateRooms() const {
331 return room_swap_callback_ != nullptr ||
332 room_navigation_callback_ != nullptr;
333 }
334
335 // Navigate to another dungeon room using the same semantics as the header
336 // arrow buttons:
337 // - If a swap callback exists (workbench mode), swap in-place.
338 // - Otherwise, use the navigation callback (opens/switches room view).
339 void NavigateToRoom(int target_room) {
340 if (target_room < 0 || target_room >= zelda3::kNumberOfRooms) {
341 return;
342 }
345 } else if (room_navigation_callback_) {
346 room_navigation_callback_(target_room);
347 }
348 }
349 void SetShowObjectPanelCallback(std::function<void()> callback) {
350 show_object_panel_callback_ = std::move(callback);
351 }
352 void SetShowSpritePanelCallback(std::function<void()> callback) {
353 show_sprite_panel_callback_ = std::move(callback);
354 }
355 void SetShowItemPanelCallback(std::function<void()> callback) {
356 show_item_panel_callback_ = std::move(callback);
357 }
358 void SetShowRoomListCallback(std::function<void()> callback) {
359 show_room_list_callback_ = std::move(callback);
360 }
361 void SetShowRoomMatrixCallback(std::function<void()> callback) {
362 show_room_matrix_callback_ = std::move(callback);
363 }
364 void SetShowEntranceListCallback(std::function<void()> callback) {
365 show_entrance_list_callback_ = std::move(callback);
366 }
367
374
377 }
379
380 // Overlay toggles (used by settings panels / workbench UI).
404 }
411
412 bool show_grid() const { return show_grid_; }
413 void set_show_grid(bool show) { show_grid_ = show; }
414 int custom_grid_size() const { return custom_grid_size_; }
415 void set_custom_grid_size(int size) {
416 custom_grid_size_ = size > 0 ? size : 1;
417 }
419 void set_show_object_bounds(bool show) { show_object_bounds_ = show; }
423 }
427 void set_show_texture_debug(bool show) { show_texture_debug_ = show; }
428 bool show_layer_info() const { return show_layer_info_; }
429 void set_show_layer_info(bool show) { show_layer_info_ = show; }
438
439 // Mutable pointer accessors for OverlayManagerPanel binding.
440 bool* mutable_show_grid() { return &show_grid_; }
462 void SetShowRoomGraphicsCallback(std::function<void()> callback) {
463 show_room_graphics_callback_ = std::move(callback);
464 }
465 void SetShowDoorEditorCallback(std::function<void()> callback) {
466 show_door_editor_callback_ = std::move(callback);
467 }
468 void SetShowDungeonSettingsCallback(std::function<void()> callback) {
469 show_dungeon_settings_callback_ = std::move(callback);
470 }
471 void SetSaveRoomCallback(std::function<void(int)> callback) {
472 save_room_callback_ = std::move(callback);
473 }
475 std::function<void(int, const zelda3::RoomObject&)> callback) {
476 edit_graphics_callback_ = std::move(callback);
477 }
481 void SetPinned(bool pinned) { is_pinned_ = pinned; }
482 void SetPinCallback(std::function<void(bool)> callback) {
483 pin_callback_ = std::move(callback);
484 }
486 const project::YazeProject* project() const { return project_; }
487
488 // Canvas access
490 const gui::Canvas& canvas() const { return canvas_; }
491
492 // Object interaction access
494
498
499 // Enable/disable object interaction mode
500 void SetObjectInteractionEnabled(bool enabled) {
502 }
506
507 // Make the room header controls non-interactive while still allowing canvas
508 // pan/zoom (useful for split/compare views).
509 void SetHeaderReadOnly(bool read_only) { header_read_only_ = read_only; }
510 bool header_read_only() const { return header_read_only_; }
511
512 // Hide the header chrome entirely (useful for stitched/split layouts where a
513 // parent container provides its own metadata/controls).
514 void SetHeaderVisible(bool visible) { header_visible_ = visible; }
515 bool header_visible() const { return header_visible_; }
522
523 // Set and get the object render mode
528
529 // Layer visibility controls (per-room) using RoomLayerManager
530 void SetLayerVisible(int room_id, zelda3::LayerType layer, bool visible) {
531 GetRoomLayerManager(room_id).SetLayerVisible(layer, visible);
532 }
533 bool IsLayerVisible(int room_id, zelda3::LayerType layer) const {
534 auto it = room_layer_managers_.find(room_id);
535 return it != room_layer_managers_.end() ? it->second.IsLayerVisible(layer)
536 : true;
537 }
538
539 // Legacy compatibility - BG1 visibility (combines layout + objects)
540 void SetBG1Visible(int room_id, bool visible) {
541 auto& mgr = GetRoomLayerManager(room_id);
542 mgr.SetLayerVisible(zelda3::LayerType::BG1_Layout, visible);
543 mgr.SetLayerVisible(zelda3::LayerType::BG1_Objects, visible);
544 }
545 void SetBG2Visible(int room_id, bool visible) {
546 auto& mgr = GetRoomLayerManager(room_id);
547 mgr.SetLayerVisible(zelda3::LayerType::BG2_Layout, visible);
548 mgr.SetLayerVisible(zelda3::LayerType::BG2_Objects, visible);
549 }
550 bool IsBG1Visible(int room_id) const {
551 auto it = room_layer_managers_.find(room_id);
552 if (it == room_layer_managers_.end())
553 return true;
554 return it->second.IsLayerVisible(zelda3::LayerType::BG1_Layout) ||
555 it->second.IsLayerVisible(zelda3::LayerType::BG1_Objects);
556 }
557 bool IsBG2Visible(int room_id) const {
558 auto it = room_layer_managers_.find(room_id);
559 if (it == room_layer_managers_.end())
560 return true;
561 return it->second.IsLayerVisible(zelda3::LayerType::BG2_Layout) ||
562 it->second.IsLayerVisible(zelda3::LayerType::BG2_Objects);
563 }
564
565 // Layer blend mode controls
566 void SetLayerBlendMode(int room_id, zelda3::LayerType layer,
568 GetRoomLayerManager(room_id).SetLayerBlendMode(layer, mode);
569 }
571 zelda3::LayerType layer) const {
572 auto it = room_layer_managers_.find(room_id);
573 return it != room_layer_managers_.end()
574 ? it->second.GetLayerBlendMode(layer)
576 }
577
578 // Per-object translucency
579 void SetObjectTranslucent(int room_id, size_t object_index, bool translucent,
580 uint8_t alpha = 128) {
581 GetRoomLayerManager(room_id).SetObjectTranslucency(object_index,
582 translucent, alpha);
583 }
584
585 // Layer manager access
587 return room_layer_managers_[room_id];
588 }
590 static zelda3::RoomLayerManager default_manager;
591 auto it = room_layer_managers_.find(room_id);
592 return it != room_layer_managers_.end() ? it->second : default_manager;
593 }
594
595 // Legacy BG2 layer type (mapped to blend mode)
596 void SetBG2LayerType(int room_id, int type) {
597 auto& mgr = GetRoomLayerManager(room_id);
599 switch (type) {
600 case 0:
602 break;
603 case 1:
605 break;
606 case 2:
608 break;
609 case 3:
611 break;
612 case 4:
614 break;
615 default:
617 break;
618 }
619 mgr.SetLayerBlendMode(zelda3::LayerType::BG2_Layout, mode);
620 mgr.SetLayerBlendMode(zelda3::LayerType::BG2_Objects, mode);
621 }
622 int GetBG2LayerType(int room_id) const {
624 switch (mode) {
626 return 0;
628 return 1;
630 return 2;
632 return 3;
634 return 4;
635 }
636 return 0;
637 }
638
639 // Set the object to be placed
641 // Pass palette group first so ghost preview can render correctly
644 }
647 false);
648 }
649
650 // Scroll the canvas to center on the given tile coordinates.
651 // The pending target is consumed by Draw() on the next frame.
652 void ScrollToTile(int tile_x, int tile_y) {
653 pending_scroll_target_ = {tile_x, tile_y};
654 }
656 return pending_scroll_target_.has_value();
657 }
658 std::optional<std::pair<int, int>> GetPendingScrollTarget() const {
660 }
661
662 // Object manipulation
664
665 // Entity visibility controls
666 void SetSpritesVisible(bool visible) {
668 }
670 void SetPotItemsVisible(bool visible) {
672 }
674
677 int col = 0;
678 int row = 0;
679 bool placed = false;
680 bool connected_to_start = false;
681 };
682
683 std::array<bool, zelda3::kNumberOfRooms> room_mask{};
684 std::array<RoomPlacement, zelda3::kNumberOfRooms> room_positions{};
685 std::array<std::string, zelda3::kNumberOfRooms> room_floor_labels{};
686 std::vector<std::string> floor_order;
687 std::vector<DungeonConnectedRoomLink> links;
688 // Staircase configuration anomalies aggregated across the whole
689 // connected component. Order is "first-encountered during BFS".
690 std::vector<DungeonStaircaseIssue> staircase_issues;
691 // Resolved links whose destination room falls outside the project's
692 // current dungeon registry scope (only populated when scoping is active).
693 // The runtime would still traverse these; the matrix omits the target
694 // rooms by default but surfaces the link as a diagnostic so the user can
695 // see "current dungeon connects out to room X via staircase".
696 std::vector<DungeonConnectedRoomLink> out_of_scope_links;
697 // True when BFS is restricted to a project-registry dungeon group.
699 int room_count = 0;
701 int min_col = 0;
702 int max_col = 0;
703 int min_row = 0;
704 int max_row = 0;
705 };
706
707 private:
709 friend class
711 friend class
713
715 int x = 0;
716 int y = 0;
717 int w = 0;
718 int h = 0;
719 };
720
722 const zelda3::RoomObject& object, int canvas_x,
723 int canvas_y);
724 void DrawRoomHeader(zelda3::Room& room, int room_id);
725 void DrawRoomNavigation(int room_id);
726 void DrawRoomPropertyTable(zelda3::Room& room, int room_id);
727 void DrawRecentRoomBreadcrumbs(int room_id);
728 void DrawLayerControls(zelda3::Room& room, int room_id);
729 void DrawCompactLayerToggles(int room_id);
730 void PopulateCanvasContextMenu(int room_id);
731 void AddInteractionContextMenuItems(int room_id);
732 void AddLoadedRoomContextMenuItems(int room_id);
734 std::vector<gui::CanvasMenuItem> BuildSelectionContextMenuItems(int room_id);
735 std::optional<zelda3::RoomObject> GetObjectUnderContextCursor(int room_id);
738 std::optional<gui::CanvasMenuItem> BuildOpenContextMenu();
743 std::string BuildRoomMetadataSummary(const zelda3::Room& room,
744 int room_id) const;
745 std::string BuildDrawIssueReport(const zelda3::Room& room, int room_id) const;
746 std::string BuildSelectionIssueReport(const zelda3::Room& room,
747 int room_id) const;
748 void OpenIssueReportPopup(const std::string& title,
749 const std::string& summary,
750 const std::string& kind_label,
751 const std::string& diagnostics, int room_id,
752 int default_category_index);
753 absl::Status PrepareIssueReportPopup(const std::string& title,
754 const std::string& summary,
755 const std::string& kind_label,
756 const std::string& diagnostics,
757 int room_id, int default_category_index);
758 std::string BuildIssueReportClipboardText() const;
759 absl::Status CaptureIssueReportScreenshot();
760 absl::Status AppendIssueReportToLog();
761 absl::Status EnsureIssueReportPersisted();
764 void SetIssueReportPopupStatus(std::string message, bool is_error);
766 void DrawIssueReportStatusMessage() const;
767 void RenderSprites(const gui::CanvasRuntime& rt, const zelda3::Room& room);
768 void RenderPotItems(const gui::CanvasRuntime& rt, const zelda3::Room& room);
770 const zelda3::Room& room);
771
772 // Touch interaction: long-press context menu for entities
774 const zelda3::Room& room);
775
776 // Visualization
778 const zelda3::Room& room);
781 GetCollisionOverlayCache(int room_id);
782
783 // Draw semi-transparent overlay on stored value 1 / BG2 overlay objects when
784 // mask mode is active.
786 const zelda3::Room& room);
787 void DrawPersistentDebugWindows(int room_id);
788 void DrawRoomDebugWindow(zelda3::Room& room, int room_id);
789 void DrawTextureDebugWindow(zelda3::Room& room, int room_id);
790 void DrawLayerInfoWindow(int room_id);
792 int room_id);
793 void DrawCoordinateOverlayHud(int room_id);
794 bool ValidateRoomCanvasRequest(int room_id);
798 void RefreshActiveRoomCanvasState(zelda3::Room& room, int room_id);
800 void SyncCanvasCaptureRegion(const gui::CanvasRuntime& canvas_rt);
801 void ConsumePendingCanvasScroll(const gui::CanvasRuntime& canvas_rt);
802 void DrawHeaderHiddenMetadataHud(int room_id);
803 void PrepareRoomStateForCanvas(zelda3::Room& room, int room_id);
804 void DrawRoomCanvasContent(const gui::CanvasRuntime& canvas_rt,
805 zelda3::Room& room, int room_id);
806 void HandleRoomCanvasDropTargets(zelda3::Room& room, int room_id);
807 void DrawChangePingOverlay(const gui::CanvasRuntime& canvas_rt,
808 const zelda3::Room& room);
809 void RecordVisitedRoom(int room_id);
810
811 // Room graphics management
812 // Load: Read from ROM, Render: Process pixels, Draw: Display on canvas
813 absl::Status LoadAndRenderRoomGraphics(int room_id);
818 int ApplyConnectedStaircaseIssueAutoFixes(int center_room_id);
819 bool DrawRoomBackgroundLayers(int room_id); // Draw room buffers to canvas
820
821 Rom* rom_ = nullptr;
823 gui::Canvas canvas_{"##DungeonCanvas", ImVec2(0x200, 0x200)};
824 gui::Canvas connected_canvas_{"##DungeonConnectedCanvas",
825 ImVec2(0x200, 0x200)};
826 // ObjectRenderer removed - use ObjectDrawer for rendering (production system)
828
829 // Touch gesture handler for long-press context menus on touch devices
831
832 // Scroll target
833 std::optional<std::pair<int, int>> pending_scroll_target_;
834
835 // Room data
838 std::vector<int> recently_visited_rooms_;
841 // Used by overworld editor for double-click entrance → open dungeon room
842 ImVector<int> active_rooms_;
851 // Last-frame visibility of the connected-mode side panel (overview /
852 // preview). Used to apply hysteresis when the viewport width crosses the
853 // panel's min-size threshold, so dragging the pane splitter past the
854 // threshold doesn't cause a sudden ~220 px horizontal snap.
857 ImVec2 connected_controls_custom_position_value_ = ImVec2(0.0f, 0.0f);
862
863 // Object interaction state
865
866 // Per-room layer managers (4-way visibility, blend modes, per-object translucency)
867 std::map<int, zelda3::RoomLayerManager> room_layer_managers_;
868
869 // Palette data
873 std::function<void(int)> room_navigation_callback_;
874 std::function<void(int, int)>
875 room_swap_callback_; // (old_room_id, new_room_id)
876 std::function<void()> show_object_panel_callback_;
877 std::function<void()> show_sprite_panel_callback_;
878 std::function<void()> show_item_panel_callback_;
879 std::function<void()> show_room_list_callback_;
880 std::function<void()> show_room_matrix_callback_;
881 std::function<void()> show_entrance_list_callback_;
882 std::function<void()> show_room_graphics_callback_;
883 std::function<void()> show_door_editor_callback_;
884 std::function<void()> show_dungeon_settings_callback_;
885 std::function<void(int)> save_room_callback_;
886 std::function<void(int, const zelda3::RoomObject&)> edit_graphics_callback_;
889 bool is_pinned_ = false;
890 std::function<void(bool)> pin_callback_;
892
902 bool show_room_details_ = false;
904 bool header_read_only_ = false;
905 bool header_visible_ = true;
907
909 std::vector<uint16_t> track_tile_order_;
910 std::vector<uint16_t> switch_tile_order_;
912 std::unordered_map<int, DungeonRenderingHelpers::CollisionOverlayCache>
914 std::bitset<256> minecart_sprite_ids_{};
915
916 // Object rendering cache
924 std::vector<ObjectRenderCache> object_render_cache_;
925 uint64_t last_palette_hash_ = 0;
926
927 // Debug state flags
931 bool show_layer_info_ = false;
932 bool show_grid_ = false; // Grid off by default for dungeon editor
934 false; // Show camera coordinates on hover (toggle via Debug menu)
935 int layout_override_ = -1; // -1 for no override
938 ObjectRenderMode::Emulator; // Default to emulator rendering
939
940 // Object outline filtering toggles
942 bool show_type1_objects = true; // Standard objects (0x00-0xFF)
943 bool show_type2_objects = true; // Extended objects (0x100-0x1FF)
944 bool show_type3_objects = true; // Special objects (0xF00-0xFFF)
945 bool show_layer0_objects = true; // Primary / upper layer (BG1)
946 bool show_layer1_objects = true; // BG2 overlay / lower layer (BG2)
947 bool show_layer2_objects = true; // BG1 overlay room stream
948 };
950
951 // Entity overlay visibility toggles
953 bool show_sprites = true; // Show sprite entities
954 bool show_pot_items = true; // Show pot item entities
955 bool show_chests = true; // Show chest entities (future)
956 };
958
960
961 // Previous room state for change detection (per-viewer)
964 int prev_layout_ = -1;
966
975 std::string issue_report_popup_id_ = "##DungeonIssueReportPopup";
987 std::vector<ChangePingRect> change_ping_rects_;
989};
990
991} // namespace editor
992} // namespace yaze
993
994#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)
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)
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)
std::function< void()> show_entrance_list_callback_
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group)
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
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 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 SetCurrentPaletteGroup(const gfx::PaletteGroup &group)
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 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.
Declarative menu item definition.
Definition canvas_menu.h:64
Modern project structure with comprehensive settings consolidation.
Definition project.h:172