280. 从调色板 RAM 生成背景调色板
根据 PPU 调色板 RAM 字节构建 RGB 背景调色板。
第 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 颜色索引写入 PPU 调色板 RAM。
这个辅助函数把
PPU palette RAM bytes -> RGB background palettes什么是 PPU 调色板 RAM?
PPU 调色板 RAM 是一块映射在以下位置的 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