見出し画像

SGDK学習メモ:No.8、SCROLLとWINDOWのVRAMアドレスが重複している場合の挙動を確認してみる

*以下SGDKは記述時点で最新版のSGDK 2.00 (january 2024)を使用しています


前々回、前回の補足事項です。

VRAM内のメモリマッピングは(ある程度)自由に変更が可能で、更に複数の項目に同じVRAM領域を割り当てることも可能です。

5. VRAM MAPPING
(中略)
Also, AREA can be overlapped. Therefore, TABLE can be commonly used by SCROLL screen and WINDOW for example.

GENESIS Technical Overview ,P.79

今回はSCROLL BとWINDOWに同じVRAMアドレスを割り当てた場合の挙動を確認してみます。
正直想像通りではありますが、実際に試してみたということで。文字に起こしてみるとちょっとまどろっこしいです。


SCROLL BとWINDOWに同じVRAMアドレスを割り当て、それらに背景画像(タイル)をセットしてみる

以下はSGDKデフォルト時のVRAMマッピングです。

デフォルト時

今回SCROLL BとWINDOWに同じアドレスを設定します。

具体的には
VDP_setWindowAddress ( 0xC000 )
を実行しています

この状態でSCROLL BとWINDOWに背景用の画像(タイル)をセットしてみます。
前々回は画面上部にWINDOWを表示(横分割)したので、今回は画面左側(縦分割)を試します。

SCROLL BとWINDOWに同じアドレス (0xC000)を設定後、
SCROLL Bに_(アンダースコア)、A、B、Cをセットした状態、
この時点でWINDOWには何も行っていません
ボタン押下によりWINDOWに0~3の4タイルをセットした状態、
WINDOWの表示に必要な表示位置と表示(セル)数をセット""にも関わらず
WINDOWに設定したタイルが表示されます、
今回SCROLL BとWINDOWはアドレスが同じため
0~3がWINDOWではなくSCROLL Bとして表示されています
SCROLL Bのタイル("_")のアドレスにあるデータが
WINDOWで指定したタイル("0-3")で上書きされたので、
重ね合わせ処理は行われていません
(通常なら0、2の下に存在するアンダースコアが存在しない)
ボタン押下によりWINDOWの表示位置をセット、
具体的にはVDP_setWindowHPos(FALSE, 2)
を実行していますが上図では判別できません
画面全体を右にスクロールさせた状態、
縦分割したWINDOWの表示は行われます、
WINDOWとSCROLL Bの左はじに
同じタイルが表示されています
WINDOWとSCROLL Bを重ねた状態、
優先順位は標準のままなので
WINDOW(SCROLL A) > SCROLL Bの状態、
上図の左側の"3"はWINDOWなので
SCROLL Bの"B"より優先的(上)に表示されています

今回のソースコードです。

#include <genesis.h>

//VRAMアドレス
#define HSCROLL_TABLE_ADDR 0xA800
#define SPRITE_LIST_ADDR   0xAC00
#define WINDOW_ADDR        0xB000
#define BGA_ADDR           0xC000
#define BGB_ADDR           0xE000


static const int sciSlash = 0x05AF; //word"/" , 1455
static const int sciA = 0x05C1;     //word"A" , 1473
static const int sciOne = 0x05B0;   //word"1" , 1456

static const int sciComma = 0x05AC;   //word"," , 1452
static const int sciDot = 0x05AE;   //word"." , 1454
static const int sciUScore = 0x05DF;   //word"_" , 1503
static const int sciVBar = 0x05FC;   //word"|" , 1532


s16 currentScreenX=0;
s16 currentScreenY=0;


//背景初期化
//BG_Bの表示範囲に値を埋める
void bgInit(){
    //BG_B , "_"を敷きつめる
    VDP_fillTileMapRect(BG_B,TILE_ATTR_FULL(PAL0,FALSE,FALSE,FALSE,sciUScore),0,0,39,27);

    //BG_B,A(右端、垂直)とB(下部、水平)とC(AとBの交差点)を置く
    VDP_fillTileMapRect(BG_B,TILE_ATTR_FULL(PAL1,FALSE,FALSE,FALSE,sciA),39,0,1,27);
    VDP_fillTileMapRect(BG_B,TILE_ATTR_FULL(PAL1,FALSE,FALSE,FALSE,sciA+1),0,27,39,1);
    VDP_setTileMapXY(BG_B,TILE_ATTR_FULL(PAL1,FALSE,FALSE,FALSE,sciA+2),39,27);
}


//VDP アドレスログ出力(デバッグ用)
void logVramAddresses(){
    kprintf("VDP_getBGAAddress(): %x,(%u)",VDP_getBGAAddress(),VDP_getBGAAddress());

    kprintf("VDP_getBGBAddress(): %x,(%u)",VDP_getBGBAddress(),VDP_getBGBAddress());
    kprintf("VDP_getWindowAddress(): %x,(%u)",VDP_getWindowAddress(),VDP_getWindowAddress());

    kprintf("VDP_getSpriteListAddress(): %x,(%u)",VDP_getSpriteListAddress(),VDP_getSpriteListAddress());
    kprintf("VDP_getHScrollTableAddress(): %x,(%u)",VDP_getHScrollTableAddress(),VDP_getHScrollTableAddress());
}

//VDP アドレスセット(未使用)
void setVramAddresses(){
    VDP_setBGBAddress         ( BGB_ADDR           );

    VDP_setBGAAddress         ( BGA_ADDR           );
    VDP_setWindowAddress      ( WINDOW_ADDR        );

    VDP_setSpriteListAddress  ( SPRITE_LIST_ADDR   );
    VDP_setHScrollTableAddress( HSCROLL_TABLE_ADDR );
}


//キーイベント(コールバック)
void myJoyHandler( u16 joy, u16 changed, u16 state)
{
    if (joy == JOY_1){

        //Aボタン
        if (state & BUTTON_A){

            //WINDOW(BG_Aの一部)に0~3をセット
            VDP_setTileMapXY(WINDOW,TILE_ATTR_FULL(PAL3,FALSE,FALSE,FALSE,sciOne),0,0);
            VDP_setTileMapXY(WINDOW,TILE_ATTR_FULL(PAL3,FALSE,FALSE,FALSE,sciOne+1),0,27);


            VDP_setTileMapXY(WINDOW,TILE_ATTR_FULL(PAL3,FALSE,FALSE,FALSE,sciOne+2),3,0);
            VDP_setTileMapXY(WINDOW,TILE_ATTR_FULL(PAL3,FALSE,FALSE,FALSE,sciOne+3),3,27);
        }

        //Bボタン
        if (state & BUTTON_B){

            //WINDOWをセット
            //縦は2CELL単位の指定となる = 2だと4CELL分がWINDOWになる
            VDP_setWindowHPos(FALSE, 2);

        }

        //Cボタン
        if (state & BUTTON_C){
        }

        //Xボタン
        if (state & BUTTON_X){
        }


        //Yボタン
        if (state & BUTTON_Y){
        }


        //スタートボタン
        if (state & BUTTON_START){
        }
    }
}

//キーイベント(VBlankごと)
static void handleInput()
{
    u16 value = JOY_readJoypad(JOY_1);

    if (value & BUTTON_UP){
        currentScreenX++;
    }
    if (value & BUTTON_DOWN){
        currentScreenX--;
    }
    if (value & BUTTON_RIGHT){
        currentScreenY++;
    }
    if (value & BUTTON_LEFT){
        currentScreenY--;
    }

    // VDP_setHorizontalScrollVSync (BG_A,currentScreenY);
    VDP_setHorizontalScrollVSync(BG_B,currentScreenY);
    // VDP_setVerticalScrollVSync(BG_A,currentScreenX);
    VDP_setVerticalScrollVSync(BG_B,currentScreenX);

}


// main
int main()
{

    JOY_init();
    JOY_setEventHandler( &myJoyHandler );

    kprintf("*** 0:vram address bofore changed");
    logVramAddresses();

    //VRAMのアドレスをマッピングを変更する
    //WINDOWにSCROLL Bと同じ 0xC000 をセット
    VDP_setWindowAddress      ( 0xC000 );

    kprintf("*** 2:vram address after changed");
    logVramAddresses();

    bgInit();

    while(1)
    {
        handleInput();

        SYS_doVBlankProcess();
    }
    return (0);
}

【了】

この記事が気に入ったらサポートをしてみませんか?