ビットマップモード1

GBAの画面の表示方法には大きく分けて2種類あります。それはビットマップモードとタイルモードです。さらにビットマップモードではMode0, 1, 2とあってビットマップモードではMode3, 4, 5と別れています。図にすると次のようなものです。

Mode名称
0-2タイルモード
3-5ビットマップモード

まず最初はビットマップモードの3~5を練習してみましょう。

ビットマップモード

このモードはとあるメモリ領域に値を書き込むと、それがそのまま画面に反映されます。C言語ではint変数に123を代入するとき「int abc = 123;」という書き方をしますが、123が色データの役割を持ち、abcはメモリ領域(そのまま画面に反映されるもの)だ、と思ってください。GBAの画面サイズは240x160ドットです。1ドットにつき2バイトで表現します。240x160x2バイトなので容量は76800バイト。メモリ領域(VRAM)は、0x6000000番地から開始されます。

領域名称開始位置終了位置大きさ(バイト)
VRAM(Video RAM)0x60000000x6012C0076800

ドットを表示する関数をソースコードで書くと以下になります。

void Mode3PutPixel(u32 x, u32 y, u16 color)
{
	u16* ScreenBuffer     = (u16*)0x6000000;
	ScreenBuffer[y*240+x] = col;
}

引数xの幅は0~240、引数yの幅は0~160。それ以上の値を放り込むと簡単に壊れてしまう関数ではあります。最後の引数colorは、色(RGB)データでマクロを使って表します。

#define RGB5(r,g,b) ((r)|((g)<<5)|((b)<<10))
rgb
313131
3100
0310
0031
000
3.png

下位ビットから順番に赤、緑、青がそれぞれ5bitづつ、0~31の32段階を指定して使います。いきなりビットシフトは難しいかもしれません。そこで白色を代入した場合のプログラム的な動きを見ていきましょう。

u16 color = RGB5(31,31,31);

マクロですので次のように分解されます。

u16 color = ((31)|((31)<<5)|((31)<<10));

31とは2進数でいくつでしょうか。windowsに標準装備されている電卓をプログラマー設定して入力してみます。

1.png

この2進数表現を入れてみます。

u16 color = ((0001 1111b)|((0001 1111b)<<5)|((0001 1111b)<<10));

この値はu16単位。つまり2バイト16bitです。拡張します。

u16 color = ((0000 0000 0001 1111b)        |
            ((0000 0000 0001 1111b) <<  5) | 
            ((0000 0000 0001 1111b) << 10)  );

シフトビット計算をします。

u16 color = ((0000 0000 0001 1111b) |
            ((0000 0011 1110 0000b) | 
            ((0111 1100 0000 0000b)  );

OR計算します。

u16 color = 0111 1111 1111 1111b

この値は0x7fffです。この値は最初にいったとおり白色を意味しています。GBATEKでは次のように書かれているのでちょっと引用してみましょう。32*32*32色で32768 colorsで表現できますよ、と書いてあります。15Bit目は使わないようですね。

モード3でドットを描く

先ほどの関数を使ってドットを書いてみます。GBA版Hallo Worldです。

2.png
#include "lib/gba.h"

//---------------------------------------------------------------------------
void WaitForVsync(void)
{
	while(*(vu16*)0x4000006 >= 160) {};
	while(*(vu16*)0x4000006 <  160) {};
}
//---------------------------------------------------------------------------
void Mode3PutPixel(u32 x, u32 y, u16 color)
{
	u16* ScreenBuffer     = (u16*)0x6000000;
	ScreenBuffer[y*240+x] = color;
}
//---------------------------------------------------------------------------
int main(void)
{
	SetMode(MODE_3 | BG2_ENABLE);

	s32 i;

	for(i=0; i<20; i++)
	{
		Mode3PutPixel(5+i, 5+i, RGB5(31, 31, 31));
	}

	for(i=0; i<32; i++)
	{
		Mode3PutPixel(20+i*2, 50, RGB5(i, 0, 0));
		Mode3PutPixel(20+i*2, 60, RGB5(0, i, 0));
		Mode3PutPixel(20+i*2, 70, RGB5(0, 0, i));
		Mode3PutPixel(20+i*2, 80, RGB5(i, i, i));
	}


	for(;;)
	{
		WaitForVsync();
	}
}

まず始めにグラフィックモードをmode3を設定します。

SetMode(MODE_3 | BG2_ENABLE);

グラフィックモードの設定はヘッダファイルにあるSetMode()マクロを使っています。この内容を分解してみると

static inline void SetMode(int mode)	{REG_DISPCNT = mode;}

#define	REG_BASE	0x04000000
#define	REG_DISPCNT	*((vu16 *)(REG_BASE + 0x00))

*((vu16*)(0x04000000 + 0x00)) = MODE_3 | BG2_ENABLE

と同じ意味になり、0x04000000~0x04000001に値を入れることで設定をしています。GBATEKを引用します。

入っている値が0x403。つまり0, 1BitのBG Mode、10 BitのBG2となります。BGはチュートリアルの後半タイルモードにて説明します。今はおまじない程度なものと考えていてください。

履歴


トップ   一覧 検索 最終更新   ヘルプ   最終更新のRSS