- 追加された行はこの色です。
- 削除された行はこの色です。
#author("2023-05-14T21:42:32+09:00;2023-04-22T18:35:18+09:00","","")
#author("2023-05-15T09:34:56+09:00;2023-04-22T18:35:18+09:00","","")
* ビットマップモード2 [#c656504b]
先ほどのサンプルコードを変更して移動処理を加えてみます。
int main(void)
{
SetMode(MODE_3 | BG2_ENABLE);
s32 x=0, y=0;
for(;;)
{
if(y != 0 || x != 0)
{
Mode3PutPixel(x-1, y-1, RGB5(0, 0, 0));
}
Mode3PutPixel(x++, y++, RGB5(31, 31, 31));
if(y > 160)
{
x = 0;
y = 0;
}
}
}
変数xとyの座標には白色ドット、1つ前に描画したドットには黒色(背景色)で上書きしています。x, y共にインクリメントしているので、どのように表示されていくかは想像できると思います。ただし、残念ながらこの書き方では想像どおりの結果になりません。失敗した状態をぜひ自分の目で確かめてみてください。[[githubのtest_nowait.gba:https://github.com/akkera102/gbadev-ja/tree/main/tut03%20%E3%83%93%E3%83%83%E3%83%88%E3%83%9E%E3%83%83%E3%83%97%E3%83%A2%E3%83%BC%E3%83%892]]
変数xとyの座標には白色ドット、1つ前に描画したドットには黒色(背景色)で上書きしています。x, y共にインクリメントしているので、どのように表示されていくかは想像できると思います。ただし、残念ながらこの書き方では想像どおりの結果になりません。失敗した状態をぜひ自分の目で確かめてみてください。[[githubのtest_nowait.gba:https://github.com/akkera102/gbadev-ja/tree/main/tut03%20bitmap2]]
** 垂直同期待ちの処理を加える [#iedf4218]
失敗作からはわかることはドットが目にも留まらぬ速さで移動しすぎていることです。次に、点が滑らかに表示されておらずブツ切りにされていることにも注目します。結論から言ってしまうと垂直同期待ちの処理をしていないからです。GBAは高速で画面を書き換えています。具体的には左上0,0座標から右へ順番にドット単位で行い、その行が終わったら次の行へ、という具合です。~
失敗からわかることは、ドットが目にも留まらぬ速さで移動していることです。点が滑らかに表示されておらずブツ切りにされてもいます。結論から言ってしまうと、垂直同期待ちの処理をしていないからです。GBAは高速で画面を書き換えています。具体的には左上0,0座標から右へ順番にドット単位で行い、その行が終わったら次の行へ、という具合です。
#ref(1.png,nolink)
もう少し詳しく言い直しましょう。液晶画面は240x160ドットです。最初のラインは240ドット描画後、描画しない68ドット分が存在します。この非描画期間をH-Blankといいます。このラインが完了したら次のラインへ(0,2ドット目)からとなります。160ライン分終わった後にも68ライン分存在します。この非描画期間をV-Blankといいます。~
もう少し詳しく言い直しましょう。液晶画面は240x160ドットです。最初のラインは240ドット描画後、描画しない68ドット分が存在します。この非描画期間をH-Blankといいます。このラインが完了したら次のラインへ(0,1ドット目)からとなります。160ライン分終わった後にも68ライン分存在します。この非描画期間をV-Blankといいます。
- Horizontal Dimensions (H-Blank)
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
- Vertical Dimensions (V-Blank)
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
GBATEKのH-Blankを読むと1ドット描画するのにCPUで4サイクル。240+68=308ドットで1232サイクルと書いてありますね。V-Blankも同様に160+68ラインで228ライン。描画処理を行う場合、基本的にはこのV-Blankの間に行います。先ほどのサンプルコードはV-Blankを無視して描画した為、どこに描画されているかわからずチラついて見えたりします。オススメしません。V-Blankを調べるには以下のレジスタを参照します。~
GBATEKのH-Blankを読むと1ドット描画するのにCPUで4サイクル。240+68=308ドットで1232サイクルと書いてありますね。V-Blankも同様に160+68ラインで228ライン。描画処理を行う場合、基本的にはこのV-Blankの間に行います。先ほどのサンプルコードはV-Blankを無視して描画した為、どこに描画されているかわからず、チラついて見えたりします。オススメしません。V-Blankを調べるには以下のレジスタを参照します。
4000006h - VCOUNT - Vertical Counter (Read only)
Indicates the currently drawn scanline, values in range from 160..227 indicate 'hidden' scanlines within VBlank area.
Bit Expl.
0-7 Current Scanline (LY) (0..227) (R)
8 Not used (0) / NDS: MSB of Current Scanline (LY.Bit8) (0..262) (R)
9-15 Not Used (0)
void WaitForVsync(void)
{
while(*(vu16*)0x4000006 >= 160) {};
while(*(vu16*)0x4000006 < 160) {};
}
関数は、VCOUNT(描画中のライン)が160になるまで待つことを意味しています。~
関数は、VCOUNT(描画中のライン)が160になるまで待つことを意味しています。
** 流れ星っぽいドット表示 [#md5c1708]
#include "lib/gba.h"
//---------------------------------------------------------------------------
void WaitForVsync(void)
{
while(*(vu16*)0x4000006 >= 160) {};
while(*(vu16*)0x4000006 < 160) {};
}
//---------------------------------------------------------------------------
void Mode3PutPixel(u32 x, u32 y, u16 color)
{
u16* ScreenBuffer = (u16*)0x6000000;
ScreenBuffer[y*240+x] = color;
}
//---------------------------------------------------------------------------
int main(void)
{
SetMode(MODE_3 | BG2_ENABLE);
s32 x=0, y=0;
for(;;)
{
WaitForVsync();
if(y != 0 || x != 0)
{
Mode3PutPixel(x-1, y-1, RGB5(0, 0, 0));
}
Mode3PutPixel(x++, y++, RGB5(31, 31, 31));
if(y > 160)
{
x = 0;
y = 0;
}
}
}
***動作画面 [#m958e69b]
#ref(2.png,nolink)
** 履歴 [#p6ae87c6]
- 2023/04/22