引言
研究GBA的TILE方式已经有些时间了。这次总结一下研究成果。
放在网上,希望可以对喜欢开发GBA软件的朋友有所帮助。
一 理论部分
1 GBA显示模式
GBA有5个显示模式。MODE0 ~ 5 。估计大家已经很清楚他们之间的外部区别。
模式 层数 不可旋转防缩, 旋转/防缩 色深
TITE模式
0 4 0,1,2,3 ------ 4BIT,8BIT
1 3 0,1 2 4BIT,8BIT
2 2 ------- 2,3 4BIT,8BIT
位图模式
3 1 -------- ------- 16BIT
4 双缓冲 1 -------- ----- 4BIT,8BIT
5 双缓冲 1 -------- ----- 16BIT
造成这些差别的原因是由于96Kb 的VRAM造成的。其中,TILE模式的产生就是为了更好地利用VRAM 。而 3,4,5模式,则更加开放地让用户使用这96K内存。
TIlE方式下,使我们能看到的许多绚丽的画面,都是由许多8X8小块(TILE)组成的。在屏幕上显示则是有一定排列方式的。分为1D方式和2D方式。
关系如下
1D 方式:
tile被分割。如果想建立一个32X32,16色的OBJ,而且开始的TILE为5,那么在屏幕上显示的方式就回是这样的:
------------------------
│ 5
│ 6
│ 7
│ 8
│
------------------------
│ 9
│ 10 │ 11 │ 12 │
------------------------
│ 13 │ 14 │ 15 │ 16 │
------------------------
│ 17 │ 18 │ 19 │ 20 │
------------------------
2D方式:
TILE每一行被存储在32个格子里。 看下面。
--------------------------------
│ 5
│ 6
│ 7
│ 8
│
--------------------------------
│ 37
│ 38
│
39 │ 40
│
--------------------------------
│ 69
│ 70
│ 71
│ 72
│
--------------------------------
│ 101 │ 102 │ 103 │ 104 │
--------------------------------
编号为此TILES在内存中的位置。
而根据是否旋转又可分成 text方式和ROTATE方式.ROTATE方式下所占内存是TEXT方式下的4倍。
2 MAP和TILE的关系
MAP里记录着TILE的索引号,而真正的图象数据是保存在TILE里的,就象4/8BIT图片需要调色盘一样每个象素保存的都是调色盘里的索引值,而真正的颜色是保存在调色盘里的,然后,GBA每次都对MAP里的内容做硬件级的刷新.这就是为什么MODE4下需要翻转,而MODE 0,1,2下不用。
3寄存器和内存
由于,GBA是使用了统一编址的方式,把所有硬部件接口都直接连在了总线上,这样做的好处就是可以象操作内存一样地操作接口,方便地和这些部件交换数据,但是另一方面也减少了可利用的内存,不过对GBA来说这不算什么。
几个接口内存地址,如下
VRAM 0x06000000 ~ 0x06017fff 这里面存放这所有图形信息。(TILES也在里面)
端口是16位的。 共96Kb
PRAM 0x05000000 ~ 0x050003FF 存放调色盘信息。(什么是调色盘??自己到网上去找)
端口也是16位的.一共1Kb
还有几个重要的寄存器接口,如下
名字 内存地址
REG_BG0CNT 0x4000008
REG_BG1CNT 0x400000A
REG_BG2CNT 0x400000C
REG_BG3CNT 0x400000E
主要是定义各BG层的工作方式。而且是16位的。 (可以想象一下,他们在硬件上是怎么连的)
他们的格式为:(以REG_BG0CNT为例)
F E D C B A 9 8 7 6 5 4 3 2 1 0
Z Z V M M M M M A C X X S S P P
│_│ │ │_______│ │ │ │_│ │_│_________________ 优先级。00最高,11最低
│ │ │ │ │ │
│ │ │ │ │ │_______________________ TILE在显存中的开始位置
│ │ │ │ │_____________________________ 是否有马塞克
│ │ │ │_______________________________ 0:256色 ,1: 16 色
│ │ │__________________________________________ MAP数据的存放地址
│ │ Address = 0x6000000 +M * 0x800
│ │____________________________________________ 是否可以旋转
│________________________________________________ 大小 00 为32X32个块,256X256
从中,我们可以看到,map的数据和TILE的数据是全部放在VRAM里的。
而参数中,M和S可以分别决定MAP和TILE的开始地址。
正如上面所解释的,map 的开始地址在 VRAM + M * 0x800最小单元为 128个16BIT (因为端口是16位)
TILE开始地址在 VRAM + SS* 0X4000 最小单位是1024个16BIT
从中,我们还可以看出,zz为
text方式,最大画面限制
00 : 256x256 (32x32 tiles)
01 : 512x256 (64x32 tiles)
10 : 256x512 (32x64 tiles)
11 : 512x512 (64x64 tiles)
rotate方式下最大画面限制
00 : 128x128 (16x16 tiles)
01 : 256x256 (32x32 tiles)
10 : 512x512 (64x64 tiles)
11 : 1024x1024 (128x128 tiles)
REG_BG0HOFS0x4000010 控制BG0水平方向的卷轴
REG_BG0VOFS0x4000012 控制BG0垂直方向的卷轴
REG_BG1HOFS0x4000014 控制BG1水平方向的卷轴
REG_BG1VOFS0x4000016 控制BG1垂直方向的卷轴
REG_BG2HOFS0x4000018 控制BG2水平方向的卷轴
REG_BG2VOFS0x400001A 控制BG2垂直方向的卷轴
REG_BG3HOFS0x400001C 控制BG3水平方向的卷轴
REG_BG3VOFS0x400001E 控制BG4垂直方向的卷轴
OK,现在,我们已经清楚地了解这些寄存器的结构了。然后,我们可以做一些操作。
二 应用举例
1 在MODE0方式下对BG0画点:
我们先建立一张和GBA屏幕相同大小的图片,分辨率为240X160取名叫BGM.bmp ,必须是256色的。内容随便你。
然后用工具gfx2gba.exe 执行以下操作
gfx2gba -fsrc -M -c256 T8 bgm.bmp
然后会生成几个文件 bgm.map.c bgm.raw.c master.pal.c包含了TILE方式下必须的MAP数据和TILE数据。
而-M参数是不对MAP进行压缩。
我们只需要其中的bgm.map.c就够了。其他不需要。然后加到你的程序中。ARM的编译器回自动把他写入数据段而且只读。
然后得设置BG控制寄存器REG_BG0CNT进行初始化。因为,一般的画点函数,内部都是直接对VRAM的开始进行操作。所以,为了那些函数的可再利用性,就必须把TILE的数据放在头部。(这是利用了2D方式的特性)。而MAP数据的位置是由mmmmmm决定的。故,我们将它放在在别的地方,而不是在头部。(一般的都设置在头部,然后跟TILE数据) 所以我们决定把这个数据放在TILE的后面。
TILES数据占了240X160=38400个字节。而map数据占了60个字节( 240/8 * 160/8)
TILES就放在头部。0x6000000为开始。
MAP应该被放在内存的0x06009600。0x9600 / 0x800 = 0x12 所以MMMMM就等于 10010。
所以就得到了:
REG_BGCNT0 = 00 0 10010 1 00 0 00 00 B = 0x1210
然后把MAP数据传送到0X06009600。可以用DMA,可以用FOR,随便你。
最后不要忘了把调色盘数据也写入0x5000000
好了,初步的工作完成了,接下来,那个画点的函数就可以象在MODE3,4,5下一样使用了。
程序:
//在gba.h中已经有的定义
//macros
#define DISPCNT*(u32*)
0x04000000//Sets DISPCNT to be
#define BG0CNT*(u16*)
0x04000008//Sets BG0CNT to be
//memory layout
u16 *s_pal = (u16*)0x05000000;
//the pallette address
u16 *VideoBuffer = (u16*)0x06000000;
//the tile address
u16 *v_map0 = (u16*)0x06009600;
//bkg map
还有就是SetPix(int x,int y,u16 color);
//在GBA.H里已经有了的那个
//--------------------------------------------------------------------
const u16 pal[16];
//这里是调色盘信息,自己写点数据进去.
const u16 map[600];
//这个是GFX2GBA生成的.
//function
void initGraph()
{
BG0CNT = 0x1210;
//解释同上
DISPCNT = 0x0140;
//使用MODE0
DMA3( pal,s_pal,16 );
//初始化调色盘
DMA3( map,v_map0, 600 );
//初始化MAP
}
int C_Entry()//主程序部分
{
initGraph();
SetPix(20,20,3);
//以3号颜色在20,20的位置画一点
while(1){}
//让程序无限循环
}
//因为VRAM有限,而此画点方式太占VRAM所以不支持使用
2动态MAP//强烈建议
大家一定完过吧,这个游戏利用了大量MAP技巧.其中有个最经典的运用就是,当你选择了一个角色的时候,回出现活动范围。
原理也是对MAP数据进行操作
得到角可行走的坐标后,从新构造MAP