refactor: Replace deprecated dungeon editor guide with updated documentation

- Deleted the old D1-dungeon-editor-guide.md and F1-dungeon-editor-guide.md files to streamline documentation.
- Introduced a new DUNGEON_EDITOR_GUIDE.md that consolidates features, architecture, and usage instructions for the Dungeon Editor.
- Updated the development guide to include new naming conventions and clarified rendering processes.
- Enhanced the overall structure and content of the documentation to reflect the current production-ready status of the Dungeon Editor.
This commit is contained in:
scawful
2025-10-09 20:48:07 -04:00
parent 6c7f301177
commit c512dd7f35
11 changed files with 1026 additions and 3358 deletions

View File

@@ -1,897 +0,0 @@
# Dungeon Editor Complete Guide
**Last Updated**: October 9, 2025
**Status**: EXPERIMENTAL - Core features implemented but requires thorough testing
---
## Table of Contents
- [Overview](#overview)
- [Architecture](#architecture)
- [Implemented Features](#implemented-features)
- [Technical Details](#technical-details)
- [Usage Guide](#usage-guide)
- [Troubleshooting](#troubleshooting)
- [Next Steps](#next-steps)
- [Reference](#reference)
---
## Overview
The Dungeon Editor uses a modular card-based architecture for editing dungeon rooms in The Legend of Zelda: A Link to the Past.
**WARNING**: This editor is currently experimental. While core features are implemented, thorough testing is still required before production use.
### Key Capabilities
- Visual room editing with 512x512 canvas
- Object placement with pattern-based rendering
- Live palette editing with instant preview
- Independent dockable UI cards
- Multi-room editing support
- Automatic graphics loading
- Error recovery system
---
## Architecture
### Component Hierarchy
```
DungeonEditorV2 (Coordinator)
├── Toolbar (Toolset)
│ ├── Open Room
│ ├── Toggle Rooms List
│ ├── Toggle Room Matrix
│ ├── Toggle Entrances List
│ ├── Toggle Room Graphics
│ ├── Toggle Object Editor
│ └── Toggle Palette Editor
├── Independent Cards (all dockable)
│ ├── Rooms List Card
│ ├── Entrances List Card
│ ├── Room Matrix Card (16x19 grid)
│ ├── Room Graphics Card
│ ├── Object Editor Card
│ ├── Palette Editor Card
│ └── Room Cards (dynamic, auto-dock together)
└── Per-Room Rendering
└── Room
├── bg1_buffer_ (BackgroundBuffer)
├── bg2_buffer_ (BackgroundBuffer)
└── DungeonCanvasViewer
```
### Independent Card Architecture
**Key Principle**: Each card is a top-level ImGui window with NO table layout or window hierarchy inheritance.
```cpp
// Each card is completely independent
void DungeonEditorV2::DrawLayout() {
// Room Selector (persistent)
{
static bool show = true;
gui::EditorCard card("Room Selector", ICON_MD_LIST, &show);
if (card.Begin()) {
room_selector_.Draw();
}
card.End();
}
// Room Cards (closable, auto-dock)
for (int room_id : active_rooms_) {
bool open = true;
gui::EditorCard card(MakeCardTitle(room_id), ICON_MD_GRID_ON, &open);
if (card.Begin()) {
DrawRoomTab(room_id);
}
card.End();
if (!open) RemoveRoom(room_id);
}
}
```
**Benefits**:
- ✅ Full freedom to drag, dock, resize
- ✅ No layout constraints or inheritance
- ✅ Can be arranged however user wants
- ✅ Session-aware card titles
- ✅ ImGui handles all docking logic
---
## Implemented Features
### 1. Rooms List Card
```cpp
Features:
- Filter/search functionality
- Format: [HEX_ID] Room Name
- Click to open room card
- Double-click for instant focus
- Shows all 296 rooms (0x00-0x127)
```
### 2. Entrances List Card (ZScream Parity)
```cpp
Configuration UI:
- Entrance ID, Room ID, Dungeon ID
- Blockset, Music, Floor
- Player Position (X, Y)
- Camera Trigger (X, Y)
- Scroll Position (X, Y)
- Exit value
- Camera Boundaries (quadrant & full room)
List Features:
- Format: [HEX_ID] Entrance Name -> Room Name
- Shows entrance-to-room relationship
- Click to select and open associated room
```
### 3. Room Matrix Card (16x19 Grid)
```cpp
Layout:
- 16 columns × 19 rows = 304 cells
- Displays all 296 rooms (0x00-0x127)
- 24px cells with 1px spacing (optimized)
- Window size: 440x520
Visual Features:
- Instant loading with deterministic HSV colors
- Color calculated from room ID (no palette loading)
- Light green outline: Currently selected room
- Green outline: Open rooms
- Gray outline: Inactive rooms
Interaction:
- Click to open room card
- Hover for tooltip (room name)
- Auto-focuses existing cards
```
**Performance**:
- Before: 2-4 seconds (lazy loading 296 rooms)
- After: < 50ms (pure math, no I/O)
### 4. Room Graphics Card
```cpp
Features:
- Shows blockset graphics for selected room
- 2-column grid layout
- Auto-loads when room changes
- Up to 16 graphics blocks
- Toggleable via toolbar
```
### 5. Object Editor Card (Unified)
```cpp
Improved UX:
- Mode controls at top: None | Place | Select | Delete
- Current object info always visible
- 2 tabs:
- Browser: Object selection with previews
- Preview: Emulator rendering with controls
Object Browser:
- Categorized objects (Floor/Wall/Special)
- 32x32 preview icons
- Filter/search functionality
- Shows object ID and type
```
### 6. Palette Editor Card
```cpp
Features:
- Palette selector dropdown (20 dungeon palettes)
- 90-color grid (15 per row)
- Visual selection with yellow border
- Tooltips: color index, SNES BGR555, RGB values
- HSV color wheel picker
- Live RGB display (0-255)
- SNES format display (15-bit BGR555)
- Reset button
Live Updates:
- Edit palette all open rooms re-render automatically
- Callback system decouples palette editor from rooms
```
### 7. Room Cards (Auto-Loading)
```cpp
Improvements:
- Auto-loads graphics when properties change
- Simple status indicator ( Loaded / Not Loaded)
- Auto-saves with main Save command
- Removed manual "Load Graphics" buttons
Docking Behavior:
- ImGuiWindowClass for automatic tab grouping
- New room cards auto-dock with existing rooms
- Can be undocked independently
- Maintains session state
```
### 8. Object Drawing System
```cpp
ObjectDrawer (Native C++ Rendering):
- Pattern-based tile placement
- Fast, no emulation overhead
- Centralized pattern logic
Supported Patterns:
- 1x1 Solid (0x34)
- Rightward 2x2 (0x00-0x08) - horizontal walls
- Downward 2x2 (0x60-0x68) - vertical walls
- Diagonal Acute (0x09-0x14) - / walls
- Diagonal Grave (0x15-0x20) - \ walls
- 4x4 Blocks (0x33, 0x70-0x71) - large structures
Integration:
// Simplified from 100+ lines to 3 lines
ObjectDrawer drawer(rom_);
drawer.DrawObjectList(tile_objects_, bg1_buffer_, bg2_buffer_);
```
### 9. Cross-Editor Navigation
```cpp
From Overworld Editor:
editor_manager->JumpToDungeonRoom(room_id);
From Dungeon Editor:
- Click in Rooms List opens/focuses room card
- Click in Entrances List opens associated room
- Click in Room Matrix opens/focuses room card
EditorCard Focus System:
- Focus() method brings window to front
- Works with docked and floating windows
- Avoids duplicate cards
```
### 10. Error Handling & Recovery
```cpp
Custom ImGui Assertion Handler:
- Catches UI assertion failures
- Logs errors instead of crashing
- After 5 errors:
1. Backs up imgui.ini imgui.ini.backup
2. Deletes imgui.ini (reset workspace)
3. Resets error counter
4. Application continues running
Benefits:
- No data loss from UI bugs
- Automatic recovery
- User-friendly error handling
```
---
## Technical Details
### Rendering Pipeline
```
1. Room::CopyRoomGraphicsToBuffer()
→ Loads tile graphics into current_gfx16_ [128×N indexed pixels]
2. BackgroundBuffer::DrawFloor()
→ Fills tilemap buffer with floor tile IDs
3. ObjectDrawer::DrawObjectList()
→ Writes wall/object tiles to BG1/BG2 buffers
4. BackgroundBuffer::DrawBackground()
→ For each tile in tilemap:
- Extract 8×8 pixels from gfx16_data
- Apply palette offset (palette_id * 8 for 3BPP)
- Copy to bitmap (512×512 indexed surface)
→ Sync: memcpy(surface->pixels, bitmap_data)
5. Bitmap::SetPalette()
→ Apply 90-color dungeon palette to SDL surface
6. Renderer::RenderBitmap()
→ Convert indexed surface → RGB texture
→ SDL_CreateTextureFromSurface() applies palette
7. DungeonCanvasViewer::RenderRoomBackgroundLayers()
→ Draw texture to canvas with ImGui::Image()
```
### SNES Graphics Format
**8-bit Indexed Color (3BPP for dungeons)**:
```cpp
// Each pixel is a palette index (0-7)
// RGB color comes from applying dungeon palette
bg1_bmp.SetPalette(dungeon_pal_group[palette_id]); // 90 colors
Renderer::Get().RenderBitmap(&bitmap); // indexed → RGB
```
**Color Format: 15-bit BGR555**
```
Bits: 0BBB BBGG GGGR RRRR
││││ ││││ ││││ ││││
│└──┴─┘└──┴─┘└──┴─┘
│ Blue Green Red
└─ Unused (always 0)
Each channel: 0-31 (5 bits)
Total colors: 32,768 (2^15)
```
**Palette Organization**:
- 20 total palettes (one per dungeon color scheme)
- 90 colors per palette (full SNES BG palette)
- ROM address: `kDungeonMainPalettes` (0xDD734)
### Critical Math Formulas
**Tile Position in Tilesheet (128px wide)**:
```cpp
int tile_x = (tile_id % 16) * 8;
int tile_y = (tile_id / 16) * 8;
int pixel_offset = (tile_y * 128) + tile_x;
```
**Tile Position in Canvas (512×512)**:
```cpp
int canvas_x = (tile_col * 8);
int canvas_y = (tile_row * 8);
int pixel_offset = (canvas_y * 512) + canvas_x;
// CRITICAL: For NxN tiles, advance by (tile_row * 8 * width)
int dest_offset = (yy * 8 * 512) + (xx * 8); // NOT just (yy * 512)!
```
**Palette Index Calculation**:
```cpp
// 3BPP: 8 colors per subpalette
int final_index = pixel_value + (palette_id * 8);
// NOT 4BPP (× 16)!
// int final_index = pixel_value + (palette_id << 4); // WRONG
```
### Per-Room Buffers (Critical for Multi-Room Editing)
**Old way (broken)**: Multiple rooms shared `gfx::Arena::Get().bg1()` and corrupted each other.
**New way (fixed)**: Each `Room` has its own buffers:
```cpp
// In room.h
gfx::BackgroundBuffer bg1_buffer_;
gfx::BackgroundBuffer bg2_buffer_;
// In room.cc
bg1_buffer_.DrawFloor(...);
bg1_buffer_.DrawBackground(std::span<uint8_t>(current_gfx16_));
Renderer::Get().RenderBitmap(&bg1_buffer_.bitmap());
```
### Color Format Conversions
```cpp
// ImGui → SNES BGR555
int r_snes = (int)(imgui_r * 31.0f); // 0-1 → 0-31
int g_snes = (int)(imgui_g * 31.0f);
int b_snes = (int)(imgui_b * 31.0f);
uint16_t bgr555 = (b_snes << 10) | (g_snes << 5) | r_snes;
// SNES BGR555 → RGB (for display)
uint8_t r_rgb = (snes & 0x1F) * 255 / 31; // 0-31 → 0-255
uint8_t g_rgb = ((snes >> 5) & 0x1F) * 255 / 31;
uint8_t b_rgb = ((snes >> 10) & 0x1F) * 255 / 31;
```
---
## Usage Guide
### Opening Rooms
1. **Rooms List**: Search and click room
2. **Entrances List**: Click entrance to open associated room
3. **Room Matrix**: Visual navigation with color-coded grid
4. **Toolbar**: Use "Open Room" button
### Editing Objects
1. Toggle **Object Editor** card
2. Select mode: **Place** / **Select** / **Delete**
3. Browse objects in **Browser** tab
4. Click object to select
5. Click on canvas to place
6. Use **Select** mode for multi-select (Ctrl+drag)
### Editing Palettes
1. Toggle **Palette Editor** card
2. Select palette from dropdown (0-19)
3. Click color in 90-color grid
4. Adjust with HSV color wheel
5. See live updates in all open room cards
6. Reset color if needed
### Configuring Entrances
1. Toggle **Entrances List** card
2. Select entrance from list
3. Edit properties in configuration UI
4. All changes auto-save
5. Click entrance to jump to associated room
### Managing Layout
- All cards are dockable
- Room cards automatically tab together
- Save layout via imgui.ini
- If errors occur, layout auto-resets with backup
---
## Troubleshooting
### Common Bugs & Fixes
#### Empty Palette (0 colors)
**Symptom**: Graphics render as solid color or invisible
**Cause**: Using `palette()` method (copy) instead of `operator[]` (reference)
```cpp
// WRONG:
auto pal = group.palette(id); // Copy, may be empty
// CORRECT:
auto pal = group[id]; // Reference
```
#### Bitmap Stretched/Corrupted
**Symptom**: Graphics only in top portion, repeated/stretched
**Cause**: Wrong offset in DrawBackground()
```cpp
// WRONG:
int offset = (yy * 512) + (xx * 8); // Only advances 512 per row
// CORRECT:
int offset = (yy * 8 * 512) + (xx * 8); // Advances 4096 per row
```
#### Black Canvas Despite Correct Data
**Symptom**: current_gfx16_ has data, palette loaded, but canvas black
**Cause**: Bitmap not synced to SDL surface
```cpp
// FIX: After DrawTile() loop
SDL_LockSurface(surface);
memcpy(surface->pixels, bitmap_data.data(), bitmap_data.size());
SDL_UnlockSurface(surface);
```
#### Wrong Colors
**Symptom**: Colors don't match expected palette
**Cause**: Using 4BPP offset for 3BPP graphics
```cpp
// WRONG (4BPP):
int offset = palette_id << 4; // × 16
// CORRECT (3BPP):
int offset = palette_id * 8; // × 8
```
#### Wrong Bitmap Depth
**Symptom**: Room graphics corrupted, only showing in small portion
**Cause**: Depth parameter wrong in CreateAndRenderBitmap
```cpp
// WRONG:
CreateAndRenderBitmap(0x200, 0x200, 0x200, data, bitmap, palette);
// ^^^^^ depth should be 8!
// CORRECT:
CreateAndRenderBitmap(0x200, 0x200, 8, data, bitmap, palette);
// ^ 8-bit indexed
```
#### Emulator Preview "ROM Not Loaded"
**Symptom**: Preview shows error despite ROM being loaded
**Cause**: Emulator initialized before ROM loaded
```cpp
// WRONG (in Initialize()):
object_emulator_preview_.Initialize(rom_); // Too early!
// CORRECT (in Load()):
if (!rom_ || !rom_->is_loaded()) return error;
object_emulator_preview_.Initialize(rom_); // After ROM confirmed
```
### Debugging Tips
If objects don't appear:
1. **Check console output**:
```
[ObjectDrawer] Drawing object $34 at (16,16)
[DungeonCanvas] Rendered BG1/BG2 to canvas
```
2. **Verify tiles loaded**:
- Object must have tiles (`EnsureTilesLoaded()`)
- Check `object.tiles().empty()`
3. **Check buffer writes**:
- Add logging in `WriteTile16()`
- Verify `IsValidTilePosition()` isn't rejecting writes
4. **Verify buffer rendering**:
- Check `RenderRoomBackgroundLayers()` renders BG1/BG2
- May need `bg1.DrawBackground(gfx16_data)` after writing
### Floor & Wall Rendering Debug Guide
**What Should Happen**:
1. `DrawFloor()` writes 4096 floor tile IDs to the buffer
2. `DrawBackground()` renders those tiles + any objects to the bitmap
3. Bitmap gets palette applied
4. SDL texture created from bitmap
**Debug Output to Check**:
When you open a room and load graphics, check console for:
```
[BG:DrawFloor] tile_address=0xXXXX, tile_address_floor=0xXXXX, floor_graphics=0xXX, f=0xXX
[BG:DrawFloor] Floor tile words: XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXXX
[BG:DrawFloor] Wrote 4096 floor tiles to buffer
[BG:DrawBackground] Using existing bitmap (preserving floor)
[BG:DrawBackground] gfx16_data size=XXXXX, first 32 bytes: XX XX XX XX...
```
**Common Floor/Wall Issues**:
#### Issue 1: Floor tiles are all 0x0000
**Symptom**: `Floor tile words: 0000 0000 0000 0000 0000 0000 0000 0000`
**Cause**: `tile_address` or `tile_address_floor` is wrong, or `floor_graphics` is wrong
**Fix**: Check that room data loaded correctly
#### Issue 2: gfx16_data is all 0x00
**Symptom**: `gfx16_data size=16384, first 32 bytes: 00 00 00 00 00 00 00 00...`
**Cause**: `CopyRoomGraphicsToBuffer()` failed to load graphics
**Fix**: Check `current_gfx16_` is populated in Room
#### Issue 3: "Creating new bitmap" instead of "Using existing bitmap"
**Symptom**: DrawBackground creates a new zero-filled bitmap
**Cause**: Bitmap wasn't active when DrawBackground was called
**Fix**: DrawBackground now checks `bitmap_.is_active()` before recreating
#### Issue 4: Buffer has tiles but bitmap is empty
**Symptom**: DrawFloor reports writing tiles, but canvas shows nothing
**Cause**: DrawBackground isn't actually rendering the buffer's tiles
**Fix**: Check that `buffer_[xx + yy * tiles_w]` has non-zero values
**Rendering Flow Diagram**:
```
Room::RenderRoomGraphics()
├─1. CopyRoomGraphicsToBuffer()
│ └─> Fills current_gfx16_[16384] with tile pixel data (3BPP)
├─2. bg1_buffer_.DrawFloor()
│ └─> Writes floor tile IDs to buffer_[4096]
│ └─> Example: buffer_[0] = 0x00EE (tile 238, palette 0)
├─3. RenderObjectsToBackground()
│ └─> ObjectDrawer writes wall/object tile IDs to buffer_[]
│ └─> Example: buffer_[100] = 0x0060 (wall tile, palette 0)
├─4. bg1_buffer_.DrawBackground(current_gfx16_)
│ └─> For each tile ID in buffer_[]:
│ ├─> Extract tile_id, palette from word
│ ├─> Read 8x8 pixels from current_gfx16_[128-pixel-wide sheet]
│ ├─> Apply palette offset (palette * 8 for 3BPP)
│ └─> Write to bitmap_.data()[512x512]
├─5. bitmap_.SetPalette(dungeon_palette[90 colors])
│ └─> Applies SNES BGR555 colors to SDL surface palette
└─6. Renderer::RenderBitmap(&bitmap_)
└─> Creates SDL_Texture from indexed surface + palette
└─> Result: RGB texture ready to display
```
**Expected Console Output (Working)**:
```
[BG:DrawFloor] tile_address=0x4D62, tile_address_floor=0x4D6A, floor_graphics=0x00, f=0x00
[BG:DrawFloor] Floor tile words: 00EE 00EF 01EE 01EF 02EE 02EF 03EE 03EF
[BG:DrawFloor] Wrote 4096 floor tiles to buffer
[ObjectDrawer] Drew 73 objects, skipped 0
[BG:DrawBackground] Using existing bitmap (preserving floor)
[BG:DrawBackground] gfx16_data size=16384, first 32 bytes: 3A 3A 3A 4C 4C 3A 3A 55 55 3A 3A 55 55 3A 3A...
```
✅ Floor tiles written ✅ Objects drawn ✅ Graphics data present ✅ Bitmap preserved
**Quick Diagnostic Tests**:
1. **Run App & Check Console**:
- Open Dungeon Editor
- Select a room (try room $00, $02, or $08)
- Load graphics
- Check console output
2. **Good Signs**:
- `[BG:DrawFloor] Wrote 4096 floor tiles` ← Floor data written
- `Floor tile words: 00EE 00EF...` ← Non-zero tile IDs
- `gfx16_data size=16384, first 32 bytes: 3A 3A...` ← Graphics data present
- `[ObjectDrawer] Drew XX objects` ← Objects rendered
3. **Bad Signs**:
- `Floor tile words: 0000 0000 0000 0000...` ← No floor tiles!
- `gfx16_data size=16384, first 32 bytes: 00 00 00...` ← No graphics!
- `[BG:DrawBackground] Creating new bitmap` ← Wiping out floor!
**If Console Shows Everything Working But Canvas Still Empty**:
The issue is in **canvas rendering**, not floor/wall drawing. Check:
1. Is texture being created? (Check `Renderer::RenderBitmap`)
2. Is canvas displaying texture? (Check `DungeonCanvasViewer::DrawDungeonCanvas`)
3. Is texture pointer valid? (Check `bitmap.texture() != nullptr`)
**Quick Visual Test**:
If you see **pink/brown rectangles** but no floor/walls:
- ✅ Canvas IS rendering primitives
- ❌ Canvas is NOT rendering the bitmap texture
This suggests the bitmap texture is either:
1. Not being created
2. Being created but not displayed
3. Being created with wrong data
---
## Next Steps
### Remaining Issues
#### Issue 1: Room Layout Not Rendering (COMPLETED ✅)
- **Solution**: ObjectDrawer integration complete
- Walls and floors now render properly
#### Issue 2: Entity Interaction
**Problem**: Can't click/drag dungeon entities like overworld
**Reference**: `overworld_entity_renderer.cc` lines 23-91
**Implementation Needed**:
```cpp
// 1. Detect hover
bool IsMouseHoveringOverEntity(const Entity& entity, canvas_p0, scrolling);
// 2. Handle dragging
void HandleEntityDragging(Entity* entity, ...);
// 3. Double-click to open
if (IsMouseHoveringOverEntity(entity) && IsMouseDoubleClicked()) {
// Open entity editor
}
// 4. Right-click for context menu
if (IsMouseHoveringOverEntity(entity) && IsMouseClicked(Right)) {
ImGui::OpenPopup("Entity Editor");
}
```
**Files to Create/Update**:
- `dungeon_entity_interaction.h/cc` (new)
- `dungeon_canvas_viewer.cc` (integrate)
#### Issue 3: Multi-Select for Objects
**Problem**: No group selection/movement
**Status**: Partially implemented in `DungeonObjectInteraction`
**What's Missing**:
1. Multi-object drag support
2. Group movement logic
3. Delete multiple objects
4. Copy/paste groups
**Implementation**:
```cpp
void MoveSelectedObjects(ImVec2 delta) {
for (size_t idx : selected_object_indices_) {
auto& obj = room.GetTileObjects()[idx];
obj.x_ += delta.x;
obj.y_ += delta.y;
}
}
```
#### Issue 4: Context Menu Not Dungeon-Aware
**Problem**: Generic canvas context menu
**Solution**: Use `Canvas::AddContextMenuItem()`:
```cpp
// Setup before DrawContextMenu()
canvas_.ClearContextMenuItems();
if (!selected_objects.empty()) {
canvas_.AddContextMenuItem({
ICON_MD_DELETE " Delete Selected",
[this]() { DeleteSelectedObjects(); },
"Del"
});
}
canvas_.AddContextMenuItem({
ICON_MD_ADD " Place Object",
[this]() { ShowObjectPlacementMenu(); }
});
```
### Future Enhancements
1. **Object Preview Thumbnails**
- Replace "?" placeholders with rendered thumbnails
- Use ObjectRenderer for 64×64 bitmaps
- Cache for performance
2. **Room Matrix Bitmap Preview**
- Hover shows actual room bitmap
- Small popup with preview
- Rendered on-demand
3. **Palette Presets**
- Save/load favorite combinations
- Import/export between dungeons
- Undo/redo for palette changes
4. **Custom Object Editor**
- Let users create new patterns
- Visual pattern editor
- Save to ROM
5. **Complete Object Coverage**
- All 256+ object types
- Special objects (stairs, chests, doors)
- Layer 3 effects
---
## Reference
### File Organization
**Core Rendering**:
- `src/app/zelda3/dungeon/room.{h,cc}` - Room state, buffers
- `src/app/gfx/background_buffer.{h,cc}` - Tile → bitmap drawing
- `src/app/core/renderer.cc` - Bitmap → texture conversion
- `src/app/editor/dungeon/dungeon_canvas_viewer.cc` - Canvas display
**Object Drawing**:
- `src/app/zelda3/dungeon/object_drawer.{h,cc}` - Native C++ patterns
- `src/app/gui/widgets/dungeon_object_emulator_preview.{h,cc}` - Research tool
**Editor UI**:
- `src/app/editor/dungeon/dungeon_editor_v2.{h,cc}` - Main coordinator
- `src/app/gui/widgets/editor_card.{h,cc}` - Independent card system
- `src/app/editor/dungeon/dungeon_object_interaction.{h,cc}` - Object selection
**Palette System**:
- `src/app/gfx/snes_palette.{h,cc}` - Palette loading
- `src/app/gui/widgets/palette_editor_widget.{h,cc}` - Visual editor
- `src/app/gfx/bitmap.cc` - SetPalette() implementation
### Quick Reference: Key Functions
```cpp
// Load dungeon palette
auto& pal_group = rom->palette_group().dungeon_main;
auto palette = pal_group[palette_id]; // NOT .palette(id)!
// Apply palette to bitmap
bitmap.SetPalette(palette); // NOT SetPaletteWithTransparent()!
// Create texture from indexed bitmap
Renderer::Get().RenderBitmap(&bitmap); // NOT UpdateBitmap()!
// Tile sheet offset (128px wide)
int offset = (tile_id / 16) * 8 * 128 + (tile_id % 16) * 8;
// Canvas offset (512px wide)
int offset = (tile_row * 8 * 512) + (tile_col * 8);
// Palette offset (3BPP)
int offset = palette_id * 8; // NOT << 4 !
```
### Performance Metrics
**Matrix Loading**:
- Load time: < 50ms (pure calculation, no I/O)
- Memory allocations: ~20 per matrix draw (cached colors)
- Frame drops: None
**Room Loading**:
- Lazy loading: Rooms loaded on-demand
- Graphics caching: Reused across room switches
- Texture batching: Up to 8 textures processed per frame
---
## Status Summary
### Implemented Features
**Rendering**:
- Floor rendering with tile graphics and palettes
- Object drawing via ObjectDrawer with pattern-based rendering
- Live palette editing with HSV picker
- Per-room background buffers (no shared state corruption)
**UI**:
- Independent dockable cards
- Room matrix for visual navigation
- Entrance configuration
- Cross-editor navigation (jump between overworld/dungeon)
- Error recovery system
### In Progress
**Interaction**:
- Entity click/drag for sprites and objects
- Multi-select drag for group movement
- Context-aware right-click menu
**Enhancement**:
- Object thumbnails in selector
- Room layout visual editor
- Auto-tile placement
- Object snapping grid
---
## Build Instructions
```bash
cd /Users/scawful/Code/yaze
cmake --build build_ai --target yaze -j12
./build_ai/bin/yaze.app/Contents/MacOS/yaze
```
---
**Status**: EXPERIMENTAL
The dungeon editor provides core editing capabilities but requires thorough testing before production use. Users should save backups before editing ROMs.
### Critical Rendering Pipeline Details
#### Bitmap Data Synchronization
When updating bitmap pixel data, two memory locations must stay synchronized:
1. `data_` - C++ std::vector<uint8_t>
2. `surface_->pixels` - SDL raw pixel buffer used for texture creation
**Always use**:
- `set_data()` for bulk updates (updates both vector AND surface via memcpy)
- `WriteToPixel()` for single pixel changes
- **Never** assign directly to `mutable_data()` for replacement operations
#### Texture Update Queue
Texture operations are queued and processed in batches for performance:
```cpp
// Queue texture operation
gfx::Arena::Get().QueueTextureCommand(
gfx::Arena::TextureCommandType::UPDATE, &bitmap);
// Process queue every frame (required!)
gfx::Arena::Get().ProcessTextureQueue(renderer_);
```
#### Graphics Sheet System
All 223 graphics sheets are managed centrally by `gfx::Arena`. When one editor modifies a sheet, use `Arena::NotifySheetModified(sheet_index)` to propagate changes to all editors.

View File

@@ -0,0 +1,578 @@
# YAZE Dungeon Editor: Complete Guide
**Last Updated**: October 9, 2025
**Status**: PRODUCTION READY - Core features stable, tested, and functional
---
## Table of Contents
- [Overview](#overview)
- [Current Status](#current-status)
- [Architecture](#architecture)
- [Quick Start](#quick-start)
- [Core Features](#core-features)
- [Technical Details](#technical-details)
- [Testing](#testing)
- [Troubleshooting](#troubleshooting)
- [ROM Internals](#rom-internals)
- [Reference](#reference)
---
## Overview
The Dungeon Editor uses a modern card-based architecture for editing dungeon rooms in The Legend of Zelda: A Link to the Past. The editor features lazy loading, per-room settings, and a component-based design for maximum flexibility.
### Key Capabilities
- **Visual room editing** with 512x512 canvas
- **Object placement** with pattern-based rendering
- **Live palette editing** with instant preview
- **Independent dockable UI cards**
- **Multi-room editing** support
- **Automatic graphics loading**
- **Per-room layer visibility** settings
- **Command-line quick testing** support
---
## Current Status
### ✅ Production Ready Features
- Core rendering pipeline (floor, walls, objects, sprites)
- Object drawing via ObjectDrawer with pattern-based rendering
- Live palette editing with HSV picker
- Per-room background buffers (no shared state corruption)
- Independent dockable card system
- Cross-editor navigation (overworld ↔ dungeon)
- Error recovery system
- Test suite (29/29 tests passing - 100%)
### 🔧 Recently Fixed Issues
1. **Object Visibility** ✅ FIXED
- **Problem**: Objects drawn to bitmaps but not visible on canvas
- **Root Cause**: Textures not updated after `RenderObjectsToBackground()`
- **Fix**: Added texture UPDATE commands after object rendering
2. **Property Change Re-rendering** ✅ FIXED
- **Problem**: Changing blockset/palette didn't trigger re-render
- **Fix**: Added change detection and automatic re-rendering
3. **One-Time Rendering** ✅ FIXED
- **Problem**: Objects only rendered once, never updated
- **Fix**: Removed restrictive rendering checks
4. **Per-Room Layer Settings** ✅ IMPLEMENTED
- Each room now has independent BG1/BG2 visibility settings
- Layer type controls (Normal, Translucent, Addition, Dark, Off)
5. **Canvas Context Menu** ✅ IMPLEMENTED
- Dungeon-specific options (Place Object, Delete Selected, Toggle Layers, Re-render)
- Dynamic menu based on current selection
---
## Architecture
### Component Hierarchy
```
DungeonEditorV2 (Coordinator)
├── Dungeon Controls (Collapsible panel)
│ └── Card visibility toggles
├── Independent Cards (all fully dockable)
│ ├── Rooms List Card (filterable, searchable)
│ ├── Room Matrix Card (16x19 grid, 296 rooms)
│ ├── Entrances List Card (entrance configuration)
│ ├── Room Graphics Card (blockset graphics display)
│ ├── Object Editor Card (unified object placement)
│ ├── Palette Editor Card (90-color palette editing)
│ └── Room Cards (dynamic, auto-dock together)
└── Per-Room Rendering
└── Room
├── bg1_buffer_ (BackgroundBuffer)
├── bg2_buffer_ (BackgroundBuffer)
└── DungeonCanvasViewer
```
### Card-Based Architecture Benefits
- ✅ Full freedom to drag, dock, resize
- ✅ No layout constraints or inheritance
- ✅ Can be arranged however user wants
- ✅ Session-aware card titles
- ✅ ImGui handles all docking logic
- ✅ Independent lifetime (close Dungeon Controls, rooms stay open)
---
## Quick Start
### Launch from Command Line
```bash
# Open specific room
./yaze --rom_file=zelda3.sfc --editor=Dungeon --cards="Room 0"
# Compare multiple rooms
./yaze --rom_file=zelda3.sfc --editor=Dungeon --cards="Room 0,Room 1,Room 105"
# Full workspace
./yaze --rom_file=zelda3.sfc --editor=Dungeon \
--cards="Rooms List,Room Matrix,Object Editor,Palette Editor"
# Debug mode with logging
./yaze --debug --log_file=debug.log --rom_file=zelda3.sfc --editor=Dungeon
```
### From GUI
1. Launch YAZE
2. Load ROM (File → Open ROM or drag & drop)
3. Open Dungeon Editor (Tools → Dungeon Editor)
4. Toggle cards via "Dungeon Controls" checkboxes
5. Click room in list/matrix to open
---
## Core Features
### 1. Rooms List Card
```
Features:
- Filter/search functionality (ICON_MD_SEARCH)
- Format: [HEX_ID] Room Name
- Click to open room card
- Double-click for instant focus
- Shows all 296 rooms (0x00-0x127)
```
### 2. Room Matrix Card (Visual Navigation)
```
Layout:
- 16 columns × 19 rows = 304 cells
- Displays all 296 rooms (0x00-0x127)
- 24px cells with 1px spacing (optimized)
- Window size: 440x520
Visual Features:
- Deterministic HSV colors (no loading needed)
- Light green outline: Currently selected room
- Green outline: Open rooms
- Gray outline: Inactive rooms
Performance:
- Before: 2-4 seconds (lazy loading 296 rooms)
- After: < 50ms (pure math, no I/O)
```
### 3. Entrances List Card
```
Configuration UI (ZScream Parity):
- Entrance ID, Room ID, Dungeon ID
- Blockset, Music, Floor
- Player Position (X, Y)
- Camera Trigger (X, Y)
- Scroll Position (X, Y)
- Exit value
- Camera Boundaries (quadrant & full room)
List Features:
- Format: [HEX_ID] Entrance Name -> Room Name
- Shows entrance-to-room relationship
- Click to select and open associated room
```
### 4. Object Editor Card (Unified)
```
Improved UX:
- Mode controls at top: None | Place | Select | Delete
- Current object info always visible
- 2 tabs:
- Browser: Object selection with previews
- Preview: Emulator rendering with controls
Object Browser:
- Categorized objects (Floor/Wall/Special)
- 32x32 preview icons
- Filter/search functionality
- Shows object ID and type
```
### 5. Palette Editor Card
```
Features:
- Palette selector dropdown (20 dungeon palettes)
- 90-color grid (15 per row)
- Visual selection with yellow border
- Tooltips: color index, SNES BGR555, RGB values
- HSV color wheel picker
- Live RGB display (0-255)
- SNES format display (15-bit BGR555)
- Reset button
Live Updates:
- Edit palette → all open rooms re-render automatically
- Callback system decouples palette editor from rooms
```
### 6. Room Cards (Auto-Loading)
```
Features:
- Auto-loads graphics when properties change
- Simple status indicator (✓ Loaded / ⏳ Not Loaded)
- Auto-saves with main Save command
- Per-room layer controls (BG1/BG2 visibility, BG2 layer type)
Docking Behavior:
- ImGuiWindowClass for automatic tab grouping
- New room cards auto-dock with existing rooms
- Can be undocked independently
- Maintains session state
```
### 7. Canvas Context Menu (NEW)
```
Dungeon-Specific Options:
- Place Object (Ctrl+P)
- Delete Selected (Del) - conditional on selection
- Toggle BG1 (1)
- Toggle BG2 (2)
- Re-render Room (Ctrl+R)
Integration:
- Dynamic menu based on current state
- Consistent with overworld editor UX
```
---
## Technical Details
### Rendering Pipeline
```
1. Room::CopyRoomGraphicsToBuffer()
→ Loads tile graphics into current_gfx16_ [128×N indexed pixels]
2. BackgroundBuffer::DrawFloor()
→ Fills tilemap buffer with floor tile IDs
3. BackgroundBuffer::DrawBackground()
→ Renders floor tiles to bitmap (512×512 indexed surface)
4. Room::SetPalette()
→ Apply 90-color dungeon palette to SDL surface
5. Room::RenderObjectsToBackground()
→ ObjectDrawer writes wall/object tiles to BG1/BG2 buffers
6. gfx::Arena::QueueTextureCommand(UPDATE, &bitmap)
→ CRITICAL: Update textures after object rendering
7. gfx::Arena::ProcessTextureQueue(renderer)
→ Process queued texture operations
8. DungeonCanvasViewer::DrawRoomBackgroundLayers()
→ Draw textures to canvas with ImGui::Image()
```
### Critical Fix: Texture Update After Object Rendering
**Problem**: Objects were drawn to bitmaps but textures were never updated.
**Solution** (in `room.cc`):
```cpp
void Room::RenderRoomGraphics() {
// 1. Draw floor and background
bg1_buffer_.DrawFloor(...);
bg1_buffer_.DrawBackground(...);
// 2. Apply palette and create initial textures
bg1_bmp.SetPalette(bg1_palette);
gfx::Arena::Get().QueueTextureCommand(CREATE, &bg1_bmp);
// 3. Render objects to bitmaps
RenderObjectsToBackground();
// 4. CRITICAL FIX: Update textures with new bitmap data
gfx::Arena::Get().QueueTextureCommand(UPDATE, &bg1_bmp);
gfx::Arena::Get().QueueTextureCommand(UPDATE, &bg2_bmp);
}
```
### SNES Graphics Format
**8-bit Indexed Color (3BPP for dungeons)**:
```cpp
// Each pixel is a palette index (0-7)
// RGB color comes from applying dungeon palette
bg1_bmp.SetPalette(dungeon_pal_group[palette_id]); // 90 colors
Renderer::Get().RenderBitmap(&bitmap); // indexed → RGB
```
**Color Format: 15-bit BGR555**
```
Bits: 0BBB BBGG GGGR RRRR
││││ ││││ ││││ ││││
│└──┴─┘└──┴─┘└──┴─┘
│ Blue Green Red
└─ Unused (always 0)
Each channel: 0-31 (5 bits)
Total colors: 32,768 (2^15)
```
**Palette Organization**:
- 20 total palettes (one per dungeon color scheme)
- 90 colors per palette (full SNES BG palette)
- ROM address: `kDungeonMainPalettes` (0xDD734)
### Critical Math Formulas
**Tile Position in Tilesheet (128px wide)**:
```cpp
int tile_x = (tile_id % 16) * 8;
int tile_y = (tile_id / 16) * 8;
int pixel_offset = (tile_y * 128) + tile_x;
```
**Tile Position in Canvas (512×512)**:
```cpp
int canvas_x = (tile_col * 8);
int canvas_y = (tile_row * 8);
int pixel_offset = (canvas_y * 512) + canvas_x;
// CRITICAL: For NxN tiles, advance by (tile_row * 8 * width)
int dest_offset = (yy * 8 * 512) + (xx * 8); // NOT just (yy * 512)!
```
**Palette Index Calculation**:
```cpp
// 3BPP: 8 colors per subpalette
int final_index = pixel_value + (palette_id * 8);
// NOT 4BPP (× 16)!
// int final_index = pixel_value + (palette_id << 4); // WRONG
```
### Per-Room Buffers
**Problem**: Multiple rooms shared `gfx::Arena::Get().bg1()` and corrupted each other.
**Solution**: Each `Room` has its own buffers:
```cpp
// In room.h
gfx::BackgroundBuffer bg1_buffer_;
gfx::BackgroundBuffer bg2_buffer_;
// In room.cc
bg1_buffer_.DrawFloor(...);
bg1_buffer_.DrawBackground(std::span<uint8_t>(current_gfx16_));
Renderer::Get().RenderBitmap(&bg1_buffer_.bitmap());
```
---
## Testing
### Test Suite Status
| Test Type | Total | Passing | Pass Rate |
| ----------------- | ----- | ------- | --------- |
| **Unit Tests** | 14 | 14 | 100% ✅ |
| **Integration** | 14 | 14 | 100% ✅ |
| **E2E Tests** | 1 | 1 | 100% ✅ |
| **TOTAL** | **29**| **29** | **100%** ✅ |
### Running Tests
```bash
# Build tests (mac-ai preset)
cmake --preset mac-ai -B build_ai
cmake --build build_ai --target yaze_test
# Run all dungeon tests
./build_ai/bin/yaze_test --gtest_filter="*Dungeon*"
# Run E2E tests with GUI (normal speed)
./build_ai/bin/yaze_test --ui --show-gui --normal --gtest_filter="*DungeonEditorSmokeTest*"
# Run E2E tests in slow-motion (cinematic mode)
./build_ai/bin/yaze_test --ui --show-gui --cinematic --gtest_filter="*DungeonEditorSmokeTest*"
# Run all tests with fast execution
./build_ai/bin/yaze_test --ui --fast
```
### Test Speed Modes (NEW)
```bash
--fast # Run tests as fast as possible (teleport mouse, skip delays)
--normal # Run tests at human watchable speed (for debugging)
--cinematic # Run tests in slow-motion with pauses (for demos/tutorials)
```
---
## Troubleshooting
### Common Issues & Fixes
#### Issue 1: Objects Not Visible
**Symptom**: Floor/walls render but objects invisible
**Fix**: ✅ RESOLVED - Texture update after object rendering now working
#### Issue 2: Wrong Colors
**Symptom**: Colors don't match expected palette
**Fix**: Use `SetPalette()` not `SetPaletteWithTransparent()` for dungeons
**Reason**:
```cpp
// WRONG (extracts only 8 colors):
bitmap.SetPaletteWithTransparent(palette);
// CORRECT (applies full 90-color palette):
bitmap.SetPalette(palette);
```
#### Issue 3: Bitmap Stretched/Corrupted
**Symptom**: Graphics only in top portion, repeated/stretched
**Fix**: Wrong offset in DrawBackground()
```cpp
// WRONG:
int offset = (yy * 512) + (xx * 8); // Only advances 512 per row
// CORRECT:
int offset = (yy * 8 * 512) + (xx * 8); // Advances 4096 per row
```
#### Issue 4: Room Properties Don't Update
**Symptom**: Changing blockset/palette has no effect
**Fix**: ✅ RESOLVED - Property change detection now working
---
## ROM Internals
### Object Encoding
Dungeon objects are stored in one of three formats:
#### Type 1: Standard Objects (ID 0x00-0xFF)
```
Format: xxxxxxss yyyyyyss iiiiiiii
Use: Common geometry like walls and floors
```
#### Type 2: Large Coordinate Objects (ID 0x100-0x1FF)
```
Format: 111111xx xxxxyyyy yyiiiiii
Use: More complex or interactive structures
```
#### Type 3: Special Objects (ID 0x200-0x27F)
```
Format: xxxxxxii yyyyyyii 11111iii
Use: Critical gameplay elements (chests, switches, bosses)
```
### Core Data Tables in ROM
- **`bank_01.asm`**:
- **`DrawObjects` (0x018000)**: Master tables mapping object ID → drawing routine
- **`LoadAndBuildRoom` (0x01873A)**: Primary routine that reads and draws a room
- **`rooms.asm`**:
- **`RoomData_ObjectDataPointers` (0x1F8000)**: Table of 3-byte pointers to object data for each of 296 rooms
### Key ROM Addresses
```cpp
constexpr int dungeons_palettes = 0xDD734;
constexpr int room_object_pointer = 0x874C; // Long pointer
constexpr int kRoomHeaderPointer = 0xB5DD; // LONG
constexpr int tile_address = 0x001B52;
constexpr int tile_address_floor = 0x001B5A;
constexpr int torch_data = 0x2736A;
constexpr int blocks_pointer1 = 0x15AFA;
constexpr int pit_pointer = 0x394AB;
constexpr int doorPointers = 0xF83C0;
```
---
## Reference
### File Organization
**Core Rendering**:
- `src/app/zelda3/dungeon/room.{h,cc}` - Room state, buffers
- `src/app/gfx/background_buffer.{h,cc}` - Tile → bitmap drawing
- `src/app/core/renderer.cc` - Bitmap → texture conversion
- `src/app/editor/dungeon/dungeon_canvas_viewer.cc` - Canvas display
**Object Drawing**:
- `src/app/zelda3/dungeon/object_drawer.{h,cc}` - Native C++ patterns
- `src/app/gui/widgets/dungeon_object_emulator_preview.{h,cc}` - Research tool
**Editor UI**:
- `src/app/editor/dungeon/dungeon_editor_v2.{h,cc}` - Main coordinator
- `src/app/gui/widgets/editor_card.{h,cc}` - Independent card system
- `src/app/editor/dungeon/dungeon_object_interaction.{h,cc}` - Object selection
**Palette System**:
- `src/app/gfx/snes_palette.{h,cc}` - Palette loading
- `src/app/gui/widgets/palette_editor_widget.{h,cc}` - Visual editor
- `src/app/gfx/bitmap.cc` - SetPalette() implementation
### Quick Reference: Key Functions
```cpp
// Load dungeon palette
auto& pal_group = rom->palette_group().dungeon_main;
auto palette = pal_group[palette_id]; // NOT .palette(id)!
// Apply palette to bitmap
bitmap.SetPalette(palette); // NOT SetPaletteWithTransparent()!
// Create texture from indexed bitmap
Renderer::Get().RenderBitmap(&bitmap); // NOT UpdateBitmap()!
// Tile sheet offset (128px wide)
int offset = (tile_id / 16) * 8 * 128 + (tile_id % 16) * 8;
// Canvas offset (512px wide)
int offset = (tile_row * 8 * 512) + (tile_col * 8);
// Palette offset (3BPP)
int offset = palette_id * 8; // NOT << 4 !
```
### Performance Metrics
**Matrix Loading**:
- Load time: < 50ms (pure calculation, no I/O)
- Memory allocations: ~20 per matrix draw (cached colors)
- Frame drops: None
**Room Loading**:
- Lazy loading: Rooms loaded on-demand
- Graphics caching: Reused across room switches
- Texture batching: Up to 8 textures processed per frame
---
## Summary
The Dungeon Editor is production-ready with all core features implemented and tested. Recent fixes ensure objects render correctly, property changes trigger re-renders, and the context menu provides dungeon-specific functionality. The card-based architecture provides maximum flexibility while maintaining stability.
### Critical Points
1. **Texture Update**: Always call UPDATE after modifying bitmap data
2. **Per-Room Buffers**: Each room has independent bg1/bg2 buffers
3. **Property Changes**: Automatically detected and trigger re-renders
4. **Palette Format**: Use SetPalette() for full 90-color dungeon palettes
5. **Context Menu**: Dungeon-specific options available via right-click
---
**For detailed debugging**: See `QUICK-DEBUG-REFERENCE.txt` for command-line shortcuts.

View File

@@ -168,3 +168,9 @@ Default palettes are applied during ROM loading based on sheet index:
- Sheets 0-112: Dungeon main palettes
- Sheets 113-127: Sprite palettes
- Sheets 128-222: HUD/menu palettes
### Naming Conventions
- Load: Reading data from ROM into memory
- Render: Processing graphics data into bitmaps/textures (CPU pixel operations)
- Draw: Displaying textures/shapes on canvas via ImGui (GPU rendering)
- Update: UI state changes, property updates, input handling

View File

@@ -1,585 +0,0 @@
# Yaze Dungeon Editor: Master Guide
**Last Updated**: October 4, 2025
This document provides a comprehensive, up-to-date overview of the Yaze Dungeon Editor, consolidating all recent design plans, testing results, and critical fixes. It serves as the single source of truth for the editor's architecture, data structures, and future development.
## 1. Current Status: Production Ready
After a significant refactoring and bug-fixing effort, the Dungeon Editor's core functionality is **complete and stable**.
- **Core Logic**: The most complex features, including the 3-type object encoding/decoding system and saving objects back to the ROM, are **fully implemented**.
- **Testing**: The test suite is now **100% stable**, with all 29 unit, integration, and E2E tests passing. Critical `SIGBUS` and `SIGSEGV` crashes have been resolved by replacing the unstable `MockRom` with a real ROM file for testing.
- **Rendering**: The rendering pipeline is verified, correct, and performant, properly using the graphics arena and a component-based architecture.
- **Coordinate System**: A critical object positioning bug has been fixed, ensuring all objects render in their correct locations.
### Known Issues & Next Steps
While the core is stable, several UI and performance items remain:
1. **UI Polish (High Priority)**:
* Implement human-readable labels for rooms and entrances in selection lists.
* Add tab management features (`+` to add, `x` to close) for a better multi-room workflow.
2. **Performance (Medium Priority)**:
* Address the slow initial load time (~2.6 seconds) by implementing lazy loading for rooms.
3. **Palette System (Medium Priority)**:
* Fix the handling of palette IDs greater than 19 to prevent fallbacks to palette 0.
## 2. Architecture: A Component-Based Design
The editor was refactored into a modern, component-based architecture, reducing the main editor's complexity by **79%**. The `DungeonEditorV2` class now acts as a thin coordinator, delegating all work to specialized components.
### Core Components
- **`DungeonEditorV2`**: The main orchestrator. Manages the 3-column layout and coordinates the other components.
- **`DungeonRoomLoader`**: Handles all data loading from the ROM, now optimized with parallel processing.
- **`DungeonRoomSelector`**: Manages the UI for selecting rooms and entrances.
- **`DungeonCanvasViewer`**: Responsible for rendering the room, objects, and sprites onto the main canvas.
- **`DungeonObjectSelector`**: Provides the UI for browsing and selecting objects, sprites, and other editable elements.
- **`DungeonObjectInteraction`**: Manages all mouse input, selection, and drag-and-drop on the canvas.
- **`ObjectRenderer`**: A high-performance system for rendering individual dungeon objects, featuring a graphics cache.
### Data Flow
1. **Load**: `DungeonEditorV2::Load()` calls `DungeonRoomLoader` to load all room data from the ROM.
2. **Update**: The editor's `Update()` method calls `Draw()` on each of the three main UI components (`RoomSelector`, `CanvasViewer`, `ObjectSelector`), which render their respective parts of the 3-column layout.
3. **Interaction**: `DungeonObjectInteraction` captures mouse events on the canvas and translates them into actions, such as selecting or moving an object.
4. **Save**: Changes are propagated back through the `DungeonEditorSystem` to be written to the ROM.
## 3. Key Recent Fixes
The editor's current stability is the result of two major fixes:
### Critical Fix 1: The Coordinate System
- **Problem**: Objects were rendering at twice their correct distance from the origin, often appearing outside the canvas entirely.
- **Root Cause**: The code incorrectly assumed dungeon tiles were 16x16 pixels, using `* 16` for coordinate conversions. SNES dungeon tiles are **8x8 pixels**.
- **The Fix**: All coordinate conversion functions in `dungeon_renderer.cc`, `dungeon_canvas_viewer.cc`, and `dungeon_object_interaction.cc` were corrected to use `* 8` and `/ 8`.
### Critical Fix 2: The Test Suite
- **Problem**: The integration test suite was unusable, crashing with `SIGBUS` and `SIGSEGV` errors.
- **Root Cause**: The `MockRom` implementation had severe memory management issues, causing crashes when test data was copied.
- **The Fix**: The `MockRom` was **completely abandoned**. All 28 integration and unit tests were refactored to use a real `zelda3.sfc` ROM via the `TestRomManager`. This provides more realistic testing and resolved all crashes.
## 4. ROM Internals & Data Structures
This information is critical for understanding the editor's core logic and has been cross-referenced with the `usdasm` disassembly.
### Object Encoding
Dungeon objects are stored in one of three formats. The encoding logic is correctly implemented in `src/app/zelda3/dungeon/room_object.cc`.
- **Type 1: Standard Objects (ID 0x00-0xFF)**
- **Format**: `xxxxxxss yyyyyyss iiiiiiii`
- **Use**: Common geometry like walls and floors.
- **Type 2: Large Coordinate Objects (ID 0x100-0x1FF)**
- **Format**: `111111xx xxxxyyyy yyiiiiii`
- **Use**: More complex or interactive structures.
- **Type 3: Special Objects (ID 0x200-0x27F)**
- **Format**: `xxxxxxii yyyyyyii 11111iii`
- **Use**: Critical gameplay elements like chests, switches, and bosses.
### Core Data Tables in ROM
- **`bank_01.asm`**:
- **`DrawObjects` (0x018000)**: Master tables mapping an object's ID to its drawing routine.
- **`LoadAndBuildRoom` (0x01873A)**: The primary routine that reads and draws a room.
- **`rooms.asm`**:
- **`RoomData_ObjectDataPointers` (0x1F8000)**: A table of 3-byte pointers to the object data for each of the 296 rooms.
## 5. Testing: 100% Pass Rate
The dungeon editor has comprehensive test coverage, ensuring its stability and correctness.
| Test Type | Total | Passing | Pass Rate |
| ----------------- | ----- | ------- | --------- |
| **Unit Tests** | 14 | 14 | 100% ✅ |
| **Integration** | 14 | 14 | 100% ✅ |
| **E2E Tests** | 1 | 1 | 100% ✅ |
| **TOTAL** | **29**| **29** | **100%** ✅ |
### How to Run Tests
1. **Build the Tests**:
```bash
cmake --preset macos-dev -B build_test
cmake --build build_test --target yaze_test
```
2. **Run All Dungeon Tests**:
```bash
./build_test/bin/yaze_test --gtest_filter="*Dungeon*"
```
3. **Run E2E Smoke Test (Requires GUI)**:
```bash
./build_test/bin/yaze_test --show-gui --gtest_filter="*DungeonEditorSmokeTest*"
```
## 6. Dungeon Object Reference Tables
The following tables were generated by parsing the `DrawObjects` tables in `bank_01.asm`.
### Type 1 Object Reference Table
| ID (Hex) | ID (Dec) | Description (from assembly) |
| :--- | :--- | :--- |
| 0x00 | 0 | Rightwards 2x2 |
| 0x01 | 1 | Rightwards 2x4 |
| 0x02 | 2 | Rightwards 2x4 |
| 0x03 | 3 | Rightwards 2x4 spaced 4 |
| 0x04 | 4 | Rightwards 2x4 spaced 4 |
| 0x05 | 5 | Rightwards 2x4 spaced 4 (Both BG) |
| 0x06 | 6 | Rightwards 2x4 spaced 4 (Both BG) |
| 0x07 | 7 | Rightwards 2x2 |
| 0x08 | 8 | Rightwards 2x2 |
| 0x09 | 9 | Diagonal Acute |
| 0x0A | 10 | Diagonal Grave |
| 0x0B | 11 | Diagonal Grave |
| 0x0C | 12 | Diagonal Acute |
| 0x0D | 13 | Diagonal Acute |
| 0x0E | 14 | Diagonal Grave |
| 0x0F | 15 | Diagonal Grave |
| 0x10 | 16 | Diagonal Acute |
| 0x11 | 17 | Diagonal Acute |
| 0x12 | 18 | Diagonal Grave |
| 0x13 | 19 | Diagonal Grave |
| 0x14 | 20 | Diagonal Acute |
| 0x15 | 21 | Diagonal Acute (Both BG) |
| 0x16 | 22 | Diagonal Grave (Both BG) |
| 0x17 | 23 | Diagonal Grave (Both BG) |
| 0x18 | 24 | Diagonal Acute (Both BG) |
| 0x19 | 25 | Diagonal Acute (Both BG) |
| 0x1A | 26 | Diagonal Grave (Both BG) |
| 0x1B | 27 | Diagonal Grave (Both BG) |
| 0x1C | 28 | Diagonal Acute (Both BG) |
| 0x1D | 29 | Diagonal Acute (Both BG) |
| 0x1E | 30 | Diagonal Grave (Both BG) |
| 0x1F | 31 | Diagonal Grave (Both BG) |
| 0x20 | 32 | Diagonal Acute (Both BG) |
| 0x21 | 33 | Rightwards 1x2 |
| 0x22 | 34 | Rightwards Has Edge 1x1 |
| 0x23 | 35 | Rightwards Has Edge 1x1 |
| 0x24 | 36 | Rightwards Has Edge 1x1 |
| 0x25 | 37 | Rightwards Has Edge 1x1 |
| 0x26 | 38 | Rightwards Has Edge 1x1 |
| 0x27 | 39 | Rightwards Has Edge 1x1 |
| 0x28 | 40 | Rightwards Has Edge 1x1 |
| 0x29 | 41 | Rightwards Has Edge 1x1 |
| 0x2A | 42 | Rightwards Has Edge 1x1 |
| 0x2B | 43 | Rightwards Has Edge 1x1 |
| 0x2C | 44 | Rightwards Has Edge 1x1 |
| 0x2D | 45 | Rightwards Has Edge 1x1 |
| 0x2E | 46 | Rightwards Has Edge 1x1 |
| 0x2F | 47 | Rightwards Top Corners 1x2 |
| 0x30 | 48 | Rightwards Bottom Corners 1x2 |
| 0x31 | 49 | Nothing |
| 0x32 | 50 | Nothing |
| 0x33 | 51 | Rightwards 4x4 |
| 0x34 | 52 | Rightwards 1x1 Solid |
| 0x35 | 53 | Door Switcherer |
| 0x36 | 54 | Rightwards Decor 4x4 spaced 2 |
| 0x37 | 55 | Rightwards Decor 4x4 spaced 2 |
| 0x38 | 56 | Rightwards Statue 2x3 spaced 2 |
| 0x39 | 57 | Rightwards Pillar 2x4 spaced 4 |
| 0x3A | 58 | Rightwards Decor 4x3 spaced 4 |
| 0x3B | 59 | Rightwards Decor 4x3 spaced 4 |
| 0x3C | 60 | Rightwards Doubled 2x2 spaced 2 |
| 0x3D | 61 | Rightwards Pillar 2x4 spaced 4 |
| 0x3E | 62 | Rightwards Decor 2x2 spaced 12 |
| 0x3F | 63 | Rightwards Has Edge 1x1 |
| 0x40 | 64 | Rightwards Has Edge 1x1 |
| 0x41 | 65 | Rightwards Has Edge 1x1 |
| 0x42 | 66 | Rightwards Has Edge 1x1 |
| 0x43 | 67 | Rightwards Has Edge 1x1 |
| 0x44 | 68 | Rightwards Has Edge 1x1 |
| 0x45 | 69 | Rightwards Has Edge 1x1 |
| 0x46 | 70 | Rightwards Has Edge 1x1 |
| 0x47 | 71 | Waterfall |
| 0x48 | 72 | Waterfall |
| 0x49 | 73 | Rightwards Floor Tile 4x2 |
| 0x4A | 74 | Rightwards Floor Tile 4x2 |
| 0x4B | 75 | Rightwards Decor 2x2 spaced 12 |
| 0x4C | 76 | Rightwards Bar 4x3 |
| 0x4D | 77 | Rightwards Shelf 4x4 |
| 0x4E | 78 | Rightwards Shelf 4x4 |
| 0x4F | 79 | Rightwards Shelf 4x4 |
| 0x50 | 80 | Rightwards Line 1x1 |
| 0x51 | 81 | Rightwards Cannon Hole 4x3 |
| 0x52 | 82 | Rightwards Cannon Hole 4x3 |
| 0x53 | 83 | Rightwards 2x2 |
| 0x54 | 84 | Nothing |
| 0x55 | 85 | Rightwards Decor 4x2 spaced 8 |
| 0x56 | 86 | Rightwards Decor 4x2 spaced 8 |
| 0x57 | 87 | Nothing |
| 0x58 | 88 | Nothing |
| 0x59 | 89 | Nothing |
| 0x5A | 90 | Nothing |
| 0x5B | 91 | Rightwards Cannon Hole 4x3 |
| 0x5C | 92 | Rightwards Cannon Hole 4x3 |
| 0x5D | 93 | Rightwards Big Rail 1x3 |
| 0x5E | 94 | Rightwards Block 2x2 spaced 2 |
| 0x5F | 95 | Rightwards Has Edge 1x1 |
| 0x60 | 96 | Downwards 2x2 |
| 0x61 | 97 | Downwards 4x2 |
| 0x62 | 98 | Downwards 4x2 |
| 0x63 | 99 | Downwards 4x2 (Both BG) |
| 0x64 | 100 | Downwards 4x2 (Both BG) |
| 0x65 | 101 | Downwards Decor 4x2 spaced 4 |
| 0x66 | 102 | Downwards Decor 4x2 spaced 4 |
| 0x67 | 103 | Downwards 2x2 |
| 0x68 | 104 | Downwards 2x2 |
| 0x69 | 105 | Downwards Has Edge 1x1 |
| 0x6A | 106 | Downwards Edge 1x1 |
| 0x6B | 107 | Downwards Edge 1x1 |
| 0x6C | 108 | Downwards Left Corners 2x1 |
| 0x6D | 109 | Downwards Right Corners 2x1 |
| 0x6E | 110 | Nothing |
| 0x6F | 111 | Nothing |
| 0x70 | 112 | Downwards Floor 4x4 |
| 0x71 | 113 | Downwards 1x1 Solid |
| 0x72 | 114 | Nothing |
| 0x73 | 115 | Downwards Decor 4x4 spaced 2 |
| 0x74 | 116 | Downwards Decor 4x4 spaced 2 |
| 0x75 | 117 | Downwards Pillar 2x4 spaced 2 |
| 0x76 | 118 | Downwards Decor 3x4 spaced 4 |
| 0x77 | 119 | Downwards Decor 3x4 spaced 4 |
| 0x78 | 120 | Downwards Decor 2x2 spaced 12 |
| 0x79 | 121 | Downwards Edge 1x1 |
| 0x7A | 122 | Downwards Edge 1x1 |
| 0x7B | 123 | Downwards Decor 2x2 spaced 12 |
| 0x7C | 124 | Downwards Line 1x1 |
| 0x7D | 125 | Downwards 2x2 |
| 0x7E | 126 | Nothing |
| 0x7F | 127 | Downwards Decor 2x4 spaced 8 |
| 0x80 | 128 | Downwards Decor 2x4 spaced 8 |
| 0x81 | 129 | Downwards Decor 3x4 spaced 2 |
| 0x82 | 130 | Downwards Decor 3x4 spaced 2 |
| 0x83 | 131 | Downwards Decor 3x4 spaced 2 |
| 0x84 | 132 | Downwards Decor 3x4 spaced 2 |
| 0x85 | 133 | Downwards Cannon Hole 3x4 |
| 0x86 | 134 | Downwards Cannon Hole 3x4 |
| 0x87 | 135 | Downwards Pillar 2x4 spaced 2 |
| 0x88 | 136 | Downwards Big Rail 3x1 |
| 0x89 | 137 | Downwards Block 2x2 spaced 2 |
| 0x8A | 138 | Downwards Has Edge 1x1 |
| 0x8B | 139 | Downwards Edge 1x1 |
| 0x8C | 140 | Downwards Edge 1x1 |
| 0x8D | 141 | Downwards Edge 1x1 |
| 0x8E | 142 | Downwards Edge 1x1 |
| 0x8F | 143 | Downwards Bar 2x5 |
| 0x90 | 144 | Downwards 4x2 |
| 0x91 | 145 | Downwards 4x2 |
| 0x92 | 146 | Downwards 2x2 |
| 0x93 | 147 | Downwards 2x2 |
| 0x94 | 148 | Downwards Floor 4x4 |
| 0x95 | 149 | Downwards Pots 2x2 |
| 0x96 | 150 | Downwards Hammer Pegs 2x2 |
| 0x97 | 151 | Nothing |
| 0x98 | 152 | Nothing |
| 0x99 | 153 | Nothing |
| 0x9A | 154 | Nothing |
| 0x9B | 155 | Nothing |
| 0x9C | 156 | Nothing |
| 0x9D | 157 | Nothing |
| 0x9E | 158 | Nothing |
| 0x9F | 159 | Nothing |
| 0xA0 | 160 | Diagonal Ceiling Top Left A |
| 0xA1 | 161 | Diagonal Ceiling Bottom Left A |
| 0xA2 | 162 | Diagonal Ceiling Top Right A |
| 0xA3 | 163 | Diagonal Ceiling Bottom Right A |
| 0xA4 | 164 | Big Hole 4x4 |
| 0xA5 | 165 | Diagonal Ceiling Top Left B |
| 0xA6 | 166 | Diagonal Ceiling Bottom Left B |
| 0xA7 | 167 | Diagonal Ceiling Top Right B |
| 0xA8 | 168 | Diagonal Ceiling Bottom Right B |
| 0xA9 | 169 | Diagonal Ceiling Top Left B |
| 0xAA | 170 | Diagonal Ceiling Bottom Left B |
| 0xAB | 171 | Diagonal Ceiling Top Right B |
| 0xAC | 172 | Diagonal Ceiling Bottom Right B |
| 0xAD | 173 | Nothing |
| 0xAE | 174 | Nothing |
| 0xAF | 175 | Nothing |
| 0xB0 | 176 | Rightwards Edge 1x1 |
| 0xB1 | 177 | Rightwards Edge 1x1 |
| 0xB2 | 178 | Rightwards 4x4 |
| 0xB3 | 179 | Rightwards Has Edge 1x1 |
| 0xB4 | 180 | Rightwards Has Edge 1x1 |
| 0xB5 | 181 | Weird 2x4 |
| 0xB6 | 182 | Rightwards 2x4 |
| 0xB7 | 183 | Rightwards 2x4 |
| 0xB8 | 184 | Rightwards 2x2 |
| 0xB9 | 185 | Rightwards 2x2 |
| 0xBA | 186 | Rightwards 4x4 |
| 0xBB | 187 | Rightwards Block 2x2 spaced 2 |
| 0xBC | 188 | Rightwards Pots 2x2 |
| 0xBD | 189 | Rightwards Hammer Pegs 2x2 |
| 0xBE | 190 | Nothing |
| 0xBF | 191 | Nothing |
| 0xC0 | 192 | 4x4 Blocks In 4x4 Super Square |
| 0xC1 | 193 | Closed Chest Platform |
| 0xC2 | 194 | 4x4 Blocks In 4x4 Super Square |
| 0xC3 | 195 | 3x3 Floor In 4x4 Super Square |
| 0xC4 | 196 | 4x4 Floor One In 4x4 Super Square |
| 0xC5 | 197 | 4x4 Floor In 4x4 Super Square |
| 0xC6 | 198 | 4x4 Floor In 4x4 Super Square |
| 0xC7 | 199 | 4x4 Floor In 4x4 Super Square |
| 0xC8 | 200 | 4x4 Floor In 4x4 Super Square |
| 0xC9 | 201 | 4x4 Floor In 4x4 Super Square |
| 0xCA | 202 | 4x4 Floor In 4x4 Super Square |
| 0xCB | 203 | Nothing |
| 0xCC | 204 | Nothing |
| 0xCD | 205 | Moving Wall West |
| 0xCE | 206 | Moving Wall East |
| 0xCF | 207 | Nothing |
| 0xD0 | 208 | Nothing |
| 0xD1 | 209 | 4x4 Floor In 4x4 Super Square |
| 0xD2 | 210 | 4x4 Floor In 4x4 Super Square |
| 0xD3 | 211 | Check If Wall Is Moved |
| 0xD4 | 212 | Check If Wall Is Moved |
| 0xD5 | 213 | Check If Wall Is Moved |
| 0xD6 | 214 | Check If Wall Is Moved |
| 0xD7 | 215 | 3x3 Floor In 4x4 Super Square |
| 0xD8 | 216 | Water Overlay A 8x8 |
| 0xD9 | 217 | 4x4 Floor In 4x4 Super Square |
| 0xDA | 218 | Water Overlay B 8x8 |
| 0xDB | 219 | 4x4 Floor Two In 4x4 Super Square |
| 0xDC | 220 | Open Chest Platform |
| 0xDD | 221 | Table Rock 4x4 |
| 0xDE | 222 | Spike 2x2 In 4x4 Super Square |
| 0xDF | 223 | 4x4 Floor In 4x4 Super Square |
| 0xE0 | 224 | 4x4 Floor In 4x4 Super Square |
| 0xE1 | 225 | 4x4 Floor In 4x4 Super Square |
| 0xE2 | 226 | 4x4 Floor In 4x4 Super Square |
| 0xE3 | 227 | 4x4 Floor In 4x4 Super Square |
| 0xE4 | 228 | 4x4 Floor In 4x4 Super Square |
| 0xE5 | 229 | 4x4 Floor In 4x4 Super Square |
| 0xE6 | 230 | 4x4 Floor In 4x4 Super Square |
| 0xE7 | 231 | 4x4 Floor In 4x4 Super Square |
| 0xE8 | 232 | 4x4 Floor In 4x4 Super Square |
| 0xE9 | 233 | Nothing |
| 0xEA | 234 | Nothing |
| 0xEB | 235 | Nothing |
| 0xEC | 236 | Nothing |
| 0xED | 237 | Nothing |
| 0xEE | 238 | Nothing |
| 0xEF | 239 | Nothing |
| 0xF0 | 240 | Nothing |
| 0xF1 | 241 | Nothing |
| 0xF2 | 242 | Nothing |
| 0xF3 | 243 | Nothing |
| 0xF4 | 244 | Nothing |
| 0xF5 | 245 | Nothing |
| 0xF6 | 246 | Nothing |
| 0xF7 | 247 | Nothing |
| 0xF8 | 248 | Nothing |
| 0xF9 | 249 | Nothing |
| 0xFA | 250 | Nothing |
| 0xFB | 251 | Nothing |
| 0xFC | 252 | Nothing |
| 0xFD | 253 | Nothing |
| 0xFE | 254 | Nothing |
| 0xFF | 255 | Nothing |
### Type 2 Object Reference Table
| ID (Hex) | ID (Dec) | Description (from assembly) |
| :--- | :--- | :--- |
| 0x100 | 256 | 4x4 |
| 0x101 | 257 | 4x4 |
| 0x102 | 258 | 4x4 |
| 0x103 | 259 | 4x4 |
| 0x104 | 260 | 4x4 |
| 0x105 | 261 | 4x4 |
| 0x106 | 262 | 4x4 |
| 0x107 | 263 | 4x4 |
| 0x108 | 264 | 4x4 Corner (Both BG) |
| 0x109 | 265 | 4x4 Corner (Both BG) |
| 0x10A | 266 | 4x4 Corner (Both BG) |
| 0x10B | 267 | 4x4 Corner (Both BG) |
| 0x10C | 268 | 4x4 Corner (Both BG) |
| 0x10D | 269 | 4x4 Corner (Both BG) |
| 0x10E | 270 | 4x4 Corner (Both BG) |
| 0x10F | 271 | 4x4 Corner (Both BG) |
| 0x110 | 272 | Weird Corner Bottom (Both BG) |
| 0x111 | 273 | Weird Corner Bottom (Both BG) |
| 0x112 | 274 | Weird Corner Bottom (Both BG) |
| 0x113 | 275 | Weird Corner Bottom (Both BG) |
| 0x114 | 276 | Weird Corner Top (Both BG) |
| 0x115 | 277 | Weird Corner Top (Both BG) |
| 0x116 | 278 | Weird Corner Top (Both BG) |
| 0x117 | 279 | Weird Corner Top (Both BG) |
| 0x118 | 280 | Rightwards 2x2 |
| 0x119 | 281 | Rightwards 2x2 |
| 0x11A | 282 | Rightwards 2x2 |
| 0x11B | 283 | Rightwards 2x2 |
| 0x11C | 284 | 4x4 |
| 0x11D | 285 | Single 2x3 Pillar |
| 0x11E | 286 | Single 2x2 |
| 0x11F | 287 | Enabled Star Switch |
| 0x120 | 288 | Lit Torch |
| 0x121 | 289 | Single 2x3 Pillar |
| 0x122 | 290 | Bed 4x5 |
| 0x123 | 291 | Table Rock 4x3 |
| 0x124 | 292 | 4x4 |
| 0x125 | 293 | 4x4 |
| 0x126 | 294 | Single 2x3 Pillar |
| 0x127 | 295 | Rightwards 2x2 |
| 0x128 | 296 | Bed 4x5 |
| 0x129 | 297 | 4x4 |
| 0x12A | 298 | Portrait Of Mario |
| 0x12B | 299 | Rightwards 2x2 |
| 0x12C | 300 | Draw Rightwards 3x6 |
| 0x12D | 301 | Inter-Room Fat Stairs Up |
| 0x12E | 302 | Inter-Room Fat Stairs Down A |
| 0x12F | 303 | Inter-Room Fat Stairs Down B |
| 0x130 | 304 | Auto Stairs North Multi Layer A |
| 0x131 | 305 | Auto Stairs North Multi Layer B |
| 0x132 | 306 | Auto Stairs North Merged Layer A |
| 0x133 | 307 | Auto Stairs North Merged Layer B |
| 0x134 | 308 | Rightwards 2x2 |
| 0x135 | 309 | Water Hop Stairs A |
| 0x136 | 310 | Water Hop Stairs B |
| 0x137 | 311 | Dam Flood Gate |
| 0x138 | 312 | Spiral Stairs Going Up Upper |
| 0x139 | 313 | Spiral Stairs Going Down Upper |
| 0x13A | 314 | Spiral Stairs Going Up Lower |
| 0x13B | 315 | Spiral Stairs Going Down Lower |
| 0x13C | 316 | Sanctuary Wall |
| 0x13D | 317 | Table Rock 4x3 |
| 0x13E | 318 | Utility 6x3 |
| 0x13F | 319 | Magic Bat Altar |
### Type 3 Object Reference Table
| ID (Hex) | ID (Dec) | Description (from assembly) |
| :--- | :--- | :--- |
| 0x200 | 512 | Empty Water Face |
| 0x201 | 513 | Spitting Water Face |
| 0x202 | 514 | Drenching Water Face |
| 0x203 | 515 | Somaria Line (increment count) |
| 0x204 | 516 | Somaria Line |
| 0x205 | 517 | Somaria Line |
| 0x206 | 518 | Somaria Line |
| 0x207 | 519 | Somaria Line |
| 0x208 | 520 | Somaria Line |
| 0x209 | 521 | Somaria Line |
| 0x20A | 522 | Somaria Line |
| 0x20B | 523 | Somaria Line |
| 0x20C | 524 | Somaria Line |
| 0x20D | 525 | Prison Cell |
| 0x20E | 526 | Somaria Line (increment count) |
| 0x20F | 527 | Somaria Line |
| 0x210 | 528 | Rightwards 2x2 |
| 0x211 | 529 | Rightwards 2x2 |
| 0x212 | 530 | Rupee Floor |
| 0x213 | 531 | Rightwards 2x2 |
| 0x214 | 532 | Table Rock 4x3 |
| 0x215 | 533 | Kholdstare Shell |
| 0x216 | 534 | Hammer Peg Single |
| 0x217 | 535 | Prison Cell |
| 0x218 | 536 | Big Key Lock |
| 0x219 | 537 | Chest |
| 0x21A | 538 | Open Chest |
| 0x21B | 539 | Auto Stairs South Multi Layer A |
| 0x21C | 540 | Auto Stairs South Multi Layer B |
| 0x21D | 541 | Auto Stairs South Multi Layer C |
| 0x21E | 542 | Straight Inter-room Stairs Going Up North Upper |
| 0x21F | 543 | Straight Inter-room Stairs Going Down North Upper |
| 0x220 | 544 | Straight Inter-room Stairs Going Up South Upper |
| 0x221 | 545 | Straight Inter-room Stairs Going Down South Upper |
| 0x222 | 546 | Rightwards 2x2 |
| 0x223 | 547 | Rightwards 2x2 |
| 0x224 | 548 | Rightwards 2x2 |
| 0x225 | 549 | Rightwards 2x2 |
| 0x226 | 550 | Straight Inter-room Stairs Going Up North Lower |
| 0x227 | 551 | Straight Inter-room Stairs Going Down North Lower |
| 0x228 | 552 | Straight Inter-room Stairs Going Up South Lower |
| 0x229 | 553 | Straight Inter-room Stairs Going Down South Lower |
| 0x22A | 554 | Lamp Cones |
| 0x22B | 555 | Weird Glove Required Pot |
| 0x22C | 556 | Big Gray Rock |
| 0x22D | 557 | Agahnims Altar |
| 0x22E | 558 | Agahnims Windows |
| 0x22F | 559 | Single Pot |
| 0x230 | 560 | Weird Ugly Pot |
| 0x231 | 561 | Big Chest |
| 0x232 | 562 | Open Big Chest |
| 0x233 | 563 | Auto Stairs South Merged Layer |
| 0x234 | 564 | Chest Platform Vertical Wall |
| 0x235 | 565 | Chest Platform Vertical Wall |
| 0x236 | 566 | Draw Rightwards 3x6 |
| 0x237 | 567 | Draw Rightwards 3x6 |
| 0x238 | 568 | Chest Platform Vertical Wall |
| 0x239 | 569 | Chest Platform Vertical Wall |
| 0x23A | 570 | Vertical Turtle Rock Pipe |
| 0x23B | 571 | Vertical Turtle Rock Pipe |
| 0x23C | 572 | Horizontal Turtle Rock Pipe |
| 0x23D | 573 | Horizontal Turtle Rock Pipe |
| 0x23E | 574 | Rightwards 2x2 |
| 0x23F | 575 | Rightwards 2x2 |
| 0x240 | 576 | Rightwards 2x2 |
| 0x241 | 577 | Rightwards 2x2 |
| 0x242 | 578 | Rightwards 2x2 |
| 0x243 | 579 | Rightwards 2x2 |
| 0x244 | 580 | Rightwards 2x2 |
| 0x245 | 581 | Rightwards 2x2 |
| 0x246 | 582 | Rightwards 2x2 |
| 0x247 | 583 | Bombable Floor |
| 0x248 | 584 | 4x4 |
| 0x249 | 585 | Rightwards 2x2 |
| 0x24A | 586 | Rightwards 2x2 |
| 0x24B | 587 | Big Wall Decor |
| 0x24C | 588 | Smithy Furnace |
| 0x24D | 589 | Utility 6x3 |
| 0x24E | 590 | Table Rock 4x3 |
| 0x24F | 591 | Rightwards 2x2 |
| 0x250 | 592 | Single 2x2 |
| 0x251 | 593 | Rightwards 2x2 |
| 0x252 | 594 | Rightwards 2x2 |
| 0x253 | 595 | Rightwards 2x2 |
| 0x254 | 596 | Fortune Teller Room |
| 0x255 | 597 | Utility 3x5 |
| 0x256 | 598 | Rightwards 2x2 |
| 0x257 | 599 | Rightwards 2x2 |
| 0x258 | 600 | Rightwards 2x2 |
| 0x259 | 601 | Rightwards 2x2 |
| 0x25A | 602 | Table Bowl |
| 0x25B | 603 | Utility 3x5 |
| 0x25C | 604 | Horizontal Turtle Rock Pipe |
| 0x25D | 605 | Utility 6x3 |
| 0x25E | 606 | Rightwards 2x2 |
| 0x25F | 607 | Rightwards 2x2 |
| 0x260 | 608 | Archery Game Target Door |
| 0x261 | 609 | Archery Game Target Door |
| 0x262 | 610 | Vitreous Goo Graphics |
| 0x263 | 611 | Rightwards 2x2 |
| 0x264 | 612 | Rightwards 2x2 |
| 0x265 | 613 | Rightwards 2x2 |
| 0x266 | 614 | 4x4 |
| 0x267 | 615 | Table Rock 4x3 |
| 0x268 | 616 | Table Rock 4x3 |
| 0x269 | 617 | Solid Wall Decor 3x4 |
| 0x26A | 618 | Solid Wall Decor 3x4 |
| 0x26B | 619 | 4x4 |
| 0x26C | 620 | Table Rock 4x3 |
| 0x26D | 621 | Table Rock 4x3 |
| 0x26E | 622 | Solid Wall Decor 3x4 |
| 0x26F | 623 | Solid Wall Decor 3x4 |
| 0x270 | 624 | Light Beam On Floor |
| 0x271 | 625 | Big Light Beam On Floor |
| 0x272 | 626 | Trinexx Shell |
| 0x273 | 627 | BG2 Mask Full |
| 0x274 | 628 | Floor Light |
| 0x275 | 629 | Rightwards 2x2 |
| 0x276 | 630 | Big Wall Decor |
| 0x277 | 631 | Big Wall Decor |
| 0x278 | 632 | Ganon Triforce Floor Decor |
| 0x279 | 633 | Table Rock 4x3 |
| 0x27A | 634 | 4x4 |
| 0x27B | 635 | Vitreous Goo Damage |
| 0x27C | 636 | Rightwards 2x2 |
| 0x27D | 637 | Rightwards 2x2 |
| 0x27E | 638 | Rightwards 2x2 |
| 0x27F | 639 | Nothing |