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 > Easy Tile Question ...for all but I

#102706 - AN_D_K - Sat Sep 16, 2006 10:08 am

The 1024 index limit on a tile map. Is this for the map the game level actually uses? So if I wanted a level larger than 32x32 tiles I'd have to suddenly jump from one set of 32x32 tiles to another set when scrolling along?

I'm presuming this is the case since many GBA games do this but it may be the limit on the number of different tile graphics you can store. I can't really confirm it by google alone for the DS.

How would this affect overlaying tiles on a different background (e.g. to show selection)?

Thanks,

#102732 - Dannon - Sat Sep 16, 2006 2:51 pm

Sorry to add to your first post AN_D_K but I am also having problems with understanding some background stuff and thought we might as well use the same thread, if anyone can help that'd be great.

I am trying to create a tile manager that will control all the tiles on a couple of backgrounds on each of the screen, I understand the theory behind all of it but when it comes to coding I'm having issues, mainly on the subject of using:

Code:

BG_TILE_BASE( charBase  )
BG_MAP_BASE( screenBase )
CHAR_BASE_BLOCK( charBase )
SCREEN_BASE_BLOCK( screenBase )


I understand that these are references to memory addresses but I don't understand the whole thing completely, I mean what numbers do I pass to them?

Also, when I want to use several different tiles from a 64x64 image how do I call each tile up, do I just call the memory address of the desired tile? What is the offset for an 8x8 tile?

If someone had a small demo of any of this that'd be cool, there just doesn't seem to be any good demos of this around, I've read through a lot of the DS sources too.

Thanks.

--Dannon

#102733 - zzo38computer - Sat Sep 16, 2006 3:00 pm

The 1024 tile limit is the number of different tiles that are possible on one screen. (You can overlay tiles by creating more than one background)

Here is some code I used in one of my own software (MULTIGAM). You probably can't use it as it is, but it will show you a few things which you probably wanted to know and can help you a bit.

Code:


void gfx_init() {   
   POWER_CR=POWER_SWAP_LCDS | POWER_ALL_2D;
   vramSetMainBanks(VRAM_A_MAIN_BG,VRAM_B_MAIN_BG,VRAM_C_SUB_BG,VRAM_D_LCD);
   SUB_DISPLAY_CR=MODE_0_2D|DISPLAY_BG0_ACTIVE|DISPLAY_BG1_ACTIVE;
   DISPLAY_CR=MODE_0_2D|DISPLAY_BG0_ACTIVE|DISPLAY_BG1_ACTIVE;
   SUB_BG0_CR=BG_TILE_BASE(1);
   SUB_BG0_X0=0;
   SUB_BG0_Y0=0;
   SUB_BG1_CR=BG_TILE_BASE(1)|BG_MAP_BASE(1);
   SUB_BG1_X0=0;
   SUB_BG1_Y0=0;
   BG0_CR=BG_TILE_BASE(1);
   BG0_X0=0;
   BG0_Y0=0;
   BG1_CR=BG_TILE_BASE(1)|BG_MAP_BASE(1);
   BG1_X0=0;
   BG1_Y0=0;
   swiFastCopy(&font_bin,(u16*)(CHAR_BASE_BLOCK_SUB(1)),font_bin_size/4);
   swiFastCopy(&font_bin,(u16*)(CHAR_BASE_BLOCK(1)),font_bin_size/4);
}

void load_palette() {
   unsigned char i,r,g,b;
   for(i=0;i<16;i++) {
      r=(i&4)>>2; g=(i&2)>>1; b=(i&1)>>0;
      r=r*colorsettings[0]; g=g*colorsettings[0]; b=b*colorsettings[0];
      if(i>=8) {r=r+colorsettings[1];g=g+colorsettings[1];b=b+colorsettings[1];}
      if(r>31) r=31;
      if(g>31) g=31;
      if(b>31) b=31;
      BG_PALETTE_SUB[i*16+1] = RGB15(r,g,b);
      BG_PALETTE[i*16+1] = BG_PALETTE_SUB[i*16+1];
   }
}

char fix_menu2(char modulenum) {
   u32 i,j,k,sel=0,dig=0;

   printtext(LAYER_MAIN0,0,21,12,"RUN");
   printtext(LAYER_MAIN0,1,21,12,"DEFAULT");
   printtext(LAYER_MAIN0,2,21,12,"CONTINUE");
   printtext(LAYER_MAIN0,3,21,12,"EXIT");
   printtext(LAYER_MAIN0,9,21,7,"^/v/SELECT");
   set_tile(LAYER_MAIN0,9,21,XTILE(7,24));
   set_tile(LAYER_MAIN0,9,23,XTILE(7,25));

   while(1) {
      swiWaitForVBlank();
      k=keysDown();

      cleartext(LAYER_MAIN1,0,23);
      for(i=21;i<32;i++) set_tile(LAYER_MAIN1,sel,i,XTILE(4,219));

      ON_BREAK return 1;
      if((k&KEY_UP) && sel>0) sel--;
      if((k&KEY_DOWN) && sel<3) sel++;
      if(k&KEY_SELECT) {
         if(sel==0) {
            clear_screen();
            module_list[modulenum].function_run();
            return 1;
         }
         if(sel==1) {
            currentfixmode=FIXMODE_DEFAULT;
            module_list[modulenum].function_fix();
            currentfixmode=FIXMODE_FIX;
            return 0;
         }
         if(sel==2) return 0;
         if(sel==3) return 1;
      }
   }
}

void set_tile(char layer, char row, char col, u16 tile) {
   u16 *p=(u16*)(SCREENBLOCK(layer)+row*64+col*2);
   *p=tile;
}

void printtext(char layer, char row, char col, char color, char *str) {
   char *s=str;
   u16 *p=(u16*)(SCREENBLOCK(layer)+row*64+col*2);
   while (*s) *p++=(*s++)|(color*0x1000);
}

void cleartext(char layer, char rowstart, char rowend) {
   int i;
   for(i=rowstart;i<=rowend;i++) {
      printtext(layer,i,0,0,"                                ");
   }
}

_________________
Important: Please send messages about FWNITRO to the public forum, not privately to me.

#102738 - Dannon - Sat Sep 16, 2006 3:38 pm

Thanks for the quick reply, that does help a lot but in this:

Code:

SUB_BG0_CR=BG_TILE_BASE(1);

SUB_BG1_CR=BG_TILE_BASE(1)|BG_MAP_BASE(1);

swiFastCopy(&font_bin,(u16*)(CHAR_BASE_BLOCK_SUB(1)),font_bin_size/4);
swiFastCopy(&font_bin,(u16*)(CHAR_BASE_BLOCK(1)),font_bin_size/4);


What does the (1) mean thats being sent to TILE_BASE, MAP_BASE and BASE_BLOCK? I mean what does 1 make it do?

Also why do you divide font_bin_size by 4? I've seen a few things divided by 4 in source code but I don't know why.

Thanks, again.

--Dannon


Last edited by Dannon on Sat Sep 16, 2006 3:39 pm; edited 1 time in total

#102739 - Sausage Boy - Sat Sep 16, 2006 3:39 pm

As for Dannon's question, check this page out, http://user.chem.tue.nl/jakvijn/tonc/regbg.htm. The same applies for the DS, only you have twice as much vram, 8 charblocks instead of 4, 64 screenblocks instead of 32.

The only complicated thing is that these overlap, so screenblock 0 == charblock 0, and screenblock 8 == charblock 1, and so on.

What's important is that you use the same charBase value for BG_TILE_BASE and CHAR_BASE_BLOCK, and that you make sure it doesn't overlap with your screenBase value, which would cause corruption.
_________________
"no offense, but this is the gayest game ever"

#102886 - Dannon - Sun Sep 17, 2006 6:47 pm

Right then, I think I'm almost there, for the moment at least:

I am currenntly just trying to get a normal (256x256) background image onto a tiled background, and some tiles onto another layer but thats for after the background works, here's the code:

Code:


//   Setup the screens
   
//   Setup Main Screen   
   videoSetMode(    MODE_0_2D |
               DISPLAY_BG0_ACTIVE |
               DISPLAY_BG1_ACTIVE |
               DISPLAY_SPR_ACTIVE |
               DISPLAY_SPR_1D
            );

//   Set memory banks for main screen
   vramSetBankA( VRAM_A_MAIN_BG );      //   Background memory    - 128k
   vramSetBankB( VRAM_B_MAIN_SPRITE );   //   Sprite Memory       - 128k

//   Setup Sub Screen
   videoSetModeSub(    MODE_0_2D |
                  DISPLAY_BG0_ACTIVE |
                  DISPLAY_BG1_ACTIVE |
                  DISPLAY_SPR_ACTIVE |
                  DISPLAY_SPR_1D
               );

//   Set memory banks for sub screen
   vramSetBankC( VRAM_C_SUB_BG );      //   Background memory    - 128k
   vramSetBankD( VRAM_D_SUB_SPRITE );   //   Sprite memory       - 128k

//   Setup backgrounds for tiles   
//   Main Screen
//   Tiles
   BG0_CR =    BG_32x32 |             // Tile size - flags; BG_8x8, BG_16x16, BG_32x32, BG_64x64, BG_64x32, etc...
            BG_TILE_BASE( 1 ) |      // Char block   - Tiles - |   0   |    1    |   2   |
            BG_MAP_BASE( 8 ) |      // Screen block - Maps  - | 0...7 | 8....15 |16...23|
            BG_PRIORITY( 0 ) |      // Priority - 0 - Closest - 3 - Furthest - Sprites with same priority will be displayed on top
            BG_256_COLOR;         // Number of colours to be used in background - flags; BG_16_COLOR, BG_256_COLOR

//   Background
   BG1_CR =    BG_32x32 |          
            BG_TILE_BASE( 0 ) |      
            BG_MAP_BASE( 0 ) |      
            BG_PRIORITY( 3 ) |      
            BG_256_COLOR;      

//   Sub Screen
//   Tiles
   SUB_BG0_CR = BG_32x32 |          
            BG_TILE_BASE( 1 ) |      
            BG_MAP_BASE( 8 ) |      
            BG_PRIORITY( 0 ) |      
            BG_256_COLOR;

//   Background
   SUB_BG1_CR = BG_32x32 |          
            BG_TILE_BASE( 0 ) |      
            BG_MAP_BASE( 0 ) |      
            BG_PRIORITY( 3 ) |      
            BG_256_COLOR;


//   Background palette   
//   BG_PALETTE[0] = RGB15( 0, 0, 0 );

//   BG_PALETTE_SUB[0] = RGB15( 31,31,31 );   


//   Load data to memory
//   Main screen
//   Background
   dmaCopy( background_bin, (u16*)BG_TILE_RAM( 0 ), background_bin_size );
//   dmaCopy( background_map_bin, (u16*)BG_MAP_RAM( 0 ), background_map_bin_size );
   dmaCopy( background_pal_bin, BG_PALETTE, background_pal_bin_size );

//   Tiles
//   dmaCopy( tiles_bin, (u16*)BG_TILE_RAM( 1 ), tiles_bin_size );
//   dmaCopy( tiles_pal_bin, BG_PALETTE_SUB, tiles_pal_bin_size );


//   Sub screen
//   Background
   dmaCopy( background_bin, (u16*)(CHAR_BASE_BLOCK_SUB( 0 )), background_bin_size );
   dmaCopy( background_pal_bin, BG_PALETTE_SUB, background_pal_bin_size );


When I run this it just seems to show 1 tile but tiled completely across the screen some how, do I need to use BG_MAP_RAM somewhere? As you can see I tried it with a map on the main screen but it just showed some different tiling patterns but still with the same tile.

Also when I try to load in my tiles for BG1 it shows them on top of the background (as it should) but again each tile is garbage and it covers the entire screen.

Any suggestions?

--Dannon

EDIT: Also what the difference between using CHAR_BASE_BLOCK() and BG_TILE_RAM()?

#102970 - Cearn - Mon Sep 18, 2006 9:15 am

Dannon wrote:

Code:
// <snip>
//   Background
   BG1_CR =    BG_32x32 |          
            BG_TILE_BASE( 0 ) |      
            BG_MAP_BASE( 0 ) |      
            BG_PRIORITY( 3 ) |      
            BG_256_COLOR;

//   Background palette   
//   BG_PALETTE[0] = RGB15( 0, 0, 0 );

   dmaCopy( background_bin, (u16*)BG_TILE_RAM( 0 ), background_bin_size );
//   dmaCopy( background_map_bin, (u16*)BG_MAP_RAM( 0 ), background_map_bin_size );
   dmaCopy( background_pal_bin, BG_PALETTE, background_pal_bin_size );


The problem is that you're overwriting your data.

Like SausageBoy said, CharBlock 0 and ScreenBlock 0 use the same memory space (0600:0000 and on), so when you're copying the map into VRAM, you've overwriting the tile data, which is bad. The same thing happens with CBB 1 and SBB 8, and with your use of BG_PALETTE.

Dannon wrote:
EDIT: Also what the difference between using CHAR_BASE_BLOCK() and BG_TILE_RAM()?
They are the same: both give an address to the start of character base blocks in VRAM. But BG_TILE_RAM() is too similar to BG_TILE_BASE() that it might cause confusion: BG_TILE_BASE() is used to set the bits of REG_BGxCNT indicating which CBB to use. Needless to say, this is very different from a VRAM address. The fact that BG_TILE_RAM returns an address rather than a pointer doesn't help much either :\

For these kinds of questions, just look them up in libnds.

Code:
// in libnds/include/nds/arm9/video.h
#define BG_TILE_BASE(base) ((base) << 2)
#define BG_MAP_BASE(base)  ((base) << 8)
#define BG_BMP_BASE(base)  ((base) << 8)


#define BG_MAP_RAM(base)  (((base)*0x800) + 0x06000000)
#define BG_MAP_RAM_SUB(base) (((base)*0x800) + 0x06200000)

#define BG_TILE_RAM(base) (((base)*0x4000) + 0x06000000)
#define BG_TILE_RAM_SUB(base) (((base)*0x4000) + 0x06200000)


#define CHAR_BASE_BLOCK(n)    (((n)*0x4000)+0x6000000)
#define CHAR_BASE_BLOCK_SUB(n)    (((n)*0x4000)+0x6200000)
#define SCREEN_BASE_BLOCK(n)  (((n)*0x800)+0x6000000)
#define SCREEN_BASE_BLOCK_SUB(n)  (((n)*0x800)+0x6200000)

#103070 - Dannon - Tue Sep 19, 2006 12:43 am

Thanks.

Ok, just re read over everything... as well as most on the memory and video sections on TONC and NDSTech Wiki, again. Sorry SausageBoy completely took the opposite from what you were trying to tell me, but the re read made sense.

Anyway, I've been looking into it all for a few hours now and I understand what needs to be done, i.e. not writing the data into the same section of memory (it didn't take a few hours a to work that bit out) but how much space do I want to leave for each CBB and SBB?

In the code that I have above what do you suggest for the SBB and CBB? Should these be dependant on how much data I am loading in, if someone could point me in a direction that explains all this nicely that'd be just swell.

Also, why should BG_PALETTE overwrite anything, thats located at 0x5000000 where as the graphics data isn't starting till 0x6000000

Any help would be great, thanks in advance.

--Dannon

#103072 - tepples - Tue Sep 19, 2006 1:21 am

Each CBB is worth eight SBBs. On the GBA it's common to use CBBs 0-2 and possibly part of 3, and SBBs 28-31 (or 24-31 if you use bigger maps on some screens). (See GBA Beginners' FAQ: Graphics: In "text" modes (0, 1, 2), why are my tiles corrupted?)

The DS has larger VRAM banks. There are more bits in BGxCNT for CBBs, and you can put the SBBs into a separate 64 KiB sub-bank using bits in DISPCNT, but I haven't tried those yet. See GBATEK: DS Video BG Modes.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#103118 - Cearn - Tue Sep 19, 2006 10:23 am

Dannon wrote:
In the code that I have above what do you suggest for the SBB and CBB? Should these be dependant on how much data I am loading in.
Pretty much. As you know how much space your tiles take up, you also know how much space is left for your maps. Say you put 1kB of tile data into CBB 0. As each SBB if 2kB in size, you're only taking up half of SBB 0, leaving all the rest free for your map.

Dannon wrote:
Also, why should BG_PALETTE overwrite anything, thats located at 0x5000000 where as the graphics data isn't starting till 0x6000000
First you're putting RGB(0,0,0) into the palette, then loading background_pal_bin into it later. Or at least I thought you were. Didn't see that the 'BG_PALETTE[0]= RGB(0,0,0)' line was commented out. It's still stands as a general comment though: multiple transfers of data into BG_PALETTE will simply overwrite the data already there.

#103132 - Dannon - Tue Sep 19, 2006 2:27 pm

Thanks to everyone or their help, I now have a tiled backgound, well it's just a background that is diplayed in tiled mode but hey it's working.

I'm pretty sure I almost completely get SBBs and CBBs now, it's taken a while, just need some different sized images to try out a few things to see if whats I am thinking is completely right.

Anyway, now I have data loaded in I wan't to be able to display each tile separetly, I have read through the TONC Regular Background Tut a few times now, I understand the principle but not what commands to use on the DS, I have loaded in a 64x64 image with four tiles 32x32 in size, the data is loaded to CBB 1 and SBB 27, does there need to be some kind of loop that will draw all of the 8x8 tiles that make up the tile out or, as I set the layer up with BG_32x32 can I just call a 32x32 section ( or 'tile', if you will ).

Again if anyone can help, or point me in the direction of a good tutorial I'd be greatful.

--Dannon