Nanashi-softプログラマ専用NDSでプログラミング


◇NDSでプログラミング-2画面を操れ!-

○2画面使える画面モードを探す

前回,画面モードをフレームバッファにすると,1画面しか使えない事が分かりました
画面モードの資料を見ると,フレームバッファのサブの方は利用不可になっています
全フレームバッファーモードのサブに利用不可と書かれていますので,2画面は不可能でしょう

資料を良く見ると,16bit/pixcelモードが,extended rotationにある事がわかります
このモードにすれば 3万色の画面が表示できるでしょう
画面モード一覧を見ると,モード3〜5に extended rotationがあり,モード5では BG2とBG3に2つ定義されています
モード5を使用すると裏画面が容易に作れそうなので,このモードに切り替える事にします

・画面モード5,BG2を表示

  *(volatile unsigned int *)0x04000000=0x00010005 | 0x400;

・画面モード5,BG3を表示

  *(volatile unsigned int *)0x04000000=0x00010005 | 0x800;

ここからは BG2を使用する事にして話を進めます

○2画面使える VRAMバンクを探す

VRAMバンク一覧を見ると,A〜Iの 9つある中で唯一バンクCだけに MAIN BGと SUB BGの記述があります
これにすれば2画面使えそうな気がします

  *(volatile unsigned char *)0x04000242=0x80;

○裏画面モード設定

extended rotationには様々なモードがありますので,細かな設定を行う必要があります
レジスタ資料を見ると,BG2_CR(0x0400000C〜16bit)にセットすれば良いようです
ただ,この中身が,XDX・XDY・YDX・YDY・CX・CY……と暗号のような記号が並んでいます(汗
わかんねぇよヽ(`Д´)ノ

・まずは,裏画面モードをコントロール
14bit〜15bitに Sizeがあります
画面モード4つに,設定場所が2bitなので,0から順番と予想します
128×128は,0
256×256は,14bit目を立てて,0x4000
512×256は,15bit目を立てて,0x8000
512×512は,両方を立てて,0xC000

8bit〜12bitにある Mapですが,これは裏画面の開始アドレスをずらす時に使用するようで,先頭から使用する場合は何もしなくて良さそうです
変に設定すると,表示が上にずれてしまいました

7bit目にある Colorの項目が,8bit/pixcelなのか,16bit/pixcelなのかだと思いますので,bitを立てておきます
7bit目を立てて,0x0080

2bit〜5bitにある Tileの項目は一見不要のようですが,1を設定しなければ画面が表示されませんでした
Tileのアドレスを見ると,0〜3の4つあります。つまり,どれを表示するのかを 4bitで表すのだと解釈しました
2bit目を立てて,0x0004

まとめると,BG2の裏画面に 256×256の 16bitカラーを設定するには,

  *(volatile unsigned short *)0x0400000C = 0x4000 | 0x0080 | 0x0004;


・初期設定をする
デフォルトでは縦横に256倍に拡大されて表示されます(謎)
とりあえず,

  BG2_X0 = 0;
  BG2_Y0 = 0;
  BG2_XDX = 1 << 8;
  BG2_XDY = 0;
  BG2_YDX = 0;
  BG2_YDY = 1 << 8;
  BG2_CY = 0;
  BG2_CX = 0;

こう書いておけば,普通に表示されます
これらのパラメータの解析はまたの機会に行おうと思います

○メイン画面を表示してみる

メイン画面を赤で塗りつぶしてみます

int main(void) {
  //画面モード5,BG2を表示
  *(volatile unsigned int *)0x04000000=0x00010005 | 0x400;
  //VRAMバンクCを選択
  *(volatile unsigned char *)0x04000242=0x80;
  //BG2の裏画面に 256×256の 16bitカラーを設定
  *(volatile unsigned short *)0x0400000C = 0x4000 | 0x0080 | 0x0004;
  //BG2の裏画面を等倍表示になるよう初期設定
  BG2_X0 = 0;
  BG2_Y0 = 0;
  BG2_XDX = 1 << 8;
  BG2_XDY = 0;
  BG2_YDX = 0;
  BG2_YDY = 1 << 8;
  BG2_CY = 0;
  BG2_CX = 0;

  //赤で塗りつぶす
  for (int y=0; y < 192; y++){
  for (int x=0; x < 256; x++){
    *(unsigned short *)(0x06000000 + (x + y * 256) * 2)=0x1F | 0x8000;
  }
  }

  while(1){
  }

  return 0;
}

この画面モードでは,直接表示しているアドレスに値を入れる事で,VRAMバンクメモリを書き替えるようです。直感的で分かり易いですね
あと,注意点として,ABGRですので,先頭ビットを立てるのを忘れないようにして下さい

○サブ画面の設定

基本的に,サブはレジスタアドレスが異なるだけで,メインと考え方は同じです

・画面モード5,BG2を表示
 設定先のアドレスが異なるだけです

  *(volatile unsigned int *)0x04001000=0x00010005 | 0x400;

・VRAMバンクCの Sub BGをオンにする
 これは,既にメインで設定している所に,モード100を追加します
 これができると思ったからこそ,バンクCを選んだのです

  *(volatile unsigned char *)0x04000242=0x80 | 0x4;

・BG2の裏画面に 256×256の 16bitカラーを設定
 設定先のアドレスが異なるだけです

  *(volatile unsigned short *)0x0400100C = 0x4000 | 0x0080 | 0x0004;

・初期設定をする
 こちらも256倍になっているので,等倍設定します

  SUB_BG2_X0 = 0;
  SUB_BG2_Y0 = 0;
  SUB_BG2_XDX = 1 << 8;
  SUB_BG2_XDY = 0;
  SUB_BG2_YDX = 0;
  SUB_BG2_YDY = 1 << 8;
  SUB_BG2_CX = 0;
  SUB_BG2_CX = 0;


あと,サブ画面の VRAMの先頭アドレスは 0x06200000です

○2画面を表示してみる

ようやく2画面表示を行う下地が整いました
メイン画面を赤で,サブ画面を青で塗りつぶしてみます

int main(void) {
  //メイン画面モード5,BG2を表示
  *(volatile unsigned int *)0x04000000=0x00010005 | 0x400;
  //サブ画面モード5,BG2を表示
  *(volatile unsigned int *)0x04001000=0x00010005 | 0x400;
  //VRAMバンクCを選択し,サブ画面用アドレスもオンにする
  *(volatile unsigned char *)0x04000242=0x80 | 0x4;
  //メインBG2の裏画面に 256×256の 16bitカラーを設定
  *(volatile unsigned short *)0x0400000C = 0x4000 | 0x0080 | 0x0004;
  //メインBG2の裏画面を等倍表示になるよう初期設定
  BG2_X0 = 0;
  BG2_Y0 = 0;
  BG2_XDX = 1 << 8;
  BG2_XDY = 0;
  BG2_YDX = 0;
  BG2_YDY = 1 << 8;
  BG2_CY = 0;
  BG2_CX = 0;
  //サブBG2の裏画面に 256×256の 16bitカラーを設定
  *(volatile unsigned short *)0x0400100C = 0x4000 | 0x0080 | 0x0004;
  //サブBG2の裏画面を等倍表示になるよう初期設定
  SUB_BG2_X0 = 0;
  SUB_BG2_Y0 = 0;
  SUB_BG2_XDX = 1 << 8;
  SUB_BG2_XDY = 0;
  SUB_BG2_YDX = 0;
  SUB_BG2_YDY = 1 << 8;
  SUB_BG2_CX = 0;
  SUB_BG2_CX = 0;

  //メイン画面を赤で塗りつぶす
  for (int y=0; y < 192; y++){
  for (int x=0; x < 256; x++){
    *(unsigned short *)(0x06000000 + (x + y * 256) * 2)=0x1F | 0x8000;
  }
  }

  //サブ画面を青で塗りつぶす
  for (int y=0; y < 192; y++){
  for (int x=0; x < 256; x++){
    *(unsigned short *)(0x06200000 + (x + y * 256) * 2)=0x7C00 | 0x8000;
  }
  }

  while(1){
  }

  return 0;
}


以上で,上下両方の画面をアドレス直接書き換えで制御できるようになりました

○追記

DevkitPro 1.4.9では、BG2やSUB_BG2を記述するには registers_alt.hをインクルードする必要があります

#include <nds.h>
#include <nds/registers_alt.h>



TOPプログラマ専用NDSでプログラミング