6.7 KiB
Dungeon Object Rendering - Master Plan
Completed Phases
Phase 1: BG Layer Draw Order
Completed: 2025-11-26
- Swapped draw order: BG2 first (background), then BG1 (foreground)
- Objects on BG1 no longer covered by BG2
Phase 2: Wall Rendering Investigation
Completed: 2025-11-26
- Root cause: Bitmap initialization bug (1 byte instead of 262144)
- Created ROM-dependent integration tests confirming fix
Phase 3: Subtype1 Tile Count Lookup Table
Completed: 2025-11-26
- Added
kSubtype1TileLengths[0xF8]from ZScream - Objects now load correct tile counts (e.g., 0xC1 = 68 tiles)
Phase 4a: Type Detection Fixes
Completed: 2025-11-26
- Fix 1: Type 2/Type 3 decode order (check b1 >= 0xFC before b3 >= 0xF8)
- Fix 2: Type 2 index mask 0x7F -> 0xFF
- Fix 3: Type 3 threshold 0x200 -> 0xF80
Phase 4b: North/South Wall Draw Routines
Completed: 2025-11-26
- Fixed column-major tile ordering in DrawRightwards2x4 routines
- Updated routines: DrawRightwards2x4_1to15or26, DrawRightwards2x4spaced4_1to16
- Changed tile guard from 4 tiles to 8 tiles (column-major uses full 8 tiles)
- Objects 0x01-0x06 now render correctly
Phase 4c: Corner Wall Objects (Partial)
Completed: 2025-11-26
- Mapped BothBG diagonal variants (objects 0x0C-0x20) to existing functions
- Implemented DrawCorner4x4 for Type 2 corners (objects 0x40-0x4F)
- Added routines 17-19 to draw routine registry
Pending Phases
Phase 4c: Corner Wall Objects (Remaining)
Status: Deferred Priority: Medium
Remaining work:
- Kinked corners (3x4 and 4x3) if needed after testing
- Deep concave corners (2x2) if needed after testing
- Note: Some corner IDs may overlap with diagonal objects; needs ZScream verification
Reference - Column-Major Pattern (implemented):
Column 0 Column 1
[tile 0] [tile 4] <- Row 0
[tile 1] [tile 5] <- Row 1
[tile 2] [tile 6] <- Row 2
[tile 3] [tile 7] <- Row 3
Implemented:
- Type 2 Corners (0x40-0x4F): DrawCorner4x4 - 4x4 column-major grid
- Diagonal BothBG variants (0x0C-0x20): Mapped to existing diagonal functions
Remaining (if needed after testing):
- Kinked N/S corners (0x10-0x13): 3x4 grid
- Kinked E/W corners (0x14-0x17): 4x3 grid
- Deep Concave corners (0x18-0x1B): 2x2 grid
Note: Objects 0x10-0x1B may be diagonals rather than corners based on ZScream analysis. Verify behavior with visual testing against ZScream output.
Phase 4d: Floor Objects
Status: Not started Priority: Medium
Problem: Floor objects not rendering.
ZScream Analysis - Floor Object IDs:
Horizontal Floors (Rightwards):
| ID | Tiles | Draw Routine | Description |
|---|---|---|---|
| 0x033 | 16 | RoomDraw_Rightwards4x4_1to16 | Standard 4x4 floor |
| 0x034 | 1 | RoomDraw_Rightwards1x1Solid_1to16_plus3 | Solid floor with perimeter |
| 0x0B2 | 16 | RoomDraw_Rightwards4x4_1to16 | 4x4 floor variant |
| 0x0B3-0x0B4 | 1 | RoomDraw_RightwardsHasEdge1x1_1to16_plus2 | Edge floors |
| 0x0BA | 16 | RoomDraw_Rightwards4x4_1to16 | 4x4 floor variant |
Vertical Floors (Downwards):
| ID | Tiles | Draw Routine | Description |
|---|---|---|---|
| 0x070 | 16 | RoomDraw_DownwardsFloor4x4_1to16 | Standard 4x4 floor |
| 0x071 | 1 | RoomDraw_Downwards1x1Solid_1to16_plus3 | Solid floor with perimeter |
| 0x094 | 16 | RoomDraw_DownwardsFloor4x4_1to16 | 4x4 floor variant |
| 0x08D-0x08E | 1 | RoomDraw_DownwardsEdge1x1_1to16 | Edge floors |
Special Floors (SuperSquare patterns):
| ID | Tiles | Draw Routine | Category |
|---|---|---|---|
| 0x0C3 | 9 | RoomDraw_3x3FloorIn4x4SuperSquare | Pits, MetaLayer |
| 0x0C4-0x0CA | 16 | RoomDraw_4x4FloorIn4x4SuperSquare | Various |
| 0x0DF | 16 | RoomDraw_4x4FloorIn4x4SuperSquare | Spikes |
| 0x212 | 9 | RoomDraw_RupeeFloor | Secrets |
| 0x247 | 16 | RoomDraw_BombableFloor | Pits, Manipulable |
Layer Assignment:
- Single-layer floors: Drawn to object's assigned layer only
- Both-layer floors (MetaLayer): Objects 0x0C3-0x0E8 drawn to BOTH BG1 and BG2
- Floors typically on BG1 (background), walls on BG2 (foreground)
4x4 Floor Tile Pattern:
[0 ] [1 ] [2 ] [3 ]
[4 ] [5 ] [6 ] [7 ]
[8 ] [9 ] [10] [11]
[12] [13] [14] [15]
BombableFloor Special Pattern (irregular):
[0 ] [4 ] [2 ] [6 ]
[8 ] [12] [10] [14]
[1 ] [5 ] [3 ] [7 ]
[9 ] [13] [11] [15]
Files:
- ZScream:
ZeldaFullEditor/Data/Types/DungeonObjectDraw.cs - ZScream:
ZeldaFullEditor/Data/Types/DungeonObjectTypes.cs
Phase 5: Validation & Lifecycle Fixes
Status: Deferred Priority: Low
From original analysis:
- Object ID validation range (0x3FF -> 0xFFF)
tile_objects_not cleared on reload
Phase 6: Draw Routine Completion
Status: Deferred Priority: Low
From original analysis:
- Complete draw routine registry (routines 17-34 uninitialized)
- Currently reserves 35 routines but only initializes 17
Testing Strategy
Per-phase testing:
- Test specific object types affected by the phase
- Compare against ZScream visual output
- Verify no regressions in previously working objects
Key test rooms:
- Room 0x00: Basic walls
- Rooms with complex wall arrangements
- Agahnim's tower rooms (complex objects)
Reference Files
yaze:
src/zelda3/dungeon/object_drawer.cc- Draw routinessrc/zelda3/dungeon/object_parser.cc- Tile loadingsrc/zelda3/dungeon/room_object.cc- Object decodingdocs/internal/plans/dungeon-object-rendering-fix-plan.md- Original analysis
ZScream (authoritative reference):
ZeldaFullEditor/Data/Types/DungeonObjectDraw.cs- All draw routinesZeldaFullEditor/Data/Types/DungeonObjectTypes.cs- Object definitionsZeldaFullEditor/Data/DungeonObjectData.cs- Tile counts, routine mappingsZeldaFullEditor/Rooms/Room_Object.cs- Object class, diagonal methodsZeldaFullEditor/Rooms/Object_Draw/Subtype2_Multiple.cs- Type 2 corners
Key ZScream Insights
Critical Finding: Column-Major Tile Ordering
ZScream's RoomDraw_RightwardsXbyY and RoomDraw_DownwardsXbyY use column-major tile iteration:
for (int x = 0; x < sizex; x++) { // Outer loop: columns
for (int y = 0; y < sizey; y++) { // Inner loop: rows
draw_tile(tiles[t++], x * 8, y * 8);
}
}
This means for a 2x4 wall:
- Tiles 0-3 go in column 0 (left)
- Tiles 4-7 go in column 1 (right)
Rightwards vs Downwards Difference
The ONLY difference between horizontal and vertical routines is the increment axis:
- Rightwards:
inc = sizex * 8applied to X (repeats horizontally) - Downwards:
inc = sizey * 8applied to Y (repeats vertically)
Layer System
- BG1 = Layer 1 (background/floor)
- BG2 = Layer 2 (foreground/walls)
- Some objects draw to BOTH via
allbgflag