NES TDD

310. Маска непрозрачности фона

Построить маску непрозрачности фона на основе данных таблицы имён и таблицы шаблонов.

Урок 310 из 356 · tests/chapter_09_sprite_rendering/test_310_background_opaque_mask.py

Изменяемый файл

emulator/rendering/nametable_renderer.py

Зачем нужен этот шаг

У спрайтов есть бит приоритета, который может поместить их позади непрозрачных пикселей фона. Чтобы реализовать это корректно, функции композитинга нужно знать, является ли каждый пиксель фона непрозрачным.

Одних данных RGB-фреймбуфера недостаточно, потому что после преобразования пикселя фона в RGB мы теряем исходный индекс CHR-цвета.

Этот шаг добавляет чистую маску

BackgroundOpaqueMask = list[bool]

Где

False -> background CHR color index was 0
True  -> background CHR color index was 1, 2, or 3

Предлагаемый пример реализации

BackgroundOpaqueMask = list[bool]


def build_background_opaque_mask(
    pattern_table: bytes,
    nametable: bytes,
) -> BackgroundOpaqueMask:
    if len(nametable) != NAMETABLE_SIZE:
        raise ValueError("Nametable must be 960 bytes")

    decoded_tiles = decode_pattern_table(pattern_table)

    opaque_mask: BackgroundOpaqueMask = [False] * (
        BACKGROUND_WIDTH * BACKGROUND_HEIGHT
    )

    for tile_y in range(NAMETABLE_ROWS):
        for tile_x in range(NAMETABLE_TILES_PER_ROW):
            tile_index = nametable[tile_y * NAMETABLE_TILES_PER_ROW + tile_x]
            tile = decoded_tiles[tile_index]

            for pixel_y in range(CHR_TILE_HEIGHT):
                for pixel_x in range(CHR_TILE_WIDTH):
                    color_index = tile[pixel_y][pixel_x]

                    screen_x = tile_x * CHR_TILE_WIDTH + pixel_x
                    screen_y = tile_y * CHR_TILE_HEIGHT + pixel_y

                    mask_index = screen_y * BACKGROUND_WIDTH + screen_x
                    opaque_mask[mask_index] = color_index != 0

    return opaque_mask

Почему без таблицы атрибутов и палитровой RAM? Непрозрачность зависит только от индекса CHR-цвета. Таблица атрибутов и палитровая RAM решают, какие цвета отображаются, но они не изменяют того, является ли индекс CHR-цвета пикселя фона нулевым или ненулевым.

Вне рамок этого шага

  • применение приоритета спрайтов
  • изменение функции композитинга фреймбуфера
  • отрисовка спрайтов
  • попадание спрайта 0
  • переполнение спрайтов
  • pygame

Запустить этот урок

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