TOP > プログラミング関係解説&調査 > カラーマス(色演算)

カラーマス(色演算)

当ページの内容は、ある程度のプログラミングの知識を必要とする。
まず、プログラミング関係解説&調査をひととおり読んでいただきたい。

このページでは、スーパーファミコンの画面効果に使われるカラーマス(Color Math, 色演算)について説明しているが、カラーマスの他、ウィンドウ効果などにも使われる、HDMA転送が重要な役割を担うので、まず画面描画やHDMA転送などの説明から行う。

※以下ではHDMA転送関係の説明をしているが、筆者の理解が不十分なため、おかしな部分があるかもしれない。

背景グラフィックと効果 > メニュー画面でのサブルーチンで、BG1~3のタイルデータとBGマップデータの転送処理について大まかに説明した。
だが、これだけでは、コマンドウィンドウで選択されていない項目だけ半透明になっている効果が説明できない。
コマンドウィンドウはBG1にタイルデータなどを設置したが、コマンドウィンドウ部分のBGマップの値は、半透明でもそうでなくても同一である。
では、どこで不透明・透明を設定しているのか。

大雑把な仕組みを説明すると以下のようになる。

  1. コマンドウィンドウ部分のBG1(ウィンドウ枠)とBG3(コマンドの文字列)を通常通り描画する
  2. HDMA転送で、選択されていないBG1(ウィンドウ枠)とBG3(コマンドの文字列)部分だけ、サブスクリーンに表示しているハーフカラーマス(Half Color Math)を有効化させて半透明にする

を、コマンドウィンドウ部分を横1列(1ピクセル幅の線一本分)描画するたびに行っている。
この描画が有効になるのはコマンドウィンドウ部分だけなので、キャラから出る吹き出し部分は半透明にはならないのである。

スーパーファミコンの画面の描画方法については、グラフィックについて > グラフィックの描画についてもお読みいただきたい。

I/Oレジスタ設定

メニュー画面の半透明効果はどのように行っているのか。
まず、メニュー画面のI/Oレジスタ設定を改めて確認する。
重要なのはカラーマス関係のレジスタである。
前ページの、$C2/4F8Fで設定された、[$00:2130], [$00:2131], [$00:2131]の値がそれぞれ$12, $45, $E0となっており、詳しく見てみると以下のようになる。

[$00:2130](ColorMath制御レジスタ 色追加選択)

$12 = %0001 0010

Bit数値内容
Bit00256色のBG用ダイレクトカラーモード
(0=パレットを使う, 1=ダイレクトカラー)
Bit11サブスクリーン BG/OBJ 有効化
(0=未使用/Backdrop only, 1=使用/Backdrop+BG+OBJ)
Bit2-300(未使用ビット)
Bit4-501カラーマス有効化
(0=常に使用, 1=ウインドウの外側の色のみ, 2=ウインドウの内側の色のみ, 3=使用しない)
Bit6-700計算前の黒にクリッピングする色
(3=常に使用, 2=ウインドウの内側の色のみ, 1=ウインドウの外側の色のみ, 0=なし)
[$00:2131](ColorMath制御レジスタ 色計算指定)

$45 = %0100 0101

Bit数値内容
Bit01BG1でカラーマスを有効/無効化するか
Bit10BG2でカラーマスを有効/無効化するか
Bit21BG3でカラーマスを有効/無効化するか
Bit30BG4でカラーマスを有効/無効化するか
Bit40OBJでカラーマスを有効/無効化するか
Bit50背景 (Backdrop)でカラーマスを有効/無効化するか
Bit61ハーフカラーマス(0=ハーフカラー未使用, 1=結果を2で割る)
Bit70カラーマス加算/減算(0=加算; Main+Sub, 1=減算; Main-Sub)
[$00:2132](ColorMath制御レジスタ 固定色のデータ)

$E0 = %1110 0000

[$00:2130]のBit1が1の時は固定色が使われないため、今回は関係なし。
固定色については次ページで説明しているので参照していただきたい。

Bit数値内容
Bit71青(B)を設定 (%0=設定しない, %1=設定する)
Bit61緑(G)を設定 (%0=設定しない, %1=設定する)
Bit51赤(R)を設定 (%0=設定しない, %1=設定する)
Bit0~400000輝度 (%00000%11111)

以上から、BG1とBG3のみカラーマス処理が有効であることと、カラーマスが有効になるのは「ウインドウの外側の色のみ」であること、カラーマス処理は「ハーフカラーマス」で、明るさ(透明度)を半分とすることがわかる。
では、「ウインドウの外側の色のみ」とはどういう意味だろうか?
ウィンドウの外や中といった範囲は、ウィンドウ座標を決定するレジスタ[$00:2126][$00:2129]で決まっている。
ここでのウィンドウの外や中とは、「ウィンドウの中だから表示する」とか「外だから表示しない」の意味ではない。
中と外の範囲を決めているだけで、「ウィンドウの中は表示する」などの命令は別に行うことになる。

メニュー画面の初期設定では以下のようになっている。

レジスタ名前内容
[$00:2126]WH0ウィンドウ1左座標設定$00
[$00:2127]WH1ウィンドウ1右座標設定$00
[$00:2128]WH2ウィンドウ2左座標設定$00
[$00:2129]WH3ウィンドウ2右座標設定$00

上はウィンドウの一番右と一番左の座標を決めるレジスタである。つまりX軸の左隅と右隅である。
(Y軸の上と下隅を決める設定はない)
上だとすべて$00が入っているが、左右どちらも$00を指定すると、「ウィンドウすべてをウィンドウの外として扱う」とのことである。
つまり、上の初期状態だと、メニュー画面全体がウィンドウ外であり、BG1とBG3全体がカラーマス処理処理されて半透明になってしまう。

そこで、BG1とBG3のタイルデータとBGマップデータを送信したタイミングで、HDMA転送も仕掛けて、カラーマスを設定する。

$C2/4AEF PHP                     ;ステータスレジスタをスタックへプッシュ
$C2/4AF0 PHB                     ;DBレジスタをスタックにプッシュ
$C2/4AF1 REP #$20                ;Aを16bit幅に変更、Mフラグをクリア
$C2/4AF3 LDA $C20000,x[$C2:770A] ;Aに[$C2:770A]をロード
$C2/4AF7 INX                     ;Xをインクリメント +1
$C2/4AF8 INX                     ;Xをインクリメント +1
$C2/4AF9 DEC A                   ;をデクリメント -1
$C2/4AFA MVN C2 7E               ;データ転送
;A:転送データサイズ-1 $0018
;X:転送元アドレス $770C
;Y:転送先アドレス $3100
;オペランド:転送元と転送先バンク C2 -> 00
;$C2:770C -> $00:3100 +$0018バイト
$C2/4AFD PLB                     ;DBレジスタにスタックからプル
$C2/4AFE PLP                     ;Pレジスタにスタックからプル
$C2/4AFF RTS                     ;サブルーチン戻り

$C2/4B3B LDX #$7702              ;Xに$7702をロード
$C2/4B3E LDY #$4370              ;Yに$4370をロード
$C2/4B41 LDA #$0007              ;Aに$0007をロード
$C2/4B44 PHB                     ;DBレジスタをスタックにプッシュ
$C2/4B45 MVN C2 00               ;データ転送
;A:転送データサイズ-1 $0007
;X:転送元アドレス $7702
;Y:転送先アドレス $4370
;オペランド:転送元と転送先バンク C2 -> 00
;$C2:7702 -> $00:4370 +$0007バイト 01 26 00 31 7E 00 00 7E
$C2/4B48 PLB                     ;DBレジスタにスタックからプル
$C2/4B49 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C2/4B4B LDA #$80                ;Aに$80をロード
$C2/4B4D STA $7B    [$00:057B]   ;Aを[$00:057B]に書き込み
$C2/4B4F PLP                     ;Pレジスタにスタックからプル
$C2/4B50 RTS                     ;サブルーチン戻り

上がHDMA転送の準備である。
まず、$C2/4AFAのMVN転送で、$C2:770C$C2:7724$00:3100$00:3118にコピーする。
この値がいわゆる「HDMAテーブル」で、どのデータをいつ転送するか、といった一連の指示にあたる。
$19バイト転送しているのだが、メニュー画面については必要となるのは$0Cバイト(12バイト)である。
その値が、
0F 00 FF 18 08 2F 08 00 FF 00 00 00
である。

さらに、$C2/4B45のMVN転送で、$C2:7702$C2:7709$00:4370$00:4377にコピーする。
つまり、GDMAチャネル7の設定をしている。
これは実質HDMA転送の設定でもある。

HDMA チャネル7
I/Oアドレス
内容
[$00:4370]GDMA / HDMA設定レジスタ$01
[$00:4371]転送先指定$26=ウィンドウ1左座標設定
[$00:4373][$00:4372]データ元アドレス(開始位置)$3100
[$00:4374]データ元バンク$7E

まず、GDMA / HDMA設定レジスタ[$00:4370]には$01(%0000 0001)が入る。
HDMA転送の場合は以下のように設定される。
snes-docs-ja/memory/dma/ioreg.md

Bit内容
Bit0-2%001転送ユニット
Bit3-5%000不使用
Bit6%0テーブルモード (0=直接, 1=間接)
Bit7%0転送方向 (0=Aバス→Bバス, 1=Bバス→Aバス)

Bit0-2が%001だが、これは転送方法の指定になる。
%001の場合、指定レジスタアドレスと、指定レジスタアドレス+1に対し、転送1回につき1度書き込みを行う、という意味になる。
指定レジスタは[$00:4371]で、ここに書き込んだ値に21を付けた[$00:2126](ウィンドウ1左座標設定)と、この次のアドレス[$00:2127](ウィンドウ1右座標設定)に対し、HDMA転送で値を書き込む、という意味になる。

Bit6のテーブルモードは0で、HDMAテーブルに転送用データが入る(直接モード)。

さて、ここで$00:4370以降に書き込んだHDMAテーブルを見てみる。
今回のHDMAテーブルは、
「書き込みスキャンライン数(1バイト)」、「[$00:2126]に書き込む値(1バイト)」、「[$00:2127]に書き込む値(1バイト)」
の3バイトで構成されている。
HDMA転送を終わらせる場合、最後に$00を3バイト入れて終了させる。

では、$00:4370以降を3バイトずつ区切ってみよう。

書き込み
スキャンライン数
[$00:2126][$00:2127]
$0F$00$FF
$18$08$2F
$08$00$FF
$00$00$00

つまり、

スキャンライン内容
$00$0Fウィンドウ1左座標設定[$00:2126]$00、ウィンドウ1右座標設定[$00:2127]$FFとすることで、ウィンドウ幅すべてを「ウィンドウの中として扱う」
$10$27ウィンドウ1左座標設定[$00:2126]$08、ウィンドウ1右座標設定[$00:2127]$2Fとすることで、左から$08ピクセル~$2Fピクセルの間だけ「ウィンドウの中として扱う」
$28$2Fウィンドウ1左座標設定[$00:2126]$00、ウィンドウ1右座標設定[$00:2127]$FFとすることで、ウィンドウ幅すべてを「ウィンドウの中として扱う」

と、ウィンドウ内外の設定を変えたことになる。
また、スキャンライン$2F[$00:2127]$FFを書き込んだことで、画面一番下のスキャンラインまで[$00:2127]$FFが入ったままである。

どういうことになったのか、図にしてみよう。

少しわかりにくくなってしまったかもしれないが、X軸で$08$2Fピクセル、Y軸で$10$27ピクセルの位置は、メニュー画面で最初にカーソルがあっている「装備」コマンドのウィンドウ枠に一致するのである。
コマンドウィンドウ枠の中で、「装備」コマンド位置だけが、ウィンドウの中という扱いになったので、カラーマスは適用されない。
それ以外の位置(黄色をかけたところ)はカラーマスが適用されるため、「装備」コマンドより右側がすべて、BG1・BG3の透明度が半分になる、ということになる。
また、コマンドウィンドウよりも上、または下は、ウィンドウ1左座標設定[$00:2126]$00、ウィンドウ1右座標設定[$00:2127]$FFとしたから、ウィンドウ幅すべてがウィンドウの中という扱いになって、カラーマスは適用されない。

以上の処理により、1フレームに1回、HDMA転送によりコマンドウィンドウ枠の一部がカラーマス処理で半透明になり続ける。

また、他のコマンドを選んだ場合、HDMAテーブル$00:3100~を書き直して、スキャンライン$10$27のウィンドウ1左座標設定[$00:2126]とウィンドウ1右座標設定[$00:2127]を変更すれば、半透明になる位置を変更できることになる。
変更するのはHDMAテーブル$7E:3100~だけ、もっと言えば枠部分の座標を記したHDMAテーブル部分にあたる[$7E:3105][$7E:3104]で良く、[$00:437?]などの値を書き直す必要はない。
後は、1フレームに1回HDMA転送の命令(今回で言えばHDMAチャネル7の実行命令)さえ出せば良いことになる。
その場合は[$00:420C]%1000 0000 = $80を書き込む。

$C2/4FE1 SEP #$20                ;MフラグON Aレジスタは8bit幅
$C2/4FE3 LDA $7B    [$00:057B]   ;Aに[$00:057B]($80)をロード
$C2/4FE5 STA $420C  [$00:420C]   ;A($80)を[$00:420C]に書き込み
$C2/4FE8 LDA $79    [$00:0579]   ;Aに[$00:0579]($81)をロード
$C2/4FEA STA $4200  [$00:4200]   ;A($81)を[$00:4200](割り込み有効フラグ)に書き込み
$C2/4FED STZ $76    [$00:0576]   ;[$00:0576]に$00を書き込み
$C2/4FEF JSR $5178  [$C2:5178]   ;[$C2:5178]へジャンプ

例えば、「装備」から、ひとつ右の「持ち物」にカーソルを移すと、下の処理が行われる。

$C2/0726 BCS $06    [$072E]      ;キャリーフラグが立っているとき[$C2/072E]分岐
$C2/0728 PER $0002  [$072D]      ;PCの値にオペランド指定値をスタックに積み[$C2:072D]
$C2/072B JMP ($0532)[$C2:0893]   ;[$C2:0893]へジャンプ(レジスタをスタックに積まない)
$C2/0893 LDA $44    [$00:0544]   ;Aに[$00:0545][$00:0544](カーソル位置$0002)をロード
$C2/0895 DEC A                   ;Aをデクリメント -1
$C2/0896 ASL A                   ;Aを算術左シフト *2
$C2/0897 TAX                     ;Aの値をXレジスタに転送
$C2/0898 LDA $C27129,x[$C2:712B] ;Aに[$C2:712C][$C2:712B]をロード
$C2/089C STA $3104  [$7E:3104]   ;Aを[$7E:3105][$7E:3104]に書き込み
$C2/089F RTS                     ;サブルーチン戻り

メニュー画面のアイテム並び替えなどで紹介したが、メニュー画面ではどのコマンドでも共通して、[$00:0544][$00:0545]の2バイトがカーソル位置(ナンバリング)が入るアドレスになっている。
「装備」が$0001で、「持ち物」が$0002となる。
$C2/0893からの処理を見ると、

(カーソル位置 - 1)*2 + $C27129

で計算したアドレスの2バイトの値が、[$7E:3105][$7E:3104]、つまりメニュー画面コマンド枠の[$00:2126](ウィンドウ1左座標設定)と[$00:2127](ウィンドウ1右座標設定)に書き込まれる値になる。
要するに、$C2:7129から2バイトずつ、「装備」「持ち物」「技」「隊形」「音声」「セーブ」枠用の[$00:2126](ウィンドウ1左座標設定)と[$00:2127](ウィンドウ1右座標設定)が入る値になる。

アドレス
[$C2:712A][$C2:7129]08 2F
[$C2:712C][$C2:712B]30 5F
[$C2:712E][$C2:712D]60 77
[$C2:7130][$C2:712F]78 9F
[$C2:7132][$C2:7131]A0 C7
[$C2:7134][$C2:7133]C8 F7

Y軸のピクセル数(Y座標)として見ると、各コマンドの枠の位置とぴったり一致する。

以上がメニュー画面におけるカラーマスによる半透明処理の仕組みである。

戦闘でのカラーマス

メニュー画面のコマンドの透過はハーフカラーマス、つまり透明度の調整であったが、カラーマスは他にも、色の加算・減算を行って、元のカラーパレット指定色に、カラーマスで指定した色を加算・減算で被せることができる。
本作だと、戦闘中の効果としてよく見ることになる。
カラーマスを使わない場合、カラーパレットに登録した色しか使えないが、カラーマスで元のカラーパレットに色を加算(または減算)することで、多くの色を表現できることになる。
色の加算・減算とは何かについては、後の色の加算・減算にまとめている。

まず復習として、背景グラフィックと効果 > 戦闘でのサブルーチンで、戦闘開始時にカラーマス関係のI/Oレジスタに以下のように値が設定されていた。

I/Oレジスタ名前内容
[$00:2130]CGSWSELカラーマス制御レジスタA 色追加選択$00
[$00:2131]CGADSUBカラーマス制御レジスタB 色計算指定$00

だがこれは初期値であり、実際にはカラーマスを使う場面で新たに値が書き込まれるようになっている。

また、スプライトについて > 戦闘でのサブルーチンの通り、戦闘ではGDMA転送用に戦闘開始時点で以下のように値が入る。

アドレスn0123457
$00:43n0GDMA / HDMA
設定レジスタ
$01$00-$00$41$01$09
$00:43n1$18$22$80$04$26$26$18
転送先VRAMCGRAMWRAMOAMWindow
座標1L
Window
座標1L
VRAM
$00:43n2~3データ元アドレス----$A700$E9FD-
$00:43n4データ元バンク----$7E$C1-
$00:43n7間接HDMA
アドレス
----$7E$C1-

GDMAチャネル4と5は転送先がウィンドウ1左座標設定[$00:2126]であることから、先のメニュー画面の処理と同じく、HDMA転送を使ってウィンドウ幅を調整し、ウィンドウの中/外の設定を切り替えてカラーマス効果を使用するのだろう、ということが推測できる。

HDMA チャネル4
I/Oアドレス
内容
[$00:4340]GDMA / HDMA設定レジスタ$41
(HDMAテーブル間接モード)
[$00:4341]転送先指定$26=ウィンドウ1左座標設定
[$00:4343][$00:4342]データ元アドレス(開始位置)$A700
[$00:4344]データ元バンク$7E
HDMA チャネル5
I/Oアドレス
内容
[$00:4350]GDMA / HDMA設定レジスタ$01
(HDMAテーブル直接モード)
[$00:4351]転送先指定$26=ウィンドウ1左座標設定
[$00:4353][$00:4352]データ元アドレス(開始位置)$E9FD
[$00:4354]データ元バンク$C1

なのだが、実際には、戦闘中敵味方が何かしらの技を出したりして、カラーマスなどを使うなど、画面効果が必要な時以外はHDMAチャネル5が常に動いている。
カラーマスを使う場合は、BG3にカラーマスを使いたい場所だけタイルを設置して、画面全体のカラーマスをONにしてHDMAチャネル5を止めるという方法を使っている。
それ以外にも技の効果を出したり、敵を倒した時に敵スプライト部分だけカラーマスをかけて光らせるという処理などはHDMAチャネル4を使う。
という、筆者にはなぜこのような方法を使うのやら、よくわからない手法を使っているようである。
HDMAチャネル5をONにしたことによる効果がどこにあるのかなどもわからない。
(何かしら理由はあるはずだが、筆者の知識不足ゆえ、よくわからない。ご了承いただきたい)

ここでは例として、敵が攻撃技を使ってくる時、攻撃範囲だけ赤っぽい色に変化するカラーマス効果を紹介する。
この時のカラーマス効果は、BG3に、画面上部ウィンドウに攻撃技名、攻撃範囲マス部分に赤一色のタイルを表示させ(つまりBG3のBGマップデータを更新する)、画面上部ウィンドウにはカラーマスを適用させず、それ以外の範囲のBG1(戦闘背景)に対してカラーマス効果を適用させてBG1部分だけ赤っぽい色を載せている。

まず、BG3に画面上部ウィンドウ+攻撃技名のBGマップデータを送信し、画面上部ウィンドウ部分だけ通常通りに(カラーマスを使わず)表示させる。詳細は省略。
この後に、技範囲表示のために、カラーマスやHDMA関係のI/Oレジスタを設定し直す。
ゲーム画面では、画面上部ウィンドウと技範囲のカラーマス表示はほぼ同時に見えるが、実際にはわずかに画面上部ウィンドウの表示が速い、ということである。

$C1/89E5 LDA #$05                ;Aに$05をロード
$C1/89E7 STA $2121  [$00:2121]   ;Aを[$00:2121](CGRAM書き込みアドレス)に書き込み
$C1/89EA LDX #$ABF0              ;Xに$ABF0をロード
$C1/89ED STX $4312  [$00:4312]   ;Xを[$00:4313][$00:4312]に書き込み
$C1/89F0 LDA #$7E                ;Aに$7Eをロード
$C1/89F2 STA $4314  [$00:4314]   ;Aを[$00:4314]に書き込み
$C1/89F5 LDX #$0006              ;Xに$0006をロード
$C1/89F8 STX $4315  [$00:4315]   ;Xを[$00:4316][$00:4315]に書き込み
$C1/89FB LDA #$02                ;Aに$02をロード
$C1/89FD STA $420B  [$00:420B]   ;Aを[$00:420B]に書き込み
$C1/8A00 LDA #$04                ;Aに$04をロード
$C1/8A02 STA $212D  [$00:212D]   ;Aを[$00:212D]に書き込み サブスクリーン指定
$C1/8A05 LDA #$02                ;Aに$02をロード
$C1/8A07 STA $2130  [$00:2130]   ;Aを[$00:2130]に書き込み CGSWSEL 色追加選択
$C1/8A0A LDA $77    [$00:0377]   ;Aに[$00:0377]をロード
$C1/8A0C CMP #$81                ;Aと$81を減算比較(ステータスレジスタ変更のみ)
$C1/8A0E BEQ $0B    [$8A1B]      ;ゼロフラグが立っているとき[$8A1B]分岐
$C1/8A1B LDA #$01                ;Aに$01をロード
$C1/8A1D STA $2131  [$00:2131]   ;Aを[$00:2131]に書き込み
$C1/8A20 LDA #$E0                ;Aに$E0をロード
$C1/8A22 STA $2132  [$00:2132]   ;Aを[$00:2132]に書き込み
$C1/8A25 RTS                     ;サブルーチン戻り
I/Oアドレス名前内容
[$00:212D]TSサブスクリーン指定$04(BG3のみ使用)
[$00:2130]CGSWSELカラーマス制御レジスタA 色追加選択$02
[$00:2131]CGADSUBカラーマス制御レジスタB 色計算指定$01
[$00:2132]COLDATA固定色のデータ$E0

[$00:2130][$00:2131]について整理してみよう。

[$00:2130]

$02 = %0000 0010

Bit数値内容
Bit00256色のBG用ダイレクトカラーモード
(0=パレットを使う, 1=ダイレクトカラー)
Bit11サブスクリーン BG/OBJ 有効化
(0=未使用/Backdrop only, 1=使用/Backdrop+BG+OBJ)
Bit2-300(未使用ビット)
Bit4-500カラーマス有効化
(0=常に使用, 1=ウインドウの外側の色のみ, 2=ウインドウの内側の色のみ, 3=使用しない)
Bit6-700計算前の黒にクリッピングする色
(3=常に使用, 2=ウインドウの内側の色のみ, 1=ウインドウの外側の色のみ, 0=なし)
[$00:2131]

$01 = %0000 0001

Bit数値内容
Bit01BG1でカラーマスを有効/無効化するか
Bit10BG2でカラーマスを有効/無効化するか
Bit20BG3でカラーマスを有効/無効化するか
Bit30BG4でカラーマスを有効/無効化するか
Bit40OBJでカラーマスを有効/無効化するか
Bit50背景 (Backdrop)でカラーマスを有効/無効化するか
Bit60ハーフカラーマス(0=ハーフカラー未使用, 1=結果を2で割る)
Bit70カラーマス加算/減算(0=加算; Main+Sub, 1=減算; Main-Sub)

メニュー画面での設定とはかなり異なることがわかる。
[$00:2130]のBit4-5、カラーマス有効化範囲に%00が指定されているから、ウィンドウの中や外などは関係なく常に使用ということになる。
[$00:2131]でカラーマスを有効にするのはBG1のみ、ハーフカラーマス使用なし、カラーマスは加算、としているので、[$00:212D]でサブスクリーンに指定されたBG3が、カラーマス有効のBG1にのみ、色を加算して処理される、という意味になる。

後はBG3のBGタイルマップに、赤色の範囲を載せたい部分だけ座標と色など指示を書き込んで、HDMA転送チャネル5を停止する。
つまり、[$00:420C]$00を書き込む。

$C1/8702 LDA $F2    [$00:03F2]   ;Aに[$00:03F2]($20)をロード
$C1/8704 AND #$DF                ;Aと$DFで論理積 $20 & $DF = $00
$C1/8706 STA $F2    [$00:03F2]   ;Aを[$00:03F2]に書き込み
$C1/8708 STA $420C  [$00:420C]   ;Aを[$00:420C]に書き込み
$C1/870B LDA #$00                ;Aに$00をロード
$C1/870D STA $2123  [$00:2123]   ;Aを[$00:2123]に書き込み BG1,BG2ウィンドウマスク設定
$C1/8710 STA $212E  [$00:212E]   ;Aを[$00:212E]に書き込み メインスクリーンウインドウマスク指定
$C1/8713 RTS                     ;サブルーチン戻り

[$00:03F2]は戦闘開始時点で$20が入り(厳密には味方キャラが行動可能になったタイミング、$C1/86EE$C1/8701)、[$00:420C]に書き込むことで通常はHDMA転送チャネル5を開始させるのだが、上処理で[$00:03F2]$00が書き込まれ、[$00:420C]にも$00が書き込まれるため、HDMA転送チャネル5が停止して、カラーマスが表示される。

色の加算・減算

敵の攻撃範囲は、BG1背景に$840000この色)を加算処理する。
加算といっても、絵の具で赤を混ぜるという意味ではなく、コンピュータにおけるRGBカラーで赤を加算という意味である。

RGB - Wikipedia

スーパーファミコンでは色表示のフォーマットがBGR555である、という話はスプライトについて > 色のデータとCGRAMで説明したが、RGB24ビットカラーでも、BGR555ビットカラーでも、赤・緑・青をどれくらい混ぜるかという方法で色を表現していることに変わりはない。
ポイントは、色を混ぜる度合いを増やすほど明るくなる(白に近づく)、逆に減らすと暗くなる(黒に近づく)ということである。
このため、デジタルで赤を加算すると、赤っぽくなり、かつ、明るさが増す。
減算ならその逆である。

よって、背景に赤っぽい色を被せたい、という時、あえて純粋な赤$FF0000ではなく、ややくすんだ赤茶色っぽい色$840000を加算することで、ある程度明るさを抑えつつ、赤っぽく加工できる。

筆者が適当に描いた絵で恐縮だが、下の絵に、

それぞれ、純粋な赤である$FF0000と、BG1背景にカラーマス処理する$840000を加算処理すると、下のようになる。

$FF0000を加算処理した方は色が赤かつ明るくなりすぎていることがわかるかと思う。元々の色もわからなくなってしまう。
$840000を加算した方が、元の色がわかる程度で赤っぽくするにはちょうど良いくらいなのである。

以上、カラーマスについてざっと説明した。
次ページで、カラーマスの派生として、サブスクリーンを使わず、「固定色」という色の層(スクリーン)を利用した色の処理について説明する。



このページをシェアする

上へ