导航: 老古网老古论坛XMOS公共讨论区XMOS开源项目区单片机程序设计嵌入式系统广告区域
→发表看法:[jola]GBA编程初解(转载)



No.65941
作者:jola
邮件:ch181120@163.net
ID:10295
登陆:39次
QQ:122348673
文章数:145篇
最后登陆IP:210.21.215.18
最后登陆:2005/1/7 17:49:35
注册:2003/3/16 12:29:00
财富:637
发帖时间:2004/11/7 14:52:29
发贴者IP:202.105.135.27
标题:jola:GBA编程初解(转载)
摘要:No.65941GBA编程初解(转载) 
  在具体介绍gba编程之前,我想先感谢一个人,他就是 水银 兄。在我学习的过程中水银兄给了我很多有用的宝贵资料,在此我向他表示感谢。
  GBA是新一代的32位手掌机,强大的机能吸引了无数玩家和编程爱好者。现在用于开发的编译器有两种,一种是完全免费的GCC,和收费的ARM SDT,目前我在使用的是gcc,虽然网上也有D过来的arm sdt但我是无福享用的,23MB的大家伙啊,当初下载gcc这个12MB的东东时我就已经吐血了,可怜我的小猫啊。
  好了,废话少说,进入正题。GBA使用的是卡带也就是只读rom为存储载体虽然容量可以很大,但问题也不少。也就是说我们不可能动态的分配使用卡上的内存了尽管它可以有128MB。当然gba也为我们提供了ram,至于容量嘛……,看下面的资料知道了。
单词含义:
1. GBA - 'Game Boy Advance' ^_^
2. BG(Backgroud) - '背景'
3. Sprite - '精灵'
4. Tile - '地图图块'
5. RAM(Random Access Memory) - '随机访问存储器'

接口地址 :

  外部 RAM: 地址: 0x02000000 大小: 256Kb 作用: 存放程序及数据
  内部 RAM: 地址: 0x03000000 大小: 32Kb? 作用: 我想是高速内存,和cache作用一样吧
  IO RAM: 地址: 0x04000000 大小: 1Kb 作用: 控制图像,声音,DMA等内存映射IO
  Palette - '调色板'
  地址: 0x05000000 大小: 0x400 bytes 作用: 存放调色板数据
  VRAM(Video RAM) - '视频内存'
  地址: 0x06000000 大小: 0x20000 bytes 作用: 位图模式下存放帧缓冲数据,图块模式下存放图块数据及图块地图数据
  OAM(Object Attribute Memory) - '精灵对象属性内存'
  地址: 0x07000000 大小: 0x400 bytes 作用: 用于控制精灵
6. ROM(Read Only Memory) - '只读存储器'
地址: 0x08000000 大小: 看你的游戏卡的大小罗 作用: 存放所有的程序和数据
7. ARM - 32bit 指令系统 (RISC,精简指令集)
8. Thumb - 16bit 指令系统 (具体区别详见 )
9. DMA(Direct Memory Access) - 直接内存访问
10.DISPCNT(Display Controller) - 显示控制(内存地址)
  当初看水银兄写的gba教程时一直不明白明明是256色模式,可指向VRAM的指针却是short型的。后来才知道,gba访问VRAM时一次必须读写2个字节,即16bit。我晕~~!所以我只好严格要求自己的blit函数。虽然也找到一个可以写8bit的putpixel函数代码,但速度太慢了不适合用在显示大量图片的地方。
  需要注意的地方大概都说完了,我们可以进入代码部分了。
  虽然是专用游戏机,但显示模式也需要设定才行。
#define REG_DISPCNT *(u16*)0x04000000// 显示寄存器地址
#define VRAM 0x06000000 // 图像缓冲区地址
#define M5_VRAM 0x0600A000 // M5缓冲区地址
#define BACKBUFFER 0x010// 双缓冲/背缓冲地址
#define PALETTE 0x5000000// 调色板地址
#define MODE_3 0x03 // 240*160 15位/单缓冲区
#define MODE_4 0x04 // 240*160 8位/双缓冲区
#define MODE_5 0x05 // 160*128 15位/双缓冲区
#define BG2_ENABLE 0x0400 // BG_2
#define SetMode(Mode) REG_DISPCNT=(Mode) // 设置显示模式的宏定义

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;

typedef struct BITMAP
{
    int x,y,w,h;
    u16 MskCol;
    float bitx,bity;
    u8 flag;
    u16 *dat;
}BITMAP;

BITMAP screen;

u16 *palette_mem = (u16 *)PALETTE;

void grp_init()
{
    SetMode(MODE_4|BG2_ENABLE);
    screen.w=240;
    screen.h=160;
    screen.dat=(u16 *)VRAM;
}
这样我们就进入了240*160*256的模式了, SetMode中的BG2_ENABLE这个参数不能少否则将没有任何显示。为了能够正常的显示图象还需要设置调色板。
void set_palette(unsigned short *palette)
{
    int loop;
    for(loop=0;loop  <256;loop++)
    {
        palette_mem[loop] = palette[loop];
    }
}

调色板数据可以从bmp2gba转换bmp图象后的.h中得到,需要注意的是bmp2gba不能够正确的转换过大的图象,大概是240*160以上的图片转换后都有问题,所以我自己写了一个pic2gba,可以转换256色的pcx,bmp(未压缩,转换前还需要进行一下旋转处理),gif格式的程序,但我不知道bmp2gba是如何转换调色板数据的,所以这部分数据是不正确的。

  pic2gba使用方法:pic2gba in-file out-file。 
水银兄的教程中是直接使用图象数据的,这对以后写game可不是一个好的方法,所以我才定义了BITMAP结构既然要显示图象就需要将图象数据装入BITMAP:
BITMAP load_bitmap(int width,int height,const unsigned char *dat)
{
    BITMAP bitmap;
    bitmap.dat=(u16*)dat;
    bitmap.x=bitmap.y =0;
    bitmap.w=width;
    bitmap.h=height;
    bitmap.MskCol=*bitmap.dat;
    bitmap.flag=TRUE;
    return bitmap;
}

然后再blit:

void blit(BITMAP dst,BITMAP src,int x1,int y1,int x,int y,int w,int h)
{
    register int i=0,j;
    register u16 *_bak1,*_bak2;
    _bak1=dst.dat;
    _bak2=src.dat;
    _bak1+=x1+y1*(dst.w>  >  1);
    _bak2+=x+y*(src.w>  >  1);
    while(i  <h)
    {
        memcpy(_bak1,_bak2,w);
        _bak1+=120;
        _bak2+=src.w>  >  1;
        i++;
    }
}

这个是最快的方法了。哦,对了还有更快的方法:直接使用DMA,可惜我这没资料。
如果是要显示汉字,除了水银兄的方法外(比较适合游戏中使用)也可以把整个汉字库都放到rom中去,用这个rhzk程序来转换数据。(需要UCDOS的HZK16,ASC16两个字库。)因为这里要写点,速度要求也比较低可以使用这个函数:
inline void putpixel(BITMAP bmp,int x,int y,u8 col)
{
    u16 *tc;
    tc=bmp.dat+(y)*(bmp.w>  >  1)+(x>  >  1);
    if(x&1)*tc=((*tc&255)+(col  <  <8));
    else
        *tc=(*tc&65280)+col;
}
下面的是显示汉字的主体部分了,
struct ChinaHzk{
    short len;
    const u8 *CHzkBuf,*AHzkBuf;
    char Loadhzk,HZK;
    ChinaHzk();
}ChinaHzk;
ChinaHzk::ChinaHzk()
{
    CHzkBuf=_CHzkBuf;
    AHzkBuf=_AHzkBuf;//这两个指针在rhzk程序转换后的.h中定义
}

void hzput(int x,int y,int col,BITMAP bitmap1)
{
    u8 dot;
    register int i,j,k,mask;
    if(ChinaHzk.HZK)
    {
        for(i=0;i  <=15;i++)
        {
            for(j=0;j  <=1;j++)
            {
                dot=*ChinaHzk.CHzkBuf++;
                mask=0x80;
    &nb ......

>>返回讨论的主题



  发表回复
用户名   *您没有注册?
密码   *
验证码   * .
标题   *
心情
随便说说    我回答你    最新发现    得意的笑   
气死我了    真是没劲    坚决同意    表示反对   
大家过来    好奇怪哟    懒得理它    大家小心   
文件上传
内容


字体:      字体大小:    颜色:
粗体 斜体 下划线 居中 超级连接 Email连接 图片 Flash图片 Shockwave文件 realplay视频文件 Media Player视频文件 QuickTime视频文件 引用 飞行字 移动字 发光字 阴影字 查看更多的心情图标 背景音乐
点击加入表情
                         
选项
有回复时用短消息通知您?

   




老古网执行:31毫秒 最大:11656毫秒 查询8次