Doc.14 日本語の表示方法(タイルモード2)

タイルモードの8x8ドットでは日本語表示は厳しいけど、16x16ドットにしてみたところ、
あまりに大きすぎてガッカリされてしまったことはないでしょうか。
タイルモードは微妙なサイズの表現は不向きです。

それでも使ってみたいと思った場合、

  • マップデータ
    for(i=0; i<32*32; i++)
    {
    	Bg[1].mapBaseAdr[i] = i + (1<<12);
    }
  • タイルデータ
    • 格納領域にドット単位で描画

としていく方法しかありません。苦労する点としては描画始点位置のアドレス計算ではないかと思います。
今回は慎重に作業を進めるため、メモ書き程度の計画案を考えてみるところから始めました。

案を考える

仕様を考慮しつつ、3つほど考えてみます。
一番作っていく上でラクなの&見栄えがいいのはどれなのか、ちょっと考えてみてください。
案1〜3の図解

  • 案1 12x10ドット(余白:0x0ドット)
  • 案2 12x10ドット(余白:0x2ドット)
  • 案3 12x14ドット(余白:0x2ドット)

ここでわかることは、1番目、2番目はポインタを4個用意し、
2行目以降も位置がバラバラなので計算が恐ろしく大変になることがわかります。
もし作るとしたら、Excelかpythonなどでテーブルを予め用意した方がいいかもしれません。

3番目はx座標が偶数か奇数だけ処理が分かれそうなので比較的簡単そうです。
何回もトライ&エラーを繰り返して、以下のソースコードを作ることに成功しました。

EWRAM_CODE void BgFontDrawChr(u16 x, u16 y, u16 chr)
{
	u32 idx = BgFontGetIdx(chr);
	s32 i;

	u16* s1 = BgFont.pDat + idx * BG_FONT_DAT_SIZE / 2;
	u16* s2 = s1 + 32 / 2;
	u16* s3 = s2 + 32 / 2;
	u16* s4 = s3 + 32 / 2;

	if(x & 0x1)
	{
		u16* d1 = Bg[1].tileBaseAdr + y*1024 + (((((x+1)/2)*3)-2) * 32 / 2) + 1;
		u16* d2 = d1 + 15;
		u16* d3 = d1 + 512;
		u16* d4 = d2 + 512;

		for(i=0; i<8; i++)
		{
			*d1++ = *s1++;
			d1++;

			*d2++ = *s1++;
			*d2++ = *s2++;
			s2++;
		}

		for(i=0; i<6; i++)
		{
			*d3++ = *s3++;
			d3++;

			*d4++ = *s3++;
			*d4++ = *s4++;
			s4++;
		}
	}
	else
	{
		u16* d1 = Bg[1].tileBaseAdr + y*1024 + ((x/2)*3) * 32 / 2;
		u16* d2 = d1 + 32 / 2;
		u16* d3 = d1 + 512;
		u16* d4 = d3 + 32 / 2;

		for(i=0; i<8; i++)
		{
			*d1++ = *s1++;
			*d1++ = *s1++;

			*d2++ = *s2++;
			d2++;
			s2++;
		}

		for(i=0; i<6; i++)
		{
			*d3++ = *s3++;
			*d3++ = *s3++;

			*d4++ = *s4++;
			d4++;
			s4++;
		}
	}
}

いやーむっちゃカオスなコードですがツッコミはご勘弁ください(泣。

フォントのインデックス

以下のような関数呼び出しがあったとき、フォントのインデックスを求める計算を考えてみます。

BgFontDrawStr(0, 1, " 123あいう亜意兎★(〜_〜");

昔のコードでは

EWRAM_CODE u16 BgFontGetIdx(u16 sjis)
{
	u16 cnt = sjis - 0x8140;     //0x8140はSJISの先頭文字(' ')

	return (cnt >= FONT_SHT_MAX_CNT) ? 0 : BgFont.pSht[cnt];
}

というのものを作り、SJISコード用のフォントシート呼ばれる53960バイト
(" "〜"熙"まで。1フォントあたり2バイト)のテーブルから抽出していました。
トンデモない大きさなので今回は却下です。

ここではyasuhoさんのGBAファイラーの計算方法を
そのまま流用させていただくことになりました。

テーブルサイズは1408バイトという、驚異のダイエットに成功しています(^^;。
ポイントはSJISコードを3:5:2:6ビットに分解して、3段階のインデックステーブルにすることです。
この為、インデックス(3:5:2ビット)+開始から終点(6ビット)までの情報を記録するだけで済んでいます。

#define BG_FONT_INVALID_INDEX	5	// エラー時のインデックスコード "・"


typedef struct {
	u8 sig[2];
	u8 ver;
	u8 size;
	u8 index;
	u8 reserved[11];
} __PACKED ST_CCT_HEAD;


typedef struct {
	u8 count;
	u8 reserved[3];
} __PACKED ST_XCCTENT;


typedef struct {
	u8  start;
	u8  end;
	u16 offset;
} __PACKED ST_XCCT;


typedef struct {
	u16* pDat;	// フォントデータ
	u8*  pCct;	// フォントシート
} ST_BG_FONT;


EWRAM_CODE u16 BgFontGetIdx(u16 code)
{
	if(_IsSJIS(HIBYTE(code)) == FALSE)
	{
		return BG_FONT_INVALID_INDEX;
	}


	// level 1 ---------------------------------
	u16 c0 = HIBYTE(code) >> 5;
	u16 c1 = HIBYTE(code) & 0x1f;
	u16 i1;

	if(c0 == 4)
	{
		// 80-9F
		i1 = ((u16*)BgFont.pCct)[c1];
	}
	else
	{
		// E0-FF
		i1 = ((u16*)BgFont.pCct)[c1 + 32];
	}

	if(i1 == 0)
	{
		return BG_FONT_INVALID_INDEX;
	}


	// level 2 ---------------------------------
	u16 c2 = LOBYTE(code) >> 6;
	u16 i2 = ((u16*)(BgFont.pCct + i1))[c2];

	if(i2 == 0)
	{
		return BG_FONT_INVALID_INDEX;
	}

	ST_XCCTENT* pXccTent = (ST_XCCTENT*)(BgFont.pCct + i2);
	ST_XCCT*    pXcct    = (ST_XCCT*)(BgFont.pCct + i2 + sizeof(ST_XCCTENT));


	// level 3 ---------------------------------
	u16 c3 = LOBYTE(code) & 0x3f;
	u16 i;

	for(i=0; i<pXccTent->count; i++)
	{
		if(c3 >= pXcct->start && c3 <= pXcct->end)
		{
			return pXcct->offset + (c3 - pXcct->start);
		}

		pXcct++;
	}

	return BG_FONT_INVALID_INDEX;
}

とりあえず細かい話はダウンロードしつつ、コードを読んでいただければ幸いです。

ttf2bmp

最後に、今回はbdfを使わずフォントに丸みのあるttf形式を採用しました。
bmp生成にはpython + pygameを使用し、サーフェイスに1文字づつ描画した後、
スクリーンキャプチャの要領で保存をしています。

# -*- coding:sjis -*-
import pygame
import codecs
import os


def main():
    # フォントコードが書かれたテキストを読み込みます
    file = codecs.open('font_idx.txt', 'r', 'utf_16')
    str = file.read()
    file.close()


    # サーフェイスの大きさを定義します
    str_len = len(str)
    cy = (((str_len * 16) / 256) + 1) * 16

    pygame.init()
    scn = pygame.Surface((256, cy))
    scn.fill((255, 255, 255))


    # ttfフォントを読み込みます
    font = pygame.font.Font("みかちゃん.ttf", 12)


    # 1文字づつ、サーフェイスに書き込んでいきます
    x = 0
    y = 0
    for i in range(str_len):
        sur = font.render(str[i], True, (0,0,0))
        scn.blit(sur, (x,y))
        x = x + 16
        if x >= 256:
            x = 0
            y = y + 16

    # サーフェイスを保存します
    pygame.image.save(scn, "font_mika.bmp")
    return


if __name__ == '__main__': main()
# end of file
clip_2.png

12x14ドット(余白:0x2ドット)の日本語表示例

int main()
{
	BgInit();
	BgFontInit();

	BgAsciiDrawStr(0, 0, "ASCII FONT TEST");
	BgFontDrawStr(0, 1, " 123あいう亜意兎★(〜_〜");


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

動作画面

clip_1.png

履歴

  • 2014/11/18
  • 2008/05/26

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

Last-modified: 2015-10-07 (水) 21:52:24 (2556d)