Last Updated: October 10, 2025
Related: E2-development-guide.md, E5-debugging-guide.md
Overview
The Dungeon Editor uses a modern card-based architecture (DungeonEditorV2) with self-contained room rendering. This guide covers the architecture, recent refactoring work, and next development steps.
Key Features
- ✅ Visual room editing with 512x512 canvas per room
- ✅ Object position visualization - Colored outlines by layer (Red/Green/Blue)
- ✅ Per-room settings - Independent BG1/BG2 visibility and layer types
- ✅ Flexible docking - EditorCard system for custom workspace layouts
- ✅ Self-contained rooms - Each room owns its bitmaps and palettes
- ✅ Overworld integration - Double-click entrances to open dungeon rooms
Architecture Improvements ✅
- Room Buffers Decoupled - No dependency on Arena graphics sheets
- ObjectRenderer Removed - Standardized on ObjectDrawer (~1000 lines deleted)
- LoadGraphicsSheetsIntoArena Removed - Using per-room graphics (~66 lines)
- Old Tab System Removed - EditorCard is the standard
- Texture Atlas Infrastructure - Future-proof stub created
- Test Suite Cleaned - Deleted 1270 lines of redundant tests
UI Improvements ✅
- Room ID in card title:
[003] Room Name
- Properties reorganized into clean 4-column table
- Compact layer controls (1 row instead of 3)
- Room graphics canvas height fixed (1025px → 257px)
- Object count in status bar
Architecture
Component Overview
DungeonEditorV2 (UI Layer)
├─ Card-based UI system
├─ Room window management
├─ Component coordination
└─ Lazy loading
DungeonEditorSystem (Backend Layer)
├─ Sprite/Item/Entrance/Door/Chest management
├─ Undo/Redo functionality
├─ Room properties management
└─ Dungeon-wide operations
Room (Data Layer)
├─ Self-contained buffers (bg1_buffer_, bg2_buffer_)
├─ Object storage (tile_objects_)
├─ Graphics loading
└─ Rendering pipeline
Room Rendering Pipeline
TODO: Update this to latest code.
1. LoadRoomGraphics(blockset)
└─> Reads blocks[] from ROM
└─> Loads blockset data → current_gfx16_
2. LoadObjects()
└─> Parses object data from ROM
└─> Creates tile_objects_[]
└─> SETS floor1_graphics_, floor2_graphics_ ← CRITICAL!
3. RenderRoomGraphics() [SELF-CONTAINED]
├─> DrawFloor(floor1_graphics_, floor2_graphics_)
├─> DrawBackground(current_gfx16_)
├─> SetPalette(full_90_color_dungeon_palette)
├─> RenderObjectsToBackground()
│ └─> ObjectDrawer::DrawObjectList()
└─> QueueTextureCommand(UPDATE/CREATE)
4. DrawRoomBackgroundLayers(room_id)
└─> ProcessTextureQueue() → GPU textures
└─> canvas_.DrawBitmap(bg1, bg2)
5. DrawObjectPositionOutlines(room)
└─> Colored rectangles by layer
└─> Object ID labels
Room Structure (Bottom to Top)
Understanding ALTTP dungeon composition is critical:
Room Composition:
├─ Room Layout (BASE LAYER - immovable)
│ ├─ Walls (structural boundaries, 7 configurations of squares in 2x2 grid)
│ ├─ Floors (walkable areas, repeated tile pattern set to BG1/BG2)
├─ Layer 0 Objects (floor decorations, some walls)
├─ Layer 1 Objects (chests, decorations)
└─ Layer 2 Objects (stairs, transitions)
Doors: Positioned at room edges to connect rooms
Key Insight: Layouts are immovable base structure. Objects are placed ON TOP and can be moved/edited. This allows for large rooms, 4-quadrant rooms, tall/wide rooms, etc.
Next Development Steps
High Priority (Must Do)
1. Door Rendering at Room Edges
What: Render doors with proper patterns at room connections
Pattern Reference: ZScream's door drawing patterns
Implementation:
void DungeonCanvasViewer::DrawDoors(const zelda3::Room& room) {
}
2. Object Name Labels from String Array
File: dungeon_canvas_viewer.cc:416
(DrawObjectPositionOutlines)
What: Show real object names instead of just IDs
Implementation:
std::string label = absl::StrFormat("0x%02X", obj.id_);
std::string object_name = GetObjectName(obj.id_);
std::string label = absl::StrFormat("%s\n0x%02X", object_name.c_str(), obj.id_);
std::string GetObjectName(int16_t object_id) {
return "Object";
}
4. Fix Plus Button to Select Any Room
File: dungeon_editor_v2.cc:228
(DrawToolset)
Current Issue: Opens Room 0x00 (Ganon) always
Fix:
show_room_selector_ = true;
ImGui::OpenPopup("SelectRoomToOpen");
}
if (ImGui::BeginPopup("SelectRoomToOpen")) {
static int selected_room = 0;
ImGui::InputInt("Room ID", &selected_room);
if (ImGui::Button("Open")) {
OnRoomSelected(selected_room);
ImGui::CloseCurrentPopup();
}
ImGui::EndPopup();
}
Medium Priority (Should Do)
6. Fix InputHexByte +/- Button Events
File: src/app/gui/input.cc
(likely)
Issue: Buttons don't respond to clicks
Investigation Needed:
- Check if button click events are being captured
- Verify event logic matches working examples
- Keep existing event style if it works elsewhere
Lower Priority (Nice to Have)
9. Move Backend Logic to DungeonEditorSystem
What: Separate UI (V2) from data operations (System)
Migration:
- Sprite management → DungeonEditorSystem
- Item management → DungeonEditorSystem
- Entrance/Door/Chest → DungeonEditorSystem
- Undo/Redo → DungeonEditorSystem
Result: DungeonEditorV2 becomes pure UI coordinator
Quick Start
Build & Run
cd /Users/scawful/Code/yaze
cmake --preset mac-ai -B build_ai
cmake --build build_ai --target yaze -j12
# Run dungeon editor
./build_ai/bin/yaze.app/Contents/MacOS/yaze --rom_file=zelda3.sfc --editor=Dungeon
# Open specific room
./build_ai/bin/yaze.app/Contents/MacOS/yaze --rom_file=zelda3.sfc --editor=Dungeon --cards="Room 0x00"
Testing & Verification
Debug Commands
# Verify floor values load correctly
./build_ai/bin/yaze.app/Contents/MacOS/yaze --rom_file=zelda3.sfc --editor=Dungeon 2>&1 | grep "floor1="
# Expected: floor1=4, floor2=8 (NOT 0!)
# Check object rendering
./build_ai/bin/yaze.app/Contents/MacOS/yaze --rom_file=zelda3.sfc --editor=Dungeon 2>&1 | grep "Drawing.*objects"
# Check object drawing details
./build_ai/bin/yaze.app/Contents/MacOS/yaze --rom_file=zelda3.sfc --editor=Dungeon 2>&1 | grep "Writing Tile16"
Related Documentation
Last Updated: October 10, 2025
Contributors: Dungeon Editor Refactoring Session