280. Фоновые палитры из палитровой RAM
Построение RGB-фоновых палитр из байтов палитровой RAM PPU.
Урок 280 из 356 · tests/chapter_05_rendering_pipeline/test_280_background_palettes_from_palette_ram.py
Справочная информация
https://www.nesdev.org/wiki/PPU_palettes#Palette_RAMФайл для создания
emulator/rendering/palette_ram.pyПочему этот шаг важен
Рендерер таблицы имён с учётом атрибутов ожидает четыре разрешённые RGB-фоновые палитры:
background_palettes[palette_id][color_index]Но настоящие игры NES не хранят RGB-цвета в таблице имён или таблице атрибутов. Они записывают индексы цвета NES в палитровую RAM PPU.
Эта вспомогательная функция преобразует
PPU palette RAM bytes -> RGB background palettesЧто такое палитровая RAM PPU?
Палитровая RAM PPU — это небольшая область в 32 байта, отображённая по адресу
$3F00-$3F1FДля этого шага мы используем только первые 16 байтов
$3F00-$3F0F = background palette areaЭти байты хранят индексы цвета NES $00-$3F, а не значения RGB.
Поток
palette RAM byte
-> NES color index $00-$3F
-> get_nes_rgb_color(index)
-> RGB tupleФоновый / универсальный цвет фона
При рендеринге фона индекс цвета 0 использует общий цвет фона по адресу $3F00.
Поэтому каждая возвращаемая фоновая палитра использует один и тот же первый RGB-цвет
background_palettes[0][0] == backdrop
background_palettes[1][0] == backdrop
background_palettes[2][0] == backdrop
background_palettes[3][0] == backdropРасположение фоновой палитры для $3F00-$3F0F:
$3F00 -> backdrop / universal background color
palette 0:
entry 0 -> $3F00
entry 1 -> $3F01
entry 2 -> $3F02
entry 3 -> $3F03
palette 1:
entry 0 -> $3F00
entry 1 -> $3F05
entry 2 -> $3F06
entry 3 -> $3F07
palette 2:
entry 0 -> $3F00
entry 1 -> $3F09
entry 2 -> $3F0A
entry 3 -> $3F0B
palette 3:
entry 0 -> $3F00
entry 1 -> $3F0D
entry 2 -> $3F0E
entry 3 -> $3F0FОбратите внимание
$3F04, $3F08, and $3F0C are not used as independent background color-0
entries in this simplified helper. Color index 0 uses the shared backdrop.Пример возможной реализации
from emulator.rendering.framebuffer import RGBColor
from emulator.rendering.nes_palette import get_nes_rgb_color
PALETTE_RAM_SIZE = 16
TOTAL_PALETTES = 4
COLORS_PER_PALETTE = 4
BackgroundPalettes = list[list[RGBColor]]
def build_background_palettes_from_palette_ram(
palette_ram: bytes,
) -> BackgroundPalettes:
if len(palette_ram) != PALETTE_RAM_SIZE:
raise ValueError(f"Background palette RAM must be {PALETTE_RAM_SIZE} bytes")
backdrop_color = get_nes_rgb_color(palette_ram[0])
background_palettes = []
for palette_id in range(TOTAL_PALETTES):
base = palette_id * COLORS_PER_PALETTE
palette = [
backdrop_color,
get_nes_rgb_color(palette_ram[base + 1]),
get_nes_rgb_color(palette_ram[base + 2]),
get_nes_rgb_color(palette_ram[base + 3]),
]
background_palettes.append(palette)
return background_palettesВне рамок этого шага
- палитры спрайтов
- поведение прозрачности спрайтов
- зеркалирование палитровой RAM
- чтение напрямую с шины PPU
- акцентированные цвета PPUMASK
- отображение через pygame
Запустить этот урок
uv run pytest tests/chapter_05_rendering_pipeline/test_280_background_palettes_from_palette_ram.py -v