「PPU/BG」の編集履歴(バックアップ)一覧はこちら
PPU/BG - (2017/08/28 (月) 13:28:22) の1つ前との変更点
追加された行は緑色になります。
削除された行は赤色になります。
***目次 [#lcf94fc4]
-[[BGモード>#rf00f240]]
-[[タイルマップとキャラクタマップ>#ue7ed8c6]]
-[[BGスクロール>#n902fda8]]
-[[ダイレクトカラーモード>#dc67e4d8]]
-[[モード 0>#mode0]]
-[[モード 1>#mode1]]
-[[モード 2>#mode2]]
-[[モード 3>#mode3]]
-[[モード 4>#mode4]]
-[[モード 5>#mode5]]
-[[モード 6>#mode6]]
-[[モード 7>#mode7]]
-[[BGのレンダリング>#jc1c09b6]]
***BGモード [#rf00f240]
7 つの画面モードと、主に 2 つの状態変化がある。
画面モードは、[[0x2105>IO ポート (メイン)/0x2105]] のビット 0 ~ 2 で設定できる。
モード 1 の状態変化は [[0x2105>IO ポート (メイン)/0x2105]] のビット 3 で設定でき、
モード 7 の状態変化は [[0x2133>IO ポート (メイン)/0x2133]] のビット 6 で設定できる。
|モード|>|>|>|BGの色数|h
|~|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 は透明色に設定されている。
***タイルマップとキャラクタマップ [#ue7ed8c6]
それぞれのBGはVRAMの2つの領域が関係している。
1つはタイルマップ、もう1つはキャラクタデータに使用される。
タイルマップアドレスはは [[0x2107 ~ 0x210a>IO ポート (メイン)/0x2107]] のビット 2 ~ 7 で選択する。
タイルマップのサイズは同じレジスタのビット 0 ~ 1 で選択する。
全てのタイルマップは 32x32 だが、ビット 0 ~ 1 は
メモリ上でどのようにレイアウトされるかを指定する。
|値|サイズ|内容|h
|00|32x32|AA&br;AA|
|01|64x32|AB&br;AB|
|10|32x64|AA&br;BB|
|11|64x64|AB&br;CD|
タイルマップアドレスの最初の 0x800 (2048) バイトはタイルマップAで、
次の 0x800 バイトが B、C、D というように続く。
Aのみが必要とされる場合、他の場所は空の領域とされる。
タイルマップのそれぞれの項目は 2 バイトで、次のようなフォーマットになっている。
|15|14|13|12|11|10|9|8|h
|v|h|o|p|p|p|c|c|
|7|6|5|4|3|2|1|0|h
|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>IO ポート (メイン)/0x210B]]
で指定される場所から始まるアドレスに配置されている。
(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>IO ポート (メイン)/0x2105]] でキャラクタサイズが指定された場合、
16x16 ピクセルブロックのタイルとすることができ、1 つのタイルに
タイル、タイル + 1、タイル + 16、タイル + 17 が使われる。
この場合、32x32 タイルマップで、通常の 256x256 ピクセルサイズではなく、
512x512 サイズが使われる。
同様に、64x64 タイルマップでは、BG は 1024x1024 ピクセルまで拡張される。
これらは 16x16 スプライトの時のようにラッピング処理がされることはなく、
Tile=0x2ff を指定した場合、0x2ff, 0x300, 0x30f, 0x310 を使うことになる。
もちろん、 0x3FF からは 0x000 に行く。
このモードで反転フラグをセットした場合、個々の 8x8 タイルではなく、
16x16 タイルが反転される。
***BGスクロール [#n902fda8]
BG モードとインターレス設定によるが、
モード 0 ~ 6 は 256x224 か 256x239 ピクセルの画面を表示する。
[[0x210d ~ 0x2114>IO ポート (メイン)/0x210D]] のスクロールレジスタで、
256x256 ~ 1024x1024 ピクセルの BG の表示領域を調節することができる。
BG を画面外に移動することはできず、
画面外に移動するような設定にした時は単純にラップされる。
(BG を 1024x1024 に設定した場合はどう考えてもできない)
[[0x210d ~ 0x2114>IO ポート (メイン)/0x210D]] は全て 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を足す必要があるだろう)
***ダイレクトカラーモード [#dc67e4d8]
モード 3, 4, 7 の 256 色 BG では、[[0x2130>IO ポート (メイン)/0x2130]] のビット 0 に
1 が設定されている時、ダイレクトカラーモードが有効になる。
このモードでは、パレットの指定 ('ppp') が無視され、
キャラクタデータではパレットインデックスの代わりに
BBGGGRRR で表される色を指定する。
3 ビットの ppp は bgr になり、色データの追加分として使われる。
-赤 (R) = RRRr0
-緑 (G) = GGGg0
-青 (B) = BBb00
ダイレクトカラーモードでは黒いピクセルを指定することはできない。
値が 0 のキャラクタデータは透明色として扱われる。
黒を表示するためには、黒に一番近い値を使うと良いだろう。
(01, 08, 09 辺りが良い)
***モード 0 [#mode0]
それぞれ最大 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 [#mode1]
16 色の BG が 2 面と、4 色の BG が 1 面ある。
パレットエントリの開始位置は次の式で計算できる。
ppp * ncolors
[[0x2105>IO ポート (メイン)/0x2105]] のビット 3 の設定によって背景の優先順位は変化する。
表示の優先順位は次の順 (前面から背面へ)
-優先順位 1 の BG3 ([[0x2105>IO ポート (メイン)/0x2105]] のビット 3 がセットされている時)
-優先順位 3 のスプライト
-優先順位 1 の BG1
-優先順位 1 の BG2
-優先順位 2 のスプライト
-優先順位 0 の BG1
-優先順位 0 の BG2
-優先順位 1 のスプライト
-優先順位 1 の BG3 ([[0x2105>IO ポート (メイン)/0x2105]] のビット 3 がクリアされている時)
-優先順位 0 のスプライト
-優先順位 0 の BG3
***モード 2 [#mode2]
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 [#mode3]
このモードは、256 色の BG と 16 色の BG がある。
パレットエントリの開始位置は次の式で計算できる。
BG1: 0
BG2: ppp*16
表示の優先順位は次の順 (前面から背面へ)
-優先順位 3 のスプライト
-優先順位 1 の BG1
-優先順位 2 のスプライト
-優先順位 1 の BG2
-優先順位 1 のスプライト
-優先順位 0 の BG1
-優先順位 0 のスプライト
-優先順位 0 の BG2
注 : [[0x2130>IO ポート (メイン)/0x2130]] レジスタで、BG1 をダイレクトカラーモードに設定できる。
***モード 4 [#mode4]
このモードは、256 色の BG と 4 色の BG がある。
パレットエントリの開始位置は次の式で計算できる。
BG1: 0
BG2: ppp*4
表示の優先順位は次の順 (前面から背面へ)
-優先順位 3 のスプライト
-優先順位 1 の BG1
-優先順位 2 のスプライト
-優先順位 1 の BG2
-優先順位 1 のスプライト
-優先順位 0 の BG1
-優先順位 0 のスプライト
-優先順位 0 の BG2
注 : [[0x2130>IO ポート (メイン)/0x2130]] レジスタで、BG1 をダイレクトカラーモードに設定できる。
モード 4 は、 "タイル毎オフセット" を使う、2 番目のモード。
モード 2 と同じように機能する。
しかし SNES には、2つのオフセット値をロードする時間がないので、
代わりに次のような処理を行う。
Val = GetTile(BG3, ...)
if (Val&0x8000) {
Hval = 0
Vval = Val
} else {
Hval = Val
Vval = 0
}
***モード 5 [#mode5]
このモードは、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>IO ポート (メイン)/0x2133]] 参照) の時、
224 か 239 の高さの代わりに、448 か 478 の高さを使う。
[[0x213F>IO ポート (メイン)/0x213F]] のビット 7 の指定で、偶数ラインと奇数ラインを交互に表示する。
注 : ここに書いたように表示するには、 [[0x212C と 0x212D>IO ポート (メイン)/0x212C]] で同じ値を指定しなければならない。
***モード 6 [#mode6]
このモードでは、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 [#mode7]
このモードは、他のモードと極端に違う。
256色のBGが1面あるが、タイルマップとキャラクタマップの
配置の仕方は全く異なる。
タイルマップとキャラクタマップは重なっており、
***BGのレンダリング [#jc1c09b6]
+水平・垂直オフセットを取得
(それぞれレジスタから取得するか、"タイル毎オフセット" により計算される)
+これらの値をプレイ画面に変換する
注 : モード 7 ではこの工程がかなり複雑
+座標に合わせてタイルマップを取得する
+タイルマップを使ってキャラクタデータを取得する
+必要であれば、画像を非ビットプレーンに展開してバッファに格納する
詳細は[[画面のレンダリング>PPU/画面のレンダリング]]参照
#contents()
***BGモード [#rf00f240]
7 つの画面モードと、主に 2 つの状態変化がある。
画面モードは、[[0x2105>IO ポート (メイン)/0x2105]] のビット 0 ~ 2 で設定できる。
モード 1 の状態変化は [[0x2105>IO ポート (メイン)/0x2105]] のビット 3 で設定でき、
モード 7 の状態変化は [[0x2133>IO ポート (メイン)/0x2133]] のビット 6 で設定できる。
|モード|>|>|>|BGの色数|h
|~|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 は透明色に設定されている。
***タイルマップとキャラクタマップ [#ue7ed8c6]
それぞれのBGはVRAMの2つの領域が関係している。
1つはタイルマップ、もう1つはキャラクタデータに使用される。
タイルマップアドレスはは [[0x2107 ~ 0x210a>IO ポート (メイン)/0x2107]] のビット 2 ~ 7 で選択する。
タイルマップのサイズは同じレジスタのビット 0 ~ 1 で選択する。
全てのタイルマップは 32x32 だが、ビット 0 ~ 1 は
メモリ上でどのようにレイアウトされるかを指定する。
|値|サイズ|内容|h
|00|32x32|AA&br;AA|
|01|64x32|AB&br;AB|
|10|32x64|AA&br;BB|
|11|64x64|AB&br;CD|
タイルマップアドレスの最初の 0x800 (2048) バイトはタイルマップAで、
次の 0x800 バイトが B、C、D というように続く。
Aのみが必要とされる場合、他の場所は空の領域とされる。
タイルマップのそれぞれの項目は 2 バイトで、次のようなフォーマットになっている。
|15|14|13|12|11|10|9|8|h
|v|h|o|p|p|p|c|c|
|7|6|5|4|3|2|1|0|h
|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>IO ポート (メイン)/0x210B]]
で指定される場所から始まるアドレスに配置されている。
(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>IO ポート (メイン)/0x2105]] でキャラクタサイズが指定された場合、
16x16 ピクセルブロックのタイルとすることができ、1 つのタイルに
タイル、タイル + 1、タイル + 16、タイル + 17 が使われる。
この場合、32x32 タイルマップで、通常の 256x256 ピクセルサイズではなく、
512x512 サイズが使われる。
同様に、64x64 タイルマップでは、BG は 1024x1024 ピクセルまで拡張される。
これらは 16x16 スプライトの時のようにラッピング処理がされることはなく、
Tile=0x2ff を指定した場合、0x2ff, 0x300, 0x30f, 0x310 を使うことになる。
もちろん、 0x3FF からは 0x000 に行く。
このモードで反転フラグをセットした場合、個々の 8x8 タイルではなく、
16x16 タイルが反転される。
***BGスクロール [#n902fda8]
BG モードとインターレス設定によるが、
モード 0 ~ 6 は 256x224 か 256x239 ピクセルの画面を表示する。
[[0x210d ~ 0x2114>IO ポート (メイン)/0x210D]] のスクロールレジスタで、
256x256 ~ 1024x1024 ピクセルの BG の表示領域を調節することができる。
BG を画面外に移動することはできず、
画面外に移動するような設定にした時は単純にラップされる。
(BG を 1024x1024 に設定した場合はどう考えてもできない)
[[0x210d ~ 0x2114>IO ポート (メイン)/0x210D]] は全て 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を足す必要があるだろう)
***ダイレクトカラーモード [#dc67e4d8]
モード 3, 4, 7 の 256 色 BG では、[[0x2130>IO ポート (メイン)/0x2130]] のビット 0 に
1 が設定されている時、ダイレクトカラーモードが有効になる。
このモードでは、パレットの指定 ('ppp') が無視され、
キャラクタデータではパレットインデックスの代わりに
BBGGGRRR で表される色を指定する。
3 ビットの ppp は bgr になり、色データの追加分として使われる。
-赤 (R) = RRRr0
-緑 (G) = GGGg0
-青 (B) = BBb00
ダイレクトカラーモードでは黒いピクセルを指定することはできない。
値が 0 のキャラクタデータは透明色として扱われる。
黒を表示するためには、黒に一番近い値を使うと良いだろう。
(01, 08, 09 辺りが良い)
***モード 0 [#mode0]
それぞれ最大 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 [#mode1]
16 色の BG が 2 面と、4 色の BG が 1 面ある。
パレットエントリの開始位置は次の式で計算できる。
ppp * ncolors
[[0x2105>IO ポート (メイン)/0x2105]] のビット 3 の設定によって背景の優先順位は変化する。
表示の優先順位は次の順 (前面から背面へ)
-優先順位 1 の BG3 ([[0x2105>IO ポート (メイン)/0x2105]] のビット 3 がセットされている時)
-優先順位 3 のスプライト
-優先順位 1 の BG1
-優先順位 1 の BG2
-優先順位 2 のスプライト
-優先順位 0 の BG1
-優先順位 0 の BG2
-優先順位 1 のスプライト
-優先順位 1 の BG3 ([[0x2105>IO ポート (メイン)/0x2105]] のビット 3 がクリアされている時)
-優先順位 0 のスプライト
-優先順位 0 の BG3
***モード 2 [#mode2]
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 [#mode3]
このモードは、256 色の BG と 16 色の BG がある。
パレットエントリの開始位置は次の式で計算できる。
BG1: 0
BG2: ppp*16
表示の優先順位は次の順 (前面から背面へ)
-優先順位 3 のスプライト
-優先順位 1 の BG1
-優先順位 2 のスプライト
-優先順位 1 の BG2
-優先順位 1 のスプライト
-優先順位 0 の BG1
-優先順位 0 のスプライト
-優先順位 0 の BG2
注 : [[0x2130>IO ポート (メイン)/0x2130]] レジスタで、BG1 をダイレクトカラーモードに設定できる。
***モード 4 [#mode4]
このモードは、256 色の BG と 4 色の BG がある。
パレットエントリの開始位置は次の式で計算できる。
BG1: 0
BG2: ppp*4
表示の優先順位は次の順 (前面から背面へ)
-優先順位 3 のスプライト
-優先順位 1 の BG1
-優先順位 2 のスプライト
-優先順位 1 の BG2
-優先順位 1 のスプライト
-優先順位 0 の BG1
-優先順位 0 のスプライト
-優先順位 0 の BG2
注 : [[0x2130>IO ポート (メイン)/0x2130]] レジスタで、BG1 をダイレクトカラーモードに設定できる。
モード 4 は、 "タイル毎オフセット" を使う、2 番目のモード。
モード 2 と同じように機能する。
しかし SNES には、2つのオフセット値をロードする時間がないので、
代わりに次のような処理を行う。
Val = GetTile(BG3, ...)
if (Val&0x8000) {
Hval = 0
Vval = Val
} else {
Hval = Val
Vval = 0
}
***モード 5 [#mode5]
このモードは、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>IO ポート (メイン)/0x2133]] 参照) の時、
224 か 239 の高さの代わりに、448 か 478 の高さを使う。
[[0x213F>IO ポート (メイン)/0x213F]] のビット 7 の指定で、偶数ラインと奇数ラインを交互に表示する。
注 : ここに書いたように表示するには、 [[0x212C と 0x212D>IO ポート (メイン)/0x212C]] で同じ値を指定しなければならない。
***モード 6 [#mode6]
このモードでは、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 [#mode7]
このモードは、他のモードと極端に違う。
256色のBGが1面あるが、タイルマップとキャラクタマップの
配置の仕方は全く異なる。
タイルマップとキャラクタマップは重なっており、
***BGのレンダリング [#jc1c09b6]
+水平・垂直オフセットを取得
(それぞれレジスタから取得するか、"タイル毎オフセット" により計算される)
+これらの値をプレイ画面に変換する
注 : モード 7 ではこの工程がかなり複雑
+座標に合わせてタイルマップを取得する
+タイルマップを使ってキャラクタデータを取得する
+必要であれば、画像を非ビットプレーンに展開してバッファに格納する
詳細は[[画面のレンダリング>PPU/画面のレンダリング]]参照