backend-infra-engineer: Post v0.3.9-hotfix7 snapshot (build cleanup)
This commit is contained in:
@@ -0,0 +1,198 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user