# 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:** 1. Test specific object types affected by the phase 2. Compare against ZScream visual output 3. 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 routines - `src/zelda3/dungeon/object_parser.cc` - Tile loading - `src/zelda3/dungeon/room_object.cc` - Object decoding - `docs/internal/plans/dungeon-object-rendering-fix-plan.md` - Original analysis **ZScream (authoritative reference):** - `ZeldaFullEditor/Data/Types/DungeonObjectDraw.cs` - All draw routines - `ZeldaFullEditor/Data/Types/DungeonObjectTypes.cs` - Object definitions - `ZeldaFullEditor/Data/DungeonObjectData.cs` - Tile counts, routine mappings - `ZeldaFullEditor/Rooms/Room_Object.cs` - Object class, diagonal methods - `ZeldaFullEditor/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: ```csharp 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 * 8` applied to X (repeats horizontally) - **Downwards:** `inc = sizey * 8` applied to Y (repeats vertically) ### Layer System - BG1 = Layer 1 (background/floor) - BG2 = Layer 2 (foreground/walls) - Some objects draw to BOTH via `allbg` flag