272. 颜色索引网格转帧缓冲

将颜色索引网格转换为 RGB 帧缓冲数据。

272 / 356 · tests/chapter_05_rendering_pipeline/test_272_color_index_grid_to_framebuffer.py

待创建的文件

emulator/rendering/color_index_renderer.py

为什么需要这一步

之前的 PPU/CHR 辅助函数产生的是颜色索引,而不是 RGB 像素。例如,decode_chr_tile() 产生的值类似于:

0, 1, 2, 3

这些值是调色板索引,还不是可以直接显示的颜色。

这一步创建一个纯渲染辅助函数,用来映射

color-index grid + RGB palette -> Framebuffer

什么是颜色索引网格?颜色索引网格是一个二维网格,其中每个数字都指向调色板中的一项。

最小示例

grid = [
    [0, 1, 1, 0, ...],
    [2, 3, 3, 0, ...],
    ...
]

palette = [
    (0, 0, 0),
    (85, 85, 85),
    (170, 170, 170),
    (255, 255, 255),
]

预期的帧缓冲像素

(x=0, y=0) -> palette[0] -> (0, 0, 0)
(x=1, y=0) -> palette[1] -> (85, 85, 85)
(x=0, y=1) -> palette[2] -> (170, 170, 170)
(x=1, y=1) -> palette[3] -> (255, 255, 255)

建议的实现示例

from emulator.rendering.framebuffer import Framebuffer, RGBColor

Grid = list[list[int]]


def color_index_grid_to_framebuffer(
    grid: Grid,
    palette: list[RGBColor],
) -> Framebuffer:
    height = len(grid)
    width = len(grid[0])

    framebuffer = Framebuffer(width=width, height=height)

    for y, row in enumerate(grid):
        for x, color_index in enumerate(row):
            framebuffer.set_pixel(x, y, palette[color_index])

    return framebuffer

重要的简化

目前假设输入总是有效的

grid is not empty
grid is rectangular
palette contains every used index
color indexes are valid

如果以后这成为调试问题,可以再添加更多校验。

架构规则

这个辅助函数只是纯粹的数据转换,不应该导入 pygame、CPU、PPU 时序、ROM 加载或前端代码。

本步骤不涉及

  • NES 调色板内存查找
  • 直接渲染 CHR 图块
  • 直接渲染图案表
  • 渲染名称表/背景
  • pygame 显示

运行本课

uv run pytest tests/chapter_05_rendering_pipeline/test_272_color_index_grid_to_framebuffer.py -v