最後は垂直同期待ちの処理です。
void WaitForVsync(void) { while(*(vu16*)0x4000006 >= 160) {}; while(*(vu16*)0x4000006 < 160) {}; }
GBAは高速で画面を書き換えています。
具体的には左上から右へ順番にドット単位で行い、
そのラインが終わったら次のラインへ、という具合です。
#ref(): File not found: "clip_3.png" at page "tutorial.3"
もう少し詳しく言い直しましょう。液晶画面は240x160ドットです。
最初のラインは240ドット描画後、描画しない68ドット分が存在します。
この非描画期間をH-Blankといいます。
Horizontal Dimensions The drawing time for each dot is 4 CPU cycles. Visible 240 dots, 57.221 us, 960 cycles - 78% of h-time H-Blanking 68 dots, 16.212 us, 272 cycles - 22% of h-time Total 308 dots, 73.433 us, 1232 cycles - ca. 13.620 kHz
仕様書を読むと1ドット描画するのにCPUで4サイクル。
240+68=308ドットで1232サイクルと書いてありますね。
次に、160ライン分終わった後にも68ライン分存在します。
この非描画期間をV-Blankといいます。
Vertical Dimensions Visible (*) 160 lines, 11.749 ms, 197120 cycles - 70% of v-time V-Blanking 68 lines, 4.994 ms, 83776 cycles - 30% of v-time Total 228 lines, 16.743 ms, 280896 cycles - ca. 59.737 Hz
描画処理を行う場合、基本的にはこのV-Blankの間に行います。
V-Blankを無視して描画した場合、チラついて見えたりするのでオススメしません。
他のサンプルでは無視していますけどね。(^^;
先ほどの関数は、VCOUNT(描画中のライン)が160になるまで待つことを
意味しています。
1ドットごとに点を打つことができるようになりましたので
いろいろな描画ができるようになると思います。
// モード3で四角形を塗りつぶす void Mode3DrawBox(u32 sx, u32 sy, u32 ex, u32 ey, u16 col) { u32 x, y; for(y=sy; y<ey; y++) { for(x=sx; x<ex; x++) { Mode3PutPixel(x, y, col); } } }
他にも、直線を引いたり、円や三角形を描画することもできます。
直線の描画は、有名なブレゼンハムのアルゴリズムなどを検索してみてください。
CGプログラムの本などを見てアルゴリズムを学ぶのもいいと思います。
次に、画像ファイルをGBA上に表示させてみる関数を考えてみます。
画像は液晶画面のサイズに合わせた240x160ドットなので、内容は以下のようになります。
void Mode3DrawImage(u16* img) { u16* ScreenBuffer = (u16*)0x6000000; u16 x, y; for(y=0; y<160; y++) { for(x=0; x<240; x++) { ScreenBuffer[y*240+x] = img[y*240+x]; } } }
引数の画像データ(色データ)の配列から1つ1つを描画をしていきます。
この配列をどのように生成するかですが、devkitProに標準装備されているgritというツールを
使用して出力するのが手っ取り早いです。使い方はDoc.3 画像加工ツールの使い方を参照してください。
#include "lib/gba.h" #include "res.h" //--------------------------------------------------------------------------- void WaitForVsync(void) { while(*(vu16*)0x4000006 >= 160) {}; while(*(vu16*)0x4000006 < 160) {}; } //--------------------------------------------------------------------------- void Mode3DrawImage(u16* img) { u16* ScreenBuffer = (u16*)0x6000000; u32 x, y; for(y=0; y<160; y++) { for(x=0; x<240; x++) { ScreenBuffer[y*240+x] = img[y*240+x]; } } } //--------------------------------------------------------------------------- int main(void) { // モード設定 SetMode(MODE_3 | BG2_ENABLE); // 画像の読み込み Mode3DrawImage((u16*)&imageBitmap); for(;;) { WaitForVsync(); } }
モード3で、240x160のpng画像の表示
#ref(): File not found: "clip_1.png" at page "tutorial.3"