- 追加された行はこの色です。
- 削除された行はこの色です。
- doc.12 へ行く。
#author("2024-02-14T20:21:46+09:00;2023-05-30T00:18:35+09:00","","")
#author("2024-02-14T20:22:17+09:00;2023-05-30T00:18:35+09:00","","")
* ビットマップモードの文字表示1 [#r824d2f2]
GBAにはフォント表示の機能がないので自前に用意しなくてはいけません。加えてフォント自体を自作するのは大変な労力です。そこで着目したのがインターネットに存在するフリーフォント。以下に紹介したフォントはライセンスがかなり緩いものとなっています。本来なら使用料などの金銭的な問題がありますので、ライセンスを確認せずに使うことは避けてください。
- [[漢字12x10ドットフォント:https://z.apps.atjp.jp/k12x10/]]
- [[M+ FONTS:https://mplus-fonts.osdn.jp/]]
- [[東雲フォント:https://openlab.jp/efont/shinonome/]]
- [[美咲フォント:https://littlelimit.net/misaki.htm]]
** フォントの形式はbdfを使おう [#k6a9f1c8]
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進数で表されていて、ビットが立っている個所は''色あり''、立っていない個所は''色なし''と考えます。
-BITMAP~ENDCHARを2進数に変換
00100000
00100000
00100000
00100000
00100000
00100000
00000000
01100000
01100000
00000000
2進数に変換してみたのが上記です。この文字は良く見ると「!」(ビックリマーク)の形をしていることがうっすらとわかると思います。bdfファイルには複数のBITMAP~ENDCHARがありますが、何文字あるかをカウントしているのはヘッダ部の''CHARS''です。このbdfファイルは''160文字''入っていることがわかります。
- k6x10.bdf(26行目)
CHARS 160
** bdfからbmp(ビットマップ)へ [#n4399737]
bdfの内容はどのように文字が並んでいたり、字体がさっぱり想像つかないと思います。そこでグラフィカルに出力してくれるツール([[bdf2bmp:http://hp.vector.co.jp/authors/VA013241/font/bdf2bmp.html]])を使って確認してみましょう。使用はコンソールでコマンド入力します。
bdfの内容はどのように文字が並んでいたり、字体がさっぱり想像つかないと思います。そこでグラフィカルに出力してくれるツール([[bdf2bmp:https://hp.vector.co.jp/authors/VA013241/font/bdf2bmp.html]])を使って確認してみましょう。使用はコンソールでコマンド入力します。
- コマンド入力
bdf2bmp.exe -s 0 -c 160 k6x10.bdf k6x10.bmp
Total glyphs = 160
BMP width = 960 pixels
BMP height = 10 pixels
BMP filesize = 10678 bytes
- オプションの意味
-sN: 文字仕切り(spacing)の幅を Nピクセルにします。
-cN: 文字の折り返しカウントをN個で指定します。
文字の間に余白(ドット)を0にして、文字160個分の列を折り返しなし、というコマンドをします。
#ref(1.png,nolink)
出力画像の最初の字体は「 」(空白スペース)、次に「!」(ビックリマーク)。この順番には決まり事があり、俗に文字コードと呼ばれています。ホームページを見ていたら文字化けしている現象を目にするのは、ブラウザがコード変換を間違えたからです。1文字6x10ドット、160文字あるので画像全体の大きさは960x10ドットとなります。
0x20 (空白スペース)
0x21 !
0x22 "
0x23 #
0x24 $
0x25 %
(以下略・・・)
** gritを使ってGBA用に変換 [#vde62d22]
さて、k6x10.bmpをgritで''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
(以下略・・・)
縦960×横10=9600バイト。仮に2文字目の「!」(ビックリマーク)をmode3で表示したいと考えてみます。ビックリマークの最初のドット座標はx=6,y=0で、そこから横に6ドット分が1行目ということになります。次に2行目のドット座標はx=6,y=1で、そこから横に6ドット分が2行目となります。疑似的なコードに落としこんでみましょう。
#ref(2.png,nolink)
index_x=6;
index_y=0;
s32 x, y;
for(y=0; y<10; y++)
{
for(x=0; x<6; x++)
{
if(data[(index_y+y)*960 + index_x+x] == 0x01)
{
GBA VRAM = 黒色;
}
else
{
GBA VRAM = 白色;
}
}
}
** mode3の表示 [#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(3.png,nolink)
** 履歴 [#wbebfadd]
- 2023/04/16
- 2007/10/07