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 <functional>
6#include <map>
7#include <optional>
8#include <unordered_map>
9#include <vector>
10
11#include "app/editor/editor.h"
16#include "core/project.h"
19#include "dungeon_room_store.h"
20#include "imgui/imgui.h"
21#include "rom/rom.h"
23#include "zelda3/dungeon/room.h"
25#include "zelda3/game_data.h"
26
27namespace yaze {
28namespace editor {
29
30class MinecartTrackEditorPanel;
31
35enum class ObjectRenderMode {
36 Manual, // Use ObjectDrawer routines
37 Emulator, // Use SNES emulator
38 Hybrid // Emulator with manual fallback
39};
40
42 public:
47
48 void DrawDungeonCanvas(int room_id);
49 void Draw(int room_id);
50
52 rom_ = ctx.rom;
55 }
56 EditorContext context() const { return {rom_, game_data_}; }
57 void SetRom(Rom* rom) {
58 rom_ = rom;
60 }
61 Rom* rom() const { return rom_; }
64 void SetRenderer(gfx::IRenderer* renderer) { renderer_ = renderer; }
65
66 // Room data access
68 DungeonRoomStore* rooms() const { return rooms_; }
69 bool HasRooms() const { return rooms_ != nullptr; }
70
71 // Best-effort "current room" context for auxiliary panels that are driven by
72 // whichever room the viewer is currently drawing.
73 int current_room_id() const { return current_room_id_; }
74
75 // Workbench/Inspector integration.
76 void SetCompactHeaderMode(bool compact) { compact_header_mode_ = compact; }
78 void SetRoomDetailsExpanded(bool expanded) { show_room_details_ = expanded; }
79
80 // Used by overworld editor when double-clicking entrances
81 void set_active_rooms(const ImVector<int>& rooms) { active_rooms_ = rooms; }
83
84 // Palette access
88 void SetCurrentPaletteId(uint64_t id) { current_palette_id_ = id; }
92 void SetRoomNavigationCallback(std::function<void(int)> callback) {
93 room_navigation_callback_ = std::move(callback);
94 }
95 // Callback to swap the current room in-place (for arrow navigation)
96 void SetRoomSwapCallback(std::function<void(int, int)> callback) {
97 room_swap_callback_ = std::move(callback);
98 }
99
100 bool CanNavigateRooms() const {
101 return room_swap_callback_ != nullptr ||
102 room_navigation_callback_ != nullptr;
103 }
104
105 // Navigate to another dungeon room using the same semantics as the header
106 // arrow buttons:
107 // - If a swap callback exists (workbench mode), swap in-place.
108 // - Otherwise, use the navigation callback (opens/switches room view).
109 void NavigateToRoom(int target_room) {
110 if (target_room < 0 || target_room >= zelda3::kNumberOfRooms) {
111 return;
112 }
115 } else if (room_navigation_callback_) {
116 room_navigation_callback_(target_room);
117 }
118 }
119 void SetShowObjectPanelCallback(std::function<void()> callback) {
120 show_object_panel_callback_ = std::move(callback);
121 }
122 void SetShowSpritePanelCallback(std::function<void()> callback) {
123 show_sprite_panel_callback_ = std::move(callback);
124 }
125 void SetShowItemPanelCallback(std::function<void()> callback) {
126 show_item_panel_callback_ = std::move(callback);
127 }
128 void SetShowRoomListCallback(std::function<void()> callback) {
129 show_room_list_callback_ = std::move(callback);
130 }
131 void SetShowRoomMatrixCallback(std::function<void()> callback) {
132 show_room_matrix_callback_ = std::move(callback);
133 }
134 void SetShowEntranceListCallback(std::function<void()> callback) {
135 show_entrance_list_callback_ = std::move(callback);
136 }
137
144
147 }
149
150 // Overlay toggles (used by settings panels / workbench UI).
174 }
181
182 bool show_grid() const { return show_grid_; }
183 void set_show_grid(bool show) { show_grid_ = show; }
185 void set_show_object_bounds(bool show) { show_object_bounds_ = show; }
189 }
193 void set_show_texture_debug(bool show) { show_texture_debug_ = show; }
194 bool show_layer_info() const { return show_layer_info_; }
195 void set_show_layer_info(bool show) { show_layer_info_ = show; }
204
205 // Mutable pointer accessors for OverlayManagerPanel binding.
206 bool* mutable_show_grid() { return &show_grid_; }
228 void SetShowRoomGraphicsCallback(std::function<void()> callback) {
229 show_room_graphics_callback_ = std::move(callback);
230 }
231 void SetShowDungeonSettingsCallback(std::function<void()> callback) {
232 show_dungeon_settings_callback_ = std::move(callback);
233 }
234 void SetSaveRoomCallback(std::function<void(int)> callback) {
235 save_room_callback_ = std::move(callback);
236 }
238 std::function<void(int, const zelda3::RoomObject&)> callback) {
239 edit_graphics_callback_ = std::move(callback);
240 }
244 void SetPinned(bool pinned) { is_pinned_ = pinned; }
245 void SetPinCallback(std::function<void(bool)> callback) {
246 pin_callback_ = std::move(callback);
247 }
248 void SetProject(const project::YazeProject* project);
249
250 // Canvas access
252 const gui::Canvas& canvas() const { return canvas_; }
253
254 // Object interaction access
256
260
261 // Enable/disable object interaction mode
262 void SetObjectInteractionEnabled(bool enabled) {
264 }
268
269 // Make the room header controls non-interactive while still allowing canvas
270 // pan/zoom (useful for split/compare views).
271 void SetHeaderReadOnly(bool read_only) { header_read_only_ = read_only; }
272 bool header_read_only() const { return header_read_only_; }
273
274 // Hide the header chrome entirely (useful for stitched/split layouts where a
275 // parent container provides its own metadata/controls).
276 void SetHeaderVisible(bool visible) { header_visible_ = visible; }
277 bool header_visible() const { return header_visible_; }
284
285 // Set and get the object render mode
290
291 // Layer visibility controls (per-room) using RoomLayerManager
292 void SetLayerVisible(int room_id, zelda3::LayerType layer, bool visible) {
293 GetRoomLayerManager(room_id).SetLayerVisible(layer, visible);
294 }
295 bool IsLayerVisible(int room_id, zelda3::LayerType layer) const {
296 auto it = room_layer_managers_.find(room_id);
297 return it != room_layer_managers_.end() ? it->second.IsLayerVisible(layer)
298 : true;
299 }
300
301 // Legacy compatibility - BG1 visibility (combines layout + objects)
302 void SetBG1Visible(int room_id, bool visible) {
303 auto& mgr = GetRoomLayerManager(room_id);
304 mgr.SetLayerVisible(zelda3::LayerType::BG1_Layout, visible);
305 mgr.SetLayerVisible(zelda3::LayerType::BG1_Objects, visible);
306 }
307 void SetBG2Visible(int room_id, bool visible) {
308 auto& mgr = GetRoomLayerManager(room_id);
309 mgr.SetLayerVisible(zelda3::LayerType::BG2_Layout, visible);
310 mgr.SetLayerVisible(zelda3::LayerType::BG2_Objects, visible);
311 }
312 bool IsBG1Visible(int room_id) const {
313 auto it = room_layer_managers_.find(room_id);
314 if (it == room_layer_managers_.end())
315 return true;
316 return it->second.IsLayerVisible(zelda3::LayerType::BG1_Layout) ||
317 it->second.IsLayerVisible(zelda3::LayerType::BG1_Objects);
318 }
319 bool IsBG2Visible(int room_id) const {
320 auto it = room_layer_managers_.find(room_id);
321 if (it == room_layer_managers_.end())
322 return true;
323 return it->second.IsLayerVisible(zelda3::LayerType::BG2_Layout) ||
324 it->second.IsLayerVisible(zelda3::LayerType::BG2_Objects);
325 }
326
327 // Layer blend mode controls
328 void SetLayerBlendMode(int room_id, zelda3::LayerType layer,
330 GetRoomLayerManager(room_id).SetLayerBlendMode(layer, mode);
331 }
333 zelda3::LayerType layer) const {
334 auto it = room_layer_managers_.find(room_id);
335 return it != room_layer_managers_.end()
336 ? it->second.GetLayerBlendMode(layer)
338 }
339
340 // Per-object translucency
341 void SetObjectTranslucent(int room_id, size_t object_index, bool translucent,
342 uint8_t alpha = 128) {
343 GetRoomLayerManager(room_id).SetObjectTranslucency(object_index,
344 translucent, alpha);
345 }
346
347 // Layer manager access
349 return room_layer_managers_[room_id];
350 }
352 static zelda3::RoomLayerManager default_manager;
353 auto it = room_layer_managers_.find(room_id);
354 return it != room_layer_managers_.end() ? it->second : default_manager;
355 }
356
357 // Legacy BG2 layer type (mapped to blend mode)
358 void SetBG2LayerType(int room_id, int type) {
359 auto& mgr = GetRoomLayerManager(room_id);
361 switch (type) {
362 case 0:
364 break;
365 case 1:
367 break;
368 case 2:
370 break;
371 case 3:
373 break;
374 case 4:
376 break;
377 default:
379 break;
380 }
381 mgr.SetLayerBlendMode(zelda3::LayerType::BG2_Layout, mode);
382 mgr.SetLayerBlendMode(zelda3::LayerType::BG2_Objects, mode);
383 }
384 int GetBG2LayerType(int room_id) const {
386 switch (mode) {
388 return 0;
390 return 1;
392 return 2;
394 return 3;
396 return 4;
397 }
398 return 0;
399 }
400
401 // Set the object to be placed
403 // Pass palette group first so ghost preview can render correctly
406 }
409 false);
410 }
411
412 // Scroll the canvas to center on the given tile coordinates.
413 // The pending target is consumed by Draw() on the next frame.
414 void ScrollToTile(int tile_x, int tile_y) {
415 pending_scroll_target_ = {tile_x, tile_y};
416 }
418 return pending_scroll_target_.has_value();
419 }
420 std::optional<std::pair<int, int>> GetPendingScrollTarget() const {
422 }
423
424 // Object manipulation
426
427 // Entity visibility controls
428 void SetSpritesVisible(bool visible) {
430 }
432 void SetPotItemsVisible(bool visible) {
434 }
436
437 private:
439 const zelda3::RoomObject& object, int canvas_x,
440 int canvas_y);
441 void DrawRoomHeader(zelda3::Room& room, int room_id);
442 void DrawRoomNavigation(int room_id);
443 void DrawRoomPropertyTable(zelda3::Room& room, int room_id);
444 void DrawLayerControls(zelda3::Room& room, int room_id);
445 void DrawCompactLayerToggles(int room_id);
446 void RenderSprites(const gui::CanvasRuntime& rt, const zelda3::Room& room);
447 void RenderPotItems(const gui::CanvasRuntime& rt, const zelda3::Room& room);
449 const zelda3::Room& room);
450
451 // Touch interaction: long-press context menu for entities
453 const zelda3::Room& room);
454
455 // Visualization
457 const zelda3::Room& room);
460 GetCollisionOverlayCache(int room_id);
461
462 // Draw semi-transparent overlay on BG2/Layer 1 objects when mask mode is active
464 const zelda3::Room& room);
465
466 // Room graphics management
467 // Load: Read from ROM, Render: Process pixels, Draw: Display on canvas
468 absl::Status LoadAndRenderRoomGraphics(int room_id);
469 void DrawRoomBackgroundLayers(int room_id); // Draw room buffers to canvas
470
471 Rom* rom_ = nullptr;
473 gui::Canvas canvas_{"##DungeonCanvas", ImVec2(0x200, 0x200)};
474 // ObjectRenderer removed - use ObjectDrawer for rendering (production system)
476
477 // Touch gesture handler for long-press context menus on touch devices
479
480 // Scroll target
481 std::optional<std::pair<int, int>> pending_scroll_target_;
482
483 // Room data
486 // Used by overworld editor for double-click entrance → open dungeon room
487 ImVector<int> active_rooms_;
489
490 // Object interaction state
492
493 // Per-room layer managers (4-way visibility, blend modes, per-object translucency)
494 std::map<int, zelda3::RoomLayerManager> room_layer_managers_;
495
496 // Palette data
500 std::function<void(int)> room_navigation_callback_;
501 std::function<void(int, int)>
502 room_swap_callback_; // (old_room_id, new_room_id)
503 std::function<void()> show_object_panel_callback_;
504 std::function<void()> show_sprite_panel_callback_;
505 std::function<void()> show_item_panel_callback_;
506 std::function<void()> show_room_list_callback_;
507 std::function<void()> show_room_matrix_callback_;
508 std::function<void()> show_entrance_list_callback_;
509 std::function<void()> show_room_graphics_callback_;
510 std::function<void()> show_dungeon_settings_callback_;
511 std::function<void(int)> save_room_callback_;
512 std::function<void(int, const zelda3::RoomObject&)> edit_graphics_callback_;
515 bool is_pinned_ = false;
516 std::function<void(bool)> pin_callback_;
518
528 bool show_room_details_ = false;
530 bool header_read_only_ = false;
531 bool header_visible_ = true;
533
535 std::vector<uint16_t> track_tile_order_;
536 std::vector<uint16_t> switch_tile_order_;
538 std::unordered_map<int, DungeonRenderingHelpers::CollisionOverlayCache>
540 std::bitset<256> minecart_sprite_ids_{};
541
542 // Object rendering cache
550 std::vector<ObjectRenderCache> object_render_cache_;
551 uint64_t last_palette_hash_ = 0;
552
553 // Debug state flags
557 bool show_layer_info_ = false;
558 bool show_grid_ = false; // Grid off by default for dungeon editor
560 false; // Show camera coordinates on hover (toggle via Debug menu)
561 int layout_override_ = -1; // -1 for no override
564 ObjectRenderMode::Emulator; // Default to emulator rendering
565
566 // Object outline filtering toggles
568 bool show_type1_objects = true; // Standard objects (0x00-0xFF)
569 bool show_type2_objects = true; // Extended objects (0x100-0x1FF)
570 bool show_type3_objects = true; // Special objects (0xF00-0xFFF)
571 bool show_layer0_objects = true; // Layer 0 (BG1)
572 bool show_layer1_objects = true; // Layer 1 (BG2)
573 bool show_layer2_objects = true; // Layer 2 (BG3)
574 };
576
577 // Entity overlay visibility toggles
579 bool show_sprites = true; // Show sprite entities
580 bool show_pot_items = true; // Show pot item entities
581 bool show_chests = true; // Show chest entities (future)
582 };
584
586
587 // Previous room state for change detection (per-viewer)
590 int prev_layout_ = -1;
592};
593
594} // namespace editor
595} // namespace yaze
596
597#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
const zelda3::RoomLayerManager & GetRoomLayerManager(int room_id) const
void SetShowEntranceListCallback(std::function< void()> callback)
std::optional< std::pair< int, int > > pending_scroll_target_
void SetLayerBlendMode(int room_id, zelda3::LayerType layer, zelda3::LayerBlendMode mode)
void SetEditorSystem(zelda3::DungeonEditorSystem *system)
void RenderPotItems(const gui::CanvasRuntime &rt, const zelda3::Room &room)
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)
void SetShowRoomGraphicsCallback(std::function< void()> 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 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)
zelda3::GameData * game_data() const
std::function< void()> show_entrance_list_callback_
void SetCurrentPaletteGroup(const gfx::PaletteGroup &group)
void SetShowRoomListCallback(std::function< void()> callback)
DungeonObjectInteraction object_interaction_
void SetObjectRenderMode(ObjectRenderMode mode)
DungeonObjectInteraction & object_interaction()
std::function< void()> show_room_list_callback_
void SetShowRoomMatrixCallback(std::function< void()> callback)
const project::YazeProject * project_
void SetRoomNavigationCallback(std::function< void(int)> callback)
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)
zelda3::RoomLayerManager & GetRoomLayerManager(int room_id)
ObjectRenderMode GetObjectRenderMode() const
void DrawMaskHighlights(const gui::CanvasRuntime &rt, const zelda3::Room &room)
std::function< void()> show_dungeon_settings_callback_
void SetRoomSwapCallback(std::function< void(int, int)> 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 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)
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_
void SetGameData(zelda3::GameData *game_data)
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 SetEditorSystem(zelda3::DungeonEditorSystem *system)
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:150
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)
ObjectRenderMode
Handles the main dungeon canvas rendering and interaction.
LayerBlendMode
Layer blend modes for compositing.
LayerType
Layer types for the 4-way visibility system.
constexpr int kNumberOfRooms
Lightweight view into the essential runtime context (Rom + GameData)
Definition editor.h:71
zelda3::GameData * game_data
Definition editor.h:73
Represents a group of palettes.
Modern project structure with comprehensive settings consolidation.
Definition project.h:164