GBA 开发简单入门

一. GBA开发包--DevKitAdv 简介

DevKitAdv 主要包括两部分,一是GCC++编译器,二是 GBA库.

GCC++编译器功能和我们常用的VC差不多,只不过少了个编辑源代码的文本编辑器(至少我没发现,我用的是EditPlus,UltraEdit也可以

),还有就是--不支持类(class),真是让人头痛,只能用struct来替代.它的作用是把我们写的代码编译成二进制的可执行文件,当然这

个可执行文件是相对GBA和GBA模拟器而言的.就象Windows里的EXE文件无法在Mac机上使用是一样的道理;

没啥好说的,解压后就可以直接使用,编译时设置DevKitAdv的路径就可以了,建议做一个批处理文件,比如 go.bat

set PATH=d:/devkitadv/bin;%PATH%

cmd (win98是command)

三. 最简单的 GBA 程序 (t1)

// main.c

// 一些基本数据类型

typedef unsigned char u8;

typedef unsigned short u16;

typedef unsigned long u32;

#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 15bits/单缓冲区

#define MODE_4 0x04    // 240*160 8bits/双缓冲区

#define MODE_5 0x05    // 160*128 15bits/双缓冲区

#define BG2_ENABLE 0x0400   // BG_2

#define SetMode(Mode) REG_DISPCNT=(Mode)     // 设置显示模式的宏定义

// ----------- 主程序 ------------

int main()

{

//设置屏幕模式,这里使用MODE_4

SetMode (MODE_4 | BG2_ENABLE);

}1.MODE_5和MODE_3都是16bits,但MODE_3只有单缓冲,制作动画效果肯定没双缓冲好,因此排除MODE_3;

2.MODE_4是8bits,理论上256色对于掌机够用了,虽然16bits真彩的诱惑没有人想抗拒,可MODE_5只有160*128咧,在实际应用中建议还

是使用MODE_4.

很简单吧--的确是的,现在要用GCC编译它:

gcc -lm -o main.elf main.c

objcopy -v -O binary main.elf main.bin

你会看目录下多了个"main.bin",这个就是能在GBA模拟器上执行的二进制文件!

教程中t1-t7目录为源程序目录,里面有个make.bat,修改代码后直接执行它就可以编译,但要注意我的devkitadv是装在D:,你要是装在

别的盘就得改一下make.bat的path参数.

四. 在MODE_4背景层画图的 GBA 程序 (t2)

在GBA的MODE_4里画一幅图要经过3个步骤:

1. 把原始256色图像文件转换成 *.h / *.c 的数据文件,我们用的是 < BMP2GBA >

,这里以"image.bmp"为例,转换后我们就得到了一个"image.h"文件;

2. 在程序开头#include "image.h",这样就能在程序中使用"image.h"定义的调色板和图像数据;

3. 在程序中把"image.h"定义的调色板和图像数据写入MODE_4背景层的调色板和图像缓冲区.

另外,GBA还有专为精灵设置的物体层,它的用法和背景层一样,只是功能有点不一样,地址是0x06000000.有关用这里就不详细说了,大

家可以把精灵数据直接输出到物体缓冲区就可以了.

下面是源程序:

... ...

// 包含图像调色板和数据的头文件

#include "gfx/image.h"

// ----------- 全局变量 --------

// 系统调色板

u16* palette_mem=(u16*)PALETTE;

// 图像缓冲区

u16* video_buffer=(u16*)VRAM;

// ----------- 函数定义 ---------

// MODE_4绘图函数

void Draw(u16* src_palette,u16* src_data,u16* dst_palette,u16* dst_data);

// ----------- 主程序 ------------

int main()

{

// 设置屏幕模式,这里使用MODE_4

SetMode (MODE_4 | BG2_ENABLE);

// 在背景层画图,Palette和Data是在"image.h"定义的调色板和图像数据数组名

Draw(Palette,Data,palette_mem,video_buffer);

}

// MODE_4绘图函数

void Draw(u16* src_palette,u16* src_data,u16* dst_palette,u16* dst_data)

{

int loop,x,y;

// 写入目的调色板

for(loop = 0; loop < 256; loop++)

dst_palette[loop] = src_palette[loop];

// 写入图像缓冲区

for(x = 0; x < 120; x++)

{

for(y = 0; y < 160; y++)

{

dst_data[(y) *120 + (x)]=src_data[(y) *120 + (x)];

}

}

}编译后得到main.bin,然后在GBA模拟器里运行,就可以得到这样的结果:

大家看了可能有点失望~是啊,256色用来看PPMM实在... ...下一步我们就使用MODE_5来画16bits真彩的MM!

五. 在MODE_5画图的 GBA 程序 (t3)

在GBA的MODE_5里画一幅图也要经过相似3个步骤,只不过不需要调色板数据:

1. 把原始真彩图像文件转换成 *.h / *.c 的数据文件,我们用的是 < Targa2GBA >

,这里以"image.bmp"(240*160)为例,DOS窗口下进Targa2GBA目录,输入"t2g mode5 image.bmp

image.h",转换后我们就得到了一个"image.h"文件;

2. 在程序开头#include "image.h",这样就能在程序中使用"image.h"定义的图像数据;

3. 在程序中把"image.h"定义的图像数据写入图像缓冲区.

下面就是源程序:

// 包含图像数据的头文件

#include "gfx/image.h"

// ----------- 全局变量 --------

// 图像缓冲区

u16* video_buffer=(u16*)VRAM;

// ----------- 函数定义 ---------

// MODE_5绘图函数

void Draw(int x,int y,int w,int h,u16 *src_data,u16 *dst_data);

// ----------- 主程序 ------------

int main()

{

// 设置屏幕模式,这里使用MODE_5

SetMode (MODE_5 | BG2_ENABLE);

// 在背景层画图,image是在"image.h"定义的图像数据数组名

Draw(0,0,240,160,image,video_buffer);

}

// MODE_5绘图函数

void Draw(int x,int y,int w,int h,u16 *src_data,u16 *dst_data)

{

int i,o,idst;

// 把源图像数据复制到图像缓冲区的指定地方

idst =(y*160)+x;

for (i=0;i

{

for (o=0;o

{

if (*src_data != 0)

{

dst_data[idst] = *src_data;

}

idst++;

src_data++;

}

idst += (160-w);

}

}

编译后运行结果:

呵呵,是不是很棒?这是24bits "image.bmp"(240*160) 在MODE_5

16bits下的显示结果,240*160的图像到了MODE_5下的160*128,也就是MODE_5的满屏显示画面只有这么大.

六. 全屏显示的 MODE_5 GBA 程序 (t4)

由于GBA不支持线性的图像变换,因此得到的结果会产生一些马赛克的现象,现在还是附上这个变换函数和最终结果,其实质量还是可以

接受的,大家可以试试使用这个新的MODE_5.

// 切换到新MODE_5全屏模式,page为缓冲区,原理是把显示寄存器数据X,Y交换,得到128*160的显示,GBA就会全屏显示.

void SetFlipMode(int page)

{

u16  *ioreg=(u16*)0x4000000;

*ioreg=5+((page&1)>>4)+(1>>10);

ioreg[0x10]=0;

ioreg[0x11]=256;

ioreg[0x12]=128;

ioreg[0x13]=0;

}

int main()

{

// 设置屏幕模式,这里使用MODE_5

SetMode (MODE_5 | BG2_ENABLE);

// 切换模式

SetFlipMode(0);

// 在背景层画图,image是在"image.h"定义的图像数据数组名

Draw(0,0,240,160,image,video_buffer);

return(0);

}

Come on,来看看结果:

此时就是新MODE_5下的全屏模式,图像被翻转并放大,因为MODEL_5的分辨率是160*128,而上面的程序画的是240*160的图像,所以有部

分就看不到了.

如果要象MODEL_4那样正常显示我们的图像,那么只有对原图像文件做点手脚才行了,下面就是处理新MODEL_5下图像文件的步骤:

1.把原图像顺时针旋转90度;

2.再将图像水平翻转;

3.调整图像大小至 160*128.

这里是示意图:

原图 1 2 3

OK,把步骤3后的图像编译进bin就可以得到:

大家可以看到有轻微的马赛克,但比起256色的效果还是要好一些,到底使用什么模式还得看做的游戏类型,如果是一些经典

RPG/ACT/SLG等还是建议用MODE_4.

七. GBA的双缓冲显示(t5)

大家在做上面MODEL_5的程序时一定会发现图像在闪动(第六节的240*160的MM象被破了相...),而MODEL_4下却比较稳定--这是因为

MODEL_5下要处理16bits(实质上是15bits)的图像,数据量比MODEL_4下的8bits大很多,在没使用双缓冲的情况下,图像填充时就会造成

闪烁,这就是为什么我们抛弃了MODEL_3的原因...

原理也很简单,图像在背缓冲区里填充好之后再直接输出到前缓冲区显示,程序里就是一个 "等待同步-> 交换缓冲" 的过程:

... ...

// ----------- 全局变量 --------

// 图像缓冲区

u16* video_buffer=(u16*)M5_VRAM;

// ----------- 函数定义 ---------

... ...

// 等待缓冲区数据同步

void WaitSync ();

// 交换缓冲区内容

void SwapScreen ();

// ----------- 主程序 ------------

int main()

{

// 设置屏幕模式,这里使用MODE_5

SetMode (MODE_5 | BG2_ENABLE);

while(1)

{

// 在背景层画图,image是在"image.h"定义的图像数据数组名

Draw(0,0,240,160,image,video_buffer);

WaitSync();

SwapScreen();

}

}

// 等待缓冲区数据同步

void WaitSync ()

{

while (*(volatile u16*)0x4000006<160) {};

}

// 交换缓冲区

void SwapScreen ()

{

if (REG_DISPCNT & BACKBUFFER)

{

REG_DISPCNT &= ~BACKBUFFER;

video_buffer = (u16*) M5_VRAM;

}

else

{

REG_DISPCNT |= BACKBUFFER;

video_buffer = (u16*) VRAM;

}

}

八. GBA 的按键输入(t6)

讲了老半天的图像,虽说是对着MM,但大家一定也有点烦了,我们现在就换个方向,来看看GBA的控制.

... ...

// 按键控制

#define KEY_A 1

#define KEY_B 2

#define KEY_SELECT 4

#define KEY_START 8

#define KEY_RIGHT 16

#define KEY_LEFT 32

#define KEY_UP 64

#define KEY_DOWN 128

#define KEY_R 256

#define KEY_L 512

volatile u32* KEYS = (volatile u32*)0x04000130;

// 包含图像调色板和数据的头文件

#include "gfx/image.h"

// ----------- 全局变量 --------

// 图像缓冲区

u16* video_buffer=(u16*)M5_VRAM;

// 图像显示坐标

int img_x,img_y;

// ----------- 函数定义 ---------

// 按键控制

void KeyAction();

... ...

// ----------- 主程序 ------------

int main()

{

// 设置屏幕模式,这里使用MODE_5

SetMode (MODE_5 | BG2_ENABLE);

while(1)

{

// 处理按键事件

KeyAction();

// 在背景层画图,image是在"image.h"定义的图像数据数组名

Draw(img_x,img_y,96,64,image,video_buffer);

WaitSync();

SwapScreen();

}

}

// 处理按键事件

void KeyAction()

{

// 上方向键

if(! ( (*KEYS) & KEY_UP) )

{

img_y+=5;

}

// 下方向键

if(! ( (*KEYS) & KEY_DOWN) )

{

img_y-=5;

}

}

简单吧,这个例子响应上下按键来控制图像上下移动.我们没有先清除背缓冲就在里面填充图像数据,所以你可以看到图像移动后,原来

位置上的图像仍在背缓冲里,这样可以很清楚的看到双缓冲的工作过程.

什么?太丑了,那好,加一个背景就OK了嘛... ...后一幅是带ALPHA.

#include "bg.h"

... ...

// 先画背景

Draw(0,0,160,128,bg,video_buffer);

// 再画MM

Draw(img_x,img_y,96,64,image,video_buffer);

... ...

九. 简单声音输出(t7)

Simple is the Best(简洁至上),这里我们使用一个现成的声音模块(Troff Player,by Vova &

Serge).这里还要用到一个转换工具< MOD2GBA >,用来把MOD音乐文件转换成GBA的 *.c / *.h

声音数据文件.MOD和MIDI差不多,但支持更多更强的效果.

// MOD数据文件

#include "song_data.h"

// MOD播放函数文件

#include "modplayer.h"

// ----------- 主程序 ------------

int main()

{

//设置屏幕模式,这里使用MODE_4

SetMode (MODE_4 | BG2_ENABLE);

// 初始化声音(声道数,音量)

InitSound(2, 7);

// 初始化音乐(节拍,循环)

InitSong(20000, 0);

while(1)

{

// 更新音乐播放状态

UpdateSong();

}

}

OK,就这么EZ.

十. 用图块建立可滚动/缩放/旋转的背景(t8)

这一节主要是源程序中注释为主,这里就不详细说明了."gba.h"包含基本宏定义,"maths.h"是sin/cos乘256后的值数组,"main.h"包括

了我们定义背景结构及操作背景的函数.

程序中的地图背景是由不同的图块所构成,而这些图块统一紧挨着放在一个图像文件,这样每个图块就会有一个索引号;地图信息只要

记录这张地图里共有多少个

单位(图块)以及每个单位对应的图块索引号就OK了,在例子中"gfx/tiles.h"就是图块大本营,而"gfx/level1.h"则是图块索引排列表.

地图工具为"map

editor beta 4".

背景的滚动/缩放/旋转是通过一系列的简单数学计算,修改GBA系统提供的一些背景属性来完成,因为是由硬件来完成背景的操作

(MODE_1),所以速度很快,我还有个MODE_5下直接修改像素点位置来完成旋转的例程,待会儿大家可以比较一下.

十一. MODE_5下的背景旋转(t9)

这个例子通过计算旋转后像素的新位置来完成旋转,原理很简单,可以直接应用到精灵上.

// ----------- 主程序 ------------

int main()

{

// 角度

int i=0;

// 设置屏幕模式,这里使用MODE_5

SetMode (MODE_5 | BG2_ENABLE);

while(1)

{

// 在背景层画图,image是在"image.h"定义的图像数据数组名

Draw(0,0,128,128,bg,video_buffer);

// 将旋转后的背景数据写入图像缓冲

RotateBG(bg,video_buffer,i++);

if (i==360) i=0;

}

}

// 旋转背景

void RotateBG(u16 *src,u16 *dst,int angle)

{

int x,y,ys,yc,tx,ty;

unsigned int srcptr=0,dstptr =0;

// 计算旋转后像素的指针

for (y=-80;y<80;y++)

{

ys = y * Sin [angle];

yc = y * Cos [angle];

for (x=-80;x<80;x++)

{

tx =(((x*Cos [angle]) - ys))>>7;

ty =(((x*Sin [angle]) + yc))>>7;

srcptr = (((ty<<7)+tx+(160*80+80)) & 16383);

dst [dstptr] = src [srcptr];

dstptr++;

}

}

}

十二. GBA下的中文显示

呵呵,英文的还没来得及写就先把中文搞掂了~~~~

这里所做的程序核心技术来自于DOS下的中文显示技术.其实和老外用位图来显示26个英文字母原理大同小异,我们使用16*16点阵字库

来完成中文的显示.

大家一定知道在输入法里有一个从没用过区位(内码)输入法,这个输入法使用4个数字来完成中文输入----估计没有谁会用它来和MM聊

天.中文字库其实也就可以看成一张很大的位图,上面按一定顺序画满了常用的汉字,而区位(内码)输入法的4个数字代表了一个汉字在

字库里所在的区和具体位置.

举个例子,"说"字的区位码是"4321",当我们选择区位输入而且在记事本里输入"4321",输入法程序就会马上到字库里4321区域,然后把

4321区域的点阵(位图)数据传给系统显示出来,这样"说"字就出来了.

在GBA里显示中文是一样的原理,但由于GBA没有文件输入/输出函数,我们不得不先把二进制的点阵字库转换成数组存储数据,包括区位

码和点阵(位图)数组.这里就不详细说明原理了,我为大家做好了一个

转换工具----" HZK2GBA "(汉字库->GBA).附带源程序^_^.

你首先得把你所有的文字做成一个文本文件,比如" zk.txt ",然后执行" hzk2gba zk.txt "来得到" GBAZK.h

"文件,这就是GBA可用的字库数组头文件.

这样做的目的是不用把字库里所有的汉字送入GBA,只留下我们用到的汉字,可以很大的节省空间和内存.

接下来的工作就是利用得到的" GBAZK.h "在GBA里写下你想写的话.

... ...

#define RGB(r,g,b) ((r)+(g<<5)+(b<<10))   // 设置GBA的色彩

#define MAX 10240        // 最大字符数

// 包含中文字库数据的头文件

#include "gfx/GBAZK.h"

// ----------- 全局变量 --------

// 图像缓冲区

u16* video_buffer=(u16*)VRAM;

// ----------- 主程序 ------------

int main()

{

// 设置屏幕模式,这里使用MODE_5

SetMode (MODE_5 | BG2_ENABLE);

// 写入字符

DrawText("水银教程",20,20,255,0,0);

}

//- 写中文字符函数 ----------------

void DrawText(unsigned char *str,int x,int y,int r,int g,int b)

{

int i,j,k,n;

// 字符所在区,位,实际位置

int qu, wei, location;

while(*str)

{

// 得到单字的区位码

qu = *(str++)-0xa0;

wei = *(str++)-0xa0;

location = qu*94+wei;

// 在字库里查找

for(n=0 ;n

{

if(ZKQW[n]==location)

{

// 根据字符数据画出字符

for(i=0;i<16;i++)

for(j=0;j<2;j++)

for(k=0;k<8;k++)

if(convert(ZKDATA[n*32+i*2+j],7-k))

DrawPixel(x+j*8+k,y+i,r,g,b);

x+=16;

}

}

}

}

int convert(u16 str,int n)

{

return((str>>n)&0x1);

}

//- 画点函数 ---------------------

void DrawPixel(int x, int y, int r, int g, int b)

{

video_buffer[x+y*160] = RGB(r,g,b);

}

就这么多了,字体样式的问题得等下一步解决TrueType字体显示才行,字体大小嘛,大家自己用背景/物体层的缩放或是直接缩放像素的

方法试试.至于英文的显示~~~~~

^_* ,好困噢~~~~ 下回见!!!!!

到这里先告一个段落了,大家可以到www.gbadev.com上了解更多的东西,我这里就不累赘了.

linux如何将图片转为gba数组,GBA 开发简单入门相关推荐

  1. GBA 开发简单入门

    1.为什么要选用GBA作为嵌入式系统学习平台 我们知道,任天堂公司的GameBoy Advance(简称GBA)一款非常出色的掌上游戏机,该产品占领了全球90%以上的掌上游戏机市场. 抛开游戏功能不说 ...

  2. 图片转为pdf怎么弄?简单几个步骤轻松转换

    在日常工作和生活中,我们常常需要将图片转换为PDF格式的文档,以满足资料存档和共享的需要.虽然转换过程看起来有些麻烦,但只要选择正确的工具和方法,就能轻松完成. 下面,小编将为大家介绍两种常见的将图片 ...

  3. python三维矩阵出图_python读取图片的方式,以及将图片以三维数组的形式输出方法...

    python 三维npy数组如何画成三维图片 画成三维图片? 你要是想要看空间分布的话画散点图就可以啊,用matplotlib 网页链接 要是那种各种弯曲的面,也是matplotlib 网页链接 再就 ...

  4. python将图片转为二进制_python 图片 数组到二进制的互相转换

    需要导入以下包,没有的通过pip安装 import matplotlib.pyplot as plt import cv2 from PIL import Image from io import B ...

  5. python 怎么将数组转为列表_图片转换成pdf格式怎么操作?什么软件能将图片转为pdf?...

    伙伴们好,你们知道如何把图片转为pdf格式吗?前一阵子我参加了一个家居行业大会,在会议上拍摄了不少会议照片,包括主持人讲话.嘉宾出席.观众提问.产品推广等环节都拍摄了不同的角度.拍摄好后,需要传送给写 ...

  6. Nodejs 使用 Buffer 将图片转为 base64

    一直以为图片转为 base64 很复杂,结果今天看了下 Docusaurus 的 plugin-ideal-image 插件源码,居然只要一行代码就完事了: const toBase64 = (ext ...

  7. Linux下BMP图片缩放

    Linux下BMP图片缩放   MP是英文Bitmap(位图)的简写,它是Windows操作系统中的标准图像文件格式,能够被多种Windows应用程序所支持.随着Windows操作系统的流行与丰富的W ...

  8. python图片转为二进制流_python将图片转为二进制-女性时尚流行美容健康娱乐mv-ida网...

    女性时尚流行美容健康娱乐mv-ida网 mvida时尚娱乐网 首页 美容 护肤 化妆技巧 发型 服饰 健康 情感 美体 美食 娱乐 明星八卦 首页  > 高级搜索 mysql 5.7.9 lin ...

  9. 本地图片转为file类型

    本地图片转为file类型 一.场景描述 二.解决思路 三.具体实现 1.相对路径转base64 2.base64转blob 一.场景描述 类似我们页面中有一些图片,当用户点击页面上对应图片时,我们需要 ...

最新文章

  1. easyui table 数据表筛选条件
  2. 仿微信选取图片发表朋友圈功能
  3. 【图像处理】彩色图像自适应对比度增强(OpenCV实现)
  4. css如何去掉已经存在的样式_CSS 选择器的介绍和使用(一)
  5. 测试用例设计方法——正交表详解
  6. PPT 宏 macro图片crop
  7. 《离散数学》速成-练习题答案(含题目)
  8. 7-4 厘米换算英尺英寸
  9. MSN机器人 博客助手 for I-Favourite
  10. IO口电压域io-domain核对流程
  11. ios wifi 定位_一种IOS设备的集中式Wifi室内定位方法
  12. laravel-admin Model does not exists添加模型报错
  13. React + Koa2打造『官方管理后台』10 总结
  14. 上海亚商投顾:两市震荡引分化 汽车产业链获青睐
  15. require(): open_basedir restriction in effect错误解决
  16. Android用mediaPlayer.prepare()报错
  17. plc程序结构及其特点介绍
  18. mysql-installer-community.msi新手安装教程(详细图文)
  19. 计算机网络安全教程(第三版)第七章简答题答案
  20. 日本语能力测试考点地址及联系方式

热门文章

  1. 让ChatGPT显示图片和动态GIF图
  2. (个人搬运 “请认真看完帖子“ )职教星2.8.2可用
  3. java数组冒泡排序
  4. 北京dns服务器ip地址_什么是DNS? 域名系统,DNS服务器和IP地址概念介绍
  5. 接口调试插件RESTED使用post的方法
  6. i5 1135g7和i7 1165g7核显一样吗 i51135g7和i71165g7的相差大吗
  7. Spring Security登录成功后,用户信息保存在哪,如何获取?
  8. [蓝桥杯][历届试题]蚂蚁感冒(模拟全过程)
  9. java词法分析器实验报告_词法分析器实验报告(JAVA)
  10. 一、C++简介以及qt安装及配置(华清笔记)