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 "imgui/imgui.h"
20#include "rom/rom.h"
22#include "zelda3/dungeon/room.h"
24#include "zelda3/game_data.h"
25
26namespace yaze {
27namespace editor {
28
29class MinecartTrackEditorPanel;
30
34enum class ObjectRenderMode {
35 Manual, // Use ObjectDrawer routines
36 Emulator, // Use SNES emulator
37 Hybrid // Emulator with manual fallback
38};
39
41 public:
46
47 void DrawDungeonCanvas(int room_id);
48 void Draw(int room_id);
49
51 rom_ = ctx.rom;
54 }
55 EditorContext context() const { return {rom_, game_data_}; }
56 void SetRom(Rom* rom) {
57 rom_ = rom;
59 }
60 Rom* rom() const { return rom_; }
63 void SetRenderer(gfx::IRenderer* renderer) { renderer_ = renderer; }
64
65 // Room data access
66 void SetRooms(std::array<zelda3::Room, 0x128>* rooms) { rooms_ = rooms; }
67 std::array<zelda3::Room, 0x128>* rooms() const { return rooms_; }
68 bool HasRooms() const { return rooms_ != nullptr; }
69
70 // Best-effort "current room" context for auxiliary panels that are driven by
71 // whichever room the viewer is currently drawing.
72 int current_room_id() const { return current_room_id_; }
73
74 // Workbench/Inspector integration.
75 void SetCompactHeaderMode(bool compact) { compact_header_mode_ = compact; }
77 void SetRoomDetailsExpanded(bool expanded) { show_room_details_ = expanded; }
78
79 // Used by overworld editor when double-clicking entrances
80 void set_active_rooms(const ImVector<int>& rooms) { active_rooms_ = rooms; }
82
83 // Palette access
87 void SetCurrentPaletteId(uint64_t id) { current_palette_id_ = id; }
91 void SetRoomNavigationCallback(std::function<void(int)> callback) {
92 room_navigation_callback_ = std::move(callback);
93 }
94 // Callback to swap the current room in-place (for arrow navigation)
95 void SetRoomSwapCallback(std::function<void(int, int)> callback) {
96 room_swap_callback_ = std::move(callback);
97 }
98
99 bool CanNavigateRooms() const {
100 return room_swap_callback_ != nullptr ||
101 room_navigation_callback_ != nullptr;
102 }
103
104 // Navigate to another dungeon room using the same semantics as the header
105 // arrow buttons:
106 // - If a swap callback exists (workbench mode), swap in-place.
107 // - Otherwise, use the navigation callback (opens/switches room view).
108 void NavigateToRoom(int target_room) {
109 if (target_room < 0 || target_room >= zelda3::kNumberOfRooms) {
110 return;
111 }
114 } else if (room_navigation_callback_) {
115 room_navigation_callback_(target_room);
116 }
117 }
118 void SetShowObjectPanelCallback(std::function<void()> callback) {
119 show_object_panel_callback_ = std::move(callback);
120 }
121 void SetShowSpritePanelCallback(std::function<void()> callback) {
122 show_sprite_panel_callback_ = std::move(callback);
123 }
124 void SetShowItemPanelCallback(std::function<void()> callback) {
125 show_item_panel_callback_ = std::move(callback);
126 }
127 void SetShowRoomListCallback(std::function<void()> callback) {
128 show_room_list_callback_ = std::move(callback);
129 }
130 void SetShowRoomMatrixCallback(std::function<void()> callback) {
131 show_room_matrix_callback_ = std::move(callback);
132 }
133 void SetShowEntranceListCallback(std::function<void()> callback) {
134 show_entrance_list_callback_ = std::move(callback);
135 }
136
143
146 }
148
149 // Overlay toggles (used by settings panels / workbench UI).
173 }
180
181 bool show_grid() const { return show_grid_; }
182 void set_show_grid(bool show) { show_grid_ = show; }
184 void set_show_object_bounds(bool show) { show_object_bounds_ = show; }
188 }
192 void set_show_texture_debug(bool show) { show_texture_debug_ = show; }
193 bool show_layer_info() const { return show_layer_info_; }
194 void set_show_layer_info(bool show) { show_layer_info_ = show; }
203
204 // Mutable pointer accessors for OverlayManagerPanel binding.
205 bool* mutable_show_grid() { return &show_grid_; }
227 void SetShowRoomGraphicsCallback(std::function<void()> callback) {
228 show_room_graphics_callback_ = std::move(callback);
229 }
230 void SetShowDungeonSettingsCallback(std::function<void()> callback) {
231 show_dungeon_settings_callback_ = std::move(callback);
232 }
233 void SetSaveRoomCallback(std::function<void(int)> callback) {
234 save_room_callback_ = std::move(callback);
235 }
237 std::function<void(int, const zelda3::RoomObject&)> callback) {
238 edit_graphics_callback_ = std::move(callback);
239 }
243 void SetPinned(bool pinned) { is_pinned_ = pinned; }
244 void SetPinCallback(std::function<void(bool)> callback) {
245 pin_callback_ = std::move(callback);
246 }
247 void SetProject(const project::YazeProject* project);
248
249 // Canvas access
251 const gui::Canvas& canvas() const { return canvas_; }
252
253 // Object interaction access
255
259
260 // Enable/disable object interaction mode
261 void SetObjectInteractionEnabled(bool enabled) {
263 }
267
268 // Make the room header controls non-interactive while still allowing canvas
269 // pan/zoom (useful for split/compare views).
270 void SetHeaderReadOnly(bool read_only) { header_read_only_ = read_only; }
271 bool header_read_only() const { return header_read_only_; }
272
273 // Hide the header chrome entirely (useful for stitched/split layouts where a
274 // parent container provides its own metadata/controls).
275 void SetHeaderVisible(bool visible) { header_visible_ = visible; }
276 bool header_visible() const { return header_visible_; }
277
278 // Set and get the object render mode
283
284 // Layer visibility controls (per-room) using RoomLayerManager
285 void SetLayerVisible(int room_id, zelda3::LayerType layer, bool visible) {
286 GetRoomLayerManager(room_id).SetLayerVisible(layer, visible);
287 }
288 bool IsLayerVisible(int room_id, zelda3::LayerType layer) const {
289 auto it = room_layer_managers_.find(room_id);
290 return it != room_layer_managers_.end() ? it->second.IsLayerVisible(layer)
291 : true;
292 }
293
294 // Legacy compatibility - BG1 visibility (combines layout + objects)
295 void SetBG1Visible(int room_id, bool visible) {
296 auto& mgr = GetRoomLayerManager(room_id);
297 mgr.SetLayerVisible(zelda3::LayerType::BG1_Layout, visible);
298 mgr.SetLayerVisible(zelda3::LayerType::BG1_Objects, visible);
299 }
300 void SetBG2Visible(int room_id, bool visible) {
301 auto& mgr = GetRoomLayerManager(room_id);
302 mgr.SetLayerVisible(zelda3::LayerType::BG2_Layout, visible);
303 mgr.SetLayerVisible(zelda3::LayerType::BG2_Objects, visible);
304 }
305 bool IsBG1Visible(int room_id) const {
306 auto it = room_layer_managers_.find(room_id);
307 if (it == room_layer_managers_.end())
308 return true;
309 return it->second.IsLayerVisible(zelda3::LayerType::BG1_Layout) ||
310 it->second.IsLayerVisible(zelda3::LayerType::BG1_Objects);
311 }
312 bool IsBG2Visible(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::BG2_Layout) ||
317 it->second.IsLayerVisible(zelda3::LayerType::BG2_Objects);
318 }
319
320 // Layer blend mode controls
321 void SetLayerBlendMode(int room_id, zelda3::LayerType layer,
323 GetRoomLayerManager(room_id).SetLayerBlendMode(layer, mode);
324 }
326 zelda3::LayerType layer) const {
327 auto it = room_layer_managers_.find(room_id);
328 return it != room_layer_managers_.end()
329 ? it->second.GetLayerBlendMode(layer)
331 }
332
333 // Per-object translucency
334 void SetObjectTranslucent(int room_id, size_t object_index, bool translucent,
335 uint8_t alpha = 128) {
336 GetRoomLayerManager(room_id).SetObjectTranslucency(object_index,
337 translucent, alpha);
338 }
339
340 // Layer manager access
342 return room_layer_managers_[room_id];
343 }
345 static zelda3::RoomLayerManager default_manager;
346 auto it = room_layer_managers_.find(room_id);
347 return it != room_layer_managers_.end() ? it->second : default_manager;
348 }
349
350 // Legacy BG2 layer type (mapped to blend mode)
351 void SetBG2LayerType(int room_id, int type) {
352 auto& mgr = GetRoomLayerManager(room_id);
354 switch (type) {
355 case 0:
357 break;
358 case 1:
360 break;
361 case 2:
363 break;
364 case 3:
366 break;
367 case 4:
369 break;
370 default:
372 break;
373 }
374 mgr.SetLayerBlendMode(zelda3::LayerType::BG2_Layout, mode);
375 mgr.SetLayerBlendMode(zelda3::LayerType::BG2_Objects, mode);
376 }
377 int GetBG2LayerType(int room_id) const {
379 switch (mode) {
381 return 0;
383 return 1;
385 return 2;
387 return 3;
389 return 4;
390 }
391 return 0;
392 }
393
394 // Set the object to be placed
396 // Pass palette group first so ghost preview can render correctly
399 }
402 false);
403 }
404
405 // Scroll the canvas to center on the given tile coordinates.
406 // The pending target is consumed by Draw() on the next frame.
407 void ScrollToTile(int tile_x, int tile_y) {
408 pending_scroll_target_ = {tile_x, tile_y};
409 }
411 return pending_scroll_target_.has_value();
412 }
413 std::optional<std::pair<int, int>> GetPendingScrollTarget() const {
415 }
416
417 // Object manipulation
419
420 // Entity visibility controls
421 void SetSpritesVisible(bool visible) {
423 }
425 void SetPotItemsVisible(bool visible) {
427 }
429
430 private:
432 const zelda3::RoomObject& object, int canvas_x,
433 int canvas_y);
434 void DrawRoomHeader(zelda3::Room& room, int room_id);
435 void DrawRoomNavigation(int room_id);
436 void DrawRoomPropertyTable(zelda3::Room& room, int room_id);
437 void DrawLayerControls(zelda3::Room& room, int room_id);
438 void DrawCompactLayerToggles(int room_id);
439 void RenderSprites(const gui::CanvasRuntime& rt, const zelda3::Room& room);
440 void RenderPotItems(const gui::CanvasRuntime& rt, const zelda3::Room& room);
442 const zelda3::Room& room);
443
444 // Touch interaction: long-press context menu for entities
446 const zelda3::Room& room);
447
448 // Visualization
450 const zelda3::Room& room);
453 GetCollisionOverlayCache(int room_id);
454
455 // Draw semi-transparent overlay on BG2/Layer 1 objects when mask mode is active
457 const zelda3::Room& room);
458
459 // Room graphics management
460 // Load: Read from ROM, Render: Process pixels, Draw: Display on canvas
461 absl::Status LoadAndRenderRoomGraphics(int room_id);
462 void DrawRoomBackgroundLayers(int room_id); // Draw room buffers to canvas
463
464 Rom* rom_ = nullptr;
466 gui::Canvas canvas_{"##DungeonCanvas", ImVec2(0x200, 0x200)};
467 // ObjectRenderer removed - use ObjectDrawer for rendering (production system)
469
470 // Touch gesture handler for long-press context menus on touch devices
472
473 // Scroll target
474 std::optional<std::pair<int, int>> pending_scroll_target_;
475
476 // Room data
477 std::array<zelda3::Room, 0x128>* rooms_ = nullptr;
479 // Used by overworld editor for double-click entrance → open dungeon room
480 ImVector<int> active_rooms_;
482
483 // Object interaction state
485
486 // Per-room layer managers (4-way visibility, blend modes, per-object translucency)
487 std::map<int, zelda3::RoomLayerManager> room_layer_managers_;
488
489 // Palette data
493 std::function<void(int)> room_navigation_callback_;
494 std::function<void(int, int)>
495 room_swap_callback_; // (old_room_id, new_room_id)
496 std::function<void()> show_object_panel_callback_;
497 std::function<void()> show_sprite_panel_callback_;
498 std::function<void()> show_item_panel_callback_;
499 std::function<void()> show_room_list_callback_;
500 std::function<void()> show_room_matrix_callback_;
501 std::function<void()> show_entrance_list_callback_;
502 std::function<void()> show_room_graphics_callback_;
503 std::function<void()> show_dungeon_settings_callback_;
504 std::function<void(int)> save_room_callback_;
505 std::function<void(int, const zelda3::RoomObject&)> edit_graphics_callback_;
508 bool is_pinned_ = false;
509 std::function<void(bool)> pin_callback_;
511
521 bool show_room_details_ = false;
523 bool header_read_only_ = false;
524 bool header_visible_ = true;
525
527 std::vector<uint16_t> track_tile_order_;
528 std::vector<uint16_t> switch_tile_order_;
530 std::unordered_map<int, DungeonRenderingHelpers::CollisionOverlayCache>
532 std::bitset<256> minecart_sprite_ids_{};
533
534 // Object rendering cache
542 std::vector<ObjectRenderCache> object_render_cache_;
543 uint64_t last_palette_hash_ = 0;
544
545 // Debug state flags
549 bool show_layer_info_ = false;
550 bool show_grid_ = false; // Grid off by default for dungeon editor
552 false; // Show camera coordinates on hover (toggle via Debug menu)
553 int layout_override_ = -1; // -1 for no override
556 ObjectRenderMode::Emulator; // Default to emulator rendering
557
558 // Object outline filtering toggles
560 bool show_type1_objects = true; // Standard objects (0x00-0xFF)
561 bool show_type2_objects = true; // Extended objects (0x100-0x1FF)
562 bool show_type3_objects = true; // Special objects (0xF00-0xFFF)
563 bool show_layer0_objects = true; // Layer 0 (BG1)
564 bool show_layer1_objects = true; // Layer 1 (BG2)
565 bool show_layer2_objects = true; // Layer 2 (BG3)
566 };
568
569 // Entity overlay visibility toggles
571 bool show_sprites = true; // Show sprite entities
572 bool show_pot_items = true; // Show pot item entities
573 bool show_chests = true; // Show chest entities (future)
574 };
576
578
579 // Previous room state for change detection (per-viewer)
582 int prev_layout_ = -1;
584};
585
586} // namespace editor
587} // namespace yaze
588
589#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::array< zelda3::Room, 0x128 > * rooms() const
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)
std::array< zelda3::Room, 0x128 > * rooms_
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)
MinecartTrackEditorPanel * minecart_track_panel_
void SetRooms(std::array< zelda3::Room, 0x128 > *rooms)
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:70
zelda3::GameData * game_data
Definition editor.h:72
Represents a group of palettes.
Modern project structure with comprehensive settings consolidation.
Definition project.h:120