PPU > BG

※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

BGモード

7 つの画面モードと、主に 2 つの状態変化がある。 画面モードは、0x2105 のビット 0 ~ 2 で設定できる。 モード 1 の状態変化は 0x2105 のビット 3 で設定でき、 モード 7 の状態変化は 0x2133 のビット 6 で設定できる。

モード BGの色数
1 2 3 4
0 4 4 4 4
1 16 16 4 -
2 16 16 - -
3 256 16 - -
4 256 4 - -
5 16 4 - -
6 16 - - -
7 256 - - -
7 拡張BG 256 128 - -

全てのモードの全てのBGでパレット番号 0 は透明色に設定されている。

タイルマップとキャラクタマップ

それぞれのBGはVRAMの2つの領域が関係している。 1つはタイルマップ、もう1つはキャラクタデータに使用される。

タイルマップアドレスはは 0x2107 ~ 0x210a のビット 2 ~ 7 で選択する。 タイルマップのサイズは同じレジスタのビット 0 ~ 1 で選択する。 全てのタイルマップは 32x32 だが、ビット 0 ~ 1 は メモリ上でどのようにレイアウトされるかを指定する。

サイズ 内容
00 32x32 AA
AA
01 64x32 AB
AB
10 32x64 AA
BB
11 64x64 AB
CD

タイルマップアドレスの最初の 0x800 (2048) バイトはタイルマップAで、 次の 0x800 バイトが B、C、D というように続く。 Aのみが必要とされる場合、他の場所は空の領域とされる。

タイルマップのそれぞれの項目は 2 バイトで、次のようなフォーマットになっている。

15 14 13 12 11 10 9 8
v h o p p p c c
7 6 5 4 3 2 1 0
c c c c c c c c
  • v/h : タイルの垂直/水平反転
  • o : タイルの優先順位
  • ppp : タイルのパレット パレットの色数は画面モードとBGに依存
  • cccccccccc : タイル番号

タイルマップから特定タイルのワードアドレスを見つけるには (X と Y)、 次の式を使う。

(Addr<<9) + ((Y&0x1f)<<5) + (X&0x1f) + 
(SY ? ((Y&0x20)<<(SX ? 6 : 5)) : 0) + 
(SX ? ((X&0x20)<<5) : 0)

タイルのキャラクタデータは 0x210b ~ 0x210c で指定される場所から始まるアドレスに配置されている。

(Base<<13) + (TileNumber * 8*NumBitplanes)

それぞれのタイルは通常 8x8 ピクセルのサイズで、ビットプレーンで保存される。 1行はそれぞれ 1 バイトで構成され、一番左端はビット 7 で指定する。 4 色のタイルでは、ビットプレーン 0 と 1 が 1 ワードの下位バイト、 上位バイトとして保存され、8 ワードで 1 つのタイルを構成する。 16 色タイルでは、4 色と同様に 0, 1 が保存され、それに 2, 3 が続くような 形式で保存される。 256 色タイルでは同じ方法で、2 つの 16 色タイルが続くような形式で保存される。

0x2105 でキャラクタサイズが指定された場合、 16x16 ピクセルブロックのタイルとすることができ、1 つのタイルに タイル、タイル + 1、タイル + 16、タイル + 17 が使われる。 この場合、32x32 タイルマップで、通常の 256x256 ピクセルサイズではなく、 512x512 サイズが使われる。 同様に、64x64 タイルマップでは、BG は 1024x1024 ピクセルまで拡張される。 これらは 16x16 スプライトの時のようにラッピング処理がされることはなく、 Tile=0x2ff を指定した場合、0x2ff, 0x300, 0x30f, 0x310 を使うことになる。 もちろん、 0x3FF からは 0x000 に行く。 このモードで反転フラグをセットした場合、個々の 8x8 タイルではなく、 16x16 タイルが反転される。

BGスクロール

BG モードとインターレス設定によるが、 モード 0 ~ 6 は 256x224 か 256x239 ピクセルの画面を表示する。 0x210d ~ 0x2114 のスクロールレジスタで、 256x256 ~ 1024x1024 ピクセルの BG の表示領域を調節することができる。

BG を画面外に移動することはできず、 画面外に移動するような設定にした時は単純にラップされる。 (BG を 1024x1024 に設定した場合はどう考えてもできない)

0x210d ~ 0x2114 は全て 2 度書きレジスタで、16ビット値を設定する。 これらのレジスタへ値を書き込んだ場合、その値はバッファに保存される。 これらいずれかのレジスタに新しい値を書き込んだ場合、 現在のレジスタ値と、6バイトのいずれかのレジスタに対して 直前に書き込まれた 1 バイトの値が新しい値と合成されて書き込まれる。

BGnHOFS の場合 : (NewByte<<8) | (PrevByte&~7) | ((CurrentValue>>8)&7)
BGnVOFS の場合 : (NewByte<<8) | PrevByte

ほとんどの場合、この詳細は重要ではなく、普通に 1 つのレジスタに 2 度書き込めば 問題は起こらないのだが、いくつかのゲームで 1 度だけ書き込んだり、 他に変なことをしていることがある。

タイルマップエントリからスクリーン上の特定のX,Y座標を計算する時には 次の式を使う。

Size = 8 か 16。0x2105 で指定される
TileX = (X + BGnHOFS) / Size
TileY = (Y + BGnVOFS) / Size
TileX と TileY の位置にあるタイルを検索する。詳細は以下

注 : 多くのゲームで垂直スクロール位置は 0 ではなく -1 に設定されている。 これは、SNES が OBJ データをスキャンライン毎に 1 つ前の位置を参照するためである。 1番最初の行では、OBJ データは何もロードされていない。 SNESは実際にはスキャンライン0に出力しない。 インターレス画面では、行 0 を無視するために -1 ではなく -2 を指定する必要がある。 (エミュレータでは1の代わりに2を足す必要があるだろう)

ダイレクトカラーモード

モード 3, 4, 7 の 256 色 BG では、0x2130 のビット 0 に 1 が設定されている時、ダイレクトカラーモードが有効になる。 このモードでは、パレットの指定 ('ppp') が無視され、 キャラクタデータではパレットインデックスの代わりに BBGGGRRR で表される色を指定する。 3 ビットの ppp は bgr になり、色データの追加分として使われる。

  • 赤 (R) = RRRr0
  • 緑 (G) = GGGg0
  • 青 (B) = BBb00

ダイレクトカラーモードでは黒いピクセルを指定することはできない。 値が 0 のキャラクタデータは透明色として扱われる。 黒を表示するためには、黒に一番近い値を使うと良いだろう。 (01, 08, 09 辺りが良い)

モード 0

それぞれ最大 4 色が出る 4 つの BG がある。 パレットエントリの開始位置は次の式で計算できる。

ppp * 4 + (BG# - 1) * 32

表示の優先順位は次の順 (前面から背面へ)

  • 優先順位 3 のスプライト
  • 優先順位 1 の BG1
  • 優先順位 1 の BG2
  • 優先順位 2 のスプライト
  • 優先順位 0 の BG1
  • 優先順位 0 の BG2
  • 優先順位 1 のスプライト
  • 優先順位 1 の BG3
  • 優先順位 1 の BG4
  • 優先順位 0 のスプライト
  • 優先順位 0 の BG3
  • 優先順位 0 の BG4

モード 1

16 色の BG が 2 面と、4 色の BG が 1 面ある。 パレットエントリの開始位置は次の式で計算できる。

ppp * ncolors

0x2105 のビット 3 の設定によって背景の優先順位は変化する。 表示の優先順位は次の順 (前面から背面へ)

  • 優先順位 1 の BG3 (0x2105 のビット 3 がセットされている時)
  • 優先順位 3 のスプライト
  • 優先順位 1 の BG1
  • 優先順位 1 の BG2
  • 優先順位 2 のスプライト
  • 優先順位 0 の BG1
  • 優先順位 0 の BG2
  • 優先順位 1 のスプライト
  • 優先順位 1 の BG3 (0x2105 のビット 3 がクリアされている時)
  • 優先順位 0 のスプライト
  • 優先順位 0 の BG3

モード 2

16 色の BG が 2 面ある。 パレットエントリの開始位置は次の式で計算できる。

ppp * 16

表示の優先順位は次の順 (前面から背面へ)

  • 優先順位 3 のスプライト
  • 優先順位 1 の BG1
  • 優先順位 2 のスプライト
  • 優先順位 1 の BG2
  • 優先順位 1 のスプライト
  • 優先順位 0 の BG1
  • 優先順位 0 のスプライト
  • 優先順位 0 の BG2

モード 2 は、"タイル毎オフセット" を使う最初のモード。 このモードでは、BG3 のタイルデータはエンコードされていて、 BG1, BG2 の両方またはいずれかの、それぞれのタイルの (可能であれば) HOffset, VOffset の両方またはいずれかを 置き換える。

可視状態のスキャンラインについて考えると、 通常、次に示すような方法でピクセルを取得する。

HOFS = X + BGnHOFS
VOFS = Y + BGnVOFS
Pixel[X,Y] = GetPixel(GetTile(BGn, HOFS, VOFS), HOFS, VOFS)

"タイル毎オフセット" の時は、もう少し複雑になる。

 HOFS = X + BGnHOFS
 VOFS = Y + BGnVOFS
 ValidBit = BG1 の時 : 0x2000, BG2 の時 : 0x4000

 if (!IsFirst8x8Tile(BGn, HOFS)) {
   /* この計算は正しいだろうと思うが... */
   Hval = GetTile(BG3, (HOFS&7)|(((X-8)&~7)+(BG3HOFS&~7)), BG3VOFS)
   Vval = GetTile(BG3, (HOFS&7)|(((X-8)&~7)+(BG3HOFS&~7)), BG3VOFS + 8)
   if (Hval&ValidBit) HOFS = (HOFS&7) | ((X&~7) + (Hval&~7))
   if (Vval&ValidBit) VOFS = Y + Vval
 }
 Pixel[X,Y] = GetPixel(Get8x8Tile(BGn, HOFS, VOFS), HOFS, VOFS)

言い換えれば、BGn の 0-32 の可視状態のタイルと、 BG3 の"可視" のタイルは同じになる。 BGn のタイル 0 のオフセットは普通で、 1 <= T < 33 の範囲にある BGn のタイル T はオフセットデータを BG3 の タイル T - 1 から取得する。 このとき、タイルが実際に配置されているかどうかは問題ではない。

可視の左端のタイルはいつでも通常で (最短、1 ピクセルが可視になるが、 クリップウインドウを使う時にまだ悩むことになるだろう)、 次のタイルは、BG3 の左端のタイルのが何になるかによって、タイルマップエントリを使う。 "新しい"オフセットは BGnVOFS レジスタをオーバーライドするが、 BGnHOFS オフセットの下位 3 ビットはまだ使われるだろう。 スクリーンの現在の Y 座標は BG3 のタイルマップの参照している どの行にも影響しない。Y 座標が常に 0 の時も

一方、たとえ BGn が 16x16 タイルでも、 BG3 は、それぞれ 8x8 サブタイルのオフセットを指定することができる。 BG3 が 16x16 の時、オフセットは関連する BGn の 8x8 サブタイルに適用される。 BG3 が 16x16 の時、Hval と Vval に同じタイルを最後まで使う。

モード 3

このモードは、256 色の BG と 16 色の BG がある。 パレットエントリの開始位置は次の式で計算できる。

BG1: 0
BG2: ppp*16

表示の優先順位は次の順 (前面から背面へ)

  • 優先順位 3 のスプライト
  • 優先順位 1 の BG1
  • 優先順位 2 のスプライト
  • 優先順位 1 の BG2
  • 優先順位 1 のスプライト
  • 優先順位 0 の BG1
  • 優先順位 0 のスプライト
  • 優先順位 0 の BG2

注 : 0x2130 レジスタで、BG1 をダイレクトカラーモードに設定できる。

モード 4

このモードは、256 色の BG と 4 色の BG がある。 パレットエントリの開始位置は次の式で計算できる。

BG1: 0
BG2: ppp*4

表示の優先順位は次の順 (前面から背面へ)

  • 優先順位 3 のスプライト
  • 優先順位 1 の BG1
  • 優先順位 2 のスプライト
  • 優先順位 1 の BG2
  • 優先順位 1 のスプライト
  • 優先順位 0 の BG1
  • 優先順位 0 のスプライト
  • 優先順位 0 の BG2

注 : 0x2130 レジスタで、BG1 をダイレクトカラーモードに設定できる。

モード 4 は、 "タイル毎オフセット" を使う、2 番目のモード。 モード 2 と同じように機能する。 しかし SNES には、2つのオフセット値をロードする時間がないので、 代わりに次のような処理を行う。

   Val = GetTile(BG3, ...)
   if (Val&0x8000) {
     Hval = 0
     Vval = Val
   } else {
     Hval = Val
     Vval = 0
   }

モード 5

このモードは、16 色の BG と 4 色の BG がある。 パレットエントリの開始位置は次の式で計算できる。

ppp * ncolors

表示の優先順位は次の順 (前面から背面へ)

  • 優先順位 3 のスプライト
  • 優先順位 1 の BG1
  • 優先順位 2 のスプライト
  • 優先順位 1 の BG2
  • 優先順位 1 のスプライト
  • 優先順位 0 の BG1
  • 優先順位 0 のスプライト
  • 優先順位 0 の BG2

このモードは、これまでのモードと違う点が多々ある。 通常の 8/16 ピクセル幅のタイルを使う代わりに、 常に 16 ピクセル幅のタイルを使う (高さは 8 または 16 ピクセル)。 それから、ピクセル列の半分だけ使用する。 (0ベースで、偶数番号のピクセルはサブスクリーンに、 奇数番号のピクセルはメインスクリーンのタイルに使用される) そして、スクリーンを仮想的に 512 ピクセル幅で表示する。 同様に、インターレスモードが ON (0x2133 参照) の時、 224 か 239 の高さの代わりに、448 か 478 の高さを使う。 0x213F のビット 7 の指定で、偶数ラインと奇数ラインを交互に表示する。 注 : ここに書いたように表示するには、 0x212C と 0x212D で同じ値を指定しなければならない。

モード 6

このモードでは、16 色の BG のみを使う。 パレットエントリの開始位置は次の式で計算できる。

ppp * ncolors

表示の優先順位は次の順 (前面から背面へ)

  • 優先順位 3 のスプライト
  • 優先順位 1 の BG1
  • 優先順位 2 のスプライト
  • 優先順位 1 のスプライト
  • 優先順位 0 の BG1
  • 優先順位 0 のスプライト

このモードは、モード 5 と同じように動作する。 また、 "タイル毎オフセット" の機能も追加される。 こちらはモード 2 のように動作する。 しかし、モード 6 では 8 ピクセル幅 (16 ハーフピクセル) のタイルが使用され、 BG3 も BG1 と同じようにこれが適応される。 8 ハーフピクセルにも 16 ピクセル幅の領域にも オフセットを適用することはできない。 (2 つの 8 ピクセル領域に 2 つのオフセット値を使う時は除く)

モード 7

このモードは、他のモードと極端に違う。 256色のBGが1面あるが、タイルマップとキャラクタマップの 配置の仕方は全く異なる。

タイルマップとキャラクタマップは重なっており、

BGのレンダリング

  1. 水平・垂直オフセットを取得 (それぞれレジスタから取得するか、"タイル毎オフセット" により計算される)
  2. これらの値をプレイ画面に変換する 注 : モード 7 ではこの工程がかなり複雑
  3. 座標に合わせてタイルマップを取得する
  4. タイルマップを使ってキャラクタデータを取得する
  5. 必要であれば、画像を非ビットプレーンに展開してバッファに格納する

詳細は画面のレンダリング参照