Files
yaze/docs/internal/plans/dungeon-object-rendering-phase4-handoff.md

257 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 4: Dungeon Object Rendering - 0x80-0xFF Mapping Fixes
## Status: Steps 1, 2, 3, 4 Complete (2024-12-04)
### Completed
- **Step 1**: Quick mapping fixes (6 corrections using existing routines)
- **Step 2**: Simple variant routines (10 new routines, IDs 65-74)
- **Step 3**: Diagonal ceiling routines (4 new routines, IDs 75-78, covering 12 objects)
- **Step 4**: SuperSquare routines (9 new routines, IDs 56-64)
### Remaining
- **Step 5**: Special/logic-dependent routines (6 new routines)
### Test Updates Required
Some unit tests assert old (incorrect) mappings and need to be updated:
- `test/unit/zelda3/dungeon/draw_routine_mapping_test.cc`
- `test/unit/zelda3/dungeon/object_drawing_comprehensive_test.cc`
---
## Context
This document provides a handoff plan for completing Phase 4 of the dungeon object rendering system fixes. Phases 1-3 have been completed:
- **Phase 1**: Parser fixes (Type 2 index mask, routine pointer offset, removed fake mappings)
- **Phase 2**: Dimension calculation fixes (dual-nibble bug, diagonal wall off-by-one)
- **Phase 3**: Routine implementations for 0x40-0x7F range (13 new routines added)
## Phase 4 Scope
Fix object-to-routine mappings for the 0x80-0xFF range. The audit identified a **75.8% error rate** (97/128 objects with wrong mappings).
## Reference Files
- **Assembly Ground Truth**: `assets/asm/usdasm/bank_01.asm` (lines 397-516 for 0x80-0xF7)
- **Implementation File**: `src/zelda3/dungeon/object_drawer.cc` (lines 330-479)
- **Header File**: `src/zelda3/dungeon/object_drawer.h`
## Strategy
### Tier 1: Easy Fixes (Use Existing Routines)
These objects can be fixed by simply changing the routine ID to an existing routine:
| Object | Current | Correct Routine | Assembly Reference |
|--------|---------|-----------------|-------------------|
| 0x81-0x84 | 30 (4x3) | NEW: DownwardsDecor3x4spaced2 | `RoomDraw_DownwardsDecor3x4spaced2_1to16` |
| 0x88 | 30 (4x3) | NEW: DownwardsBigRail3x1_plus5 | `RoomDraw_DownwardsBigRail3x1_1to16plus5` |
| 0x89 | 11 | NEW: DownwardsBlock2x2spaced2 | `RoomDraw_DownwardsBlock2x2spaced2_1to16` |
| 0x8D-0x8E | 25 (1x1) | 13 (DownwardsEdge1x1) | `RoomDraw_DownwardsEdge1x1_1to16` |
| 0x90-0x91 | 8 | 8 (Downwards4x2_1to15or26) | Already correct! |
| 0x92-0x93 | 11 | 7 (Downwards2x2_1to15or32) | `RoomDraw_Downwards2x2_1to15or32` |
| 0x94 | 16 | 43 (DownwardsFloor4x4) | `RoomDraw_DownwardsFloor4x4_1to16` |
| 0xB0-0xB1 | 25 | NEW: RightwardsEdge1x1_plus7 | `RoomDraw_RightwardsEdge1x1_1to16plus7` |
| 0xB6-0xB7 | 8 | 1 (Rightwards2x4_1to15or26) | `RoomDraw_Rightwards2x4_1to15or26` |
| 0xB8-0xB9 | 11 | 0 (Rightwards2x2_1to15or32) | `RoomDraw_Rightwards2x2_1to15or32` |
| 0xBB | 11 | 55 (RightwardsBlock2x2spaced2) | `RoomDraw_RightwardsBlock2x2spaced2_1to16` |
### Tier 2: New Routine Implementations Required
These need new draw routines to be implemented:
#### 2A: Simple Variants (Low Effort)
| Routine Name | Objects | Pattern | Notes |
|-------------|---------|---------|-------|
| `DrawDownwardsDecor3x4spaced2_1to16` | 0x81-0x84 | 3x4 tiles, 6-row spacing | Similar to existing `DrawDownwardsDecor4x4spaced2_1to16` |
| `DrawDownwardsBigRail3x1_1to16plus5` | 0x88 | 3x1 tiles, +5 modifier | Vertical version of existing `DrawRightwardsBigRail1x3_1to16plus5` |
| `DrawDownwardsBlock2x2spaced2_1to16` | 0x89 | 2x2 tiles, 4-row spacing | Vertical version of existing `DrawRightwardsBlock2x2spaced2_1to16` |
| `DrawDownwardsCannonHole3x4_1to16` | 0x85-0x86 | 3x4 cannon hole | Vertical version of existing cannon hole |
| `DrawDownwardsBar2x5_1to16` | 0x8F | 2x5 bar pattern | New pattern |
| `DrawDownwardsPots2x2_1to16` | 0x95 | 2x2 pots | Interactive object |
| `DrawDownwardsHammerPegs2x2_1to16` | 0x96 | 2x2 hammer pegs | Interactive object |
| `DrawRightwardsEdge1x1_1to16plus7` | 0xB0-0xB1 | 1x1 edge, +7 modifier | Similar to existing edge routines |
| `DrawRightwardsPots2x2_1to16` | 0xBC | 2x2 pots | Interactive object |
| `DrawRightwardsHammerPegs2x2_1to16` | 0xBD | 2x2 hammer pegs | Interactive object |
#### 2B: Complex/Special Routines (Higher Effort)
| Routine Name | Objects | Pattern | Notes |
|-------------|---------|---------|-------|
| `DrawDiagonalCeilingTopLeftA` | 0xA0 | Diagonal ceiling variant A | Complex diagonal pattern |
| `DrawDiagonalCeilingBottomLeftA` | 0xA1 | Diagonal ceiling variant A | Complex diagonal pattern |
| `DrawDiagonalCeilingTopRightA` | 0xA2 | Diagonal ceiling variant A | Complex diagonal pattern |
| `DrawDiagonalCeilingBottomRightA` | 0xA3 | Diagonal ceiling variant A | Complex diagonal pattern |
| `DrawDiagonalCeilingTopLeftB` | 0xA5, 0xA9 | Diagonal ceiling variant B | Complex diagonal pattern |
| `DrawDiagonalCeilingBottomLeftB` | 0xA6, 0xAA | Diagonal ceiling variant B | Complex diagonal pattern |
| `DrawDiagonalCeilingTopRightB` | 0xA7, 0xAB | Diagonal ceiling variant B | Complex diagonal pattern |
| `DrawDiagonalCeilingBottomRightB` | 0xA8, 0xAC | Diagonal ceiling variant B | Complex diagonal pattern |
| `DrawBigHole4x4_1to16` | 0xA4 | 4x4 big hole | Special floor cutout |
| `Draw4x4BlocksIn4x4SuperSquare` | 0xC0, 0xC2 | 4x4 in 16x16 super square | Large composite object |
| `Draw3x3FloorIn4x4SuperSquare` | 0xC3, 0xD7 | 3x3 in 16x16 super square | Large composite object |
| `Draw4x4FloorIn4x4SuperSquare` | 0xC5-0xCA, 0xD1-0xD2, 0xD9, 0xDF-0xE8 | 4x4 floor pattern | Most common super square |
| `Draw4x4FloorOneIn4x4SuperSquare` | 0xC4 | Single 4x4 in super square | Variant |
| `Draw4x4FloorTwoIn4x4SuperSquare` | 0xDB | Two 4x4 in super square | Variant |
| `DrawClosedChestPlatform` | 0xC1 | Chest platform (closed) | 68-tile special object |
| `DrawOpenChestPlatform` | 0xDC | Chest platform (open) | State-dependent |
| `DrawMovingWallWest` | 0xCD | Moving wall (west) | Logic-dependent |
| `DrawMovingWallEast` | 0xCE | Moving wall (east) | Logic-dependent |
| `DrawCheckIfWallIsMoved` | 0xD3-0xD6 | Wall movement check | Logic-only, no tiles |
| `DrawWaterOverlayA8x8_1to16` | 0xD8 | Water overlay A | Semi-transparent overlay |
| `DrawWaterOverlayB8x8_1to16` | 0xDA | Water overlay B | Semi-transparent overlay |
| `DrawTableRock4x4_1to16` | 0xDD | Table rock pattern | 4x4 repeating |
| `DrawSpike2x2In4x4SuperSquare` | 0xDE | Spikes in super square | Hazard object |
## Implementation Approach
### Step 1: Quick Wins (30 min)
Fix the easy ID corrections that use existing routines:
- 0x8D-0x8E: Change from 25 to 13
- 0x92-0x93: Change from 11 to 7
- 0x94: Change from 16 to 43
- 0xB6-0xB7: Change from 8 to 1
- 0xB8-0xB9: Change from 11 to 0
- 0xBB: Change from 11 to 55
### Step 2: Add Simple Variant Routines (2-3 hours)
Create the Tier 2A routines by copying existing patterns and adjusting for vertical/horizontal orientation:
```cpp
// Example: DrawDownwardsBlock2x2spaced2_1to16 (mirror of existing horizontal routine)
void ObjectDrawer::DrawDownwardsBlock2x2spaced2_1to16(
const RoomObject& obj, gfx::BackgroundBuffer& bg,
std::span<const gfx::TileInfo> tiles, [[maybe_unused]] const DungeonState* state) {
int size = obj.size_ & 0x0F;
int count = size + 1;
for (int s = 0; s < count; s++) {
if (tiles.size() >= 4) {
int base_y = obj.y_ + (s * 4); // 4-tile Y spacing
WriteTile8(bg, obj.x_, base_y, tiles[0]);
WriteTile8(bg, obj.x_ + 1, base_y, tiles[1]);
WriteTile8(bg, obj.x_, base_y + 1, tiles[2]);
WriteTile8(bg, obj.x_ + 1, base_y + 1, tiles[3]);
}
}
}
```
### Step 3: SuperSquare Routines (4-6 hours)
The `4x4FloorIn4x4SuperSquare` pattern is used by ~20 objects. Understanding it unlocks many fixes:
```
SuperSquare = 16x16 tile area (128x128 pixels)
- Draws 4x4 tile patterns at each corner position
- Some variants fill differently (3x3, single, two, etc.)
```
Analyze the assembly at `RoomDraw_4x4FloorIn4x4SuperSquare` to understand the exact tile placement.
### Step 4: Diagonal Ceiling Routines (2-3 hours)
8 diagonal ceiling variants (A and B × 4 corners). These are similar to existing diagonal wall routines but for ceiling tiles.
### Step 5: Logic-Dependent Objects (1-2 hours)
- `DrawMovingWallWest/East`: Check wall state before drawing
- `DrawCheckIfWallIsMoved`: Logic-only, maps to "Nothing" for rendering
- `DrawClosedChestPlatform/OpenChestPlatform`: Check chest state
## Testing Strategy
1. **Visual Verification**: Load a ROM and visually compare dungeon rooms against screenshots or another editor (ZScream, Hyrule Magic)
2. **Target Rooms for Testing**:
- Hyrule Castle rooms (variety of floor patterns)
- Eastern Palace (diagonal ceilings at 0xA0-0xAC)
- Thieves' Town (moving walls at 0xCD-0xCE)
- Ice Palace (water overlays at 0xD8, 0xDA)
3. **Object Selection Test**: After rendering fixes, verify objects can be clicked/selected properly
## Current Routine Registry
As of Phase 4 Steps 1, 2, 3, 4 completion, we have 79 routines (0-78):
| ID Range | Description |
|----------|-------------|
| 0-6 | Rightwards basic patterns |
| 7-15 | Downwards basic patterns |
| 16 | Rightwards 4x4 |
| 17-18 | Diagonal BothBG |
| 19-39 | Various patterns (corners, edges, chests, etc.) |
| 40-42 | Rightwards 4x2, Decor4x2spaced8, CannonHole4x3 |
| 43-50 | New vertical routines (Phase 3.2) |
| 51-55 | New horizontal routines (Phase 3.3) |
| **56-64** | **Phase 4 SuperSquare routines** |
| **65-74** | **Phase 4 Step 2 simple variant routines** |
| **75-78** | **Phase 4 Step 3 diagonal ceiling routines** |
### Phase 4 New Routines (IDs 56-78)
**SuperSquare Routines (IDs 56-64)**:
| ID | Routine Name | Objects |
|----|--------------|---------|
| 56 | Draw4x4BlocksIn4x4SuperSquare | 0xC0, 0xC2 |
| 57 | Draw3x3FloorIn4x4SuperSquare | 0xC3, 0xD7 |
| 58 | Draw4x4FloorIn4x4SuperSquare | 0xC5-0xCA, 0xD1-0xD2, 0xD9, 0xDF-0xE8 |
| 59 | Draw4x4FloorOneIn4x4SuperSquare | 0xC4 |
| 60 | Draw4x4FloorTwoIn4x4SuperSquare | 0xDB |
| 61 | DrawBigHole4x4_1to16 | 0xA4 |
| 62 | DrawSpike2x2In4x4SuperSquare | 0xDE |
| 63 | DrawTableRock4x4_1to16 | 0xDD |
| 64 | DrawWaterOverlay8x8_1to16 | 0xD8, 0xDA |
**Step 2 Simple Variant Routines (IDs 65-74)**:
| ID | Routine Name | Objects |
|----|--------------|---------|
| 65 | DrawDownwardsDecor3x4spaced2_1to16 | 0x81-0x84 |
| 66 | DrawDownwardsBigRail3x1_1to16plus5 | 0x88 |
| 67 | DrawDownwardsBlock2x2spaced2_1to16 | 0x89 |
| 68 | DrawDownwardsCannonHole3x6_1to16 | 0x85-0x86 |
| 69 | DrawDownwardsBar2x3_1to16 | 0x8F |
| 70 | DrawDownwardsPots2x2_1to16 | 0x95 |
| 71 | DrawDownwardsHammerPegs2x2_1to16 | 0x96 |
| 72 | DrawRightwardsEdge1x1_1to16plus7 | 0xB0-0xB1 |
| 73 | DrawRightwardsPots2x2_1to16 | 0xBC |
| 74 | DrawRightwardsHammerPegs2x2_1to16 | 0xBD |
**Step 3 Diagonal Ceiling Routines (IDs 75-78)**:
| ID | Routine Name | Objects |
|----|--------------|---------|
| 75 | DrawDiagonalCeilingTopLeft | 0xA0, 0xA5, 0xA9 |
| 76 | DrawDiagonalCeilingBottomLeft | 0xA1, 0xA6, 0xAA |
| 77 | DrawDiagonalCeilingTopRight | 0xA2, 0xA7, 0xAB |
| 78 | DrawDiagonalCeilingBottomRight | 0xA3, 0xA8, 0xAC |
New routines should continue from ID 79.
## Files to Modify
1. **`src/zelda3/dungeon/object_drawer.h`**
- Add declarations for new draw routines
2. **`src/zelda3/dungeon/object_drawer.cc`**
- Update `object_to_routine_map_` entries (lines 330-479)
- Add new routine implementations
- Register new routines in `InitializeDrawRoutines()` (update reserve count)
3. **`src/zelda3/dungeon/object_dimensions.cc`** (optional)
- Update dimension calculations if needed for new patterns
## Priority Order
1. **Highest**: Fix existing routine ID mappings (Step 1)
2. **High**: Implement `Draw4x4FloorIn4x4SuperSquare` (unlocks ~20 objects)
3. **Medium**: Add simple variant routines (Step 2)
4. **Medium**: Diagonal ceiling routines (Step 4)
5. **Lower**: Logic-dependent and special objects (Step 5)
## Notes
- The audit found that objects 0x97-0x9F, 0xAD-0xAF, 0xBE-0xBF, 0xE9-0xF7 correctly map to `RoomDraw_Nothing_B` (routine 38)
- Some objects like 0xD3-0xD6 (`CheckIfWallIsMoved`) are logic-only and don't render tiles
- Interactive objects (pots, hammer pegs) may need additional state handling