Files
yaze/docs/internal/agents/draw_routine_tracker.md

11 KiB
Raw Permalink Blame History

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

  1. Outline matches expected dimensions per ASM calculations
  2. Draw pattern matches visual appearance in original game
  3. Tile ordering correct (column-major vs row-major)
  4. Repetition behavior correct (single draw vs size-based repeat)
  5. BG2 overlay objects visible through BG1 floor
  6. 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

  1. 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.

  2. Dark Room Effect (0x08): Implemented via SDL_SetSurfaceColorMod(surface, 128, 128, 128) which reduces brightness to 50%. Applied after compositing.

  3. 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

  1. Register routine in InitializeDrawRoutines():

    object_to_routine_map_[0x31] = CUSTOM_ROUTINE_ID;
    object_to_routine_map_[0x32] = CUSTOM_ROUTINE_ID;
    
  2. Add draw routine to registry:

    draw_routines_.push_back([](ObjectDrawer* self, ...) {
      self->DrawCustomObject(obj, bg, tiles, state);
    });
    
  3. 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.