11 KiB
Dungeon Draw Routine Tracker
Status: Active
Owner: dungeon-rendering-specialist
Created: 2025-12-07
Last Reviewed: 2025-12-09
Next Review: 2025-12-23
Summary
This document is the single source of truth for dungeon object draw routine implementation status. It consolidates information from previous handoff documents and provides a comprehensive reference for fixing remaining issues.
Recent Changes (2025-12-09)
| Change | Details |
|---|---|
| Unified draw routine registry | Created DrawRoutineRegistry singleton for ObjectDrawer/ObjectGeometry parity |
| BG1 mask rectangle API | Added GeometryBounds::GetBG1MaskRect() and RequiresBG1Mask() for 94 affected rooms |
| Fixed vertical rails 0x8A-0x8C | Applied CORNER+MIDDLE+END pattern matching horizontal rail 0x22 |
| Custom objects 0x31/0x32 | Registered with routine 130 for Oracle of Secrets minecart tracks |
| Selection bounds for diagonals | Added selection_bounds field for tighter hit testing on 0xA0-0xA3 |
| Audited 0x233 staircase | Confirmed 32x32 (4x4 tile) dimensions correct per ASM |
Previous Changes (2025-12-07)
| Change | Details |
|---|---|
| Fixed routine 16 dimensions | DrawRightwards4x4_1to16 now correctly calculates width = 32 * count based on size |
| Added BG2 mask propagation logging | Debug output shows when Layer 1 objects trigger floor masking |
| BG2 masking research complete | 94 rooms affected, fix implemented in MarkBG1Transparent |
Completed Fixes
| Object ID | Name | Issue | Fix Applied |
|---|---|---|---|
| 0x5E | Block | Inverted tile ordering | Fixed column-major order |
| 0x5D/0x88 | Thick Rails | Repeated edges | Fixed cap-middle-cap pattern |
| 0xF99 | Chest | Repeated based on size | Changed to DrawSingle2x2 |
| 0xFB1 | Big Chest | Repeated based on size | Changed to DrawSingle4x3 |
| 0xF92 | Blue Rupees | Not correct at all | Implemented DrawRupeeFloor per ASM |
| 0xFED | Water Grate | Wrong outline, repeated | Changed to DrawSingle4x3 |
| 0x3A | Wall Decors | Spacing wrong (6 tiles) | Fixed to 8 tiles per ASM |
| 0x39/0x3D | Pillars | Spacing wrong (6 tiles) | Fixed to 4 tiles per ASM |
| 0xFEB | Large Decor | Outline too small | Fixed to 64x64 (4x4 tile16s) |
| 0x138-0x13B | Spiral Stairs | Wrong 4x4 pattern | Fixed to 4x3 per ASM |
| 0xA0-0xAC | Diagonal Ceilings | Vertical line instead of triangle | Fixed triangle fill pattern |
| 0xC0/0xC2 etc | SuperSquare | Fixed 32x32 dimensions | Now uses size parameter |
| 0xFE6 | Pit | Should not repeat | Uses DrawActual4x4 (32x32, no repeat) |
| 0x55-0x56 | Wall Torches | Wrong pattern | Fixed to 1x8 column with 12-tile spacing |
| 0x22 | Small Rails | Internal parts repeat | Now CORNER+MIDDLE*count+END pattern |
| 0x23-0x2E | Carpet Trim | Wrong pattern | Now CORNER+MIDDLE*count+END pattern |
| 0x033 | Floor 4x4 | Wrong BG2 mask size | Fixed dimension to use size parameter |
| 0x12D-0x12F | InterRoom Fat Stairs | Wrong dimensions (32x24) | Fixed to 32x32 (4x4 tiles) |
| 0x130-0x133 | Auto Stairs | Wrong dimensions (32x24) | Fixed to 32x32 (4x4 tiles) |
| 0xF9E-0xFA9 | Straight InterRoom Stairs | Wrong dimensions (32x24) | Fixed to 32x32 (4x4 tiles) |
| 0x8A-0x8C | Vertical Rails | Using wrong horizontal routine | Fixed CORNER+MIDDLE+END pattern |
| 0x31/0x32 | Custom Objects | Not registered in draw routine map | Registered with routine 130 |
| 0x233 | AutoStairsSouthMergedLayer | Need audit | Confirmed 32x32 (4x4 tiles) correct |
| 0xDC | OpenChestPlatform | Layer check missing | Added layer handling documentation |
In Progress / Known Issues
| Object ID | Name | Issue | Status |
|---|---|---|---|
| 0x00 | Ceiling | Outline should be like 0xC0 | Needs different dimension calc |
| 0xC0 | Large Ceiling | SuperSquare routine issues | Needs debug |
| 0x22 vs 0x8A-0x8E | Rails | Horizontal fixed, vertical needs match | Medium priority |
| 0xA0-0xA3 | Diagonal Ceilings | Outline too large for selection | May need UI-level fix |
| 0x3D | Torches | Top half draws pegs | ROM tile data issue |
| 0x95/0x96 | Vertical Pegs | Outline appears square | May be UI issue |
Pending Fixes
| Object ID | Name | Issue | Priority |
|---|---|---|---|
| Pit Edges | Various | Single tile thin based on direction | Low |
Note: Staircase objects 0x12D-0x137 (Fat/Auto Stairs), Type 3 stairs (0xF9E-0xFA9), and 0x233 (AutoStairsSouthMergedLayer) have been audited as of 2025-12-09. All use 32x32 (4x4 tile) dimensions matching the ASM.
Size Calculation Formulas (from ASM)
| Routine | Formula |
|---|---|
| GetSize_1to16 | count = (size & 0x0F) + 1 |
| GetSize_1to15or26 | count = size; if 0, count = 26 |
| GetSize_1to15or32 | count = size; if 0, count = 32 |
| GetSize_1to16_timesA | count = (size & 0x0F + 1) * A |
| SuperSquare | size_x = (size & 0x0F) + 1; size_y = ((size >> 4) & 0x0F) + 1 |
Draw Routine Architecture
Routine ID Ranges
- 0-55: Basic patterns (2x2, 4x4, edges, etc.)
- 56-64: SuperSquare patterns
- 65-82: Decorations, pots, pegs, platforms
- 83-91: Stairs
- 92-115: Special/interactive objects
New Routines Added (Phase 2)
- Routine 113: DrawSingle4x4 - Single 4x4 block, no repetition
- Routine 114: DrawSingle4x3 - Single 4x3 block, no repetition
- Routine 115: DrawRupeeFloor - Special 6x8 pattern with gaps
Tile Ordering
Most routines use COLUMN-MAJOR order: tiles advance down each column, then right to next column.
Rail Pattern Structure
[CORNER tile 0] -> [MIDDLE tile 1 × count] -> [END tile 2]
BG2 Masking (Layer Compositing)
Overview
94 rooms have Layer 1 (BG2) overlay objects that need to show through BG1 floor tiles.
Implementation
When a Layer 1 object is drawn to BG2 buffer, MarkBG1Transparent is called to mark the corresponding BG1 pixels as transparent (255), allowing BG2 content to show through during compositing.
Affected Objects (Example: Room 001)
| Object ID | Position | Size | Dimensions |
|---|---|---|---|
| 0x033 | (22,13) | 4 | 160×32 px (5 × 4x4 blocks) |
| 0x034 | (23,16) | 14 | 144×8 px (18 × 1x1 tiles) |
| 0x071 | (22,13) | 0 | 8×32 px (1×4 tiles) |
| 0x038 | (24,12) | 1 | 48×24 px (2 statues) |
| 0x13B | (30,10) | 0 | 32×24 px (spiral stairs) |
Testing
Use scripts/analyze_room.py to identify Layer 1 objects:
python3 scripts/analyze_room.py --rom roms/alttp_vanilla.sfc 1 --compositing
python3 scripts/analyze_room.py --rom roms/alttp_vanilla.sfc --list-bg2
Files Reference
| File | Purpose |
|---|---|
src/zelda3/dungeon/object_drawer.cc |
Main draw routines and ID mapping |
src/zelda3/dungeon/object_drawer.h |
Draw routine declarations |
src/zelda3/dungeon/draw_routines/special_routines.cc |
Complex special routines |
src/zelda3/dungeon/room_layer_manager.cc |
Layer compositing |
assets/asm/usdasm/bank_01.asm |
Reference ASM disassembly |
scripts/analyze_room.py |
Room object analysis tool |
Validation Criteria
- Outline matches expected dimensions per ASM calculations
- Draw pattern matches visual appearance in original game
- Tile ordering correct (column-major vs row-major)
- Repetition behavior correct (single draw vs size-based repeat)
- BG2 overlay objects visible through BG1 floor
- No build errors after changes
Exit Criteria
- All high-priority issues resolved
- Medium-priority issues documented with investigation notes
- BG2 masking working for all 94 affected rooms
- Staircase audit complete (0x12D-0x233)
- No regression in existing working routines
Layer Merge Type Effects
Current Implementation Status
| Merge ID | Name | Effect | Status |
|---|---|---|---|
| 0x00 | Off | BG2 visible, no effects | Working |
| 0x01 | Parallax | BG2 visible, parallax scroll | Not implemented |
| 0x02 | Dark | BG2 translucent blend | Simplified (no true blend) |
| 0x03 | On top | BG2 hidden but in subscreen | Partial |
| 0x04 | Translucent | BG2 translucent | Simplified |
| 0x05 | Addition | Additive blending | Simplified |
| 0x06 | Normal | Standard dungeon | Working |
| 0x07 | Transparent | Water/fog effect | Simplified |
| 0x08 | Dark room | Master brightness 50% | Working (SDL color mod) |
Known Limitations
-
Translucent Blending (0x02, 0x04, 0x05, 0x07): Currently uses threshold-based pixel copying instead of true alpha blending. True blending would require RGB palette lookups which is expensive for indexed color mode.
-
Dark Room Effect (0x08): Implemented via
SDL_SetSurfaceColorMod(surface, 128, 128, 128)which reduces brightness to 50%. Applied after compositing. -
Parallax Scrolling (0x01): Not implemented - would require separate layer offset during rendering.
Implementation Details
Dark Room (0x08):
// In room_layer_manager.cc CompositeToOutput()
if (current_merge_type_id_ == 0x08) {
SDL_SetSurfaceColorMod(output.surface(), 128, 128, 128);
}
Translucent Layers:
// In ApplyLayerMerging()
if (merge_type.Layer2Translucent) {
SetLayerBlendMode(LayerType::BG2_Layout, LayerBlendMode::Translucent);
SetLayerBlendMode(LayerType::BG2_Objects, LayerBlendMode::Translucent);
}
Future Improvements
- Implement true alpha blending for translucent modes (requires RGB conversion)
- Add parallax scroll offset support for merge type 0x01
- Consider per-scanline HDMA effects simulation
Custom Objects (Oracle of Secrets)
Status: Not Working
Custom objects (IDs 0x31, 0x32) use external binary files instead of ROM tile data. These are used for minecart tracks and custom furniture in Oracle of Secrets.
Issues
| Issue | Description |
|---|---|
| Routine not registered | 0x31/0x32 have no entry in object_to_routine_map_ |
| DrawCustomObject incomplete | Routine exists but isn't called |
| Previews don't work | Object selector can't preview custom objects |
Required Fixes
-
Register routine in InitializeDrawRoutines():
object_to_routine_map_[0x31] = CUSTOM_ROUTINE_ID; object_to_routine_map_[0x32] = CUSTOM_ROUTINE_ID; -
Add draw routine to registry:
draw_routines_.push_back([](ObjectDrawer* self, ...) { self->DrawCustomObject(obj, bg, tiles, state); }); -
Ensure CustomObjectManager initialized before drawing
Project Configuration
[files]
custom_objects_folder=/path/to/Dungeons/Objects/Data
[feature_flags]
enable_custom_objects=true
Full Documentation
See HANDOFF_CUSTOM_OBJECTS.md for complete details.
Related Documentation
dungeon-object-rendering-spec.md- ASM-based rendering specificationHANDOFF_BG2_MASKING_FIX.md- BG2 masking implementation detailsHANDOFF_CUSTOM_OBJECTS.md- Custom objects systemdungeon-layer-compositing-research.md- Layer system researchcomposite-layer-system.md- Layer compositing implementation details