199 lines
7.8 KiB
Markdown
199 lines
7.8 KiB
Markdown
# Dungeon Object Rendering Fix Plan
|
|
|
|
## Completed Phases
|
|
|
|
### Phase 1: BG Layer Draw Order - COMPLETED (2025-11-26)
|
|
**File:** `src/app/editor/dungeon/dungeon_canvas_viewer.cc:900-971`
|
|
**Fix:** Swapped draw order - BG2 drawn first (background), then BG1 (foreground with objects)
|
|
**Result:** Objects on BG1 no longer covered by BG2
|
|
|
|
### Phase 2: Wall Rendering Investigation - COMPLETED (2025-11-26)
|
|
**Finding:** Bitmap initialization was the issue, not draw routines
|
|
**Root Cause:** Test code was creating bitmap with `{0}` which only allocated 1 byte instead of 262144
|
|
**Verification:** Created ROM-dependent integration tests:
|
|
- `test/integration/zelda3/dungeon_graphics_transparency_test.cc`
|
|
- All 5 tests pass confirming:
|
|
- Graphics buffer has 13% transparent pixels
|
|
- Room graphics buffer has 31.9% transparent pixels
|
|
- Wall objects load 8 tiles each correctly
|
|
- BG1 has 24,000 non-zero pixels after object drawing
|
|
|
|
**Wall tiles confirmed working:** 0x090, 0x092, 0x093, 0x096, 0x098, 0x099, 0x0A2, 0x0A4, 0x0A5, 0x0AC, 0x0AD
|
|
|
|
### Phase 3: Subtype1 Tile Count Lookup Table - COMPLETED (2025-11-26)
|
|
**File:** `src/zelda3/dungeon/object_parser.cc:18-57`
|
|
**Fix:** Added `kSubtype1TileLengths[0xF8]` lookup table from ZScream's DungeonObjectData.cs
|
|
**Changes:**
|
|
- Added 248-entry tile count lookup table for Subtype 1 objects
|
|
- Modified `GetSubtype1TileCount()` helper function to use lookup table
|
|
- Updated `GetObjectSubtype()` and `ParseSubtype1()` to use dynamic tile counts
|
|
- Objects now load correct number of tiles (e.g., 0xC1 = 68 tiles, 0x33 = 16 tiles)
|
|
|
|
**Source:** [ZScream DungeonObjectData.cs](https://github.com/Zarby89/ZScreamDungeon)
|
|
|
|
## All Critical Phases Complete
|
|
|
|
**Root Cause Summary**: Multiple issues - layer draw order (FIXED), bitmap sizing (FIXED), tile counts (FIXED).
|
|
|
|
## Critical Findings
|
|
|
|
### Finding 1: Hardcoded Tile Count (ROOT CAUSE)
|
|
- **Location**: `src/zelda3/dungeon/object_parser.cc:141,160,178`
|
|
- **Issue**: `ReadTileData(tile_data_ptr, 8)` always reads 8 tiles
|
|
- **Impact**:
|
|
- Simple objects (walls: 8 tiles) render correctly
|
|
- Medium objects (carpets: 16 tiles) render incomplete
|
|
- Complex objects (Agahnim's altar: 84 tiles) severely broken
|
|
- **Fix**: Use ZScream's `subtype1Lengths[]` lookup table
|
|
|
|
### Finding 2: Type 2/Type 3 Boundary Collision
|
|
- **Location**: `src/zelda3/dungeon/room_object.cc:184-190, 204-208`
|
|
- **Issue**: Type 2 objects with Y positions 3,7,11,...,63 encode to `b3 >= 0xF8`, triggering incorrect Type 3 decoding
|
|
- **Impact**: 512 object placements affected
|
|
|
|
### Finding 3: Type 2 Subtype Index Mask
|
|
- **Location**: `src/zelda3/dungeon/object_parser.cc:77, 147-148`
|
|
- **Issue**: Uses mask `0x7F` for 256 IDs, causing IDs 0x180-0x1FF to alias to 0x100-0x17F
|
|
- **Fix**: Use `object_id & 0xFF` or `object_id - 0x100`
|
|
|
|
### Finding 4: Type 3 Subtype Heuristic
|
|
- **Location**: `src/zelda3/dungeon/room_object.cc:18-28, 74`
|
|
- **Issue**: `GetSubtypeTable()` uses `id_ >= 0x200` but Type 3 IDs are 0xF00-0xFFF
|
|
- **Fix**: Change to `id_ >= 0xF00`
|
|
|
|
### Finding 5: Object ID Validation Range
|
|
- **Location**: `src/zelda3/dungeon/room.cc:966`
|
|
- **Issue**: Validates `r.id_ <= 0x3FF` but decoder can produce IDs up to 0xFFF
|
|
- **Fix**: Change to `r.id_ <= 0xFFF`
|
|
|
|
### Finding 6: tile_objects_ Not Cleared on Reload
|
|
- **Location**: `src/zelda3/dungeon/room.cc:908`
|
|
- **Issue**: Calling LoadObjects() twice causes object duplication
|
|
- **Fix**: Add `tile_objects_.clear()` at start of LoadObjects()
|
|
|
|
### Finding 7: Incomplete Draw Routine Registry
|
|
- **Location**: `src/zelda3/dungeon/object_drawer.cc:170`
|
|
- **Issue**: Reserves 35 routines but only initializes 17 (indices 0-16)
|
|
- **Impact**: Object IDs mapping to routines 17-34 fallback to 1x1 drawing
|
|
|
|
## Implementation Plan
|
|
|
|
### Phase 1: Fix BG Layer Draw Order (CRITICAL - DO FIRST)
|
|
|
|
**File:** `src/app/editor/dungeon/dungeon_canvas_viewer.cc`
|
|
**Location:** `DrawRoomBackgroundLayers()` (lines 900-968)
|
|
|
|
**Problem:** BG1 is drawn first, then BG2 is drawn ON TOP with 255 alpha, covering BG1 content.
|
|
|
|
**Fix:** Swap the draw order - draw BG2 first (background), then BG1 (foreground):
|
|
|
|
```cpp
|
|
void DungeonCanvasViewer::DrawRoomBackgroundLayers(int room_id) {
|
|
// ... validation code ...
|
|
|
|
// Draw BG2 FIRST (background layer - underneath)
|
|
if (layer_settings.bg2_visible && bg2_bitmap.is_active() ...) {
|
|
// ... existing BG2 draw code ...
|
|
}
|
|
|
|
// Draw BG1 SECOND (foreground layer - on top)
|
|
if (layer_settings.bg1_visible && bg1_bitmap.is_active() ...) {
|
|
// ... existing BG1 draw code ...
|
|
}
|
|
}
|
|
```
|
|
|
|
### Phase 2: Investigate North/South Wall Draw Routines
|
|
|
|
**Observation:** Left/right walls (vertical, Downwards routines 0x60+) work, but up/down walls (horizontal, Rightwards routines 0x00-0x0B) don't.
|
|
|
|
**Files to check:**
|
|
- `src/zelda3/dungeon/object_drawer.cc` - Rightwards draw routines
|
|
- Object-to-routine mapping for wall IDs
|
|
|
|
**Wall Object IDs:**
|
|
- 0x00: Ceiling (routine 0 - DrawRightwards2x2_1to15or32)
|
|
- 0x01-0x02: North walls (routine 1 - DrawRightwards2x4_1to15or26)
|
|
- 0x03-0x04: South walls (routine 2 - DrawRightwards2x4spaced4_1to16)
|
|
- 0x60+: East/West walls (Downwards routines - WORKING)
|
|
|
|
**Possible issues:**
|
|
1. Object tiles not being loaded for Subtype1 0x00-0x0B
|
|
2. Draw routines have coordinate bugs
|
|
3. Objects assigned to wrong layer (BG2 instead of BG1)
|
|
|
|
### Phase 3: Subtype1 Tile Count Fix
|
|
|
|
**Files to modify:**
|
|
- `src/zelda3/dungeon/object_parser.cc`
|
|
|
|
Add ZScream's tile count lookup table:
|
|
```cpp
|
|
static constexpr uint8_t kSubtype1TileLengths[0xF8] = {
|
|
04,08,08,08,08,08,08,04,04,05,05,05,05,05,05,05,
|
|
05,05,05,05,05,05,05,05,05,05,05,05,05,05,05,05,
|
|
05,09,03,03,03,03,03,03,03,03,03,03,03,03,03,06,
|
|
06,01,01,16,01,01,16,16,06,08,12,12,04,08,04,03,
|
|
03,03,03,03,03,03,03,00,00,08,08,04,09,16,16,16,
|
|
01,18,18,04,01,08,08,01,01,01,01,18,18,15,04,03,
|
|
04,08,08,08,08,08,08,04,04,03,01,01,06,06,01,01,
|
|
16,01,01,16,16,08,16,16,04,01,01,04,01,04,01,08,
|
|
08,12,12,12,12,18,18,08,12,04,03,03,03,01,01,06,
|
|
08,08,04,04,16,04,04,01,01,01,01,01,01,01,01,01,
|
|
01,01,01,01,24,01,01,01,01,01,01,01,01,01,01,01,
|
|
01,01,16,03,03,08,08,08,04,04,16,04,04,04,01,01,
|
|
01,68,01,01,08,08,08,08,08,08,08,01,01,28,28,01,
|
|
01,08,08,00,00,00,00,01,08,08,08,08,21,16,04,08,
|
|
08,08,08,08,08,08,08,08,08,01,01,01,01,01,01,01,
|
|
01,01,01,01,01,01,01,01
|
|
};
|
|
```
|
|
|
|
### Phase 4: Object Type Detection Fixes (Deferred)
|
|
|
|
- Type 2/Type 3 boundary collision
|
|
- Type 2 index mask (0x7F vs 0xFF)
|
|
- Type 3 detection heuristic (0x200 vs 0xF00)
|
|
|
|
### Phase 5: Validation & Lifecycle Fixes (Deferred)
|
|
|
|
- Object ID validation range (0x3FF → 0xFFF)
|
|
- tile_objects_ not cleared on reload
|
|
|
|
### Phase 6: Draw Routine Completion (Deferred)
|
|
|
|
- Complete draw routine registry (routines 17-34)
|
|
|
|
## Testing Strategy
|
|
|
|
### Test Objects by Complexity
|
|
| Object ID | Tiles | Description | Expected Result |
|
|
|-----------|-------|-------------|-----------------|
|
|
| 0x000 | 4 | Ceiling | Works |
|
|
| 0x001 | 8 | Wall (north) | Works |
|
|
| 0x033 | 16 | Carpet | Should render fully |
|
|
| 0x0C1 | 68 | Chest platform | Should render fully |
|
|
| 0x215 | 80 | Prison cell | Should render fully |
|
|
|
|
### Rooms to Test
|
|
- Room 0x00 (Simple walls)
|
|
- Room with carpets
|
|
- Agahnim's tower rooms
|
|
- Fortune teller room (uses 242-tile objects)
|
|
|
|
## Files to Read Before Implementation
|
|
|
|
1. `/Users/scawful/Code/yaze/src/zelda3/dungeon/object_parser.cc` - **PRIMARY** - Find the hardcoded `8` in tile loading
|
|
2. `/Users/scawful/Code/ZScreamDungeon/ZeldaFullEditor/Data/DungeonObjectData.cs` - Verify tile table values
|
|
|
|
## Estimated Impact
|
|
|
|
- **Phase 1 alone** should fix ~90% of broken Subtype1 objects (most common type)
|
|
- Simple walls/floors already work (they use 4-8 tiles)
|
|
- Carpets (16 tiles), chest platforms (68 tiles), and complex objects will now render fully
|
|
|
|
## Risk Assessment
|
|
|
|
- **Low Risk**: Adding a lookup table is additive, doesn't change existing logic flow
|
|
- **Mitigation**: Compare visual output against ZScream for a few test rooms
|