LVGL NES 模拟器
lv_nes
是一个使用触摸屏游玩 NES 游戏的演示包。采用了最简单最基础的 NES 模拟器实现方式,运行较为卡顿,不过也更容易理解 lvgl
系统的相关操作实现。
获取&配置软件包
软件包可以在【全志在线开发者社区 - 资源下载】找到,下载 lv_nes扩展软件包
即可。
同样的,下载后把软件包放置到 Tina SDK
的根目录里。并重命名为lv_nes.tar.gz
然后打开命令行,解压 lv_nes
软件包
tar xvf lv_nes.tar.gz
接下来就可以在 make menuconfig
中的 Gui->littlevgl
目录中找到 lv_nes
选项。勾选这个选项。
make && pack
编译打包并烧录开发板,就可以使用 lv_nes
目录运行 模拟器了。
可以使用触摸屏与按键操作游戏的运行。
源码结构
lv_nes
的源码包括三个部分,第一个部分是显示输出的对接,第二个部分是 UI 的绘制与输入处理,第三个部分是 NES 模拟器。
显示输出的对接
显示输出对接位于 main.c
这里我们使用 sunxifb
作为显示接口。引入 sunxifb
的头文件。
#include "lv_drivers/display/sunxifb.h"
接下来便是初始化显示驱动与显示驱动的注册
lv_disp_drv_t disp_drv;
lv_disp_draw_buf_t disp_buf;
/*LittlevGL 初始化*/
lv_init();
/*初始化 sunxifb*/
uint32_t rotated = LV_DISP_ROT_NONE;
sunxifb_init(rotated);
/*获取屏幕的大小*/
static uint32_t width, height;
sunxifb_get_sizes(&width, &height);
static lv_color_t *buf;
/*申请缓冲区内存*/
buf = (lv_color_t *)sunxifb_alloc(width * height * sizeof(lv_color_t), "lv_nes");
if (buf == NULL)
{
sunxifb_exit();
printf("malloc draw buffer fail\n");
return 0;
}
/*初始化输出缓冲区*/
lv_disp_draw_buf_init(&disp_buf, buf, NULL, width * height);
/*初始化 LVGL 侧显示驱动*/
lv_disp_drv_init(&disp_drv);
disp_drv.draw_buf = &disp_buf;
disp_drv.flush_cb = sunxifb_flush;
disp_drv.hor_res = width;
disp_drv.ver_res = height;
disp_drv.rotated = rotated;
disp_drv.screen_transp = 0;
lv_disp_drv_register(&disp_drv);
同时,除了显示输出,还有触摸的输入需要对接,这里我们使用的是 evdev
驱动作为触摸输入。
lv_indev_drv_t indev_drv;
evdev_init();
lv_indev_drv_init(&indev_drv);
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = evdev_read;
/*注册触摸*/
lv_indev_t *evdev_indev = lv_indev_drv_register(&indev_drv);
UI 的绘制与输入处理
UI 的绘制位于 lv_nes.c
中,绘制了屏幕所显示的按钮,模拟器图像输出的位置。由于源码较多这里只给出函数名称,具体实现可以参阅代码。
static void init_ctl_btn(lv_obj_t *obj) // 绘制屏幕按钮
static void lv_nes_constructor(const lv_obj_class_t *class_p, lv_obj_t *obj) // 模拟器图像输出
按键处理同样位于相同源文件内。
static void ctl_btn_event(lv_event_t *e) // 按键事件监听
static void *nes(void *arg) // 按键处理
另外,由于 NES 的输出为 256 * 240 分辨率,对于开发板屏幕来说太小了,所以使用缩放方法将输出扩大一倍
lv_img_set_zoom(nes->img, 512);
NES 模拟器的实现
要实现 NES 模拟器的功能,就需要实现一个最基础的 NES 系统。包括了 ppu.c
,cart.c
,cpu.c
三个文件,实现了最基础的 NES 模拟环境。
其中最重要的是 ppu.c
,它实现了 NES 输出图像回调 lvgl
并显示的功能。
obj->dsc->data = (uint8_t *)pixels;
lv_img_set_src(obj->img, obj->dsc);
由于 NES 模拟器并没有进行任何优化,使用这里直接输出图像会导致系统缩放时产生大量 CPU 占用,导致更加卡顿的情况出现,所以这里采用了跳输出的方法。每四帧回调 lv_img_set_src
方法输出一次图像。
obj->dsc->data = (uint8_t *)pixels;
if(idx == 4)
{
lv_img_set_src(obj->img, obj->dsc);
idx = 0;
} else {
idx++;
}