タイルモードモードの文字表示2

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

としていく方法しかありません。苦労する点としては描画始点位置のアドレス計算ではないかと思います。

案を考える

試行錯誤の結果、案3の12x14ドット(余白:0x2ドット)が収まりのよさそうな形になりました。BGのアドレス座標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
1.png

12x14ドット(余白:0x2ドット)のタイルモード日本語表示

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

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

	(中略) 

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

動作画面

2.png

履歴


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