本文通过描述一次完整的移植 VBA 项目( VisualBoyAdvanced ,一款高性能的 GBA 游戏机模拟器)项目进入 OMS 系统,进而了解 OMS 的图形系统的工作原理,希望为在做项目移植开发的读者提供相关方面有益的启发。
VisualBoyAdvance 被公认为最好的 GBA 模拟器,其性能优异,工作稳定,支持 GB,GBC,GBA 全系列游戏机模拟,该软件具备了跨平台能力,可以在 windows 和 linux 系统中运行,放置在 sf.net 中,其项目是完全开源,代码全部使用 C++ 和汇编语言实现,
项目地址: http://sourceforge.net/projects/vba/ ,
最新版本号为 1.7.2 ,源码包解压尺寸为 7.6 兆。
要做移植,首先要从原始项目的目录结构入手:
├─ m4 automake 配置文件
├─ po 不同语种的字符串配置
├─ src
│ ├─ gb GBA 模拟器核心引擎
│ ├─ gtk 封装 GTK 库
│ │ └─ images 界面资源
│ ├─ i386 针对 i386CPU 做的光栅处理优化代码
│ ├─ prof 调整模拟性能代码
│ ├─ sdl 封装跨平台二维图形库
│ └─ win32 windows 下窗口实现
└─ win32 windows 下缺失的相关库的实现代码
├─ include
│ ├─ cximage
│ ├─ png
│ └─ zlib
├─ lib
│ └─ win32
└─ SDL-1.2.2
├─ include
└─ lib
通过目录的分析,得知界面窗口系统的实现分别放置在不同的目录 (gtk,sdl,windows) 下,而 OMS 系统( android )底层是基于 linux 实现的,但系统剔除了 gtk 界面库,所以选择 sdl 实现是比较好的策略,之后再重新对 sdl 内部的函数逐一替换,即可完成窗口系统的移植,同时系统配套的 CPU 选用的是 arm9 系列,所以 i386 下的针对 cpu 的优化代码也应抛弃,总结如下 : 需要添加 android 编译系统规范的 android.mk 文件,配置中应将 win32,src/win32,src/i386,src/gtk 这几个目录忽略, 调用 sdl 函数的代码也应该全部去掉,并移入 OMS 自己的 GUI 接入的代码,,由上述几步之后最终剩下的都是 C++ 代码,采用 OMS 平台的交叉版本的 gcc 进行编译,同时为方便 OMS 系统的管理,应该将以上 native 代码编译成 jni 动态库,供上层的 java 界面应用使用,即可完成移植。
1 ,将 VisualBoyAdvance 目录放入 packages/apps 目录下,创建 android.mk 文件,
创建工程编译配置项:
include $(CLEAR_VARS)
LOCAL_MODULE := libvba
include $(BUILD_SHARED_LIBRARY)
LOCAL_MODULE_TAGS := tests
LOCAL_SHARED_LIBRARIES := libc libm libui libpng libz
2 ,将目录中的 C++ 源码文件列表放入 android.mk 文件列表中,在 VisualBoyAdvance 目录下使用如下命令,
find -name *.cpp | grep -v win32 | grep -v gtk | awk 'BEGIN{print "common_SRC_FILES:= //"} {print $0 " //"}'
common_SRC_FILES:= /
./src/gb/gbGlobals.cpp /
./src/gb/gbPrinter.cpp /
… # 省略很多文件列表
./src/bilinear.cpp # 结尾处连接符手工删除
3 ,手工将 ./src/sdl/SDL.cpp 里面所有涉及 sdl api 调用的函数全部注空,待填入新的窗口系统处理代码。
4 ,试着在该目录下键入 mm 命令编译,正常情况下,能够一次编译通过,如有问题,应将编译错误解决。
5 , SDL 模块的替换思路如下:输入事件用 jni 接口方式,从 java 层获取的键盘事件传入 , 游戏输出的画面帧则通过直接写入 java 层申请得到 Surface 对应的 native 对象,并及时刷新来实现。
6 ,用 eclipse 创建 java 层代码 , 主要是创建全屏的窗口,窗口类型为 SurfaceView ,并将 Surface 对象通过 jni 接口传入 libvba 中,同理将窗口获取的事件传入 libvba 中,将启动应用的参数( rom 文件路径以及其它配置项)传入 libvba 中,最终由 libvba 来实现对 rom 的模拟执行,将用户的输入转为每一帧的游戏画面,并呈现在手机屏幕上。
最大的收获就是通过这次移植,对窗口系统有了比较清晰的认识,在 java 层的用户输入可以传入本地代码,图形输出系统在平台内部核心代码则都是通过本地代码来实现的,可以用本地代码直接访问 .