基礎知識
戦闘関係
前ページのカラーマス関係の処理の例として、もうひとつ、I/Oレジスタアドレス[$00:2132]で設定できる固定色の効果を紹介する。
SF編では、コンピュータ端末などを調べた時、背景を暗めにして、緑色の文字のテキスト(カタカナと英数字のみ)を表示する場面がある。
昔のコンピュータのディスプレイ表示を再現した演出になるが、この時、背景にあたるBG1とBG2、キャラのスプライト(OBJ)を暗めにし、テキストのBG3のみ通常の緑色の文字を表示、という画面効果はどのように作られているのか?
その答えが「固定色(Backdrop Color)」である。
背景色という名称で説明されているウェブサイトもあるようだが、BG(背景)と用語が混ざってしまうので、他ウェブサイト様での説明も参考に「固定色」という名称で説明していく。
固定色は[$00:2130]のBit1が0(サブスクリーンが無効化)の状態でなければ有効化されないため、カラーマスの効果では使われていない。
固定色の効果だが、画面上のRGBの色(というよりもRGBそれぞれの輝度)を別の色に変更する、というものである。
スーパーファミコンにおける色については、スプライトについて > 色のデータとCGRAMで触れたが、青(B)・緑(G)・赤(R)の3色をどれだけ混ぜるかという度合いで色を作っている。
BGR555フォーマットを使っているため、各色について5ビットの明るさが設定できる(%00000~%11111)。
本作では、スプライトであっても背景であっても、色は2バイト(16ビット)で以下のように設定する。
例えば色が$01FA(この色)と設定されていたら、
$01FA = %0 00000 01111 11010
| 色 | - | B(青) | G(緑) | R(青) |
|---|---|---|---|---|
| Bit | 0 | 00000 | 01111 | 11010 |
というように、青(B)・緑(G)・赤(R)それぞれ5ビットの数値で色を作っている。
この元々の5ビットの数値を、[$00:2132]に書き込む値によって加算または減算して変化させることが可能なのが固定色の効果である。
カラーマスの場合は、BGやOBJをサブスクリーンに設定してカラーマスとして重ねて色を変えていたが、固定色の場合は「固定色」という層を重ねて色を変える、というような考え方でだいたいあっている。
ただ、サブスクリーン+カラーマスと、固定色を同時に使うことはできない(らしい)。
このため、サブスクリーンが無効化されていないと固定色は効果を発揮しない。
本作ではほとんどの場合で、戦闘とメニュー画面ではカラーマス、フィールドでは固定色で色効果を出しているようである。
固定色を加算するか減算するかは、カラーマスと同様に、[$00:2131]のBit7で決める。
3色を同時に暗めな色に変更すれば(減算処理で値を減らせば)、指定したBGやスプライトが暗めになる、という仕組みである。
逆に、色を加算して、明るめにしたり、赤だけ値を上げたり、といった処理も可能である。
ただ、輝度を加算・減算するので、全体的に明るくなったり暗くなってしまう。
回想シーンで全体をセピア色にしたいという場合、元の画面を単純に黄色めにするだけでは画面全体が明るく(または暗く)かつ黄色くなってしまうので、固定色処理は向いていない。
本作で回想シーンのセピア色に変更する場合、カラーパレットそのものを変えている。
なお、HDMA入門 - マリオ4改造 @wiki - atwiki(アットウィキ)の「スクリーンあれこれ」以降が、日本語で読める固定色のわかりやすい解説になるので、合わせて参考にしていただきたい。
まず、フィールドにおけるI/Oレジスタの設定から説明する必要がある。
背景グラフィックと効果 > フィールドでのサブルーチンでも説明したが、グラフィックのI/Oレジスタ関係初期設定は、シナリオ開始時、またはセーブデータから再開時は$C0/0DF6から、マップ切り替え時は途中で合流して$C0/0E1Aから$C0/0ED7までで設定される。
この処理の最中に、$00:0A04の値で分岐する箇所がある。
では、$00:0A04とは何だろうか?
これは[$00:2132]に関係する値なので、[$00:2132]について合わせて説明する。
どのシナリオでも、まず、以下処理で[$00:2132]の初期化が行われる。
$C0/0EAB LDA #$E0 ;Aに$E0をロード $C0/0EAD STA $2132 [$00:2132] ;Aを[$00:2132]に書き込み
つまり[$00:2132]の初期値は$E0である。
その後、以下の$C0/302B~の処理が入り、[$00:0A04]~[$00:0A07]の値が決まるのだが、$C0/302Bの時点でのYの値でシナリオ毎に何が書き込まれるか決まる。
SF編ならY:0232だし、幕末編ならY:0201、近未来編ならY:0253……と変わってくる。
($C0/302B~の処理が入るタイミングはシナリオにより多少異なる。例えば近未来編だとアキラの幼少時の回想のタイミング)
下はSF編の場合である。
$C0/302B LDA $8E00,y[$7F:9032] ;Aに[$7F:9032]($83)をロード $C0/302E STA $000A04[$00:0A04] ;Aを[$00:0A04]に書き込み $C0/3032 LDA $8E01,y[$7F:9033] ;Aに[$7F:9033]($16)をロード $C0/3035 STA $000A05[$00:0A05] ;Aを[$00:0A05]に書き込み $C0/3039 LDA $8E02,y[$7F:9034] ;Aに[$7F:9034]($16)をロード $C0/303C STA $000A06[$00:0A06] ;Aを[$00:0A06]に書き込み $C0/3040 LDA $8E03,y[$7F:9035] ;Aに[$7F:9035]($16)をロード $C0/3043 STA $000A07[$00:0A07] ;Aを[$00:0A07]に書き込み $C0/3047 PHY ;Yレジスタをスタックへプッシュ $C0/3048 PHB ;DBレジスタをスタックにプッシュ $C0/3049 LDA #$00 ;Aに$00をロード $C0/304B PHA ;Aレジスタをスタックにプッシュ $C0/304C PLB ;DBレジスタにスタックからプル $C0/304D JSR $4104 [$C0:4104] ;[$C0:4104]へジャンプ
[$00:0A04]~[$00:0A07]に入る値は$7F:90??~であり、この値は上処理よりもさらに前の処理で決まるが省略。また、$7F:90??~はシナリオ毎に固定である。
何はともあれ重要なのは、[$00:0A04]~[$00:0A07]はカラーマス関係のI/Oポートアドレスに関する値で、シナリオ毎に異なる値が入る、ということである。
[$00:0A04]は、シナリオ開始時に、SF編以外$00、SF編は$83が書き込まれる。
[$00:0A04]に$00以外の数値が入る時は、固定色を使って画面の色を変更する時のみ、と見て良いようであるが、シナリオ開始のタイミングで$00以外が入るのはおそらくSF編だけである。
[$00:0A04]に$00以外の数値が入っている場合、この後にグラフィックのI/Oレジスタ関係初期設定が行われた時に、固定色使用時の分岐が入ることになる。
$C0/0E77 LDA $0A04 [$00:0A04] ;Aに[$00:0A04](SF編なら$83、他シナリオは$00)をロード $C0/0E7A BNE $3D [$0EB9] ;ゼロフラグが立っていないとき[$0EB9]分岐 ;ゼロフラグOFF(固定色使用) $C0/0EB9 STA $2131 [$00:2131] ;Aを[$00:2131](ColorMath制御レジスタ 色計算指定)に書き込み $C0/0EBC STZ $2130 [$00:2130] ;[$00:2130](ColorMath制御レジスタ 色追加選択)に$00を書き込み $C0/0EBF LDA $0A05 [$00:0A05] ;Aに[$00:0A05]($16)をロード $C0/0EC2 ORA #$80 ;Aと$80で論理和 $C0/0EC4 STA $2132 [$00:2132] ;Aを[$00:2132](ColorMath制御レジスタ 固定色のデータ)に書き込み $C0/0EC7 LDA $0A06 [$00:0A06] ;Aに[$00:0A06]($16)をロード $C0/0ECA ORA #$40 ;Aと$40で論理和 $C0/0ECC STA $2132 [$00:2132] ;Aを[$00:2132](ColorMath制御レジスタ 固定色のデータ)に書き込み $C0/0ECF LDA $0A07 [$00:0A07] ;Aに[$00:0A07]($16)をロード $C0/0ED2 ORA #$20 ;Aと$20で論理和 $C0/0ED4 STA $2132 [$00:2132] ;Aを[$00:2132](ColorMath制御レジスタ 固定色のデータ)に書き込み ;処理合流 $C0/0ED7 RTS ;サブルーチン戻り
$C0/0E7Aのゼロフラグ判定で分岐が起こり、[$00:0A04]に00が入っているSF編以外のシナリオだと、[$00:2130]~[$00:2132]は、以下のように初期値が入る。
| アドレス | 名称 | 内容 | 値 |
|---|---|---|---|
[$00:2131] | CGADSUB | カラーマス制御レジスタB 色計算指定 | [$00:0144] |
[$00:2130] | CGSWSEL | カラーマス制御レジスタA 色追加選択 | $30 |
[$00:2132] | COLDATA | サブスクリーン固定色のデータ | $E0 |
一方、SF編だと$C0/0EB9~$C0/0ED4の処理により、以下のようになる。
| アドレス | 名称 | 内容 | 値 |
|---|---|---|---|
[$00:2131] | CGADSUB | カラーマス制御レジスタB 色計算指定 | $83 |
[$00:2130] | CGSWSEL | カラーマス制御レジスタA 色追加選択 | $00 |
[$00:2132] | COLDATA | サブスクリーン固定色のデータ | $96 $56 $36 |
SF編だと、[$00:0A04]~[$00:0A07]の値が以下のように処理されることがわかる。
[$00:0A04]→[$00:2131][$00:0A05] | $80→ [$00:2132](1回目)[$00:0A06] | $40→ [$00:2132](2回目)[$00:0A07] | $20→ [$00:2132](3回目)*|はビット論理和演算子
以上がSF編シナリオ開始時での初期値で、この状態で最初の画面が表示される。地球を背景にして、「- スペース・ドッグ TSQ-05 -」で始まる緑色の文字テキストが表示される場面である。
この時点から、固定色を利用し、背景をやや暗めにして、緑色の文字を表示する処理が開始されている。
SF編では明るさを表現するために同じように固定色で調整を行っている場面が多々ある。
例えば、終盤(船長室でのイベント中)から、船内全体が停電で薄暗くなる演出があるが、これはカラーパレットを変えたのではなく、同じく固定色の効果を使っている。
他シナリオだと、最終編の時のダンジョンで徐々に暗くなる演出も、この固定色の効果になる。
また、[$00:2132]が3回連続で書き込まれていることもポイント。
[$00:2132]の設定方法は後で記す通り、特殊なのである。
では、[$00:2130]~[$00:2132]についてもう少し詳しく見てみよう。
[$00:2130], [$00:2131]についてはこれまでも説明したことがあるが、あらためて説明をする。
[$00:2130](ColorMath制御レジスタ 色追加選択)$00 = %0000 0000
| Bit | 数値 | 内容 |
|---|---|---|
| Bit0 | 0 | 256色のBG用ダイレクトカラーモード (0=パレットを使う, 1=ダイレクトカラー) |
| Bit1 | 0 | サブスクリーン BG/OBJ 有効化 (0=未使用/Backdrop only, 1=使用/Backdrop+BG+OBJ) |
| Bit2-3 | 00 | (未使用ビット) |
| Bit4-5 | 00 | カラーマス有効化 (0=常に使用, 1=ウインドウの外側の色のみ, 2=ウインドウの内側の色のみ, 3=使用しない) |
| Bit6-7 | 00 | 計算前の黒にクリッピングする色 (3=常に使用, 2=ウインドウの内側の色のみ, 1=ウインドウの外側の色のみ, 0=なし) |
[$00:2131](ColorMath制御レジスタ 色計算指定)$83 = %1000 0011
| Bit | 数値 | 内容 |
|---|---|---|
| Bit0 | 1 | BG1でカラーマスを有効/無効化するか |
| Bit1 | 1 | BG2でカラーマスを有効/無効化するか |
| Bit2 | 0 | BG3でカラーマスを有効/無効化するか |
| Bit3 | 0 | BG4でカラーマスを有効/無効化するか |
| Bit4 | 0 | OBJでカラーマスを有効/無効化するか |
| Bit5 | 0 | Backdropでカラーマスを有効/無効化するか |
| Bit6 | 0 | ハーフカラーマス(0=ハーフカラー未使用, 1=結果を2で割る) |
| Bit7 | 1 | カラーマス加算/減算(0=加算; Main+Sub, 1=減算; Main-Sub) |
[$00:2132](ColorMath制御レジスタ 固定色のデータ)$96 = %1001 0110
$56 = %0101 0110
$36 = %0011 0110
| Bit | 内容 |
|---|---|
| Bit7 | 青(B)を設定 (%0=設定しない, %1=設定する) |
| Bit6 | 緑(G)を設定 (%0=設定しない, %1=設定する) |
| Bit5 | 赤(R)を設定 (%0=設定しない, %1=設定する) |
| Bit0~4 | 輝度 (%00000~%11111) |
まず[$00:2130], [$00:2131]だけまとめると、[$00:2130]のBit1は0だから、サブスクリーンを使わず、固定色が有効化される。
[$00:2131]で、カラーマスを有効にしているのはBG1とBG2であり、テキストが表示されるBG3は対象外である。
また、Bit7でカラーマス処理は色を減算する設定になっている。
前ページでは加算する処理の話をしたが、色を加算する時は明るくなることに対し、減算は色が暗くなる。
そして固定色を指定する[$00:2132]だが、指定方法を見ると、上3ビットはそれぞれ青・緑・赤のいずれかの色について固定色を設定するかどうか、そして指定した場合、下5ビットで固定色の輝度を変えることになる。
という仕組みのため、青・緑・赤を同時に変えたい時は、
というように、3回、[$00:2132]に値を書き込む必要がある。
3回別々に処理をするため、厳密に言えば、例えば青色の固定色の処理をしてから緑色の固定色の処理をするまでは、画面の青色要素だけが輝度処理された状態となるのだが、連続してサブルーチンで処理する場合、一瞬で終わるため、「青色部分だけ色が変わった」などと人間の目で認識できたりはしない。
シナリオ開始時初期値は、$E0(%1110 0000)であり、これは固定色が黒一色塗りつぶしであることを意味しているのだが、画面が真っ暗になるということではなく、透明な背景という扱いになるらしい。
つまり、$E0が書き込まれている時、固定色は実質無効化、何の意味も成さない。
さて、SF編の場合、初期値の後に以下処理で新たに[$00:2132]に値が設定され、SF編が開始になっている。
$C0/0EBF LDA $0A05 [$00:0A05] ;Aに[$00:0A05]($16)をロード $C0/0EC2 ORA #$80 ;Aと$80で論理和 $C0/0EC4 STA $2132 [$00:2132] ;Aを[$00:2132](ColorMath制御レジスタ 固定色のデータ)に書き込み $C0/0EC7 LDA $0A06 [$00:0A06] ;Aに[$00:0A06]($16)をロード $C0/0ECA ORA #$40 ;Aと$40で論理和 $C0/0ECC STA $2132 [$00:2132] ;Aを[$00:2132](ColorMath制御レジスタ 固定色のデータ)に書き込み $C0/0ECF LDA $0A07 [$00:0A07] ;Aに[$00:0A07]($16)をロード $C0/0ED2 ORA #$20 ;Aと$20で論理和 $C0/0ED4 STA $2132 [$00:2132] ;Aを[$00:2132](ColorMath制御レジスタ 固定色のデータ)に書き込み
この処理は、
[$00:0A05](青用輝度) | $80→ [$00:2132](1回目)[$00:0A06](緑用輝度) | $40→ [$00:2132](2回目)[$00:0A07](赤用輝度) | $20→ [$00:2132](3回目)このように、固定色の色別[$00:2132]書き込み処理だったということがわかる。
$80, $40, $20と論理和を取って書き込むことで、各色の輝度に対応させているのである。
[$00:0A05]~[$00:0A07]がすべて$16(%0001 0110)だから、青・緑・赤すべての色の輝度を%10110下げる(減算する)という意味である。
この色の減算が有効なのはBG1とBG2だけであるから、BG1とBG2の輝度を%10110($16)下げ、テキスト表示のBG3だけ輝度はそのまま表示、ということになる。
輝度は%00000~%11111($00~$1F)の32段階だから、$16(22)下げるということはかなり明るさを下げるということになる。
(色の減算で負になるようなら単純に黒にする)
これが、オープニングにおける、地球を背景にして、「- スペース・ドッグ TSQ-05 -」……が表示された時の処理である。
SF編を進めると、コンピュータ端末を調べた時などに、背景の輝度が下がって緑色の文字のテキストだけ輝度を下げずに表示される。
この時は、BG1とBG2だけでなく、キャラのスプライトも輝度が下がる。
[$00:2131]で、BG1とBG2だけカラーマス指定だが、SF編オープニングでコギトエルゴスム号が宇宙を航行しているシーンの直後に、以下のように[$00:2131]の値の更新が行われる。
$C0/302B LDA $8E00,y[$7F:9085] ;Aに[$7F:9085]($93)をロード $C0/302E STA $000A04[$00:0A04] ;Aを[$00:0A04]に書き込み $C0/3032 LDA $8E01,y[$7F:9086] ;Aに[$7F:9086]($08)をロード $C0/3035 STA $000A05[$00:0A05] ;Aを[$00:0A05]に書き込み $C0/3039 LDA $8E02,y[$7F:9087] ;Aに[$7F:9087]($08)をロード $C0/303C STA $000A06[$00:0A06] ;Aを[$00:0A06]に書き込み $C0/3040 LDA $8E03,y[$7F:9088] ;Aに[$7F:9088]($08)をロード $C0/3043 STA $000A07[$00:0A07] ;Aを[$00:0A07]に書き込み $C0/3047 PHY ;Yレジスタをスタックへプッシュ $C0/3048 PHB ;DBレジスタをスタックにプッシュ $C0/3049 LDA #$00 ;Aに$00をロード $C0/304B PHA ;Aレジスタをスタックにプッシュ $C0/304C PLB ;DBレジスタにスタックからプル $C0/304D JSR $4104 [$C0:4104] ;[$C0:4104]へジャンプ
[$00:0A04]~[$00:0A07]に入る値が、[$7F:9085]~[$7F:9088]に変更され、以下のように値が更新される。
| アドレス | 値 |
|---|---|
[$00:0A04] | $93 |
[$00:0A05] | $08 |
[$00:0A06] | $08 |
[$00:0A07] | $08 |
$C0/0E66 LDA $0A48 [$00:0A48] ;Aに[$00:0A48]をロード $C0/0E69 BNE $1D [$0E88] ;ゼロフラグが立っていないとき[$0E88]分岐 $C0/0E6B LDA $0140 [$00:0140] ;Aに[$00:0140]をロード $C0/0E6E STA $212C [$00:212C] ;Aを[$00:212C]に書き込み $C0/0E71 LDA $0141 [$00:0141] ;Aに[$00:0141]をロード $C0/0E74 STA $212D [$00:212D] ;Aを[$00:212D]に書き込み $C0/0E77 LDA $0A04 [$00:0A04] ;Aに[$00:0A04]($93)をロード $C0/0E7A BNE $3D [$0EB9] ;ゼロフラグが立っていないとき[$0EB9]分岐 $C0/0EB9 STA $2131 [$00:2131] ;Aを[$00:2131]に書き込み $C0/0EBC STZ $2130 [$00:2130] ;[$00:2130]に$00を書き込み $C0/0EBF LDA $0A05 [$00:0A05] ;Aに[$00:0A05]($08)をロード $C0/0EC2 ORA #$80 ;Aと$80で論理和 $C0/0EC4 STA $2132 [$00:2132] ;Aを[$00:2132]に書き込み $C0/0EC7 LDA $0A06 [$00:0A06] ;Aに[$00:0A06]($08)をロード $C0/0ECA ORA #$40 ;Aと$40で論理和 $C0/0ECC STA $2132 [$00:2132] ;Aを[$00:2132]に書き込み $C0/0ECF LDA $0A07 [$00:0A07] ;Aに[$00:0A07]($08)をロード $C0/0ED2 ORA #$20 ;Aと$20で論理和 $C0/0ED4 STA $2132 [$00:2132] ;Aを[$00:2132]に書き込み $C0/0ED7 RTS ;サブルーチン戻り
最終的に、上処理で[$00:2130]~[$00:2132]も更新される。
[$00:2130]に$93 = %1001 0011が書き込まれたため、BG1, BG2, OBJ(スプライト)でカラーマスが有効化されたことになり、以降はおそらくSF編エンディングまで、[$00:2130]には$93が入ったままである。
これで、コンピュータを調べた時などに、BG1, BG2, OBJは固定色の減算処理で暗くなり、BG3のテキストだけ通常の色(緑色)で表示される、という処理が行われることになる。
明るさ調整のために固定色を使う場合、青・緑・赤すべての色の輝度を同じ値だけ上下させることになる。
[$00:0A05]~[$00:0A07]は先に述べた通り、[$00:2132]の青・緑・赤の輝度の値が入ることになるので、明るさが変わる時に値が更新される。
コンピュータを調べた時などは、徐々に画面を暗くして文字表示するが、輝度減算分を$00から$17まで1フレームに1回増やして画面を滑らかに暗くしているようである。
($C0/D001~$C0/D0CAあたりが処理になるが省略)
先にあげた、
$01FA = %0 00000 01111 11010
このBGR555フォーマットの色(この色)の輝度を各色で$17 = %10111下げる場合、
%0 00000 00000 00011 = $0003
24ビットカラーだと$180000(この色)で、やや赤いがほぼ黒である。
よほど明るめの色でないと、真っ黒になるくらいまで、明るさが下がることがわかる。
とはいえコギトエルゴスム号は壁や床が白く明るめなので、輝度をかなり下げても背景はそこそこ見えるようになっている(そのあたりは計算して輝度を下げていると思われる)。
戦闘においては「マザーイメージ」使用時のように、画面全体を赤っぽくする処理があるが、こちらはBG3を赤一色で塗りつぶし+カラーマス色加算処理で赤くしており、固定色での処理ではない。
技による色の処理は基本的にBG3に色を付けて、カラーマスで色加算、としているようである。
このため、BG3でカラーマス加算をしている時、BG3にテキストを表示していない。
一方、フィールドの場合はBG3でセリフウィンドウなどの表示をすることが多いため、状況にもよるが画面全体の輝度・色味を変える場合は固定色で処理することが多いようである。
SF編では青・緑・赤すべての色の輝度を変更しているが、原始編エンディングの最後で、画面全体がピンクっぽくなる場面では、固定色加算を使っている。
元の画面が暗めなので(夜の洞窟、かつ、黒一色部分が多い)、色加算で画面を多少明るくしても演出として問題はない。
(もしこの場面が元々全体的に明るめだったら、カラーパレットで処理していたのではないか、と思う)
原始編エンディングでは、
| アドレス | 値 |
|---|---|
[$00:0A04] | $03 |
[$00:0A05] | $01 |
[$00:0A06] | $00 |
[$00:0A07] | $06 |
というように設定され、[$00:2131]に$03、[$00:2132]には青・緑・赤の輝度(5ビット)にそれぞれ$01, $00, $06が入る。
つまり、元の色味から、青の度合いを+$01、赤の度合いを+$06する。
例えば元が夜の洞窟の壁などに使われる色・$398C = %0 01110 01100 01100(この色)だったら、
%0 01111 01100 10010 = $3D92
24ビットカラーだと$94637B(この色)であり、かなりピンクっぽくなることがわかる。
以上が固定色の大まかな説明である。
固定色を決める[$00:2132]も、HDMA転送を使うことにより、1スキャンラインずつ値を変えて色のグラデーションを作るといったことも可能であるようだが、本作で使われているかどうかまでは未確認。
ゲームのタイトル画面の空の背景などはグラデーション効果で作っているかのようだが、実際にはこの画面では横に流れる雲の移動を多重スクロールさせるためにHDMA転送を使っており、背景色は単純に色別にタイルを並べて作っているだけのようだ。