注意:本文使用的所有图片都是8BPP未切割模式,帧数越多占用ROM内存空间越大
经过测试,172帧的图片占用了将近3MB空间
🎬 GBA动态图片/视频实现教程
本教程将介绍两种在GBA游戏中实现GIF动态图片/视频文件播放的方案,并提供详细的实施步骤。
实例一:使用GIF图制作动态游戏封面
github地址:如果不想看教程的可以直接看GITHUB仓库

素材准备:
-
一段GIF动图(建议使用视频转换生成,帧数不宜过多)这里我直接使用了从rmxp里弄出来的动态图片
-
图像编辑工具 Gale
具体步骤:
1. 分解GIF帧
使用Python脚本将GIF的每一帧提取并转换为GBA可用的索引颜色模式图片。
下面提供了一个AI的Python脚本模板。运行时,根据提示:
-
输入您的GIF文件路径
-
设置色板颜色数量(例如,若封面除背景外还有标题等元素,可为背景单独分配128色)
注意:若脚本生成的索引图片效果未达预期,您也可以使用Photoshop等工具手动逐帧处理。脚本同时会输出原始帧图片供您备用或参考。
#!/usr/bin/env python3
"""
GIF转GBA动画工具 - 精简版
功能:提取GIF → 去重 → 索引色转换(首色固定为黑色) → 生成GBA/C头文件
"""
from PIL import Image
import os
import hashlib
import json
from pathlib import Path
def extract_and_deduplicate_gif(gif_path):
"""
提取GIF并去除重复帧
返回: (去重后的帧列表, 播放序列, 帧时长列表)
"""
print(f"处理GIF: {Path(gif_path).name}")
try:
gif = Image.open(gif_path)
all_frames = []
all_durations = []
print("提取原始帧...")
frame_count = 0
while True:
try:
frame = gif.copy()
if frame.mode != 'RGBA':
frame = frame.convert('RGBA')
all_frames.append(frame)
all_durations.append(gif.info.get('duration', 100))
frame_count += 1
if frame_count % 10 == 0:
print(f" 已提取 {frame_count} 帧...")
gif.seek(gif.tell() + 1)
except EOFError:
break
print(f"✓ 提取 {len(all_frames)} 帧")
except Exception as e:
print(f"✗ 打开GIF失败: {e}")
return None, None, None
# 去重
print("去重处理...")
frame_hashes = {}
unique_frames = []
unique_durations = []
frame_sequence = []
for i, (frame, duration) in enumerate(zip(all_frames, all_durations)):
img_byte_arr = hashlib.md5(frame.tobytes()).hexdigest()
if img_byte_arr in frame_hashes:
unique_index = frame_hashes[img_byte_arr]
frame_sequence.append(unique_index)
else:
unique_index = len(unique_frames)
frame_hashes[img_byte_arr] = unique_index
unique_frames.append(frame)
unique_durations.append(duration)
frame_sequence.append(unique_index)
print(f"✓ 去重完成: {len(all_frames)} → {len(unique_frames)} 帧")
return unique_frames, frame_sequence, unique_durations
def convert_to_indexed_with_black_first(image, color_count):
"""
转换为索引颜色,确保第一色为纯黑色(#000000)
参数:
image: PIL图像 (RGBA模式)
color_count: 目标颜色数量
返回:
indexed_image: 索引颜色图像
"""
# 1. 处理透明度:透明区域转换为白色,以便后续处理
if image.mode == 'RGBA':
# 创建白色背景
background = Image.new('RGB', image.size, (255, 255, 255))
# 如果有透明度通道,使用它作为蒙版
if image.getchannel('A').getextrema() != (255, 255):
background.paste(image.convert('RGB'), mask=image.split()[3])
else:
background.paste(image.convert('RGB'))
rgb_image = background
else:
rgb_image = image.convert('RGB')
# 2. 转换为索引颜色(比目标少1色,因为要留位置给黑色)
temp_indexed = rgb_image.convert(
'P',
palette=Image.ADAPTIVE,
colors=color_count-1, # 先使用少一色
dither=Image.NONE
)
# 3. 获取并修改调色板:在第一位置插入纯黑色
palette = temp_indexed.getpalette()
if palette:
# 创建新的调色板,大小为 color_count * 3
new_palette = [0] * (color_count * 3) # 初始全黑
# 第一色设置为纯黑色 (0,0,0)
new_palette[0] = 0
new_palette[1] = 0
new_palette[2] = 0
# 将原调色板复制到后面位置(偏移3个位置)
for i in range(len(palette)):
new_palette[i + 3] = palette[i]
# 创建新图像并应用调色板
indexed_image = temp_indexed.copy()
# 调整颜色索引:原图中的所有颜色索引+1(为黑色让出0号位置)
data = bytearray(indexed_image.tobytes())
for j in range(len(data)):
if data[j] < color_count - 1: # 确保在有效范围内
data[j] = data[j] + 1 # 索引+1
indexed_image = Image.frombytes('P', indexed_image.size, bytes(data))
indexed_image.putpalette(new_palette)
else:
# 回退方案:创建简单调色板
indexed_image = rgb_image.convert(
'P',
palette=Image.ADAPTIVE,
colors=color_count,
dither=Image.NONE
)
return indexed_image
def save_gba_animation(base_name, unique_frames, frame_sequence, durations, output_dir, color_count=0):
"""
保存GBA动画所需的所有文件
"""
output_path = Path(output_dir)
output_path.mkdir(exist_ok=True)
print(f"保存到: {output_path}")
frame_files = []
# 1. 保存原始帧(去重后)
print("保存原始帧...")
for i, frame in enumerate(unique_frames):
filename = f"original_{i:03d}.png"
filepath = output_path / filename
frame.save(filepath, 'PNG')
frame_files.append(filename)
# 2. 如果指定了颜色数量,保存索引帧
indexed_files = []
if color_count > 0:
print(f"转换索引模式 ({color_count}色,首色为黑)...")
indexed_dir = output_path / "indexed"
indexed_dir.mkdir(exist_ok=True)
for i, frame in enumerate(unique_frames):
indexed_image = convert_to_indexed_with_black_first(frame, color_count)
filename = f"indexed_{i:03d}.png"
filepath = indexed_dir / filename
indexed_image.save(filepath, 'PNG')
indexed_files.append(filename)
print(f"✓ 已保存 {len(indexed_files)} 个索引图像")
# 创建序列数组定义
sequence_array = f"static const u8 s{base_name}_ANIM_SEQUENCE[] = {{\n "
sequence_lines = []
for i in range(0, len(frame_sequence), 16):
chunk = frame_sequence[i:i+16]
sequence_lines.append(", ".join(f"{x:3d}" for x in chunk))
sequence_array += ",\n ".join(sequence_lines)
sequence_array += "\n};"
print(sequence_array)
return output_path
def main():
"""主函数"""
print("=" * 60)
print("GIF转GBA动画工具 - 精简版")
print("=" * 60)
# 输入GIF文件路径
gif_path = input("GIF文件路径: ").strip()
if not os.path.exists(gif_path):
print(f"✗ 文件不存在: {gif_path}")
return
# 输入颜色数量
color_input = input("颜色数量 (0=不转换,1-256=索引颜色): ").strip()
try:
color_count = int(color_input)
if color_count < 0 or color_count > 256:
print("✗ 颜色数量需在0-256之间")
return
except ValueError:
print("✗ 输入无效")
return
# 处理GIF
unique_frames, frame_sequence, durations = extract_and_deduplicate_gif(gif_path)
if not unique_frames:
return
# 生成输出目录名
base_name = Path(gif_path).stem
if color_count > 0:
output_dir = f"{base_name}_gif"
else:
output_dir = f"{base_name}_original"
# 保存所有文件
save_gba_animation(base_name, unique_frames, frame_sequence, durations, output_dir, color_count)
# 显示摘要
print("\n" + "=" * 60)
print("处理完成!")
print("=" * 60)
print(f"输出目录: {output_dir}")
print(f"唯一帧数: {len(unique_frames)}")
print(f"序列长度: {len(frame_sequence)}")
if color_count > 0:
print(f"颜色模式: {color_count}色索引 (首色#000000透明)")
print(f"索引图像: {output_dir}/indexed/")
print(f"原始图像: {output_dir}/")
print(f"头文件: {output_dir}/gba_animation.h")
# 显示序列前部分
sample = frame_sequence[:min(15, len(frame_sequence))]
print(f"序列预览: {sample}{'...' if len(frame_sequence) > 15 else ''}")
if __name__ == "__main__":
main()
由于宝石版本的封面除了背景外还有大标题,这里我只给背景图分配了128个颜色

运行成功后会在目录下生成一个文件夹,其中indexed里是索引好的图片素材,外面的orginal是未索引的帧素材

2.编写代码
定位到 src/title_screen.c 文件,开始编写代码。
首先,需要将处理好的每一帧索引图片的图块数据(Tiles)和调色板数据(Palette)以数组形式声明。在此示例中,sTitleScreenBackgroundGfxTable 和 sTitleScreenBackgroundPalTable 两个数组直接按动画的实际播放顺序列出了每一帧的对应数据。
static const u32 sTitleScreenBackground0Gfx[] = INCBIN_U32("graphics/title_screen/bg/bg_gif/indexed/indexed_000.8bpp.lz");
static const u16 sTitleScreenBackground0Pal[] = INCBIN_U16("graphics/title_screen/bg/bg_gif/indexed/indexed_000.gbapal");
static const u32 sTitleScreenBackground1Gfx[] = INCBIN_U32("graphics/title_screen/bg/bg_gif/indexed/indexed_001.8bpp.lz");
static const u16 sTitleScreenBackground1Pal[] = INCBIN_U16("graphics/title_screen/bg/bg_gif/indexed/indexed_001.gbapal");
static const u32 sTitleScreenBackground2Gfx[] = INCBIN_U32("graphics/title_screen/bg/bg_gif/indexed/indexed_002.8bpp.lz");
static const u16 sTitleScreenBackground2Pal[] = INCBIN_U16("graphics/title_screen/bg/bg_gif/indexed/indexed_002.gbapal");
static const u32 sTitleScreenBackground3Gfx[] = INCBIN_U32("graphics/title_screen/bg/bg_gif/indexed/indexed_003.8bpp.lz");
static const u16 sTitleScreenBackground3Pal[] = INCBIN_U16("graphics/title_screen/bg/bg_gif/indexed/indexed_003.gbapal");
static const u32 sTitleScreenBackground4Gfx[] = INCBIN_U32("graphics/title_screen/bg/bg_gif/indexed/indexed_004.8bpp.lz");
static const u16 sTitleScreenBackground4Pal[] = INCBIN_U16("graphics/title_screen/bg/bg_gif/indexed/indexed_004.gbapal");
static const u32 *const sTitleScreenBackgroundGfxTable[] =
{
sTitleScreenBackground0Gfx,
sTitleScreenBackground1Gfx,
sTitleScreenBackground2Gfx,
sTitleScreenBackground3Gfx,
sTitleScreenBackground4Gfx,
sTitleScreenBackground3Gfx,
sTitleScreenBackground2Gfx,
sTitleScreenBackground1Gfx,
};
static const u16 *const sTitleScreenBackgroundPalTable[] =
{
sTitleScreenBackground0Pal,
sTitleScreenBackground1Pal,
sTitleScreenBackground2Pal,
sTitleScreenBackground3Pal,
sTitleScreenBackground4Pal,
sTitleScreenBackground3Pal,
sTitleScreenBackground2Pal,
sTitleScreenBackground1Pal,
};
为了简化操作,这里采用了最直观的方式——直接按帧顺序排列资源,而非先建立资源表再通过索引编号来映射序列。您可以根据项目的复杂度和维护需求,选择是否将其重构为更解耦的表格与索引控制形式。
由于直接输出的gif图是未经过切割的,所以可以共用同一个tilemap,这里提供一个通用的完整图片tilemap,将他也写入到代码里
static const u32 sTitleScreenBackgroundTilemap[] = INCBIN_U32("graphics/title_screen/bg/full.bin.lz");
完整的代码如下:

3.处理原版的大标题
原版的大标题一共有224色,其中128色将会被我们的背景占用,有16色时原本的裂空座背景色板,所以需要重新处理大标题缩小使用的颜色数量(根据你的图片最大色板来,比如你背景图在处理时只用了64色,那么大标题可以使用240-64=176色)
用gale打开graphics\title_screen下的pokemon_logo.png文件,将大标题的色板减少,可以使用ps减少,这里我们直接用gale减少色板
点击上方的All Frames->Color Depth,选择8BPP,右边的数量填成你可以给大标题使用的色板数量


点击ok后大标题会被压到指定的颜色
点击右侧的调色板左下方的按钮,选择保存色板

保存色板后重新点击按钮,选择LoadPalette,左下角加载刚刚保存的色板文件
接下来需要把左侧的色板移动到右侧的下方,首先需要根据你背景的色板数量找到大标题色板起始位置
比如:我的背景有128色,而gale一行颜色有16个,所以1-8行是背景所占用的颜色,我们把大标题的颜色移动到第九行开始

框选左边的所有颜色,找到右侧第九行开始的位置,左键点击就能把颜色放置过去

接着左侧下方黑色的颜色,将右侧上方原本的颜色都填充成黑色

点击确定,保存图片
定位到 graphics_file_rule.mk 文件,找到与大标题色板(pokemon_logo.pal)相关的生成规则并将其删除。这一步是告知编译系统,不再需要从单独的 .pal 文件生成 pokemon_logo.gbapal。

删除 graphics/title_screen/ 目录下的 pokemon_logo.pal 文件。我们将直接使用大标题的图片色板作为调色板数据
4.代码编写(代码部分可能不是很清楚,可以直接看文章开头的github差异对比改动)
实现GIF动态效果的核心机制是:在固定的时间间隔(每N帧延迟)后,将下一帧动画的图块(Tile)和调色板(Palette)数据更新到背景层(BG)上。
在原版函数 Task_TitleScreenPhase3 中,已有 tCounter 参数可用于控制延迟计时。我们只需在此基础上新增一个参数(例如 tAnimNum)来追踪当前应播放的动画帧编号。
#define tAnimNum data[7] // 新增一个 tAnimNum使用task data[7]来记录动画帧编号
static void Task_TitleScreenPhase3(u8 taskId)
{
if (JOY_NEW(A_BUTTON) || JOY_NEW(START_BUTTON))
{
FadeOutBGM(4);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_WHITEALPHA);
SetMainCallback2(CB2_GoToMainMenu);
}
else if (JOY_HELD(CLEAR_SAVE_BUTTON_COMBO) == CLEAR_SAVE_BUTTON_COMBO)
{
SetMainCallback2(CB2_GoToClearSaveDataScreen);
}
else if (JOY_HELD(RESET_RTC_BUTTON_COMBO) == RESET_RTC_BUTTON_COMBO
&& CanResetRTC() == TRUE)
{
FadeOutBGM(4);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
SetMainCallback2(CB2_GoToResetRtcScreen);
}
else if (JOY_HELD(BERRY_UPDATE_BUTTON_COMBO) == BERRY_UPDATE_BUTTON_COMBO)
{
FadeOutBGM(4);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_BLACK);
SetMainCallback2(CB2_GoToBerryFixScreen);
}
else
{
SetGpuReg(REG_OFFSET_BG2Y_L, 0);
SetGpuReg(REG_OFFSET_BG2Y_H, 0);
if (++gTasks[taskId].tCounter & 1)
{
gTasks[taskId].tBg1Y++;
gBattle_BG1_Y = gTasks[taskId].tBg1Y / 2;
gBattle_BG1_X = 0;
}
// UpdateLegendaryMarkingColor(gTasks[taskId].tCounter); // 由于原版的背景已经被替换,这里将裂空座发光效果删除
if (gTasks[taskId].tCounter % 8 == 0) // 每8次循环切换一次动画
{
LoadPalette(sTitleScreenBackgroundPalTable[gTasks[taskId].tAnimNum % NELEMS(sTitleScreenBackgroundPalTable)], 0, 128 * 2); // 加载新的色板,注意后面的128 * 2是背景色板大小 * 2
TransferPlttBuffer();
LZ77UnCompVram(sTitleScreenBackgroundGfxTable[gTasks[taskId].tAnimNum % NELEMS(sTitleScreenBackgroundGfxTable)], (void *)(BG_CHAR_ADDR(0)));
gTasks[taskId].tAnimNum++;
}
if ((gMPlayInfo_BGM.status & 0xFFFF) == 0)
{
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 16, RGB_WHITEALPHA);
SetMainCallback2(CB2_GoToCopyrightScreen);
}
}
}
#undef tAnimNum
注意函数里的 LoadPalette(sTitleScreenBackgroundPalTable[gTasks[taskId].tAnimNum % NELEMS(sTitleScreenBackgroundPalTable)], 0, 128 * 2); 其中的128是背景的颜色数量,避免覆盖大标题的色板
接着需要重新安排封面bg的配置,这里将删除云朵效果,并将云朵的bg隐藏,由于背景没有切除重复块,所以背景tile会占用大量的空间,需要将大标题的tile位置移位
// bg2
DecompressDataWithHeaderVram(gTitleScreenPokemonLogoGfx, (void *)(BG_CHAR_ADDR(3))); // 将大标题加载到char地址3
DecompressDataWithHeaderVram(gTitleScreenPokemonLogoTilemap, (void *)(BG_SCREEN_ADDR(19))); // 将大标题的tilemap放到中间空闲位置
LoadPalette(gTitleScreenBgPalettes, BG_PLTT_ID(0), 15 * PLTT_SIZE_4BPP);
// 不再加载裂空座背景和云朵图片
// // bg3
// DecompressDataWithHeaderVram(sTitleScreenRayquazaGfx, (void *)(BG_CHAR_ADDR(2)));
// DecompressDataWithHeaderVram(sTitleScreenRayquazaTilemap, (void *)(BG_SCREEN_ADDR(26)));
// bg1
// DecompressDataWithHeaderVram(sTitleScreenCloudsGfx, (void *)(BG_CHAR_ADDR(3)));
// DecompressDataWithHeaderVram(gTitleScreenCloudsTilemap, (void *)(BG_SCREEN_ADDR(30)));
ScanlineEffect_Stop();
ResetTasks();
ResetSpriteData();
FreeAllSpritePalettes();
gReservedSpritePaletteCount = 9;
LoadPaletteFast(sTitleScreenBackgroundPalTable[0], 0, 128 * 2); // 加载第一帧的色板,避免瞬时的花屏问题
LZ77UnCompVram(sTitleScreenBackgroundTilemap, (void *)(BG_SCREEN_ADDR(20))); // 将full tilemap加载到大标题后面
LoadCompressedSpriteSheet(&sSpriteSheet_EmeraldVersion[0]);
LoadCompressedSpriteSheet(&sSpriteSheet_PressStart[0]);
LoadCompressedSpriteSheet(&sPokemonLogoShineSpriteSheet[0]);
LoadPalette(gTitleScreenEmeraldVersionPal, OBJ_PLTT_ID(0), PLTT_SIZE_4BPP);
LoadSpritePalette(&sSpritePalette_PressStart[0]);
gMain.state = 2;
break;
接着修改case 4中对bg的配置:
将BG0(背景层)设置为256色,并且将BGCNT_SCREENBASE指定到加载的tilemap位置
将BG1(大标题图层)BGCNT_SCREENBASE指定到加载的大标题tilemap位置,并把CHARBASE设置为最末端的位置
SetGpuReg(REG_OFFSET_BG0CNT, BGCNT_PRIORITY(3) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(20) | BGCNT_256COLOR | BGCNT_TXT256x256);
//SetGpuReg(REG_OFFSET_BG1CNT, BGCNT_PRIORITY(2) | BGCNT_CHARBASE(3) | BGCNT_SCREENBASE(30) | BGCNT_16COLOR | BGCNT_TXT256x256);
SetGpuReg(REG_OFFSET_BG2CNT, BGCNT_PRIORITY(1) | BGCNT_CHARBASE(3) | BGCNT_SCREENBASE(19) | BGCNT_256COLOR | BGCNT_AFF256x256);
完整的修改:

最后隐藏BG1,避免云朵层显示出来

实例二:游戏中播放mp4
这里使用一个从twitter上保存的rm同人改版视频作为测试,请不要直接使用该视频
原视频:
最终效果:

处理mp4文件的python代码:
#!/usr/bin/env python3
"""
MP4转GBA帧序列工具(修正透明色问题)
功能:提取MP4帧 → 调整尺寸 → 256色索引(第一色固定为纯黑色,不被使用)
"""
import cv2
import os
from PIL import Image
import numpy as np
from pathlib import Path
def convert_to_indexed_with_transparent_black(image, color_count=256):
"""
转换为索引颜色,确保第一色(0)为纯黑色且不被图像使用
参数:
image: PIL RGB图像
color_count: 目标颜色数量
返回:
indexed_image: 索引颜色图像(第一色为纯黑且未使用)
"""
# 1. 转换为RGB模式确保处理正确
if image.mode != 'RGB':
rgb_image = image.convert('RGB')
else:
rgb_image = image
# 2. 转换为索引颜色(使用color_count-1个颜色,留出0号位置)
temp_indexed = rgb_image.convert(
'P',
palette=Image.ADAPTIVE,
colors=color_count-1, # 少1个颜色,留出0号位置
dither=Image.NONE
)
# 3. 获取原始调色板数据
palette = temp_indexed.getpalette()
if palette is None:
# 如果无法获取调色板,回退到简单转换
return rgb_image.convert('P', palette=Image.ADAPTIVE, colors=color_count)
# 4. 创建新调色板,第一色为纯黑色(0,0,0)
new_palette = [0] * (color_count * 3) # 初始全黑
# 第一色(0号)保持为纯黑色
new_palette[0] = 0 # R
new_palette[1] = 0 # G
new_palette[2] = 0 # B
# 将原始调色板复制到1号色及之后的位置
for i in range(len(palette)):
new_palette[i + 3] = palette[i] # 从第3个位置开始(跳过第一个颜色的RGB)
# 5. 调整像素索引:将所有像素索引+1,让出0号位置
indexed_data = bytearray(temp_indexed.tobytes())
for i in range(len(indexed_data)):
if indexed_data[i] < color_count - 1: # 确保在范围内
indexed_data[i] += 1 # 索引+1,跳过0号黑色
# 6. 创建新图像并应用调色板
indexed_image = Image.frombytes('P', temp_indexed.size, bytes(indexed_data))
indexed_image.putpalette(new_palette)
# 7. 验证:确保图像中确实没有使用0号颜色
unique_colors = set(indexed_data)
if 0 in unique_colors:
print("警告:图像中仍在使用0号黑色,重新处理...")
# 如果还有0号色,将其替换为1号色
for i in range(len(indexed_data)):
if indexed_data[i] == 0:
indexed_data[i] = 1
indexed_image = Image.frombytes('P', temp_indexed.size, bytes(indexed_data))
indexed_image.putpalette(new_palette)
return indexed_image
def extract_frames_from_mp4(video_path, target_fps, output_size, color_count=256):
"""
从MP4提取帧并处理为GBA可用格式(修正透明色)
"""
print(f"处理视频: {Path(video_path).name}")
print(f"目标: {target_fps} FPS, 尺寸: {output_size}, 颜色: {color_count}色")
print(f"注意:第一色(0号)固定为纯黑色且不被图像使用(GBA透明色)")
# 创建输出目录
base_name = Path(video_path).stem
output_dir = Path(f"{base_name}_frames")
indexed_dir = output_dir / "indexed"
indexed_dir.mkdir(parents=True, exist_ok=True)
# 打开视频文件
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
print("✗ 无法打开视频文件")
return 0
# 获取视频信息
original_fps = cap.get(cv2.CAP_PROP_FPS)
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
frame_interval = max(1, int(original_fps / target_fps))
print(f"视频: {original_fps:.1f} FPS, {total_frames}帧")
print(f"帧间隔: {frame_interval}, 预计提取: {int(total_frames/frame_interval)}帧")
print("-" * 50)
frame_count = 0
processed_count = 0
extracted_frames = []
while True:
ret, frame = cap.read()
if not ret:
break
# 按间隔提取帧
if frame_count % frame_interval == 0:
# 1. BGR → RGB
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# 2. 转换为PIL图像
pil_img = Image.fromarray(frame_rgb)
# 3. 调整尺寸
if pil_img.size != output_size:
pil_img = pil_img.resize(output_size, Image.Resampling.LANCZOS)
# 4. 转换为RGB(确保颜色正确)
rgb_img = pil_img.convert('RGB')
# 5. 转换为索引颜色(第一色为纯黑且不被使用)
indexed_img = convert_to_indexed_with_transparent_black(rgb_img, color_count)
# 6. 验证第一色确实没有被使用
indexed_data = bytearray(indexed_img.tobytes())
unique_colors = set(indexed_data)
if 0 in unique_colors:
print(f"警告: 第{processed_count}帧仍在使用0号黑色,强制修正...")
# 将所有0号色替换为1号色
for i in range(len(indexed_data)):
if indexed_data[i] == 0:
indexed_data[i] = 1
indexed_img = Image.frombytes('P', indexed_img.size, bytes(indexed_data))
indexed_img.putpalette(indexed_img.getpalette())
# 7. 保存帧
frame_filename = f"frame_{processed_count:04d}.png"
frame_path = indexed_dir / frame_filename
indexed_img.save(frame_path, 'PNG')
# 8. 记录验证信息
final_data = bytearray(indexed_img.tobytes())
final_colors = set(final_data)
extracted_frames.append({
'index': processed_count,
'filename': frame_filename,
'uses_black': 0 in final_colors,
'color_count': len(final_colors),
'original_frame': frame_count,
'time': frame_count / original_fps
})
if 0 in final_colors:
print(f"错误: 第{processed_count}帧的0号色仍被使用!")
processed_count += 1
# 显示进度
if processed_count % 10 == 0:
progress = (frame_count / total_frames) * 100
print(f"进度: {processed_count}帧 ({progress:.1f}%)")
frame_count += 1
cap.release()
# 验证所有帧的第一色都没有被使用
black_used_count = sum(1 for f in extracted_frames if f['uses_black'])
if black_used_count > 0:
print(f"警告: {black_used_count}帧仍然在使用0号黑色(透明色)")
else:
print("✓ 所有帧的第一色(0号)均为未使用的纯黑色(GBA透明色)")
# 生成头文件
generate_gba_header(output_dir, base_name, extracted_frames, {
'video_path': video_path,
'original_fps': original_fps,
'target_fps': target_fps,
'output_size': output_size,
'color_count': color_count,
'total_frames': processed_count,
'black_unused': black_used_count == 0
})
return processed_count
def generate_gba_header(output_dir, base_name, frames, video_info):
"""生成GBA头文件"""
# 创建序列数组
sequence_array = f"static const u16 s{base_name}_FRAMES[] = {{ // 帧文件索引\n"
for i in range(0, len(frames), 16):
indices = [f"{i:3d}" for i in range(i, min(i+16, len(frames)))]
sequence_array += " " + ", ".join(indices) + ",\n"
sequence_array = sequence_array.rstrip(",\n") + "\n};"
# 创建调色板信息(固定第一色为黑色)
palette_info = f"""
// 调色板信息:第一色(0)为纯黑色(0,0,0) - GBA透明色
// 实际使用颜色:{video_info['color_count']-1}色(从1号色开始)
#define {base_name.upper()}_PALETTE_SIZE {video_info['color_count']}
#define {base_name.upper()}_USABLE_COLORS {video_info['color_count']-1}
#define {base_name.upper()}_TRANSPARENT_COLOR 0 // 纯黑色,透明
// 注意:图像中不使用0号颜色,所有像素使用1-{video_info['color_count']-1}号颜色
"""
header_content = f"""// {base_name} - GBA视频帧数据
// 自动生成,已修复透明色问题
// 帧数: {len(frames)}
// 尺寸: {video_info['output_size'][0]}x{video_info['output_size'][1]}
// 色板: {video_info['color_count']}色(第一色为透明黑)
// 透明色处理: {'✓ 正确' if video_info['black_unused'] else '✗ 有问题'}
#ifndef _{base_name.upper()}_H_
#define _{base_name.upper()}_H_
#include <gba_types.h>
// 帧数量
#define {base_name.upper()}_FRAME_COUNT {len(frames)}
// 帧序列(按顺序)
{sequence_array}
{palette_info}
// 重要提示:
// 1. 所有图像的第一色(0号)是纯黑色(0,0,0),在GBA中作为透明色
// 2. 图像中实际只使用1-{video_info['color_count']-1}号颜色
// 3. 加载调色板时,确保0号色保持为(0,0,0)
#endif // _{base_name.upper()}_H_
"""
header_path = output_dir / f"{base_name}.h"
with open(header_path, 'w', encoding='utf-8') as f:
f.write(header_content)
print(f"✓ 生成GBA头文件: {header_path}")
def main():
print("=" * 60)
print("MP4转GBA工具(修正透明色版)")
print("重要:第一色(0号)固定为纯黑色且不被图像使用")
print("=" * 60)
# 输入参数
video_path = input("MP4文件路径: ").strip()
if not Path(video_path).exists():
print("文件不存在"); return
try:
target_fps = float(input("提取帧率 (FPS): ").strip())
if not 0.1 <= target_fps <= 60:
print("帧率需0.1-60"); return
except:
print("输入无效"); return
size_input = input("输出尺寸 (宽x高, 默认240x160): ").strip()
if 'x' in size_input:
try:
w, h = map(int, size_input.lower().split('x'))
output_size = (w, h)
except:
output_size = (240, 160)
else:
output_size = (240, 160)
color_input = input("颜色数量 (16/256, 默认256): ").strip()
color_count = 256
if color_input in ['16', '256']:
color_count = int(color_input)
print(f"\n开始处理...")
print(f"尺寸: {output_size[0]}x{output_size[1]}")
print(f"颜色: {color_count}色(实际使用{color_count-1}色,0号透明)")
frame_count = extract_frames_from_mp4(
video_path=video_path,
target_fps=target_fps,
output_size=output_size,
color_count=color_count
)
if frame_count > 0:
print(f"\n✓ 完成: {frame_count}帧")
print(f"输出: {Path(video_path).stem}_frames/indexed/")
print(f"头文件: {Path(video_path).stem}_frames/{Path(video_path).stem}.h")
if __name__ == "__main__":
try:
import cv2
from PIL import Image
except ImportError:
print("请安装: pip install opencv-python pillow")
exit(1)
main()
C代码:
#include "global.h"
#include "battle.h"
#include "title_screen.h"
#include "sprite.h"
#include "gba/m4a_internal.h"
#include "clear_save_data_menu.h"
#include "decompress.h"
#include "event_data.h"
#include "intro.h"
#include "m4a.h"
#include "main.h"
#include "main_menu.h"
#include "palette.h"
#include "reset_rtc_screen.h"
#include "berry_fix_program.h"
#include "sound.h"
#include "sprite.h"
#include "task.h"
#include "scanline_effect.h"
#include "gpu_regs.h"
#include "trig.h"
#include "graphics.h"
#include "constants/rgb.h"
#include "constants/songs.h"
static void Task_PrintMp4(u8 taskID);
static const u32 sTestGfx0[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0000.8bpp.lz");
static const u16 sTestPal0[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0000.gbapal");
static const u32 sTestGfx1[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0001.8bpp.lz");
static const u16 sTestPal1[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0001.gbapal");
static const u32 sTestGfx2[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0002.8bpp.lz");
static const u16 sTestPal2[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0002.gbapal");
static const u32 sTestGfx3[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0003.8bpp.lz");
static const u16 sTestPal3[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0003.gbapal");
static const u32 sTestGfx4[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0004.8bpp.lz");
static const u16 sTestPal4[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0004.gbapal");
static const u32 sTestGfx5[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0005.8bpp.lz");
static const u16 sTestPal5[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0005.gbapal");
static const u32 sTestGfx6[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0006.8bpp.lz");
static const u16 sTestPal6[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0006.gbapal");
static const u32 sTestGfx7[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0007.8bpp.lz");
static const u16 sTestPal7[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0007.gbapal");
static const u32 sTestGfx8[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0008.8bpp.lz");
static const u16 sTestPal8[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0008.gbapal");
static const u32 sTestGfx9[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0009.8bpp.lz");
static const u16 sTestPal9[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0009.gbapal");
static const u32 sTestGfx10[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0010.8bpp.lz");
static const u16 sTestPal10[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0010.gbapal");
static const u32 sTestGfx11[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0011.8bpp.lz");
static const u16 sTestPal11[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0011.gbapal");
static const u32 sTestGfx12[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0012.8bpp.lz");
static const u16 sTestPal12[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0012.gbapal");
static const u32 sTestGfx13[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0013.8bpp.lz");
static const u16 sTestPal13[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0013.gbapal");
static const u32 sTestGfx14[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0014.8bpp.lz");
static const u16 sTestPal14[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0014.gbapal");
static const u32 sTestGfx15[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0015.8bpp.lz");
static const u16 sTestPal15[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0015.gbapal");
static const u32 sTestGfx16[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0016.8bpp.lz");
static const u16 sTestPal16[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0016.gbapal");
static const u32 sTestGfx17[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0017.8bpp.lz");
static const u16 sTestPal17[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0017.gbapal");
static const u32 sTestGfx18[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0018.8bpp.lz");
static const u16 sTestPal18[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0018.gbapal");
static const u32 sTestGfx19[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0019.8bpp.lz");
static const u16 sTestPal19[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0019.gbapal");
static const u32 sTestGfx20[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0020.8bpp.lz");
static const u16 sTestPal20[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0020.gbapal");
static const u32 sTestGfx21[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0021.8bpp.lz");
static const u16 sTestPal21[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0021.gbapal");
static const u32 sTestGfx22[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0022.8bpp.lz");
static const u16 sTestPal22[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0022.gbapal");
static const u32 sTestGfx23[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0023.8bpp.lz");
static const u16 sTestPal23[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0023.gbapal");
static const u32 sTestGfx24[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0024.8bpp.lz");
static const u16 sTestPal24[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0024.gbapal");
static const u32 sTestGfx25[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0025.8bpp.lz");
static const u16 sTestPal25[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0025.gbapal");
static const u32 sTestGfx26[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0026.8bpp.lz");
static const u16 sTestPal26[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0026.gbapal");
static const u32 sTestGfx27[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0027.8bpp.lz");
static const u16 sTestPal27[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0027.gbapal");
static const u32 sTestGfx28[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0028.8bpp.lz");
static const u16 sTestPal28[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0028.gbapal");
static const u32 sTestGfx29[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0029.8bpp.lz");
static const u16 sTestPal29[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0029.gbapal");
static const u32 sTestGfx30[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0030.8bpp.lz");
static const u16 sTestPal30[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0030.gbapal");
static const u32 sTestGfx31[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0031.8bpp.lz");
static const u16 sTestPal31[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0031.gbapal");
static const u32 sTestGfx32[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0032.8bpp.lz");
static const u16 sTestPal32[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0032.gbapal");
static const u32 sTestGfx33[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0033.8bpp.lz");
static const u16 sTestPal33[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0033.gbapal");
static const u32 sTestGfx34[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0034.8bpp.lz");
static const u16 sTestPal34[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0034.gbapal");
static const u32 sTestGfx35[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0035.8bpp.lz");
static const u16 sTestPal35[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0035.gbapal");
static const u32 sTestGfx36[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0036.8bpp.lz");
static const u16 sTestPal36[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0036.gbapal");
static const u32 sTestGfx37[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0037.8bpp.lz");
static const u16 sTestPal37[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0037.gbapal");
static const u32 sTestGfx38[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0038.8bpp.lz");
static const u16 sTestPal38[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0038.gbapal");
static const u32 sTestGfx39[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0039.8bpp.lz");
static const u16 sTestPal39[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0039.gbapal");
static const u32 sTestGfx40[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0040.8bpp.lz");
static const u16 sTestPal40[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0040.gbapal");
static const u32 sTestGfx41[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0041.8bpp.lz");
static const u16 sTestPal41[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0041.gbapal");
static const u32 sTestGfx42[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0042.8bpp.lz");
static const u16 sTestPal42[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0042.gbapal");
static const u32 sTestGfx43[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0043.8bpp.lz");
static const u16 sTestPal43[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0043.gbapal");
static const u32 sTestGfx44[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0044.8bpp.lz");
static const u16 sTestPal44[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0044.gbapal");
static const u32 sTestGfx45[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0045.8bpp.lz");
static const u16 sTestPal45[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0045.gbapal");
static const u32 sTestGfx46[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0046.8bpp.lz");
static const u16 sTestPal46[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0046.gbapal");
static const u32 sTestGfx47[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0047.8bpp.lz");
static const u16 sTestPal47[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0047.gbapal");
static const u32 sTestGfx48[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0048.8bpp.lz");
static const u16 sTestPal48[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0048.gbapal");
static const u32 sTestGfx49[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0049.8bpp.lz");
static const u16 sTestPal49[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0049.gbapal");
static const u32 sTestGfx50[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0050.8bpp.lz");
static const u16 sTestPal50[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0050.gbapal");
static const u32 sTestGfx51[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0051.8bpp.lz");
static const u16 sTestPal51[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0051.gbapal");
static const u32 sTestGfx52[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0052.8bpp.lz");
static const u16 sTestPal52[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0052.gbapal");
static const u32 sTestGfx53[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0053.8bpp.lz");
static const u16 sTestPal53[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0053.gbapal");
static const u32 sTestGfx54[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0054.8bpp.lz");
static const u16 sTestPal54[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0054.gbapal");
static const u32 sTestGfx55[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0055.8bpp.lz");
static const u16 sTestPal55[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0055.gbapal");
static const u32 sTestGfx56[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0056.8bpp.lz");
static const u16 sTestPal56[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0056.gbapal");
static const u32 sTestGfx57[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0057.8bpp.lz");
static const u16 sTestPal57[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0057.gbapal");
static const u32 sTestGfx58[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0058.8bpp.lz");
static const u16 sTestPal58[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0058.gbapal");
static const u32 sTestGfx59[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0059.8bpp.lz");
static const u16 sTestPal59[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0059.gbapal");
static const u32 sTestGfx60[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0060.8bpp.lz");
static const u16 sTestPal60[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0060.gbapal");
static const u32 sTestGfx61[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0061.8bpp.lz");
static const u16 sTestPal61[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0061.gbapal");
static const u32 sTestGfx62[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0062.8bpp.lz");
static const u16 sTestPal62[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0062.gbapal");
static const u32 sTestGfx63[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0063.8bpp.lz");
static const u16 sTestPal63[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0063.gbapal");
static const u32 sTestGfx64[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0064.8bpp.lz");
static const u16 sTestPal64[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0064.gbapal");
static const u32 sTestGfx65[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0065.8bpp.lz");
static const u16 sTestPal65[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0065.gbapal");
static const u32 sTestGfx66[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0066.8bpp.lz");
static const u16 sTestPal66[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0066.gbapal");
static const u32 sTestGfx67[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0067.8bpp.lz");
static const u16 sTestPal67[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0067.gbapal");
static const u32 sTestGfx68[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0068.8bpp.lz");
static const u16 sTestPal68[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0068.gbapal");
static const u32 sTestGfx69[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0069.8bpp.lz");
static const u16 sTestPal69[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0069.gbapal");
static const u32 sTestGfx70[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0070.8bpp.lz");
static const u16 sTestPal70[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0070.gbapal");
static const u32 sTestGfx71[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0071.8bpp.lz");
static const u16 sTestPal71[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0071.gbapal");
static const u32 sTestGfx72[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0072.8bpp.lz");
static const u16 sTestPal72[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0072.gbapal");
static const u32 sTestGfx73[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0073.8bpp.lz");
static const u16 sTestPal73[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0073.gbapal");
static const u32 sTestGfx74[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0074.8bpp.lz");
static const u16 sTestPal74[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0074.gbapal");
static const u32 sTestGfx75[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0075.8bpp.lz");
static const u16 sTestPal75[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0075.gbapal");
static const u32 sTestGfx76[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0076.8bpp.lz");
static const u16 sTestPal76[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0076.gbapal");
static const u32 sTestGfx77[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0077.8bpp.lz");
static const u16 sTestPal77[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0077.gbapal");
static const u32 sTestGfx78[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0078.8bpp.lz");
static const u16 sTestPal78[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0078.gbapal");
static const u32 sTestGfx79[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0079.8bpp.lz");
static const u16 sTestPal79[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0079.gbapal");
static const u32 sTestGfx80[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0080.8bpp.lz");
static const u16 sTestPal80[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0080.gbapal");
static const u32 sTestGfx81[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0081.8bpp.lz");
static const u16 sTestPal81[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0081.gbapal");
static const u32 sTestGfx82[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0082.8bpp.lz");
static const u16 sTestPal82[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0082.gbapal");
static const u32 sTestGfx83[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0083.8bpp.lz");
static const u16 sTestPal83[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0083.gbapal");
static const u32 sTestGfx84[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0084.8bpp.lz");
static const u16 sTestPal84[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0084.gbapal");
static const u32 sTestGfx85[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0085.8bpp.lz");
static const u16 sTestPal85[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0085.gbapal");
static const u32 sTestGfx86[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0086.8bpp.lz");
static const u16 sTestPal86[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0086.gbapal");
static const u32 sTestGfx87[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0087.8bpp.lz");
static const u16 sTestPal87[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0087.gbapal");
static const u32 sTestGfx88[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0088.8bpp.lz");
static const u16 sTestPal88[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0088.gbapal");
static const u32 sTestGfx89[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0089.8bpp.lz");
static const u16 sTestPal89[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0089.gbapal");
static const u32 sTestGfx90[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0090.8bpp.lz");
static const u16 sTestPal90[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0090.gbapal");
static const u32 sTestGfx91[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0091.8bpp.lz");
static const u16 sTestPal91[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0091.gbapal");
static const u32 sTestGfx92[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0092.8bpp.lz");
static const u16 sTestPal92[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0092.gbapal");
static const u32 sTestGfx93[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0093.8bpp.lz");
static const u16 sTestPal93[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0093.gbapal");
static const u32 sTestGfx94[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0094.8bpp.lz");
static const u16 sTestPal94[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0094.gbapal");
static const u32 sTestGfx95[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0095.8bpp.lz");
static const u16 sTestPal95[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0095.gbapal");
static const u32 sTestGfx96[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0096.8bpp.lz");
static const u16 sTestPal96[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0096.gbapal");
static const u32 sTestGfx97[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0097.8bpp.lz");
static const u16 sTestPal97[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0097.gbapal");
static const u32 sTestGfx98[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0098.8bpp.lz");
static const u16 sTestPal98[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0098.gbapal");
static const u32 sTestGfx99[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0099.8bpp.lz");
static const u16 sTestPal99[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0099.gbapal");
static const u32 sTestGfx100[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0100.8bpp.lz");
static const u16 sTestPal100[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0100.gbapal");
static const u32 sTestGfx101[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0101.8bpp.lz");
static const u16 sTestPal101[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0101.gbapal");
static const u32 sTestGfx102[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0102.8bpp.lz");
static const u16 sTestPal102[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0102.gbapal");
static const u32 sTestGfx103[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0103.8bpp.lz");
static const u16 sTestPal103[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0103.gbapal");
static const u32 sTestGfx104[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0104.8bpp.lz");
static const u16 sTestPal104[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0104.gbapal");
static const u32 sTestGfx105[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0105.8bpp.lz");
static const u16 sTestPal105[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0105.gbapal");
static const u32 sTestGfx106[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0106.8bpp.lz");
static const u16 sTestPal106[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0106.gbapal");
static const u32 sTestGfx107[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0107.8bpp.lz");
static const u16 sTestPal107[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0107.gbapal");
static const u32 sTestGfx108[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0108.8bpp.lz");
static const u16 sTestPal108[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0108.gbapal");
static const u32 sTestGfx109[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0109.8bpp.lz");
static const u16 sTestPal109[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0109.gbapal");
static const u32 sTestGfx110[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0110.8bpp.lz");
static const u16 sTestPal110[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0110.gbapal");
static const u32 sTestGfx111[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0111.8bpp.lz");
static const u16 sTestPal111[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0111.gbapal");
static const u32 sTestGfx112[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0112.8bpp.lz");
static const u16 sTestPal112[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0112.gbapal");
static const u32 sTestGfx113[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0113.8bpp.lz");
static const u16 sTestPal113[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0113.gbapal");
static const u32 sTestGfx114[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0114.8bpp.lz");
static const u16 sTestPal114[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0114.gbapal");
static const u32 sTestGfx115[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0115.8bpp.lz");
static const u16 sTestPal115[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0115.gbapal");
static const u32 sTestGfx116[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0116.8bpp.lz");
static const u16 sTestPal116[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0116.gbapal");
static const u32 sTestGfx117[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0117.8bpp.lz");
static const u16 sTestPal117[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0117.gbapal");
static const u32 sTestGfx118[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0118.8bpp.lz");
static const u16 sTestPal118[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0118.gbapal");
static const u32 sTestGfx119[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0119.8bpp.lz");
static const u16 sTestPal119[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0119.gbapal");
static const u32 sTestGfx120[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0120.8bpp.lz");
static const u16 sTestPal120[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0120.gbapal");
static const u32 sTestGfx121[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0121.8bpp.lz");
static const u16 sTestPal121[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0121.gbapal");
static const u32 sTestGfx122[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0122.8bpp.lz");
static const u16 sTestPal122[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0122.gbapal");
static const u32 sTestGfx123[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0123.8bpp.lz");
static const u16 sTestPal123[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0123.gbapal");
static const u32 sTestGfx124[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0124.8bpp.lz");
static const u16 sTestPal124[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0124.gbapal");
static const u32 sTestGfx125[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0125.8bpp.lz");
static const u16 sTestPal125[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0125.gbapal");
static const u32 sTestGfx126[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0126.8bpp.lz");
static const u16 sTestPal126[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0126.gbapal");
static const u32 sTestGfx127[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0127.8bpp.lz");
static const u16 sTestPal127[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0127.gbapal");
static const u32 sTestGfx128[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0128.8bpp.lz");
static const u16 sTestPal128[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0128.gbapal");
static const u32 sTestGfx129[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0129.8bpp.lz");
static const u16 sTestPal129[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0129.gbapal");
static const u32 sTestGfx130[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0130.8bpp.lz");
static const u16 sTestPal130[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0130.gbapal");
static const u32 sTestGfx131[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0131.8bpp.lz");
static const u16 sTestPal131[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0131.gbapal");
static const u32 sTestGfx132[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0132.8bpp.lz");
static const u16 sTestPal132[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0132.gbapal");
static const u32 sTestGfx133[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0133.8bpp.lz");
static const u16 sTestPal133[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0133.gbapal");
static const u32 sTestGfx134[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0134.8bpp.lz");
static const u16 sTestPal134[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0134.gbapal");
static const u32 sTestGfx135[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0135.8bpp.lz");
static const u16 sTestPal135[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0135.gbapal");
static const u32 sTestGfx136[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0136.8bpp.lz");
static const u16 sTestPal136[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0136.gbapal");
static const u32 sTestGfx137[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0137.8bpp.lz");
static const u16 sTestPal137[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0137.gbapal");
static const u32 sTestGfx138[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0138.8bpp.lz");
static const u16 sTestPal138[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0138.gbapal");
static const u32 sTestGfx139[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0139.8bpp.lz");
static const u16 sTestPal139[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0139.gbapal");
static const u32 sTestGfx140[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0140.8bpp.lz");
static const u16 sTestPal140[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0140.gbapal");
static const u32 sTestGfx141[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0141.8bpp.lz");
static const u16 sTestPal141[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0141.gbapal");
static const u32 sTestGfx142[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0142.8bpp.lz");
static const u16 sTestPal142[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0142.gbapal");
static const u32 sTestGfx143[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0143.8bpp.lz");
static const u16 sTestPal143[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0143.gbapal");
static const u32 sTestGfx144[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0144.8bpp.lz");
static const u16 sTestPal144[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0144.gbapal");
static const u32 sTestGfx145[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0145.8bpp.lz");
static const u16 sTestPal145[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0145.gbapal");
static const u32 sTestGfx146[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0146.8bpp.lz");
static const u16 sTestPal146[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0146.gbapal");
static const u32 sTestGfx147[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0147.8bpp.lz");
static const u16 sTestPal147[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0147.gbapal");
static const u32 sTestGfx148[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0148.8bpp.lz");
static const u16 sTestPal148[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0148.gbapal");
static const u32 sTestGfx149[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0149.8bpp.lz");
static const u16 sTestPal149[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0149.gbapal");
static const u32 sTestGfx150[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0150.8bpp.lz");
static const u16 sTestPal150[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0150.gbapal");
static const u32 sTestGfx151[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0151.8bpp.lz");
static const u16 sTestPal151[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0151.gbapal");
static const u32 sTestGfx152[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0152.8bpp.lz");
static const u16 sTestPal152[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0152.gbapal");
static const u32 sTestGfx153[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0153.8bpp.lz");
static const u16 sTestPal153[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0153.gbapal");
static const u32 sTestGfx154[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0154.8bpp.lz");
static const u16 sTestPal154[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0154.gbapal");
static const u32 sTestGfx155[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0155.8bpp.lz");
static const u16 sTestPal155[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0155.gbapal");
static const u32 sTestGfx156[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0156.8bpp.lz");
static const u16 sTestPal156[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0156.gbapal");
static const u32 sTestGfx157[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0157.8bpp.lz");
static const u16 sTestPal157[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0157.gbapal");
static const u32 sTestGfx158[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0158.8bpp.lz");
static const u16 sTestPal158[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0158.gbapal");
static const u32 sTestGfx159[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0159.8bpp.lz");
static const u16 sTestPal159[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0159.gbapal");
static const u32 sTestGfx160[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0160.8bpp.lz");
static const u16 sTestPal160[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0160.gbapal");
static const u32 sTestGfx161[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0161.8bpp.lz");
static const u16 sTestPal161[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0161.gbapal");
static const u32 sTestGfx162[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0162.8bpp.lz");
static const u16 sTestPal162[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0162.gbapal");
static const u32 sTestGfx163[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0163.8bpp.lz");
static const u16 sTestPal163[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0163.gbapal");
static const u32 sTestGfx164[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0164.8bpp.lz");
static const u16 sTestPal164[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0164.gbapal");
static const u32 sTestGfx165[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0165.8bpp.lz");
static const u16 sTestPal165[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0165.gbapal");
static const u32 sTestGfx166[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0166.8bpp.lz");
static const u16 sTestPal166[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0166.gbapal");
static const u32 sTestGfx167[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0167.8bpp.lz");
static const u16 sTestPal167[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0167.gbapal");
static const u32 sTestGfx168[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0168.8bpp.lz");
static const u16 sTestPal168[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0168.gbapal");
static const u32 sTestGfx169[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0169.8bpp.lz");
static const u16 sTestPal169[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0169.gbapal");
static const u32 sTestGfx170[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0170.8bpp.lz");
static const u16 sTestPal170[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0170.gbapal");
static const u32 sTestGfx171[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0171.8bpp.lz");
static const u16 sTestPal171[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0171.gbapal");
static const u32 sTestGfx172[] = INCBIN_U32("graphics/mp4/test_frames/indexed/frame_0172.8bpp.lz");
static const u16 sTestPal172[] = INCBIN_U16("graphics/mp4/test_frames/indexed/frame_0172.gbapal");
static const u32 *const sTitleScreenBackgroundGfxTable[] =
{
sTestGfx0,
sTestGfx1,
sTestGfx2,
sTestGfx3,
sTestGfx4,
sTestGfx5,
sTestGfx6,
sTestGfx7,
sTestGfx8,
sTestGfx9,
sTestGfx10,
sTestGfx11,
sTestGfx12,
sTestGfx13,
sTestGfx14,
sTestGfx15,
sTestGfx16,
sTestGfx17,
sTestGfx18,
sTestGfx19,
sTestGfx20,
sTestGfx21,
sTestGfx22,
sTestGfx23,
sTestGfx24,
sTestGfx25,
sTestGfx26,
sTestGfx27,
sTestGfx28,
sTestGfx29,
sTestGfx30,
sTestGfx31,
sTestGfx32,
sTestGfx33,
sTestGfx34,
sTestGfx35,
sTestGfx36,
sTestGfx37,
sTestGfx38,
sTestGfx39,
sTestGfx40,
sTestGfx41,
sTestGfx42,
sTestGfx43,
sTestGfx44,
sTestGfx45,
sTestGfx46,
sTestGfx47,
sTestGfx48,
sTestGfx49,
sTestGfx50,
sTestGfx51,
sTestGfx52,
sTestGfx53,
sTestGfx54,
sTestGfx55,
sTestGfx56,
sTestGfx57,
sTestGfx58,
sTestGfx59,
sTestGfx60,
sTestGfx61,
sTestGfx62,
sTestGfx63,
sTestGfx64,
sTestGfx65,
sTestGfx66,
sTestGfx67,
sTestGfx68,
sTestGfx69,
sTestGfx70,
sTestGfx71,
sTestGfx72,
sTestGfx73,
sTestGfx74,
sTestGfx75,
sTestGfx76,
sTestGfx77,
sTestGfx78,
sTestGfx79,
sTestGfx80,
sTestGfx81,
sTestGfx82,
sTestGfx83,
sTestGfx84,
sTestGfx85,
sTestGfx86,
sTestGfx87,
sTestGfx88,
sTestGfx89,
sTestGfx90,
sTestGfx91,
sTestGfx92,
sTestGfx93,
sTestGfx94,
sTestGfx95,
sTestGfx96,
sTestGfx97,
sTestGfx98,
sTestGfx99,
sTestGfx100,
sTestGfx101,
sTestGfx102,
sTestGfx103,
sTestGfx104,
sTestGfx105,
sTestGfx106,
sTestGfx107,
sTestGfx108,
sTestGfx109,
sTestGfx110,
sTestGfx111,
sTestGfx112,
sTestGfx113,
sTestGfx114,
sTestGfx115,
sTestGfx116,
sTestGfx117,
sTestGfx118,
sTestGfx119,
sTestGfx120,
sTestGfx121,
sTestGfx122,
sTestGfx123,
sTestGfx124,
sTestGfx125,
sTestGfx126,
sTestGfx127,
sTestGfx128,
sTestGfx129,
sTestGfx130,
sTestGfx131,
sTestGfx132,
sTestGfx133,
sTestGfx134,
sTestGfx135,
sTestGfx136,
sTestGfx137,
sTestGfx138,
sTestGfx139,
sTestGfx140,
sTestGfx141,
sTestGfx142,
sTestGfx143,
sTestGfx144,
sTestGfx145,
sTestGfx146,
sTestGfx147,
sTestGfx148,
sTestGfx149,
sTestGfx150,
sTestGfx151,
sTestGfx152,
sTestGfx153,
sTestGfx154,
sTestGfx155,
sTestGfx156,
sTestGfx157,
sTestGfx158,
sTestGfx159,
sTestGfx160,
sTestGfx161,
sTestGfx162,
sTestGfx163,
sTestGfx164,
sTestGfx165,
sTestGfx166,
sTestGfx167,
sTestGfx168,
sTestGfx169,
sTestGfx170,
sTestGfx171,
sTestGfx172
};
static const u16 *const sTitleScreenBackgroundPalTable[] =
{
sTestPal0,
sTestPal1,
sTestPal2,
sTestPal3,
sTestPal4,
sTestPal5,
sTestPal6,
sTestPal7,
sTestPal8,
sTestPal9,
sTestPal10,
sTestPal11,
sTestPal12,
sTestPal13,
sTestPal14,
sTestPal15,
sTestPal16,
sTestPal17,
sTestPal18,
sTestPal19,
sTestPal20,
sTestPal21,
sTestPal22,
sTestPal23,
sTestPal24,
sTestPal25,
sTestPal26,
sTestPal27,
sTestPal28,
sTestPal29,
sTestPal30,
sTestPal31,
sTestPal32,
sTestPal33,
sTestPal34,
sTestPal35,
sTestPal36,
sTestPal37,
sTestPal38,
sTestPal39,
sTestPal40,
sTestPal41,
sTestPal42,
sTestPal43,
sTestPal44,
sTestPal45,
sTestPal46,
sTestPal47,
sTestPal48,
sTestPal49,
sTestPal50,
sTestPal51,
sTestPal52,
sTestPal53,
sTestPal54,
sTestPal55,
sTestPal56,
sTestPal57,
sTestPal58,
sTestPal59,
sTestPal60,
sTestPal61,
sTestPal62,
sTestPal63,
sTestPal64,
sTestPal65,
sTestPal66,
sTestPal67,
sTestPal68,
sTestPal69,
sTestPal70,
sTestPal71,
sTestPal72,
sTestPal73,
sTestPal74,
sTestPal75,
sTestPal76,
sTestPal77,
sTestPal78,
sTestPal79,
sTestPal80,
sTestPal81,
sTestPal82,
sTestPal83,
sTestPal84,
sTestPal85,
sTestPal86,
sTestPal87,
sTestPal88,
sTestPal89,
sTestPal90,
sTestPal91,
sTestPal92,
sTestPal93,
sTestPal94,
sTestPal95,
sTestPal96,
sTestPal97,
sTestPal98,
sTestPal99,
sTestPal100,
sTestPal101,
sTestPal102,
sTestPal103,
sTestPal104,
sTestPal105,
sTestPal106,
sTestPal107,
sTestPal108,
sTestPal109,
sTestPal110,
sTestPal111,
sTestPal112,
sTestPal113,
sTestPal114,
sTestPal115,
sTestPal116,
sTestPal117,
sTestPal118,
sTestPal119,
sTestPal120,
sTestPal121,
sTestPal122,
sTestPal123,
sTestPal124,
sTestPal125,
sTestPal126,
sTestPal127,
sTestPal128,
sTestPal129,
sTestPal130,
sTestPal131,
sTestPal132,
sTestPal133,
sTestPal134,
sTestPal135,
sTestPal136,
sTestPal137,
sTestPal138,
sTestPal139,
sTestPal140,
sTestPal141,
sTestPal142,
sTestPal143,
sTestPal144,
sTestPal145,
sTestPal146,
sTestPal147,
sTestPal148,
sTestPal149,
sTestPal150,
sTestPal151,
sTestPal152,
sTestPal153,
sTestPal154,
sTestPal155,
sTestPal156,
sTestPal157,
sTestPal158,
sTestPal159,
sTestPal160,
sTestPal161,
sTestPal162,
sTestPal163,
sTestPal164,
sTestPal165,
sTestPal166,
sTestPal167,
sTestPal168,
sTestPal169,
sTestPal170,
sTestPal171,
sTestPal172
};
static const u32 sTitleScreenBackgroundTilemap[] = INCBIN_U32("graphics/title_screen/bg/full.bin.lz");
static void MainCB2(void)
{
RunTasks();
UpdatePaletteFade();
}
static void VBlankCB(void)
{
}
void RunTestAnim(void)
{
switch (gMain.state)
{
default:
case 0:
SetVBlankCallback(NULL);
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_DISPCNT, 0);
SetGpuReg(REG_OFFSET_BG2CNT, 0);
SetGpuReg(REG_OFFSET_BG1CNT, 0);
SetGpuReg(REG_OFFSET_BG0CNT, 0);
SetGpuReg(REG_OFFSET_BG2HOFS, 0);
SetGpuReg(REG_OFFSET_BG2VOFS, 0);
SetGpuReg(REG_OFFSET_BG1HOFS, 0);
SetGpuReg(REG_OFFSET_BG1VOFS, 0);
SetGpuReg(REG_OFFSET_BG0HOFS, 0);
SetGpuReg(REG_OFFSET_BG0VOFS, 0);
DmaFill16(3, 0, (void *)VRAM, VRAM_SIZE);
DmaFill32(3, 0, (void *)OAM, OAM_SIZE);
DmaFill16(3, 0, (void *)(PLTT + 2), PLTT_SIZE - 2);
ResetPaletteFade();
gMain.state = 1;
break;
case 1:
ScanlineEffect_Stop();
ResetTasks();
ResetSpriteData();
FreeAllSpritePalettes();
LoadPalette(sTitleScreenBackgroundPalTable[0], 0, 256 * 2);
LZ77UnCompVram(sTitleScreenBackgroundGfxTable[0], (void *)(BG_CHAR_ADDR(0)));
LZ77UnCompVram(sTitleScreenBackgroundTilemap, (void *)(BG_SCREEN_ADDR(20)));
gMain.state = 2;
break;
case 2:
{
u8 taskId = CreateTask(Task_PrintMp4, 0);
gMain.state = 3;
break;
}
case 3:
gMain.state = 4;
break;
case 4:
SetGpuReg(REG_OFFSET_WIN0H, 0);
SetGpuReg(REG_OFFSET_WIN0V, 0);
SetGpuReg(REG_OFFSET_WIN1H, 0);
SetGpuReg(REG_OFFSET_WIN1V, 0);
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN1_BG_ALL | WININ_WIN1_OBJ);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ | WINOUT_WINOBJ_ALL);
SetGpuReg(REG_OFFSET_BLDCNT, 0);
SetGpuReg(REG_OFFSET_BLDALPHA, 0);
SetGpuReg(REG_OFFSET_BLDY, 0);
SetGpuReg(REG_OFFSET_BG0CNT, BGCNT_PRIORITY(3) | BGCNT_CHARBASE(0) | BGCNT_SCREENBASE(20) | BGCNT_256COLOR | BGCNT_TXT256x256);
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_MODE_1
| DISPCNT_OBJ_1D_MAP
| DISPCNT_BG0_ON
| DISPCNT_OBJ_ON
| DISPCNT_WIN0_ON
| DISPCNT_OBJWIN_ON);
gMain.state = 5;
break;
case 5:
SetMainCallback2(MainCB2);
SetVBlankCallback(VBlankCB);
break;
}
}
static void Task_PrintMp4(u8 taskId)
{
if (gTasks[taskId].data[1]++ % 6 == 0)
{
DmaCopy16(3, sTitleScreenBackgroundPalTable[gTasks[taskId].data[0] % NELEMS(sTitleScreenBackgroundPalTable)], (void *)PLTT, BG_PLTT_SIZE);
LZ77UnCompVram(sTitleScreenBackgroundGfxTable[gTasks[taskId].data[0] % NELEMS(sTitleScreenBackgroundGfxTable)], (void *)(BG_CHAR_ADDR(0)));
gTasks[taskId].data[0]++;
}
}
void CB2_RunTestAnim(void)
{
SetMainCallback2(RunTestAnim);
}
总结
核心代码只有两句
DmaCopy16(3, sTitleScreenBackgroundPalTable[gTasks[taskId].data[0] % NELEMS(sTitleScreenBackgroundPalTable)], (void *)PLTT, BG_PLTT_SIZE);
LZ77UnCompVram(sTitleScreenBackgroundGfxTable[gTasks[taskId].data[0] % NELEMS(sTitleScreenBackgroundGfxTable)], (void *)(BG_CHAR_ADDR(0)));
其他流程根据需求自行编写


![[NDS中文]宝可梦白2加强v1.0.1测试版-宝可梦营地](https://pokedream.cn/wp-content/uploads/2025/12/pokew2.png)
![[GBA教程]pokeemerald实现动态地图色板功能-宝可梦营地](https://pokedream.cn/wp-content/uploads/2025/12/LittlerootTown.png)
![[记录]GBA反编译上踩过的一些坑-宝可梦营地](https://pokedream.cn/wp-content/uploads/2025/12/water.jpg)

![[NDS中文]起源心金-宝可梦营地](https://pokedream.cn/wp-content/uploads/2025/12/起源心金.jpg)

暂无评论内容