MSX:ダブルバッファリング手法メモ
ダブルバッファリング : 画面の乱れを抑制するためのテクニック
Double buffering : Anti Flicker display technique.
githubにおいてあるメモからの転載
目次
- MSX:ダブルバッファリング手法メモ
という順番で、ダブルバッファリング手法についてメモしていきます。
Warning
👉 パレットテーブルを使わない!カラーパレットテーブル という 邪魔者
VRAM全域を無駄なく使用したい場合には、配置を変更できないパレットテーブルが邪魔になります。このメモは
COLOR=(n,r,g,b)
やCOLOR=RESTORE
などのパレット操作BASIC命令を使わない 前提で書かれていますので、もしこれらの命令を使用したい場合は、 各テーブルアドレスの配置に工夫が必要になります。
前置き
問題
毎フレーム画面を書き換えている場合、 VBLANK期間
中に処理が収まらないと画面が乱れてしまいます。
特に、スプライトアトリビュートテーブルは おかしな位置におかしなスプライトが表示されるなど、 とても激しい乱れが発生します。
VDPの表示期間中に書き換えると、意図しない中途半端な状態で表示が実行されてしまうためです。
ですので、VRAM書き込みをVBLANK期間
内に完了させる必要があるのですが、
実際に、VBLANK期間
内に全てのVRAM書き込み処理を収めるのは非常に難しい事が多いです。
Note
スプライトの表示管理
SCREEN4以降のスプライトモード2では、スプライトアトリビュートテーブル+スプライトカラーテーブルへの書き込みが必要なので、
64バイト+512バイト
をVBLANK期間
内に転送する必要があります。👉 この転送量はかなり厳しめです。
👉 turboRは理論上不可能となっています。turboRではI/Oを使用したVRAM書き込みがMSX2+以前より遅くなっていますので、 スプライトアトリビュートテーブル+スプライトカラーテーブルの書き込みを
VBLANK期間
内に収める事が不可能になってしまいました。
対処法
「表示切替」または
「表示スワップ」または
「ダブルバッファリング」
と呼ばれる手法を使用します。
この手法を使うと、VBLANK期間
外に書き込んでも表示が乱れないようになります。
- VRAMの空き領域へ書き込み
- 書き込みが終わったら、書き込み終わった領域を表示ベースアドレスに設定する
表示に使用されていない領域に書き込みをすれば、表示期間中であっても表示に悪影響が起きません。
そして全ての書き込みが終わったら表示用アドレスを変更することで瞬時に表示が変化します。
(SCREEN5
以降の裏ページ書き込み&表示切替テクニックもこの手法に該当します)
VDPはキャラクタ(グラフィック)やスプライトデータを表示する際に参照するVRAMアドレスを指定する機能があります。これをベースアドレス設定と言います。
ベースアドレスの種類は、スプライト(パターンジェネレータ、アトリビュート+カラー)、キャラクタ(パターンジェネレータ、パターンカラー、パターンネーム)などがあります。
利点
この手法の優れた点は、通常の処理からの追加コストが低い事です。
追加・変更は
- 書き込み開始VRAMアドレスの変更
- 書き込み完了後のVDPレジスタ書き込み(アドレス指定)
のみとなります。
処理の効率化によって、VSYNC待ちが少なく、VSYNC処理が軽くなります。
■ メインループ
- メイン処理
- VRAM書き込み
- VSYNC処理完了待ち
■ VSYNC割り込み
- VRAM書き込みまで完了していれば、表示ベースアドレス変更(一瞬)
- BGM等の処理(タイミング安定)
ダブルバッファを使わない場合
■ メインループ
- メイン処理
- VSYNC処理完了待ち
■ VSYNC割り込み
- メイン処理が終わっていれば、VRAM転送(VBLANK期間を超えると表示化け)
- BGM処理(VRAM転送量によってもたつき)
副作用
表示期間中に切り替えても良いのですが、
表示期間中に切り替えるとそのラインを境に表示が切り替わるのでティアリングが発生します。
ティアリングが気になる場合は次のVSYNCを待ってから表示を切り替えます。
ただし、表示の反映が1フレーム遅れます。
また、VRAMの空き容量が必要になります。
VSYNCを待つ間に新しいフレームの描画を行いたい場合、 タイミングによっては、「表示中」「表示待ち」「裏で書き換え」の3つのバッファが必要になる可能性もあります。 (トリプルバッファリング)
基礎知識
テーブル名 | 内容 |
---|---|
パターン ネーム テーブル | 画面(X,Y)に表示されるキャラクタ コードのテーブル。 |
パターン カラー テーブル | キャラクタ コード毎の色テーブル または 画面座標毎の色テーブル |
パターン ジェネレータ テーブル | キャラクタ コード毎のドット パターン テーブル |
スプライト アトリビュート テーブル | スプライト番号毎の表示情報テーブル |
スプライト カラー テーブル | スプライト番号毎の色テーブル |
スプライト パターン ジェネレータ テーブル | スプライト パターン番号毎のドット パターン テーブル |
- 各テーブルは、ベースアドレスをVDPへ設定することで、表示に使用するVRAMアドレスを変更できます。
- ベースアドレスは画面モードによって、アドレスの設定単位に制限があります。
カラーパレットテーブル という 邪魔者
VRAMの空き領域をフルに使いたい場合、
(微妙な位置に配置され、移動もできない)カラーパレットテーブルが邪魔になります。
カラーパレットテーブルは本来VDPに必要な領域ではなく、
BASICのCOLOR=(n,r,g,b)
命令やCOLOR=RESTORE
命令でのパレット操作でのみ使用されます。
これらの命令を使わずに、VDPレジスタ操作で直接カラーパレット設定するようにすれば、 邪魔なカラーパレットテーブルを無視できるようになります。
デフォルトのベースアドレス
参考:MSX Datapack wiki - VRAMマップ
画面モード | パターンジェネレータ | パターンネーム | カラー/ブリンク |
---|---|---|---|
SCREEN 0 40行 | $0800-$0FFF ($800) | $0000-$03BF($3C0) | なし |
SCREEN 0 80行 | $1000-$17FF ($800) | $0000-$03BF($3C0) | $0800-$090D ($19E) |
SCREEN 3 | $0000-$07FF ($800) | $0800-$0AFF ($300) | なし |
SCREEN 1 | $0000-$07FF ($800) | $1800-$1AFF ($300) | $2000-$201F ($20) |
SCREEN 2 | $0000-$17FF ($1800) | $1800-$1AFF ($300) | $2000-$37FF ($800) |
SCREEN 4 | $0000-$17FF ($1800) | $1800-$1AFF ($300) | $2000-$37FF ($800) |
SCREEN 5/6 212行 | なし | $0000-$69FF ($6A00) | なし |
SCREEN 5/6 192行 | なし | $0000-$5FFF ($6000) | なし |
SCREEN 7/8 212行 | なし | $0000-$D3FF ($D400) | なし |
SCREEN 7/8 192行 | なし | $0000-$BFFF ($C000) | なし |
画面モード | スプライトアトリビュート | スプライトパターン | スプライトカラー |
---|---|---|---|
SCREEN 0 | なし | なし | なし |
SCREEN 3 | $1B00-$1B7F ($80) | $3800-$3FFF ($800) | なし |
SCREEN 1 | $1B00-$1B7F ($80) | $3800-$3FFF ($800) | なし |
SCREEN 2 | $1B00-$1B7F ($80) | $3800-$3FFF ($800) | なし |
SCREEN 4 | $1E00-$1E7F ($80) | $3800-$3FFF ($800) | $1C00-$1DFF ($200) |
SCREEN 5/6 | $7600-$767F ($80) | $7800-$7FFF ($800) | $7400-$75FF ($200) |
SCREEN 7/8 | $FA00-$FA7F ($80) | $F000-$F7FF ($800) | $F800-$F9FF ($200) |
※ SCREEN9
はSCREEN5/6
と同じ
※ SCREEN10/11/12
はSCREEN7/8
と同じ
ベースアドレスの設定可能な単位
参考:MSX Datapack wiki - V9938の画面モード
画面モード | パターンジェネレータ | パターンネーム | カラー/ブリンク |
---|---|---|---|
SCREEN 0 40行 | $800 | $400 | なし |
SCREEN 0 80行 | $800 | $1000 | $200 |
SCREEN 3 | $800 | $400 | なし |
SCREEN 1 | $800 | $400 | $40 |
SCREEN 2 | $800 | $400 | $2000 |
SCREEN 4 | $800 | $400 | $2000 |
SCREEN 5/6 | なし | $8000 | なし |
SCREEN 7/8 | なし | $10000 | なし |
参考:MSX Datapack wiki - VDP - レジスタの機能
スプライトモード | スプライトアトリビュート | スプライトパターン | スプライトカラー |
---|---|---|---|
スプライトモード 1 | $80 | $800 | なし |
スプライトモード 2 | $400 * n + $200 | $800 | $400 |
BASICでの書き込み先の変更
アセンブラであれば書き込み先アドレスは任意で指定していますが、
BASICは各命令の書き込み先を変更する命令はSET PAGE
しかありません。
ですが、ワークエリアの値を変更することでBASIC命令の書き込み先VRAMアドレスを変更できます。
名称 | アドレス | サイズ | 内容 |
---|---|---|---|
NAMBAS | $F922 | 2 | 現在のパターンネームテーブルのベースアドレス |
CGPBAS | $F924 | 2 | 現在のパターンジェネレータテーブルのベースアドレス |
PATBAS | $F926 | 2 | 現在のスプライトジェネレータテーブルのベースアドレス |
ATRBAS | $F928 | 2 | 現在のスプライトアトリビュートテーブルのベースアドレス |
👉 スプライトカラーテーブルはスプライトアトリビュートテーブルと連動します。
(スプライトアトリビュートテーブル - $200
になる)
例)書き込み先パターンネームテーブルを&H2000にしたい場合は、
POKE &HF922,0:POKE &HF923,&H20
スプライト表示
表示座標X、Y、表示パターン番号、表示色について、まとめて表示変更する場合。
スプライトモード1 - SCREEN1/2/3
スプライトモード1ではスプライトアトリビュートテーブルのみを操作すればよいので簡単です。
■ スプライトアトリビュートテーブル
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#5 | A14 | A13 | A12 | A11 | A10 | A9 | A8 | A7 | (ad / $80) AND $FF |
VDP R#11 | 0 | 0 | 0 | 0 | 0 | 0 | A16 | A15 | ad / $8000 |
- サイズは
32*4=128
で$80
バイト。 - ベースアドレスの単位は
$80
バイト。
ベースアドレスは
パターンネームテーブルもダブルバッファにすることを考慮すると、$1B00
と$1F00
を使うのが楽ではないでしょうか。
$1B00
: R#5=$36
,R#11=0
$1F00
: R#5=$3E
,R#11=0
' ** BASIC SAMPLE **
' PG:ページ番号
' PG=0 : base address = &H1B00
' PG=1 : base address = &H1F00
VDP(5)=&H36+PG*8
VDP(12)=0
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : base address = $1B00
; 1 : base address = $1F00
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
add a,$36 ; a = $36 + PAGE * 8
ld b,a
ld c,5
call WRTVDP
xor a
ld c,11
call WRTVDP
ret
スプライトモード2
スプライトモード2の場合、スプライトカラーテーブルが別に必要で、データサイズが大きいのがネックになります。
■ スプライトアトリビュートテーブル
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#5 | A14 | A13 | A12 | A11 | A10 | 1 | 1 | 1 | ((ad / $80) AND $FF) OR 7 |
VDP R#11 | 0 | 0 | 0 | 0 | 0 | 0 | A16 | A15 | ad / $8000 |
- サイズは
32*4=128
で$80
バイト。 - ベースアドレスは
$200
を先頭に$400
単位。 →$200+$400 * n
■ スプライトカラーテーブル
- サイズは
32*16=512
で$200
。 - ベースアドレスは
スプライトアトリビュートテーブル - $200
。
スプライトカラーテーブルはスプライト番号に対応して16バイトずつ。
Warning ※ スプライトパターン番号ではなくスプライト番号に対応する
スプライトモード2 - SCREEN4
VRAM 16KB($0000 ~ $4000)の範囲ではVRAMの空き領域がないので、ダブルバッファを確保することはできません。
ですが、MSX2以降の機能なのでVRAMは最低でも64KB($0000 ~ $FFFF)が使えます。
単純に+$4000するのが簡単かもしれません。
$1E00
: R#5=$3F
,R#11=0
$5E00
: R#5=$BF
,R#11=0
' ** BASIC SAMPLE **
' PG:ページ番号
' PG=0 : atr = &H1E00, color = &H1C00
' PG=1 : atr = &H5E00, color = &H5C00
VDP(5)=&H3F+PG*&H80
VDP(12)=0
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $1B00, color = $1C00
; 1 : atr = $1C00, color = $5C00
CHG_SPRATR: rlca ; a = a * $80
add a,$3F ; a = $3F + PAGE * $80
ld b,a
ld c,5
call WRTVDP
xor a
ld c,11
call WRTVDP
ret
スプライトモード2 - SCREEN5/6/9 (212ライン)
縦スクロールを使わない場合、
ピクセルデータが $0000 ~ $69FF の範囲だけなので、
$7200
: R#5=$E7
,R#11=0
$7600
: R#5=$EF
,R#11=0
(デフォルト)
を使用することができます。
' ** BASIC SAMPLE 1 **
' PG:ページ番号
' PG=0 : atr = &H7600, color = &H7400
' PG=1 : atr = &H7200, color = &H7000
VDP(5)=&HEF-PG*8
VDP(12)=1 ' +&H8000
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE 1 **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $7600, color = $7400
; 1 : atr = $7200, color = $7000
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
cpl ; a = -PAGE * 8
add a,$EF ; a = $EF - PAGE * 8
ld b,a
ld c,5
call WRTVDP
xor a
ld c,11
call WRTVDP
ret
スプライトモード2 - SCREEN5/6/9 (256ライン)
縦スクロールで256ライン全てを使う場合、
ピクセル表示だけで $0000 ~ $7FFF まで ページ0の範囲を全て使用してしまうので、 ページ0にスプライトテーブルを配置することができません。
この場合は、別ページにスプライトテーブルを確保します。
$B200
: R#5=$E7
,R#11=1
$B600
: R#5=$EF
,R#11=1
(デフォルト+$8000)
' ** BASIC SAMPLE 2 **
' PG:ページ番号
' PG=0 : atr = &HB600, color = &HB400
' PG=1 : atr = &HB200, color = &HB000
VDP(5)=&HEF-PG*8
VDP(12)=1 ' +&H8000
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE 2 **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $B600, color = $B400
; 1 : atr = $B200, color = $B000
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
cpl ; a = -PAGE * 8
add a,$EF ; a = $EF - PAGE * 8
ld b,a
ld c,5
call WRTVDP
ld a,1 ; +$8000
ld c,11
call WRTVDP
ret
スプライトモード2 - SCREEN7/8/9/10/11/12 (212ライン)
縦スクロールを使わない場合、
ピクセルデータが $0000 ~ $D3FF の範囲なので、
$FA00
: R#5=$F7
,R#11=1
(デフォルト)$FE00
: R#5=$FF
,R#11=1
を使用することができます。
' ** BASIC SAMPLE 1 **
' PG:ページ番号
' PG=0 : atr = &HFA00, color = &HF800
' PG=1 : atr = &HFE00, color = &HFC00
VDP(5)=&HF7+PG*8
VDP(12)=1 ' +&H8000
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE 1 **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $FA00, color = $F800
; 1 : atr = $FE00, color = $FC00
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
add a,$F7 ; a = $F7 + PAGE * 8
ld b,a
ld c,5
call WRTVDP
ld a,1 ; +$8000
ld c,11
call WRTVDP
ret
スプライトモード2 - SCREEN7/8/9/10/11/12 (256ライン)
縦スクロールを使用する場合、
ピクセルデータだけで $0000 ~ $FFFF まで ページ0の範囲を全て使用してしまうので、 ページ0にスプライトテーブルを配置することができません。
この場合は、別ページにスプライトテーブルを確保します。
$1FA00
: R#5=$F7
,R#11=3
(デフォルト+$10000)$1FE00
: R#5=$FF
,R#11=3
' ** BASIC SAMPLE 1 **
' PG:ページ番号
' PG=0 : atr = &H1FA00, color = &H1F800
' PG=1 : atr = &H1FE00, color = &H1FC00
VDP(5)=&HF7+PG*8
VDP(12)=3 ' +&H18000
'※ VDP R#11 は BASICでは VDP(12)
' (VDP S#0 が VDP(8) なので以降は番号が1つずれる)
; ** ASM SAMPLE 1 **
WRTVDP: equ $0047
;===============================================
; change sprite attribute base address
;===============================================
; in a = page no
; 0 : atr = $1FA00, color = $1F800
; 1 : atr = $1FE00, color = $1FC00
CHG_SPRATR: add a,a
add a,a
add a,a ; a = PAGE * 8
add a,$F7 ; a = $F7 + PAGE * 8
ld b,a
ld c,5
call WRTVDP
ld a,3 ; +$18000
ld c,11
call WRTVDP
ret
スプライトパターンデータ書き換え
■ スプライト パターン ジェネレータ テーブル(参考用)
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#6 | 0 | 0 | A16 | A15 | A14 | A13 | A12 | A11 | ad / $800 |
スプライトパターンジェネレータの切り替え手法はベースアドレスの変更ではなく、
スプライトパターンの数がスプライト同時表示可能数の2倍以上なのを利用して、 半分ずつ使用します。
16x16の場合パターン64個なので、
32個*2ページのパターンバッファとして扱い、
スプライト番号ひとつにつき表示パターン番号と作業用(非表示)パターン番号の2個を割り当てる。 という手法を紹介します。
全部を毎回書き換えても良いのですが、 32個のワークを用意して個別に表示に使用するパターン番号を管理するのが良いかと思います。
BASICでの例
前準備
DIM PT(31)
パターンNを書き換えたら
PT(N)=(PT(N)+32) AND 63
表示例
PUTSPRITE P,(X(P),Y(P)),C(P),PT(P)
8x8の場合は、64番以降は固定パターンなどとするとよいかもしれません。
テキスト/キャラ表示
キャラクタコードテーブルのダブルバッファリングについて。
テキスト/キャラ表示 - SCREEN 0/1/2/3/4
※ SCREEN0はWIDTH40の場合。
■ パターン ネーム テーブル
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#2 | 0 | A16 | A15 | A14 | A13 | A12 | A11 | A10 | ad / $400 |
参考例)
画面モード | 基本 | 裏 | 備考 |
---|---|---|---|
SCREEN 0 | $0000 : R#2=$00 |
$0400 : R#2=$01 |
追加で$1000 + $400 * n の 12個(計14個) |
SCREEN 1 | $1800 : R#2=$06 |
$1C00 : R#2=$07 |
$800 + $400 * n で 計12個 |
SCREEN 2 | $1800 : R#2=$06 |
$1C00 : R#2=$07 |
空き領域に余裕がない |
SCREEN 3 | $0000 : R#2=$00 |
$0C00 : R#2=$30 |
$800 + $400 * n で 12個確保可能 |
SCREEN 4 | $1800 : R#2=$06 |
$5800 : R#2=$16 |
スプライトと同じく +$4000 を使用する |
テキスト/キャラ表示 - SCREEN 0 WIDTH80
■ パターン ネーム テーブル
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#2 | 0 | A16 | A15 | A14 | A13 | A12 | 1 | 1 | ad / $1000 OR 3 |
設定可能なアドレスは
$0000
: R#2=$03
$1000
: R#2=$07
$2000
: R#2=$0B
$3000
: R#2=$0F
ですが、
パターンジェネレータテーブルがあるので $1000
は使えません。$1000
も使いたい場合は、パターンジェネレータテーブルを移動させてください。
パターン ジェネレータ テーブルを移動させる場合
候補は
$1800
: R#4=$03
$2800
: R#4=$05
$3800
: R#4=$07
になります。
Warning
※パターン ジェネレータに設定したアドレス-$800
の位置はパターン ネーム テーブルには使用できません。
■ カラー(ブリンク) テーブル (SCREEN 0 WIDTH 80)
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#3 | A13 | A12 | A11 | A10 | A9 | 1 | 1 | 1 | ad / $40 OR 3 |
VDP R#10 | 0 | 0 | 0 | 0 | 0 | A16 | A15 | A14 | ad / &H4000 |
- サイズは
$19E
- 設定単位は
$200
カラー(ブリンク)テーブルも座標に紐づけられているので、
こちらもダブルバッファにする場合があります。
候補は
$800
: R#4=$23
, R#10=0
$A00
: R#4=$27
, R#10=0
ビットマップ表示 - SCREEN 5/6/9
■ パターン ネーム テーブル
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#2 | 0 | A16 | A15 | 1 | 1 | 1 | 1 | 1 | ad / $8000 |
BASICならSET PAGE
命令で簡単に管理可能です。
ビットマップ表示 - SCREEN 7/8/10/11/12
■ パターン ネーム テーブル
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#2 | 0 | A16 | 1 | 1 | 1 | 1 | 1 | 1 | ad / $10000 |
BASICならSET PAGE
命令で簡単に管理可能です。
キャラクタパターン書き換え
■ パターン ジェネレータ テーブル (SCREEN 0/1/3)
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#4 | 0 | 0 | A16 | A15 | A14 | A13 | A12 | A11 | ad / $800 |
■ パターン ジェネレータ テーブル (SCREEN 2/4)
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#4 | 0 | 0 | A16 | A15 | A14 | A13 | 1 | 1 | INT(ad / $2000) * 4 + 3 |
- VRAMに余裕があるのはSCREEN 0, 1, 3 のみです。
- SCREEN2/4はA12,A11は
0
扱いで、8KByte($2000
)単位での指定になります。 - SCREEN 4 は、VRAMが 64KB 以上あるので、割と自由です。
参考例)
画面モード | 基本 | 裏 | 備考 |
---|---|---|---|
SCREEN 0 width 40 | $0800 : R#4=$01 |
$1000 : R#4=$02 |
余裕があるので良い感じに配置する |
SCREEN 0 width 80 | $1000 : R#4=$02 |
$1800 : R#4=$03 |
$800 + $1000 * n が安定 |
SCREEN 1 | $3800 : R#4=$07 |
$3000 : R#4=$06 |
多少余裕あり |
SCREEN 2 | $3800 : R#4=$07 |
無理 | 空き領域に余裕がない |
SCREEN 3 | $3800 : R#4=$07 |
$3000 : R#4=$06 |
多少余裕あり |
SCREEN 4 | $3800 : R#4=$07 |
$7380 : R#4=$0F |
スプライトと同じく +$4000 を使用する |
■ カラー テーブル (SCREEN 1)
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#3 | A13 | A12 | A11 | A10 | A9 | A8 | A7 | A6 | ad / $40 |
VDP R#10 | 0 | 0 | 0 | 0 | 0 | A16 | A15 | A14 | ad / $4000 |
SCREEN1の場合、カラーテーブルもダブルバッファにする事があるかもしれません。
- 8キャラ毎に色を設定するので、サイズは
256/8=32
で$20
- 設定単位は
$40
候補は、
$2000
: R#3=$80
, R#10=0
$2040
: R#3=$81
, R#10=0
■ カラー テーブル (SCREEN 2/4)
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | 計算式 |
---|---|---|---|---|---|---|---|---|---|
VDP R#3 | A13 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | INT(ad / $2000) * $80 + $7F |
VDP R#10 | 0 | 0 | 0 | 0 | 0 | A16 | A15 | A14 | ad / $4000 |
- SCREEN2/4の場合はパターンジェネレータ同様に8KByte(
$2000
)単位での指定。 - SCREEN2では余剰領域が無さ過ぎて複数用意するのは厳しいと思います。
- SCREEN4であれば+$4000を利用する等が考えられます。
SAMPLE - スプライトモード2 サンプル
Warning Sensitive Contets ※ R15注意 https://github.com/uniskie/MSX_MISC_TOOLS/tree/main/LOADSRD/samples/.sensitive/KUONAI
1ラインにスプライトが8個以上並んでも消えたままにならずに点滅するようにしたサンプル。
事例紹介
- 記事:FREEDOM FIGHTER SMOOTH SCROLLING
MSXdev’20: #18 – Freedom Fighterで実装されているスムーズスクロールでもダブルバッファリングを使用しているそうです。
(※注 FREEDOM FIGHTERは、PALモードで実行しないと暴走しますので、エミュレータ等でC-BOIS MSX1 EU
などを使用して起動してください。)