** Doc.11 半角英数字の表示方法(ビットマップモード) [#q48ea042]
** Doc.11 英数字の表示方法(ビットマップモード) [#q48ea042]
GBAにはフォントを表示してくれる機能がないので自前に用意しなくてはいけません。~
しかしながらフォントを自作するのは、たくさんの作業時間が必要です。~
そこで着目したのがインターネット上に存在するフリーフォントです。~

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

- [[漢字12x10ドットフォント:http://www.softclub.co.jp/~zoro/k12x10/]]
- [[M+ FONTS:http://mplus-fonts.sourceforge.jp/]]
- [[東雲フォント:http://openlab.jp/efont/shinonome/]]
- [[美咲フォント:http://www.geocities.jp/littlimi/misaki.htm]]

** フォントの形式はbdfを使おう [#fe630c5f]
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(ビットマップ)へ [#n4399737]
bdfの内容はどのように文字が並んでいたり、字体がさっぱりわからないと思います。~
そこでグラフィカルに出力してくれるツール([[bdf2bmp:http://hp.vector.co.jp/authors/VA013241/font/bdf2bmp.html]])を使って確認してみましょう。~
使用方法はプロンプト上でコマンド入力をします。~

 bdf2bmp.exe -s 0 -c 160 k6x10.bdf k6x10.bmp

- オプションの意味
 -sN: 文字仕切り(spacing)の幅を Nピクセルにします。
 -cN: 文字の折り返しカウントをN個で指定します。

#ref(clip_2.png,nolink)

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

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

1文字6x10で、160文字あるので画像全体の大きさは960x10です。
#ref(clip_2.png,nolink)
1文字6x10、160文字あるので画像全体の大きさは960x10となります。


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

- k6x10.s(16行目)
 	.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
 
 (以下略・・・)

変換後、9600(960 * 10)バイトのデータとなりました。~
仮に2文字目の「!」(ビックリマーク)をGBA上に表示したい場合、「!」の位置は次の計算でもとめられます。~
仮に2文字目の「!」(ビックリマーク)をGBA上に表示したい場合、位置は次の計算でもとめられます。~

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

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

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


** ビットマップモードでフォントの表示例 [#p3afbcd8]
今回の例では、トップダウンで見ていった方がわかりやすいので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;
 	}
 }

*** 動作画面 [#ha93b642]
#ref(clip_1.png,nolink)


** 履歴 [#wbebfadd]
- 2014/11/15
- 2007/10/07