GBA编程初解 (转载 http://a9.vgsky.com/gba/display/display/20076292136551580.html)

来源:互联网 发布:淘宝刚买的东西失效了 编辑:程序博客网 时间:2024/04/29 15:02
<script type="text/javascript"><!--google_ad_client = "pub-8522047661450954";google_ad_width = 250;google_ad_height = 250;google_ad_format = "250x250_as";google_ad_type = "image";//2007-06-28: http://www.vgsky.comgoogle_ad_channel = "4915185990";google_ui_features = "rc:0";//--></script><script src="http://pagead2.googlesyndication.com/pagead/show_ads.js" type="text/javascript"></script>在具体介绍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 指令系统 (具体区别详见 http://gbadev.org/files/armthumb-romram.txt)
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格式的程序。

     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;
for(k=0;k<=7;k++)
{if(dot&mask)
putpixel(bitmap1,x+j*8+k,y+i,col);
mask>>=1;
}
}
}

}else
for(i=0;i<=15;i++)
{
dot=*ChinaHzk.AHzkBuf++;
mask=0x80;
for(k=0;k<=7;k++)
{if(dot&mask)
putpixel(bitmap1,x+k,y+i,col);
mask>>=1;
}
}
ChinaHzk.HZK=1;
}
//显示字符
void textout(BITMAP bitmap1,char *Str,int x,int y,unsigned char col)
{ register unsigned long offset1;
int oldx;
const u8 *_bakCHzkBuf,*_bakAHzkBuf;

_bakCHzkBuf=ChinaHzk.CHzkBuf;
_bakAHzkBuf=ChinaHzk.AHzkBuf;
oldx=x;
while(*Str)
{if(*Str==’/n’){y+=17;x=oldx;*Str++;continue;}
if(*Str==’ ’){x+=8;*Str++;continue;}

if(!(*Str&0x80)){
offset1=*Str<<4;
ChinaHzk.HZK=0;
ChinaHzk.AHzkBuf+=offset1;
hzput(x,y,col,bitmap1);
if(x+8+ChinaHzk.len<bitmap1.w)
{x+=(8+ChinaHzk.len);}
else
{y+=17;x=oldx;}
Str++;
ChinaHzk.HZK=1;
ChinaHzk.AHzkBuf=_bakAHzkBuf;
continue;}

offset1=(unsigned int)((((*Str+95)<<6)+((*Str+95)<<5))-
((*Str+95)<<1)+(*(Str+1)+95))<<5;
ChinaHzk.CHzkBuf+=(unsigned int)(offset1-778240);
hzput(x,y,col,bitmap1);
if(x+16+ChinaHzk.len<bitmap1.w)
{x+=(16+ChinaHzk.len);}
else
{y+=17;x=oldx;}
Str+=2;
ChinaHzk.CHzkBuf=_bakCHzkBuf;
}
}

//显示字符
void OutText(BITMAP bitmap,int x,int y,char *str,...)
{ va_list ptr;char *strr;
strr=(char*)malloc(strlen(str)+2);
va_start(ptr,str);
vsprintf(strr,str,ptr);
va_end(ptr);
textout(bitmap,strr,x,y,_COLOR);
free(strr);
}

你可以直接使用textout来显示也可以用OutText显示 变量-》字符 这样的信息,例:

OutText(screen,100,100,"X=%d,Y=%d",x,y);

  有了这些基本函数,我想你已经可以写出一些东西来了也许你看了这些会觉得有些眼熟,是的,如果你以前曾用过我写的游戏开发库Beauty的话,会发现基本上代码没有改变,而我当初也的确是有着样的想法, 即使在不同的平台上,不同的系统但使用一套相似的开发库进行开发可以为以后的移植工作省下很大力气。我在进行gba程序编写时就一直在使用Beauty库做测试相比之下要比用gba模拟器方便的多。

转载
http://a9.vgsky.com/gba/display/display/20076292136551580.html

 

原创粉丝点击