前回のmode0を簡単にまとめてみました。合わせてmode1、mode2も載せておきます。色々モードの紹介していきましたが、個人開発で使うのはmode0か3が主流です。あとはほとんど使っていないように思います。他は参考程度に見てください。
サイズ | 256*256~512*512 |
画面数 | 4 (BG0-3) |
色/パレット | 16色*16パレット/256色*1パレット |
キャラクタ定義数 | 1024 |
伸縮回転 | 不可能 |
mode1には、伸縮回転可能なBG、不可能なBGの2種類があります。
サイズ | 256x256~512x512 | 128x128~1024x1024 |
画面数 | 2(BG0-1) | 1(BG2) |
色/パレット | 16色/16パレットor256色/1パレット | 256色/1パレット |
キャラクタ定義数 | 1024 | 256 |
伸縮回転 | 不可能 | 可能 |
サイズ | 128x128~1024x1024 |
画面数 | 2(BG2-3) |
色/パレット | 256色*1パレット |
キャラクタ定義数 | 256 |
伸縮回転 | 可能 |
GBATEKは次のように書かれています。こちらの方がわかりやすいかもしれません。
The table summarizes the facilities of the separate BG modes (video modes). Mode Rot/Scal Layers Size Tiles Colors Features 0 No 0123 256x256..512x515 1024 16/16..256/1 SFMABP 1 Mixed 012- (BG0,BG1 as above Mode 0, BG2 as below Mode 2) 2 Yes --23 128x128..1024x1024 256 256/1 S-MABP 3 Yes --2- 240x160 1 32768 --MABP 4 Yes --2- 240x160 2 256/1 --MABP 5 Yes --2- 160x128 2 32768 --MABP
再度モード0にて、2つの絵をレイヤー表示してみます。まずメモリ領域(VRAM)に入るか確認をしながらやってみましょう。
画像のサイズは(240ではなく)256x160の16色です。タイルは32x20 = 640個。640個 * 32バイト(1タイル分のバイト数) = 20480バイト(0x5000)。色が全く同じ重複タイルも構わず使用します。マップは256x256ドットサイズを使うので32 * 32 * 2 = 2048バイト(0x800)となります。それでは対応表にうまく収まるよう、領域を確保してみます。
アドレス | マップ | キャラクタ | 確保 |
0x6000000 | 0 | 0 | bg0(kusa) |
0x6000800 | 1 | 0 | bg0(kusa) |
0x6001000 | 2 | 0 | bg0(kusa) |
0x6001800 | 3 | 0 | bg0(kusa) |
0x6002000 | 4 | 0 | bg0(kusa) |
0x6002800 | 5 | 0 | bg0(kusa) |
0x6003000 | 6 | 0 | bg0(kusa) |
0x6003800 | 7 | 0 | bg0(kusa) |
0x6004000 | 8 | 1 | bg0(kusa) |
0x6004800 | 9 | 1 | bg0(kusa) |
0x6005000 | 10 | 1 | |
0x6005800 | 11 | 1 | bg0 map |
0x6006000 | 12 | 1 | bg1 map |
0x6006800 | 13 | 1 | |
0x6007000 | 14 | 1 | |
0x6007800 | 15 | 1 | |
0x6008000 | 16 | 2 | bg1(kumo) |
0x6008800 | 17 | 2 | bg1(kumo) |
0x6009000 | 18 | 2 | bg1(kumo) |
0x6009800 | 19 | 2 | bg1(kumo) |
0x600A000 | 20 | 2 | bg1(kumo) |
0x600A800 | 21 | 2 | bg1(kumo) |
0x600B000 | 22 | 2 | bg1(kumo) |
0x600B800 | 23 | 2 | bg1(kumo) |
0x600C000 | 24 | 3 | bg1(kumo) |
0x600C800 | 25 | 3 | bg1(kumo) |
0x600D000 | 26 | 3 | |
0x600D800 | 27 | 3 | |
0x600E000 | 28 | 3 | |
0x600E800 | 29 | 3 | |
0x600F000 | 30 | 3 | |
0x600F800 | 31 | 3 |
うまく収まりましたね。レイヤー表示は上層がbg0、下層はbg3です。逆にすると当然、kusaタイルは表示されません。
#include "lib/gba.h" #include "res.h" #define BG_MAX_CNT 4 typedef struct { u32 mapBase; u16* mapBaseAdr; u32 tileBase; u16* tileBaseAdr; } ST_BG; //--------------------------------------------------------------------------- ST_BG Bg[BG_MAX_CNT]; //--------------------------------------------------------------------------- void WaitForVsync(void) { while(*(vu16*)0x4000006 >= 160) {}; while(*(vu16*)0x4000006 < 160) {}; } //--------------------------------------------------------------------------- void BgInitMem(void) { const u32 mapBase[] = { 11, 12, 0, 0 }; const u32 tileBase[] = { 0, 2, 0, 0 }; vs32 i; for(i=0; i<BG_MAX_CNT; i++) { Bg[i].mapBase = MAP_BASE(mapBase[i]); Bg[i].mapBaseAdr = MAP_BASE_ADR(mapBase[i]); Bg[i].tileBase = TILE_BASE(tileBase[i]); Bg[i].tileBaseAdr = TILE_BASE_ADR(tileBase[i]); } for(i=0; i<32*32; i++) { Bg[0].mapBaseAdr[i] = 0; Bg[1].mapBaseAdr[i] = 0; Bg[2].mapBaseAdr[i] = 0; Bg[3].mapBaseAdr[i] = 0; } for(i=0; i<0x2000; i++) { Bg[0].tileBaseAdr[i] = 0; Bg[1].tileBaseAdr[i] = 0; Bg[2].tileBaseAdr[i] = 0; Bg[3].tileBaseAdr[i] = 0; } } //--------------------------------------------------------------------------- void BgInit(void) { BgInitMem(); REG_DISPCNT = (MODE_0 | BG0_ON | BG1_ON); REG_BG0CNT = (BG_SIZE_0 | BG_16_COLOR | Bg[0].tileBase | Bg[0].mapBase); REG_BG1CNT = (BG_SIZE_0 | BG_16_COLOR | Bg[1].tileBase | Bg[1].mapBase); } //--------------------------------------------------------------------------- void BgSetTile(u32 bg, u16* pDat, u32 size) { vu32 i; for(i=0; i<size; i++) { Bg[bg].tileBaseAdr[i] = pDat[i]; } } //--------------------------------------------------------------------------- void BgSetPal(u32 pal, u16* pDat) { vu32 i; for(i=0; i<16; i++) { BG_PALETTE[pal*16+i] |= pDat[i]; } } //--------------------------------------------------------------------------- void BgSetMap(void) { vu32 i; for(i=0; i<32*20; i++) { Bg[0].mapBaseAdr[i] = i; Bg[1].mapBaseAdr[i] = i | (1 << 12); // バレット番号1を選択 } } //--------------------------------------------------------------------------- int main(void) { BgInit(); BgSetTile(0, (u16*)&bg0kusaTiles, bg0kusaTilesLen/2); BgSetTile(1, (u16*)&bg1kumoTiles, bg1kumoTilesLen/2); BgSetPal(0, (u16*)&bg0kusaPal); BgSetPal(1, (u16*)&bg1kumoPal); BgSetMap(); for(;;) { WaitForVsync(); } }