Appearance
OAM(Object Attribute Memory)
是什么
OAM(Object Attribute Memory,对象属性内存)是 GBA 上一块 1KB 的专用内存,起始地址为 0x07000000。它用于存储最多 128 个精灵(Object)的属性信息,包括位置、大小、使用的图块编号、旋转/缩放参数、显示优先级等。GBA 的渲染硬件在每一帧扫描时根据 OAM 中的数据来绘制精灵。
为什么需要
OAM 是连接精灵逻辑与渲染输出的关键数据结构。在 pokeemerald-wasm 项目中,JavaScript 渲染代码需要读取 OAM 数据来知道:
- 哪些精灵需要绘制:通过 OAM 中的启用/禁用标志判断。
- 精灵在哪里:通过 X/Y 坐标确定精灵在屏幕上的位置。
- 精灵长什么样:通过图块索引到 VRAM 中查找图形数据。
- 精灵的显示效果:通过旋转/缩放、翻转、半透明等属性调整渲染方式。
理解 OAM 的数据格式是在浏览器端正确还原 GBA 精灵渲染的前提。
原理与实现
OAM 共 1KB(1024 字节),存储 128 个精灵条目,每个条目由 4 个 16 位属性字(Attribute)组成,共 8 字节:
| 属性 | 位域 | 内容 |
|---|---|---|
| Attribute 0 (ATTR0) | bit 0-7 | Y 坐标(屏幕 Y 位置) |
| bit 8 | 旋转/缩放标志(0=禁用,1=启用) | |
| bit 9 | 双倍尺寸标志(仅当旋转/缩放启用时有效) | |
| bit 10-11 | 精灵模式(0=正常,1=半透明,2=窗口,3=禁用) | |
| bit 12 | 色深(0=16 色/4bpp,1=256 色/8bpp) | |
| bit 13-14 | 精灵形状(00=正方形,01=横向,10=纵向) | |
| Attribute 1 (ATTR1) | bit 0-8 | X 坐标(屏幕 X 位置,bit 8 为符号位,范围 -128~511) |
| bit 9-13 | 旋转/缩放参数索引(0-31,指向旋转参数集) | |
| bit 14-15 | 精灵尺寸(与形状组合确定实际大小) | |
| Attribute 2 (ATTR2) | bit 0-9 | 图块索引(在 VRAM 中的起始图块号) |
| bit 10-11 | 显示优先级(0-3,0 最高) | |
| bit 12-15 | 调色板组号(仅 16 色模式) | |
| Attribute 3 (ATTR3) | — | 旋转/缩放数据(仅当旋转/缩放启用时使用) |
精灵的实际尺寸由 Attribute 0 的形状(Shape)和 Attribute 1 的尺寸(Size)组合决定:
| 形状\尺寸 | 0 | 1 | 2 | 3 |
|---|---|---|---|---|
| 正方形 | 8×8 | 16×16 | 32×32 | 64×64 |
| 横向 | 16×8 | 32×8 | 32×16 | 64×32 |
| 纵向 | 8×16 | 8×32 | 16×32 | 32×64 |
在 pokeemerald-wasm 中的实现
在 pokeemerald-wasm 中,OAM 的处理流程为:
- 内存映射:OAM 的地址
0x07000000映射在 Wasm 线性内存中,游戏代码像在真实 GBA 上一样读写 OAM。 - 帧末读取:每帧执行完毕后(
WasmRunFrame返回后),JavaScript 渲染代码读取 OAM 区域的全部 1KB 数据。 - 精灵遍历:渲染器遍历 128 个 OAM 条目,跳过被禁用的精灵(ATTR0 的 mode=3)。
- 图块提取:根据 ATTR2 中的图块索引,从 VRAM 的 OBJ 区域提取对应的图块像素数据。
- 变换应用:如果精灵启用了旋转/缩放,根据 ATTR3 中的仿射矩阵参数对图块进行变换。
- Canvas 绘制:将处理后的精灵像素数据绘制到 Canvas 2D 上下文中,优先级低的精灵先绘制。