ページ 11

GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 01:28
by トナカイ
C言語を使ってGBAの画面上の(x,y)に点を打つとき、
点を打ちたい場所の番地は
0x06000000 + x*2 + y*480
となるのは理解出来たのですが、
なぜ背景の色を変えるときに
for(i=0;i<240*160;i++){
*ptr = color;
ptr = ptr + 1;
}
となるのかがわかりません。
x座標が1増えるとn番地からn+2番地になるのなら
for文の最後でptrの値を2増やさないといけないような気がしてしまうのですが…
すみませんが、どなたか解説お願いします。

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 11:24
by softya(ソフト屋)
GBAで開発したことがないのでハードウェアを理解してませんがptr の型が分からないと答えようがありません。 ※ptrの型が2バイトのデータ型なんじゃないかと推測されます。
あと描画モードも関係するかも知れません。
出来ればGBAのハード仕様のサイトや参考にしているサイトも教えて下さい。

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 11:52
by beatle
質問自体はGBAとは切り離すことができますね。単なるポインタ演算についての質問ですね。
どうしてポインタに1を加算するだけで2番地増えるのか。
ポインタ演算に書いてあることが役立つでしょう。

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 18:30
by トナカイ
学校の先生が作ったテキストをもとに作っているので
疑問解消の為に少し調べる以外にはサイトなどをあまり見ていないのですが、
先生の作ったテキストによれば
GBAのVRAMの領域は0x06000000から0x06017FFFまでの96kバイトで、
バス幅は16ビット、液晶ディスプレイは240*160ドットで構成され、左上の0ドット目が0x06000000番地からの2バイトに相当するそうです。
あと、質問内のptrはunsigned short型のポインタです。
説明不足ですみません。

beatleさんの紹介して下さったサイトと上記の情報を合わせてみて、背景描画のときは
ptr = ptr + 1;
の記述で番地を2増やしていることになっていて、
ある座標に点を打つときはポインタ演算でないので
2ずつ増やさなければならないのかなという考えに行き着きました。
この考え方で合っているでしょうか?

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 20:25
by beatle
トナカイ さんが書きました:beatleさんの紹介して下さったサイトと上記の情報を合わせてみて、背景描画のときは
ptr = ptr + 1;
の記述で番地を2増やしていることになっていて、
ある座標に点を打つときはポインタ演算でないので
2ずつ増やさなければならないのかなという考えに行き着きました。
この考え方で合っているでしょうか?
「ある座標に点を打つときはポインタ演算でない」とは具体的にどのようなソースコードを想定しているのでしょうか?
例えば、指定した点に指定した色を描く関数を作るとします。

コード:

void DrawPoint(int x, int y, uint16_t color)
{
    uint16_t* vram = reinterpret_cast<uint16_t*>(0x06000000);
    vram[y * 240 + x] = color; // 0x06000000 + 2 * (y * 240 + x) に color 色の点を打つ。
}
このとき
vram[y * 240 + x]
という記述は
*(vram + y * 240 + x)
と同じ意味ですので、ポインタ演算をしていると言えるでしょう。

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 21:52
by トナカイ
「ある座標に点を打つときはポインタ演算でない」というのは
下のようなコードを想定しての発言だったのですが、
beatleさんの解説をきくとそれも間違いのようですね。

コード:

 
typedef volatile unsigned short hword;
#define VRAM 0x06000000

//中略

void draw_point(hword x,hword y,hword color){
	hword *p;
	p =(hword*) (VRAM + x*2 + y*480);
	*p = color;
}
 
ということは、この場合もp=(hword*) (VRAM + x + y*240)としなければならないのでしょうか?

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 21:59
by beatle
トナカイ さんが書きました: ということは、この場合もp=(hword*) (VRAM + x + y*240)としなければならないのでしょうか?
それは違います。VRAMは整数型であってポインタ型ではないですから、
VRAM + foo
(fooは整数型とする)と書くと、整数型同士の演算となります。
ポインタ演算ではありませんので、この場合は足す数を2倍する必要があります。

もし
p= (hword*)VRAM + x + y*240
なんて書いたら、VRAMのキャストが加算より優先度が高いため、ポインタ演算になります。
そのため、足す数は2倍してはいけません。

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 22:06
by beatle
まとめると
  • ポインタ演算とはポインタ型と整数型の演算
  • ポインタ演算では、整数型の数値をポイント先の型のサイズ倍する
    例:ポインタの型がFoo*だったら、整数型の数値をsizeof(Foo)倍してから演算する
ということになります。

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 22:26
by トナカイ
わざわざまとめまでありがとうございます。では、
p= (hword*)VRAM + x * 2 + y * 480
と書いた場合、pが指す番地は(VRAM + x * 2 * 2 + y * 480 * 2)番地で、
p= (hword*)(VRAM + x * 2+ y * 480)
と書いた場合、pが指す番地は(VRAM + x * 2 + y * 480)番地なので、
先ほどのdraw_point関数の中身は合っているという理解でよろしいでしょうか?

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 22:49
by beatle
draw_point関数は、shortが2バイトの環境でなら意図した動きになるはずです。
しかし自前で2倍するのではなく、ポインタ演算で自動で2倍するようにした方が、移植性は高くなると思います。

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 23:06
by トナカイ
なるほど、確かにポインタ演算をした方が汎用性が高いですね。
ポインタ演算の存在意義が少しわかった気がします。
そしてとりあえず、現時点で抱いていた疑問は解消されました‼
何回も回答してくださって、本当にありがとうございました。

Re: GBAの画面上への点や背景の表示

Posted: 2012年6月01日(金) 23:33
by ISLe
GBAのCPUはARMだとか。
2倍するのを忘れると奇数アドレスにアクセスした途端に落ちると思います。

ポインタ演算を使うようにすれば謎のバグからも解放されることでしょう。