335. 将 PPU 背景视口转换为不透明度掩码
根据当前 PPU 滚动状态组合水平不透明度掩码视口。
第 335 / 356 · tests/chapter_13_scrolling/test_335_ppu_background_viewport_to_opaque_mask.py
待更新文件
emulator/rendering/ppu_background_renderer.py参考
https://www.nesdev.org/wiki/PPU_scrolling
https://www.nesdev.org/wiki/PPU_nametables为什么这看起来与步骤 334 相似
不透明度掩码适配器有意复制了帧缓冲区适配器的寻址结构:
decode the same viewport X
select the same horizontal logical pair
process the same left and right bases
compose using the same viewport X重要的区别在于,每个产生数据的操作都必须使用不透明度掩码路径:
ppu_background_to_opaque_mask()
compose_horizontal_opaque_mask_viewport()它绝不能意外调用
ppu_background_to_framebuffer()
compose_horizontal_framebuffer_viewport()这种有意的复制使两条路径都易于阅读。它们的对等测试可以防止这段小型重复的寻址机制发生偏差。
生成的掩码之后将被精灵优先级和 sprite-zero-hit 检测共用。此步骤只负责构建它,并不集成任何一个消费方。
范围之外
- 帧缓冲区组合
- 与 Console 集成
- 与 sprite-zero-hit 集成
- 垂直像素滚动
- pygame
完整示例实现
# emulator/rendering/ppu_background_renderer.py
# --- NEW BLOCK: COPY FRAMEBUFFER ADDRESSING FOR THE OPACITY-MASK PATH ---
def ppu_background_viewport_to_opaque_mask(
ppu: PPU,
) -> BackgroundOpaqueMask:
viewport_x, _ = decode_background_viewport_position(
temp_vram_addr=ppu.temp_vram_addr,
fine_x=ppu.fine_x,
)
nametable_y = (ppu.temp_vram_addr >> 11) & 1
left_base = BASE_NAMETABLE_ADDR + nametable_y * 0x0800
right_base = left_base + 0x0400
# Same addresses, but call the opacity-mask producer.
left = ppu_background_to_opaque_mask(
ppu,
base_nametable_addr=left_base,
)
right = ppu_background_to_opaque_mask(
ppu,
base_nametable_addr=right_base,
)
# Use the opacity-mask compositor, not the framebuffer compositor.
return compose_horizontal_opaque_mask_viewport(
left=left,
right=right,
viewport_x=viewport_x,
)运行本课
uv run pytest tests/chapter_13_scrolling/test_335_ppu_background_viewport_to_opaque_mask.py -v