329. Decodificar la posición del viewport de fondo
Decodificar una posición de viewport de fondo simplificada a partir del estado de scrolling del PPU.
Lección 329 de 356 · tests/chapter_13_scrolling/test_329_decode_background_viewport_position.py
Archivo a crear
emulator/rendering/background_viewport.pyDocumentación de referencia
https://www.nesdev.org/wiki/PPU_scrolling
https://www.nesdev.org/wiki/PPU_scrolling#PPU_internal_registers
https://www.nesdev.org/wiki/PPU_scrolling#During_renderingPor qué existe este paso
El PPU almacena el scrolling como campos de hardware empaquetados en lugar de coordenadas de píxel listas para usar. El renderizado necesita una posición simple de la esquina superior izquierda del viewport, así que este paso decodifica:
temp_vram_addr (t): yyy NN YYYYY XXXXX
fine_x (x): xxxDonde
XXXXX -> coarse X tile position, 5 bits
YYYYY -> coarse Y tile position, 5 bits
NN -> logical nametable X/Y selection
yyy -> fine Y pixel position, 3 bits
xxx -> fine X pixel position, 3 bits stored separatelyConversión a píxeles
viewport X = nametable X * 256 + coarse X * 8 + fine X
viewport Y = nametable Y * 240 + coarse Y * 8 + fine YImplementación sugerida
# emulator/rendering/background_viewport.py
NAMETABLE_PIXEL_WIDTH = 256
NAMETABLE_PIXEL_HEIGHT = 240
TILE_PIXEL_SIZE = 8
BackgroundViewportPosition = tuple[int, int]
def decode_background_viewport_position(
temp_vram_addr: int,
fine_x: int,
) -> BackgroundViewportPosition:
coarse_x = temp_vram_addr & 0b1_1111
coarse_y = (temp_vram_addr >> 5) & 0b1_1111
nametable_x = (temp_vram_addr >> 10) & 1
nametable_y = (temp_vram_addr >> 11) & 1
fine_y = (temp_vram_addr >> 12) & 0b111
viewport_x = (
nametable_x * NAMETABLE_PIXEL_WIDTH
+ coarse_x * TILE_PIXEL_SIZE
+ fine_x
)
viewport_y = (
nametable_y * NAMETABLE_PIXEL_HEIGHT
+ coarse_y * TILE_PIXEL_SIZE
+ fine_y
)
return viewport_x, viewport_y¿Por qué usar t y x en lugar del antiguo campo de scroll? $2005 recibe escrituras horizontales y verticales, mientras que el campo de scroll de compatibilidad almacena solo el último byte. Los campos t y x al estilo del hardware conservan el estado empaquetado completo.
Límite de precisión
El hardware real renderiza desde la dirección v actual más la X fina tras transferencias temporizadas de t a v. Este tutorial usa actualmente t más la X fina como una instantánea a nivel de frame. Las transferencias exactas en dot-257 y pre-render-dot-280-304 siguen siendo trabajo de timing futuro.
Otra simplificación
Los valores reales de Y grueso 30 y 31 tienen un comportamiento de ajuste especial. Este paso solo realiza una decodificación directa de campo a píxel; el ajuste del viewport llega más tarde.
Fuera del alcance
- leer bytes de nametable
- crear un framebuffer
- cruzar un límite de nametable
- transferencias de timing exactas de t -> v
- ajuste de Y grueso 30/31
- fixtures de ROM comerciales
Ejecutar esta lección
uv run pytest tests/chapter_13_scrolling/test_329_decode_background_viewport_position.py -v