[GBA教程]pokeemerald实现播放gif/mp4动态图片

[GBA教程]pokeemerald实现播放gif/mp4动态图片

注意:本文使用的所有图片都是8BPP未切割模式,帧数越多占用ROM内存空间越大

经过测试,172帧的图片占用了将近3MB空间

🎬 GBA动态图片/视频实现教程

本教程将介绍两种在GBA游戏中实现GIF动态图片/视频文件播放的方案,并提供详细的实施步骤。

实例一:使用GIF图制作动态游戏封面

github地址:如果不想看教程的可以直接看GITHUB仓库

1

素材准备:

  1. 一段GIF动图(建议使用视频转换生成,帧数不宜过多)这里我直接使用了从rmxp里弄出来的动态图片

  2. 图像编辑工具 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个颜色

image

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

image

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,将他也写入到代码里

 
full.bin
static const u32 sTitleScreenBackgroundTilemap[] = INCBIN_U32("graphics/title_screen/bg/full.bin.lz");

完整的代码如下:

image

3.处理原版的大标题

原版的大标题一共有224色,其中128色将会被我们的背景占用,有16色时原本的裂空座背景色板,所以需要重新处理大标题缩小使用的颜色数量(根据你的图片最大色板来,比如你背景图在处理时只用了64色,那么大标题可以使用240-64=176色)

用gale打开graphics\title_screen下的pokemon_logo.png文件,将大标题的色板减少,可以使用ps减少,这里我们直接用gale减少色板

点击上方的All Frames->Color Depth,选择8BPP,右边的数量填成你可以给大标题使用的色板数量

image

image

点击ok后大标题会被压到指定的颜色

点击右侧的调色板左下方的按钮,选择保存色板

image

保存色板后重新点击按钮,选择LoadPalette,左下角加载刚刚保存的色板文件

接下来需要把左侧的色板移动到右侧的下方,首先需要根据你背景的色板数量找到大标题色板起始位置

比如:我的背景有128色,而gale一行颜色有16个,所以1-8行是背景所占用的颜色,我们把大标题的颜色移动到第九行开始

image

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

image

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

image

点击确定,保存图片

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

image

删除 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位置移位

CB2_InitTitleScreen函数里的case 1中:
// 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);

完整的修改:

image

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

Task_TitleScreenPhase2函数中,删除REG_OFFSET_DISPCNT中显示BG1的参数

image

实例二:游戏中播放mp4

这里使用一个从twitter上保存的rm同人改版视频作为测试,请不要直接使用该视频

GITHUB仓库

原视频:

 

最终效果:

1

处理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)));

其他流程根据需求自行编写

© 版权声明
THE END
喜欢就支持一下吧
点赞1 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容