300. Decode sprite entry

Decode one sprite entry from OAM bytes.

Lesson 300 of 356 · tests/chapter_09_sprite_rendering/test_300_decode_sprite_entry.py

File to update

emulator/rendering/sprite_renderer.py

Why this step exists

The previous step defined SpriteEntry. Now we add the small decoder that converts raw PPU OAM bytes into one SpriteEntry.

Raw OAM layout

sprite 0 -> bytes 0, 1, 2, 3
sprite 1 -> bytes 4, 5, 6, 7
...
sprite 63 -> bytes 252, 253, 254, 255

Suggested implementation example

def decode_sprite_entry(oam: bytes | bytearray, sprite_index: int) -> SpriteEntry:
    if len(oam) < OAM_SIZE:
        raise ValueError("OAM must contain 256 bytes")

    if not 0 <= sprite_index < OAM_SPRITE_COUNT:
        raise ValueError("sprite_index must be in range 0..63")

    base = sprite_index * BYTES_PER_SPRITE

    return SpriteEntry(
        y=oam[base],
        tile_index=oam[base + 1],
        attributes=oam[base + 2],
        x=oam[base + 3],
    )

Important NES detail

The raw Y byte has special rendering semantics on real hardware. Sprites appear one scanline below the stored Y value. Do not adjust it in this decoder. This function returns raw OAM data only.

Out of scope

  • sprite attribute bit decoding
  • sprite palettes
  • rendering pixels
  • sprite 0 hit
  • sprite overflow
  • pygame

Run this lesson

uv run pytest tests/chapter_09_sprite_rendering/test_300_decode_sprite_entry.py -v