Doc.11 英数字の表示方法(ビットマップモード)

GBAにはフォントを表示してくれる機能がないので自前に用意しなくてはいけません。
しかしながらフォントを自作するのは、たくさんの作業時間が必要です。
そこで着目したのがインターネット上に存在するフリーフォントです。

以下に紹介したフォントはライセンスがかなり緩いものです。
本来ならフォントの使用料などで金銭的な問題が発生しますので
ライセンスの確認だけは怠らないでください。

フォントの形式はbdfを使おう

bdf形式はフォントを構成しているドットの集まりを記述したものです。
内容はテキストで記述されているので、エディタなので開いてみてください。

ここでは漢字12x10ドットフォントのk6x10.bdfを例に見ていきたいと思います。

  • k6x10.bdf(44〜60行目)
    STARTCHAR 21
    ENCODING 33
    SWIDTH 960 0
    DWIDTH 6 0
    BBX 6 10 0 -1
    BITMAP
    20
    20
    20
    20
    20
    20
    00
    60
    60
    00
    ENDCHAR

注意してほしい部分はBITMAP〜ENDCHARの間です。
数字が並んでいるだけでよくわからないと思いますが、実はこれが1文字分のフォントを表したものです。
この数値は16進数で表されていて、ビットが立っている個所は色あり
立っていない個所は色なしと考えます。

00100000
00100000
00100000
00100000
00100000
00100000
00000000
01100000
01100000
00000000

2進数に変換してみたのが上記です。
この文字は良く見ると「!」(ビックリマーク)の形をしていることがうっすらとわかると思います。
bdfファイルには複数のBITMAP〜ENDCHARがありますが、
何文字あるかをカウントしているのはヘッダ部のCHARSです。

  • k6x10.bdf(26行目)
    CHARS 160

このbdfファイルは、160文字入っていることになっています。

bdfからbmp(ビットマップ)へ

bdfの内容はどのように文字が並んでいたり、字体がさっぱりわからないと思います。
そこでグラフィカルに出力してくれるツール(bdf2bmp)を使って確認してみましょう。
使用方法はプロンプト上でコマンド入力をします。

bdf2bmp.exe -s 0 -c 160 k6x10.bdf k6x10.bmp
  • オプションの意味
    -sN: 文字仕切り(spacing)の幅を Nピクセルにします。
    -cN: 文字の折り返しカウントをN個で指定します。
clip_2.png

最初の字体は「 」(空白スペース)、次に「!」(ビックリマーク)、「”」(ダブルクォーテーション)。
この順番には決まり事があり、俗に文字コードテーブルと呼ばれています。

0x20  (空白スペース)
0x21 !
0x22 "
0x23 #
0x24 $
0x25 %

(以下略・・・)

1文字6x10ドット、160文字あるので画像全体の大きさは960x10ドットとなります。

gritを使ってmode3の画像に変換

さて、k6x10.bmpをgrit(GBA用画像変換ツール)を使ってmode4用に変換をします。
変換されたものは1ドットが1バイトで表されていて、文字の表示処理を作るときにラクができます。
データ容量としては無駄かもしれませんがサンプルコードということでご了承ください。

  • k6x10.s(k6x10.bmpの出力結果)
    	.section .rodata
    	.align	2
    	.global k6x10Bitmap		@ 9600 unsigned chars
    	.hidden k6x10Bitmap
    k6x10Bitmap:
    	.byte 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x01
    	.byte 0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00
    
    (以下略・・・)

仮に2文字目の「!」(ビックリマーク)をGBA上に表示したい場合、位置は次の計算でもとめられます。

1行目の位置 = 2文字目(何文字目かという情報) * 6ドット(1文字分の横のサイズ)

2行目以降の位置も、先の計算式を少し拡張して使います。

2行目以降の位置 = 2文字目(何文字目かという情報) * 6ドット(1文字分の横のサイズ)
+ (コピーしたい行 * 960ドット(画像ファイル全体の横のサイズ))

ビットマップモードでフォントの表示例

今回の例では、トップダウンで見ていった方がわかりやすいのでmain関数から説明します。

int main(void)
{
	SetMode(MODE_3 | BG2_ENABLE);

	ST_FONT f;

	f.pDat  = (u8*) &k6x10Bitmap;	// データのポインタ
	f.imgCx = 960;			// データの横サイズ
	f.cx    = 6;			// 1文字の横サイズ
	f.cy    = 10;			// 1文字の縦サイズ

	Mode3DrawFontChr(&f,  0,  0, '!', RGB5(31,31,31));

	Mode3DrawFontStr(&f, 16, 16, "ABCDEF #$%&", RGB5(31,31,31));
	Mode3DrawFontStr(&f, 16, 32, "123456 +-*/", RGB5(31,31, 0));

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

この中で出てくるST_FONT構造体は、フォントを表示するために必要なパラメータを設定します。

typedef struct {
	u8* pDat;
	u16 imgCx;
	u16 cx;
	u16 cy;
} ST_FONT;

Mode3DrawFontChrは先ほど説明した内容をコードに落としたものです。

void Mode3DrawFontChr(ST_FONT* p, s32 sx, s32 sy, u16 chr, u16 col)
{
	// 書き込む起点位置を求めます
	u16* pScreen = (u16*)VRAM + (sy * 240) + sx;

	// 書き込むフォントデータの位置を求めます
	u8* pDat = p->pDat + (chr - 0x20) * p->cx;

	s32 x, y;
	for(y=0; y<p->cy; y++)
	{
		for(x=0; x<p->cx; x++)
		{
			if(pDat[y*p->imgCx + x] == 0x00)
			{
				continue;
			}

			pScreen[y*240 + x] = col;
		}
	}
}

最後にMode3DrawFontStr関数ですが、
これは文字列を1つ1つMode3DrawFontChr関数に渡しているだけです。

void Mode3DrawFontStr(ST_FONT* p, s32 sx, s32 sy, char* str, u16 col)
{
	u16 chr;
	s32 i=0, x=0, y=0;

	for(;;)
	{
		chr = str[i++];

		if(chr == '\0')
		{
			return;
		}

		// 改行処理
		if(sx + x >= 240)
		{
			x  = 0;
			y += p->cy;

			if(sy + y + p->cy >= 160)
			{
				return;
			}
		}

		Mode3DrawFontChr(p, sx + x, sy + y, chr, col);
		x += p->cx;
	}
}

動作画面

clip_1.png

履歴

  • 2014/11/15
  • 2007/10/07

添付ファイル: fileclip_2.png 289件 [詳細] fileclip_1.png 257件 [詳細]

Last-modified: 2015-01-09 (金) 07:42:05 (2774d)