Build an opacity mask from one selected logical PPU nametable.
Lesson 333 of 356 · tests/chapter_13_scrolling/test_333_ppu_logical_nametable_to_opaque_mask.py
File to update
emulator/rendering/ppu_background_renderer.py
Reference
https://www.nesdev.org/wiki/PPU_nametables
Why this step exists
The existing helper builds the mask used by sprite priority and sprite-zero-hit detection, but originally reads only logical nametable $2000. Horizontal scrolling also needs the mask belonging to the adjacent logical nametable.
Compatibility
Omitting base_nametable_addr still selects $2000, so existing Console and sprite-zero hit callers remain valid until viewport integration is performed deliberately.
Opacity inputs
960 tile IDs from the selected logical nametable
the background pattern table selected by PPUCTRL bit 4
Opacity does not use attribute bytes, palette RAM, or final RGB colors.
Out of scope
composing the left and right masks
framebuffer rendering
Console integration
sprite-zero-hit viewport integration
vertical scrolling
Complete example implementation
# emulator/rendering/ppu_background_renderer.pydefppu_background_to_opaque_mask(
ppu: PPU,
# --- NEW LINE: OPTIONAL LOGICAL NAMETABLE SELECTION ---
base_nametable_addr: int = BASE_NAMETABLE_ADDR,
) -> BackgroundOpaqueMask:
# --- NEW BLOCK: REJECT NON-NAMETABLE BASE ADDRESSES ---if base_nametable_addr notin LOGICAL_NAMETABLE_BASE_ADDRS:
raise ValueError(
"Logical nametable base address must be $2000, $2400, $2800, $2C00"
)
nametable_bytes = bytes(
# --- UPDATED LINE: READ FROM THE SELECTED NAMETABLE ---
ppu.ppu_bus.read(base_nametable_addr + offset)
for offset inrange(NAMETABLE_SIZE)
)
...
# Everything remains the same below this point.
Run this lesson
uv run pytest tests/chapter_13_scrolling/test_333_ppu_logical_nametable_to_opaque_mask.py -v