• nes 红白机模拟器 第1篇


    对比了很多种,开源的 NES 模拟器 VirtuaNES , nestopia , FakeNES , FCEUX , InfoNES , LiteNES

    最后决定使用 LiteNES 进行移值,它是由 mynes 移值而来。LiteNES 对 mynes 代码进行整理兼容了 C99 标准,编译时无警告。

    https://github.com/NJUOS/LiteNES

    https://github.com/yaglo/mynes

    LiteNES , mynes  基于 Allegro ,Allegro 是一种提供底层画图,输入,定时器等支持的库。

    LiteNES 全部抽象提取代码到 一个 hal.c 文件里面,修改移值十分方便。下面是修改后的样子,替换这个文件。

    在修改下 Makefile 中的 gcc 改为 arm-linux-gcc 编译 即可在板子上出现 Game 画面了(经过测试,发现支持的游戏不多,有的载加不出来)

    NES 移值第1篇,仅能出现画面。以后会更新添加声音,多线程,输入等。现在只为能显示出画面。

    hal.c :

      1 /*
      2 This file present all abstraction needed to port LiteNES.
      3   (The current working implementation uses allegro library.)
      4 
      5 To port this project, replace the following functions by your own:
      6 1) nes_hal_init()
      7     Do essential initialization work, including starting a FPS HZ timer.
      8 
      9 2) nes_set_bg_color(c)
     10     Set the back ground color to be the NES internal color code c.
     11 
     12 3) nes_flush_buf(*buf)
     13     Flush the entire pixel buf's data to frame buffer.
     14 
     15 4) nes_flip_display()
     16     Fill the screen with previously set background color, and
     17     display all contents in the frame buffer.
     18 
     19 5) wait_for_frame()
     20     Implement it to make the following code is executed FPS times a second:
     21         while (1) {
     22             wait_for_frame();
     23             do_something();
     24         }
     25 
     26 6) int nes_key_state(int b) 
     27     Query button b's state (1 to be pressed, otherwise 0).
     28     The correspondence of b and the buttons:
     29       0 - Power
     30       1 - A
     31       2 - B
     32       3 - SELECT
     33       4 - START
     34       5 - UP
     35       6 - DOWN
     36       7 - LEFT
     37       8 - RIGHT
     38 */
     39 #include "hal.h"
     40 #include "fce.h"
     41 #include "common.h"
     42 
     43 /**
     44  * allegro API 不明白的看文档 
     45  * https://www.allegro.cc/manual/5/index.html
     46  */
     47 /* lcd 操作相关 头文件 */
     48 #include <sys/types.h>
     49 #include <sys/stat.h>
     50 #include <fcntl.h>
     51 #include <linux/fb.h>
     52 #include <sys/ioctl.h>
     53 #include <unistd.h>
     54 #include <string.h>
     55 #include <sys/mman.h>
     56 
     57 static int fb_fd;
     58 static unsigned char *fb_mem;
     59 static int px_width;
     60 static int line_width;
     61 static int screen_width;
     62 static struct fb_var_screeninfo var;
     63 
     64 static int lcd_fb_display_px(int color, int x, int y)
     65 {
     66     unsigned char  *pen8;
     67     unsigned short *pen16;
     68     
     69     unsigned char r,g,b;
     70     
     71     pen8 = (unsigned char *)(fb_mem + y*line_width + x*px_width);
     72     pen16 = (unsigned short *)pen8;
     73     
     74     //合并为 565 格式 16bbp
     75     r = (color>>16) & 0xff;
     76     g = (color>>8) & 0xff;
     77     b = (color>>0) & 0xff;
     78     *pen16 = (r>>3)<<11 | (g>>2)<<5 | (b>>3);
     79     
     80     return 0;
     81 }
     82 
     83 //调色板转16进行32位颜色
     84 static int pal2color(pal pal)
     85 {
     86     int color = 0;
     87     color = pal.r << 16 | pal.g <<8 | pal.b;
     88     return color;
     89 }
     90 
     91 static int lcd_fb_init()
     92 {
     93     //如果使用 mmap 打开方式 必须是 读写方式
     94     fb_fd = open("/dev/fb0", O_RDWR);
     95     if(-1 == fb_fd)
     96     {
     97         printf("cat't open /dev/fb0 
    ");
     98         return -1;
     99     }
    100     //获取屏幕参数
    101     if(-1 == ioctl(fb_fd, FBIOGET_VSCREENINFO, &var))
    102     {
    103         close(fb_fd);
    104         printf("cat't ioctl /dev/fb0 
    ");
    105         return -1;
    106     }
    107     //计算参数
    108     px_width = var.bits_per_pixel / 8;
    109     line_width = var.xres * px_width;
    110     screen_width = var.yres * line_width;
    111     
    112     fb_mem = (unsigned char *)mmap(NULL, screen_width, PROT_READ | PROT_WRITE, MAP_SHARED, fb_fd, 0);
    113     if(fb_mem == (void *)-1)
    114     {
    115         close(fb_fd);
    116         printf("cat't mmap /dev/fb0 
    ");
    117         return -1;
    118     }
    119     //清屏
    120     memset(fb_mem, 0 , screen_width);
    121     return 0;
    122 }
    123   
    124 /* Wait until next allegro timer event is fired. */
    125 void wait_for_frame()
    126 {
    127     //休眠 FPS = 60 * 1000 毫秒
    128     usleep(1/FPS*1000);
    129 }
    130 
    131 /* Set background color. RGB value of c is defined in fce.h */
    132 void nes_set_bg_color(int c)
    133 {
    134     //画背景颜色
    135     int i,j;
    136     for(i=0; i<SCREEN_WIDTH; i++)
    137     {
    138         for(j=0; j<SCREEN_HEIGHT; j++)
    139         {
    140             lcd_fb_display_px(pal2color(palette[c]), i, j);
    141         }
    142     }    
    143 }
    144 
    145 /* Flush the pixel buffer */
    146 void nes_flush_buf(PixelBuf *buf)
    147 {
    148     Pixel *p;
    149     int i,x,y,color;
    150     for (i = 0; i < buf->size; i++) 
    151     {
    152            p = &buf->buf[i];
    153            x = p->x;
    154         y = p->y;
    155 
    156         color = pal2color(palette[p->c]);
    157         lcd_fb_display_px(color, x, y);    
    158         lcd_fb_display_px(color, x+1, y);
    159         lcd_fb_display_px(color, x, y+1);
    160         lcd_fb_display_px(color, x+1, y+1);
    161         }
    162 }
    163 
    164 /* Initialization:
    165    (1) start a 1/FPS Hz timer. 
    166    (2) register fce_timer handle on each timer event */
    167 void nes_hal_init()
    168 {
    169     /**
    170      * 需要完成的事情
    171      * 1,初始化 lcd 
    172      * 2,初始化 定时器 先做简单的直接用系统延时
    173      */
    174     if(-1 == lcd_fb_init())
    175     {
    176         printf("lcd fb init error 
    ");
    177         return ;
    178     }    
    179 }
    180 
    181 /* Update screen at FPS rate by allegro's drawing function. 
    182    Timer ensures this function is called FPS times a second. */
    183 void nes_flip_display()
    184 {
    185     //设置64种颜色值 不必设置
    186 }
    187 
    188 /* Query a button's state.
    189    Returns 1 if button #b is pressed. */
    190 int nes_key_state(int b)
    191 {
    192     switch (b)
    193     {
    194         case 0: // On / Off
    195             return 1;
    196         case 1: // A
    197             return 1;
    198         case 2: // B
    199             return 1;
    200         case 3: // SELECT
    201             return 1;
    202         case 4: // START
    203             return 1;
    204         case 5: // UP
    205             return 1;
    206         case 6: // DOWN
    207             return 1;
    208         case 7: // LEFT
    209             return 1;
    210         case 8: // RIGHT
    211             return 1;
    212         default:
    213             return 1;
    214     }
    215 }
  • 相关阅读:
    JS函数调用的四种方法
    彻底弄懂css中单位px和em,rem的区别
    Image Transformation in WPF输入日志标题
    WPF DATAGRID
    WPF Datagrid multiple selecteditems in MVVM
    WPF ComboBox Binding
    Parameter of Revit API – 19: Add FamilyParameter (FamilyManager.AddParameter)
    The StringFormat property
    How to retrieve instance parameters from an uninstantiated (uninserted) family
    WPF – pass multiple parameters to a Command
  • 原文地址:https://www.cnblogs.com/ningci/p/5618351.html
Copyright © 2020-2023  润新知