gbadev.org forum archive

This is a read-only mirror of the content originally found on forum.gbadev.org (now offline), salvaged from Wayback machine copies. A new forum can be found here.

DS development > Console and Ext Background on both screen (example here)

#129243 - odelot - Mon May 21, 2007 12:16 am

Hi everyone... i waste my weekend studying the material around the net about ds development and some codes too. I started to code on DS last weekend and started with palib, but it was making the DSerial lib to crash some times...

so I decided to make my own window system to DS... the first thing that i needed to do was to find a way to the video ram as framebuffer for both screen and have text support...

i noticed that it is a doubt of many here, and there is a lot of question on forum. the main problem is how to setup the console from ndslib to subscreen, if we use all the memory on extended background..

So, i started to study some codes and I found the anwser on Win2DS code. He did what I was looking for.

His trick was to scroll the background on Y. As we know, the 16bit 256x256 framebuffer for sub screen use all bank C, and if we want to use another thing, like tile base background, we cant. But the DS Screen does not has 256x256 but 256x192. So there is memory that we can use. Then, if we make a little horizontal scroll in extended background (ex SUB_BG3_CY = 64 << 8) we are telling to DS no to use the begin of C banck (0x0620000) but an andress after the begin (if we use the scrolling command SUB_BG3_CY = 64 << 8, then DS will point the ext background to 0x06208000). So, now we have 0x8000 Bytes (32KB) of free space to use with tile map background and then to text.

I follow the WIN2DS example and didn't use the console from ndslib, but 2 tile maps, one for each screen, and then i update the maps to show the text that i wanted

concluding, using text with tile based background has its advantages and disadvantages. The advantages is that we dont need to change (redraw) the entire framebuffer to display or change text. The disadvantages is that you cannot show text in anywhere in the screen, but just in a 32x24 grid that map the screen, because of the definition of the tile background

the code below configures the DS memory to use ext background and tile based text on both screens, and for both it implements double buffering

hope that this helps you! Odelot

here is the link to code and to ascii tile and pallet files
(code) http://grad.icmc.usp.br/~fabiotp/dsDev/DSVideo.rar
(pic) http://grad.icmc.usp.br/~fabiotp/dsDev/dsDevExtBGwithText.jpg

Code:
#include "../gfx/ascii.c"


class DSVideo
{
public:
   void init ()
   {
      
      //initialing this variable that will help us with the swapBuffers of double buffering of main screen
      m_drawingMainScr1=true;


      //initializing the main screen with mode5 and extended backgrounds
      videoSetMode(MODE_5_2D |DISPLAY_BG0_ACTIVE | DISPLAY_BG3_ACTIVE);   
      //initializing the sub screen with mode5 and extended backgrounds
      videoSetModeSub(MODE_5_2D  | DISPLAY_BG0_ACTIVE | DISPLAY_BG3_ACTIVE );   

      //initializing the bank A, B and C. Note that C bank is set to be used in sub screen
      vramSetBankA (VRAM_A_MAIN_BG_0x06000000);
      vramSetBankB (VRAM_B_MAIN_BG_0x06020000);
      vramSetBankC (VRAM_C_SUB_BG);
      vramSetBankD (VRAM_D_MAIN_BG_0x06040000); // i am not sure that i need this, but...


      

      //BG3_CR (main screen) is a complicated register... it has a lot of information.
      //what we need to know is that, with OR operation, we make it, and it
      //will works like a pointer for what the DS need to show on background (BG)
      //layer, in case, the Background 3 that we enabled on videoSetMode
      //
      //as we didnt tell him here to point (using BG_MAP_BASE(x) or BG_BMP_BASE(x), etc)
      //then it will point to 0x06000000. but we will scroll the background (BG3_CY = 64 << 8)
      //so it will point to 0x06008000
      BG3_CR = BG_BMP16_256x256 | BG_PRIORITY(3);


      //same as BG3_CR, but for sub screen (0x06200000 is the adreess of
      //the begining of C bank)  - remember that this address will change
      //when we make the scrolling (SUB_BG3_CY = 64 << 8), so it will point to 0x62008000
      SUB_BG3_CR = BG_BMP16_256x256|BG_PRIORITY(3); 


      //setting up scale, rotation and scroll of our extended backgrounds
      BG3_XDX = 1 << 8;
      BG3_XDY = 0;
      BG3_YDX = 0;
      BG3_YDY = 1 << 8;
      //our bitmap looks a bit better if we center it so scroll down (256 - 192) / 2
      BG3_CX = 0;
      BG3_CY = 64 << 8;

      SUB_BG3_XDX = 1 << 8;
      SUB_BG3_XDY = 0;
      SUB_BG3_YDX = 0;
      SUB_BG3_YDY = 1 << 8;
      SUB_BG3_CX = 0;
      SUB_BG3_CY = 64 << 8;

   

      //setting up the background 0 from main and sub screen to use tile backgrounds
      //for text use (probably I need to make my own text render, as this type of text
      //do not apply for a windows system)
      BG0_CR = BG_COLOR_16 | BG_32x32 | BG_MAP_BASE(6) | BG_TILE_BASE(0);//  | BG_PRIORITY(1);
      SUB_BG0_CR = BG_COLOR_16 | BG_32x32 | BG_MAP_BASE(6) | BG_TILE_BASE(0);//  | BG_PRIORITY(0);
      

      //applying the pointers to framebuffers
      m_fbMainScr1=(u16*)  0x06008000;// (u16*)BG_BMP_RAM(2); //point to init of bank A, or 0x06008000
      m_fbMainScr2=(u16*)  0x06028000;// (u16*)BG_BMP_RAM(10); //point to init of bank B, or 0x06028000
      m_fbSubScr= (u16*)   0x06208000; //point to init of bank c, or 0x06208000
      m_fbMainScr = m_fbMainScr2; //actual backbuffer is back B
      
      m_fbSubScrEmulated = (u16*)malloc (256*256*2); //just if we will use emulated double buffering for sub screen

      int i=0;

      //cleaning the vram      
      u16* vram = (u16*)(0x06020000);
      while(i++ <= (256*256)) vram[i] = 0;
      vram = (u16*)(0x06000000); i = 0;
      while(i++ <= (256*256)) vram[i] = 0;

      
      //Load the text I use into character slot 0 for both screens
      loadText((u16*)CHAR_BASE_BLOCK(0),(u16*)BG_PALETTE);  //CHAR_BASE_BLOCK(0) = 0x6000000
      loadText((u16*)CHAR_BASE_BLOCK_SUB(0),(u16*)BG_PALETTE_SUB); //CHAR_BASE_BLOCK_SUB(0) = 0x6200000

      //setting color to text
      BG_PALETTE[0]=RGB15(0,0,0);   //background text color
      BG_PALETTE[1]=RGB15(31,31,31); //text color
      BG_PALETTE_SUB[0]=RGB15(0,0,0);
      BG_PALETTE_SUB[1] = RGB15(31, 31, 31);


   }

   //print text using tile based text on subScreen
   void printTextSubScrn(const char * str, int x, int y)
   {
      u16* map = (u16*)BG_MAP_RAM_SUB(6); //counting that it will not change
      while(*str)
      {
         if(x==32) {x=0; y++;}
         if(y==24) return;
         map[y*32+x++]=(*str)-32;
         str++;
      }
   }

   //print text using tile based text on mainScreen
   void printTextMainScrn(const char * str, int x, int y)
   {
      u16* map = (u16*)BG_MAP_RAM(6); //counting that it will not change
      while(*str)
      {
         if(x==32) {x=0; y++;}
         if(y==24) return;
         map[y*32+x++]=(*str)-32;
         str++;
      }
   }
   
   //copying text tile info and pallete to memory
   void loadText(u16 *map, u16 *palette)
   {
      
      dmaCopy((u16 *)asciiPal, (u16 *)palette, asciiPalLen);
      dmaCopy((u16 *)asciiData, (u16 *)map, asciiLen);
   }

   //swap back and front buffers of main and sub screen
   //can make separete swapBuffer methods to each screen
   //to optimizate screen refresh
   void swapBuffers ( )
   {
      //mainScreen swap code
      m_drawingMainScr1=!m_drawingMainScr1;
      if (m_drawingMainScr1)
      {
            //changing the back buffer pointer
         m_fbMainScr=m_fbMainScr2;
         //if we are drawing now main screen 1, so here we are updating the DS pointer to it
         BG3_CR = BG_BMP16_256x256 | BG_BMP_BASE(0)  |  BG_PRIORITY(3); 
      }
      else
      {   
         m_fbMainScr=m_fbMainScr1;
         BG3_CR = BG_BMP16_256x256 | BG_BMP_BASE(8)  |  BG_PRIORITY(3);
      }

      //subScreen swap code

      //usign the emulated framebuffer
      memcpy (m_fbSubScr,m_fbSubScrEmulated,256*192*2 );
      

   }


    //just to test - dont use coordinates that exceeds Y=192 and X=256, or you will mess if the memory
   void drawRectangleMainScreen (int posX, int posY, int sizeX, int sizeY, u16 color)
   {
      for (int i=posY; i<posY+sizeY; i+=1)
         for (int j=posX; j<posX+sizeX; j+=1)
            m_fbMainScr[i*256+j]= color;

   }

   //just to test - dont use coordinates that exceeds Y=192 and X=256, or you will mess if the memory
   void drawRectangleSubScreen (int posX, int posY, int sizeX, int sizeY, u16 color)
   {
      for (int i=posY; i<posY+sizeY; i+=1)
         for (int j=posX; j<posX+sizeX; j+=1)
            m_fbSubScrEmulated[i*256+j]= color;

   }

   //return the framebuffer to be used to subScreen
   //(remember to swapBuffers to refresh the DS screen)
   u16* getFrameBufferSubScr ()
   {
      return m_fbSubScrEmulated;
   }

   //return the framebuffer to be used to mainScreen
   //(remember to swapBuffers to refresh the DS screen)
   u16* getFrameBufferMainScr ()
   {
      return m_fbMainScr;
   }

private:
   //main screen framebuffer  #1
   u16* m_fbMainScr1;

   //main screen framebuffer  #2
   u16* m_fbMainScr2;

   //main screen framebuffer actual
   u16* m_fbMainScr;

   //sub screen framebuffer
   u16* m_fbSubScr;

   //emulated sub screen framebuffer  (it is crashing the rom ? )
   //u16 m_fbSubScrEmulated [65536];//use or not use it, it is the question
   u16 *m_fbSubScrEmulated;

   //what framebuffer on main screen we are drawing
   bool m_drawingMainScr1;

};

#129267 - mml - Mon May 21, 2007 9:11 am

That's a cute idea, top stuff.

#129305 - Cydrak - Mon May 21, 2007 7:27 pm

Actually, the subscreen can be double-buffered (in hardware), if you really want. This is how dual-screen 3D works: two screen buffers in C/D and you swap the screens, using display capture to update one per frame.

The trick is--you're right, you can't get two full BGs since the sub is capped at 128k. Even with 32k at the end, if you try to "spill over" into D, D doesn't map to the BG so you're out of luck. ... Except, what else does D map to?

Well... the DS has these odd "bitmap sprites", and they have not only an (X, Y) onscreen, but an (X, Y) in a big flat texture (like those portrait cut-out sheets with the wallet sizes... or 3D quads without the 3D). Does that sound useful to you? Just to give you ideas:

Bank C => sub BG
Bank D => sub OBJs
sub extended BG3 => sub buffer 0
"fleet" of sub OBJs => sub buffer 1

Code:
// Attributes for a bitmap sprite behind BG3.. at 64x64, 12 of these cover the screen.
OAM_SUB[4*n+0] = OBJ_Y(screenY) | ATTR0_NORMAL | ATTR0_BMP | ATTR0_SQUARE;
OAM_SUB[4*n+1] = OBJ_X(screenX) | ATTR1_SIZE_64;
OAM_SUB[4*n+2] = (bitmapX/8) | (bitmapY/8)<<5 | ATTR2_ALPHA(15) | ATTR2_PRIORITY(3);

    ...

// Display the BG over the bitmap OBJs. Affine settings omitted.
SUB_BG3_CR = BG_BMP16_256x256 | BG_BMP_BASE(0) | BG_PRIORITY(2);
SUB_DISPLAY_CR = MODE_5_2D | DISPLAY_SPR_2D_BMP_256 | DISPLAY_BG3_ACTIVE | DISPLAY_SPR_ACTIVE;

    ...

// Swap the BG3/OBJs each frame.
// Beware if your framebuffer uses transparency--will need to toggle the sprites' visibility, too.
SUB_DISPLAY_CR ^= DISPLAY_BG3_ACTIVE;


Hope this helps. I use very similar code to do 3D, and it works a treat.

#129308 - odelot - Mon May 21, 2007 8:08 pm

hi.. i didnt use sprites yet, as I started to code on DS just last wednesday, put i think that you are telling me to put one framebuffer on background in bank C and use bank D to put the other framebuffer splited into sprites, am I right??

Code:
     if (frameCount & 0x1)
      {
         vramSetBankC(VRAM_C_SUB_BG);
         vramSetBankD(VRAM_D_LCD);
         SetRegCapture(true, 0, 15, 3, 0, 3, 0, 0);
         scene->draw_bottom(frameCount);
      } else {
         vramSetBankC(VRAM_C_LCD);
         vramSetBankD(VRAM_D_SUB_SPRITE);
         SetRegCapture(true, 0, 15, 2, 0, 3, 0, 0);
         scene->draw_top(frameCount);
      }


i took this code from the link that i gave.... setting a bank to LCD will make the DS to not display that bank??? as you still has the ext Background pointed to back C

ah, and to use 3D on both screen you need to render in 2 pass, don t you?? like, for each frame, render to the sub, copying the framebuffer from main to sub, and then render to the main screen?

well... thanks a lot... i will try to use the double-buffering on hardware to sub screen as you tell, using sprites..

i dont want to code to 3D right now for DS, but on PC, this is the area that i study and work more on college... i think that i will try something soon on 3D... thanks again for the clue