PCエンジンのプログラミング(その4)BGの表示

nicotakuya.hatenablog.com
前回の続きです。今回は「BG」を表示したいと思います。
PCエンジンはとにかく資料が見当たらないです。頼りになるのはサンプルの「PONG」だけです。

f:id:nicotakuya:20201129010530p:plain
サンプルのPONG

PONGではBGを表示するために「#incchr」「#incpal」「#incbat」という3つのマクロを使っています。
このマクロの機能を調べるために次のようなプログラムを作ってみました。

/*BG dump by takuya matsubara*/
#include "huc.h"

#define BACKGROUND_FILE "special.pcx"
#incchr(bg_pattern,BACKGROUND_FILE,32,28);
#incpal(bg_palette,BACKGROUND_FILE);
#incbat(bg_bat,BACKGROUND_FILE,0x1000,32,28);

main()
{
	int i;
	char x,y;

	disp_on();
	cls();

	put_string("Pattern",1,1);
	for(i=0;i<66;i++){
		x=(i % 6)*5+1;
		y=(i/6)+2;
		put_hex(bg_pattern[i], 4, x,y);
	}

	put_string("Palette",1,14);
	for(i=0;i<24;i++){
		x=(i % 6)*5+1;
		y=(i/6)+15;
		put_hex(bg_palette[i], 4, x,y);
	}

	put_string("BAT(Background Attribute Table)",1,20);
	for(i=0;i<36;i++){
		x=(i % 6)*5+1;
		y=(i/6)+21;
		put_hex(bg_bat[i], 4, x,y);
	}

	while(1){
		vsync();
	}
}

以上のプログラムをPCエンジンエミュレータで実行すると、こうなります。

f:id:nicotakuya:20201130141434p:plain
実行結果

PONGの背景の画像をBGデータ化してダンプ表示します。画像はPCXファイル(special.pcx)です。
本来はもっと大量にデータがあるのですが、画面の都合で表示数を制限しています。
これを見て、わかったことは次の通り。
「#incchr」はパターンを生成するマクロ。1ピクセルのデータ量は4bit(16色)。タイル1枚あたり8×8ピクセル=データ量は16ワード。
「#incpal」はパレットを生成するマクロ。スプライト用でも使用。1色16bitのうち実データ9bit(緑3+赤3+青3bit)。全部で16色×16パレット=256ワード。
「#incbat」はBATを生成するマクロ。BAT(Background Attribute Table)というのは、タイル番号などを格納したバッファです。ファミコンでいうところのネームテーブルです。1セルを表現するために1ワード消費します。bit15~12がカラーパレット番号で、bit11~0がタイル番号です。タイル番号は0x100番から始まっています。おそらく、0x100番未満はフォントに使っているのではないでしょうか。これに関係して、VRAMの0x1000番地からパターンデータが格納されます。
サンプルのBGの描画サイズが32×28セル。なので、BAT全体のデータ量は896ワードです。BATはVRAMの0x0000~0x03FF番地(0x037F?)に格納されるようです。
要するにパターン+パレット+BATの3要素がBGには必要ということです。以上を参考にして、自作ツール(spedit)に機能を追加しました。
https://sites.google.com/site/yugenkaisyanico/sprite-editor

f:id:nicotakuya:20201130144111p:plain
BGのテストパターンを自動生成

メニューで「16色test(PC Engine BG)」ボタンを押すと、テストパターンのBGデータを自動生成します。
「bg_pattern.bin」「bg_palette.bin」「bg_bat.bin」という3つのバイナリファイルを作ります。スプライトと違って、BGはパターンデータの格納方法が特殊すぎるのですが、詳しくはspeditのソースを見てください。
続いて、BGを表示するプログラムを改良しました。

/*BG dump2 by takuya matsubara*/
#include "huc.h"

#incbin(bg_pattern,"bg_pattern.bin");
#incbin(bg_palette,"bg_palette.bin");
#incbin(bg_bat    ,"bg_bat.bin");

main()
{
	int i;
	char x,y;
	int work;

	disp_on();
	cls();

	put_string("Pattern",1,1);
	for(i=0;i<66;i++){
		x=(i % 6)*5+1;
		y=(i / 6)+2;
		work = bg_pattern[i*2]+0x100*bg_pattern[i*2+1];
		put_hex(work, 4, x,y);
	}

	put_string("Palette",1,14);
	for(i=0;i<24;i++){
		x=(i % 6)*5+1;
		y=(i / 6)+15;
		work = bg_palette[i*2]+0x100*bg_palette[i*2+1];
		put_hex(work, 4, x,y);
	}

	put_string("BAT(Background Attribute Table)",1,20);
	for(i=0;i<36;i++){
		x=(i % 6)*5+1;
		y=(i / 6)+21;
		work = bg_bat[i*2]+0x100*bg_bat[i*2+1];
		put_hex(work, 4, x,y);
	}

	while(joy(0)==0){
		vsync();
	}

	load_background(bg_pattern, bg_palette, bg_bat, 32, 28);
	for(i=0;i<16;i++){
		put_string("<Palette=",16,i);
		put_hex(i, 1, 16+9,i);
	}
	while(1){
		vsync();
	}
}

ここでは「#incbin」マクロでBGデータのバイナリファイルを組み込みます。「#incchr」「#incpal」「#incbat」マクロが不要になります。
エミュレータで実行すると、こうなります。

f:id:nicotakuya:20201130141523p:plain
実行結果

ここでゲームパッドのボタンを押すと、、、

f:id:nicotakuya:20201130141602p:plain
240色表示

、、、こうなります。
BGの行がパレット番号に対応しています。
これでわかりましたが、1パレット16色のうち1色は透明色に割り振られています。なので、実質15色です。画面の左端1列がまるごと黒くなっています。
15×16=240色が表現可能なBGの色。背景色が加わった場合は241色になります。

f:id:nicotakuya:20201130141747j:plain
変換前の画像


あと、自作ツールにBMP→BGデータの変換機能を追加してみました。たとえば、このような画像を用意します。これをPhotoshopで解像度を256x224ピクセルに調節。16色に変換してBMPで保存します。

f:id:nicotakuya:20201130141844p:plain
ツールでデータ化

ここで「PC Engine BG」のボタンを押す。
3つのバイナリファイルが生成されるので、先ほどのテストパターンと差し替えます。

f:id:nicotakuya:20201130141924p:plain
BGの表示に成功

PCエンジンエミュレータで実行すると、こうなります。BGにオリジナルの画像を表示することができました。これでPCXファイルが完全に不要になりました
現状の不満点としては、変換ツールが1パレットにしか対応していないので、同時発色が16色のみになっています。
あと、見た目が元画像よりものっぺりしてしまいました。これはパレットのカラーが24bit→9bitに変換されてしまうためです。色がくっ付いてしまったぶん、パレットを無駄に消費してしまいます。
このへんはこれから改善します。

(追記2020/12/3)

f:id:nicotakuya:20201203234339p:plain
同じパターンを飛ばしてVRAMを節約

SPEDITに新機能を追加して、同じ絵柄のパターンは登録をスキップできるようにしました。これでVRAMをいくらか節約できます。チェックボックスで機能のオン/オフが設定できます。

続き
nicotakuya.hatenablog.com