カラーパレットをかえてみよう

カラーパレットをかえてみよう

MSXにはカラー・パレットというものがある。
今のPCなら余りあるメモリでビットマップでも余裕で処理できるが、MSXはVRAMが最大128キロバイトしかないので、表現できる色は512色あるけど、そのうち16色しか使えないという制限がある。その16色をカラー・パレットというのだ。
デフォルトでは下表のように設定されているぞ。

パレット番号パレット番号
0周辺色8
19明るい赤
210
3明るい緑11明るい黄
4暗い青12暗い緑
5明るい青13
6暗い赤14
7水色15

まずはCOLORでかえてみよう

当然、このパレットの色を変えることができる。
BASICではCOLORステートメントを使う。やってみよう。

パレットの色を変える

1000 SCREEN 1 : PRINT "PUSH ANY KEY" : GOSUB 2000
1010 COLOR=(4,7,0,0) : GOSUB 2000
1020 COLOR=(4,0,7,0) : GOSUB 2000
1030 COLOR=(4,0,0,7) : GOSUB 2000
1040 COLOR=(4,5,5,5) : GOSUB 2000
1050 COLOR=NEW
1060 END

2000 I$=INKEY$ : IF I$="" THEN 2000
2010 RETURN

実行結果の絵は割愛するが、何かキーを押すたびに背景の色が、赤→緑→青→灰→青に変わるぞ。
デフォルトでは背景色のパレットが4なので、パレット番号4の色を変えている。
カッコのなかの1番左の数値がパレット番号、そして右へ順番に赤色(Red)の輝度、緑色(Green)の輝度、青色(Blue)の輝度となっている。
それぞれの輝度は3ビットであらわされるので、数値では0~7(000B~111B)ということになる。赤8×緑8×青8=512通り(色)というわけだな。
最後のNEWは、パレットが初期化されるぞ。

VRAM操作でかえてみよう

カラー・パレットは、VRAM上ではパレット・テーブルという領域に保存されている。
この領域はスクリーンモード毎に違うのでデータパックなどで確認してくれたまえ。
今回のサンプルはスクリーン1を使うので、データパックによると2020Hから32バイトということらしい。

先頭アドレスからパレット0が定義され、1パレットにつき、2バイト使用している。
その情報は次の図の通り。

カラー・パレットの仕様


それぞれ3ビットなので、1バイトに収まらないので2バイトなんだな。
それじゃ、やってみよう。

VRAMでパレットの色を変える

1000 SCREEN 1
1010 COLOR=(4,1,2,3) : GOSUB 1500
1020 GOSUB 2000

1100 SCREEN 1
1110 VPOKE &H2020+(4*2),&H13
1120 VPOKE &H2020+(4*2)+1,&H2
1130 GOSUB 1500 : GOSUB 2000
1140 END

1500 PRINT HEX$(VPEEK(&H2020+(4*2)))
1510 PRINT HEX$(VPEEK(&H2020+(4*2)+1))
1520 RETURN

2000 I$=INKEY$ : IF I$="" THEN 2000
2010 RETURN

実行結果

実行結果
実行結果

結論からいうと失敗だ。

初めはCOLORステートメントでパレットを変更した後、対象のパレット・テーブルを表示している。
赤=1、緑=2、青=3と設定しているので、その内容が正しく表示されており、背景色も変化している。

次は、VRAMを変更した後、対象のパレットテーブルを表示している。
対象のVRAMアドレスに同じ値を設定したのだが、背景色は変化していない。
しかし、VRAMの値は変更した値になっているのだ。

要するに、VRAMを変更しただけではパレットは変化しないということだな。
何か別の方法があるはずだ。
ということで調べましたよ。

VDP(n)でかえてみよう

データパックによると、VDPにはパレットレジスタなるものがあるらしい。
BASICではVDP(n)というシステム関数でアクセスできる。VDP(n)の詳しいことは次の投稿を参照してくれたまい。

そして、パレットレジスタR#16に変更したいパレット番号をセットした後、ポート#2に赤と青、もう一度ポート#2に緑の輝度をセットすればいいらしい。
VDPにはポートが4つあり、ポート#2はMAIN ROMの07H番地の値に2を足したアドレスのI/Oポートらしい。
らしいばっかりだな!

MAIN ROMの07H番地の値はPEEK関数によると98Hだったので、+2すると9AHだな。
で、BASICでポートに出力するには、OUTステートメントを使えばよい。やってみよう。

VDP(n)でパレットを変える

1000 SCREEN 1
1010 COLOR=(4,1,2,3) : GOSUB 1500
1020 GOSUB 2000

1100 SCREEN 1
1110 VDP(17)=4
1120 OUT &H9A,&H13
1130 OUT &H9A,&H02
1140 GOSUB 1500 : GOSUB 2000
1150 END

1500 PRINT HEX$(VPEEK(&H2020+(4*2)))
1510 PRINT HEX$(VPEEK(&H2020+(4*2)+1))
1520 RETURN

2000 I$=INKEY$ : IF I$="" THEN 2000
2010 RETURN

実行結果

実行結果
実行結果

前回のサンプルのVPOKEだったところを、VDP(n)とOUTにしたのがこれだ。
ちゃんと背景色が変わっているぞ。成功だ。
でも、パレット・テーブルは変わらないんかい!

今はこれが限界だな。
じゃまた。

おまけ

512色をお試しできるプログラムをつくってみたよ。
「R」「G」「B」キーを押すとそれぞれ赤緑青の輝度が上がり、シフト+「R」「G」「B」キーを押すと輝度が下がるよ。
それに合わせて、真ん中のスプライトの色が変化するぞ。

512色お試し

1000 SCREEN 1,1 : WIDTH 32 : DEFINT A-Z
1010 A$="" : FOR I=0 TO 7
1020 	A$=A$+CHR$(&HFF)
1030 NEXT : SPRITE$(0)=A$
1040 PUT SPRITE 0,(16*8-8,11*8-8),1
1050 R=0 : G=0 : B=0 : GOSUB 3000

2000 I$=INKEY$
2010 IF I$="r" AND R<7 THEN R=R+1
2020 IF I$="R" AND R>0 THEN R=R-1
2030 IF I$="g" AND G<7 THEN G=G+1
2040 IF I$="G" AND G>0 THEN G=G-1
2050 IF I$="b" AND B<7 THEN B=B+1
2060 IF I$="B" AND B>0 THEN B=B-1
2070 GOSUB 3000
2080 GOTO 2000

3000 COLOR=(1,R,G,B)
3010 LOCATE 11,15 : PRINT "RED   = ";R
3020 LOCATE 11,16 : PRINT "GREEN = ";G
3030 LOCATE 11,17 : PRINT "BLUE  = ";B
3040 RETURN