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.

Graphics > Making a scrolling background larger than 256x256

#65714 - gs2phateon - Thu Jan 05, 2006 3:49 am

I have been able to make a 256x256 scrolling background without too much difficulty, but I just can't seem to draw a 512x256 sized background. I'm using Mode 0. I changed the part that defines the size of the map, and when I run the program, the scrolling area does seem to be the right size (it'll scroll twice as far horizontally as verticall).

The map itself doesn't seem to have any problems either. I changed the program to account for the number of tiles, size of the map, and palette, so I don't think the problem lies there.

The map that actually shows up is a bit difficult to explain. It's supposed to just read:
-------------------------
Hi! My Name is
(my name)
-------------------------
The tiles are pretty messed up though. The words "Hi! My" look OK, except they seem to be missing all the tiles every other row. The words "Name is" have the same problem, but they are not on the same row as the first two, rather they are right underneath. Finally, my name is not underneath "Hi! My Name is", but it's sort of mixed in with all the other letters. It has the same problem of missing every other row of tiles. Do you think it's a map problem, like I should just try and make a new map? Or is there a bigger part of the code that I may be missing?

#65722 - tepples - Thu Jan 05, 2006 5:45 am

A 512x256 text map is stored as two 256x256 maps side-by-side: 32 rows of 32 tiles for the left half, and then 32 rows of 32 tiles for the right half. The NES and Super NES used the same layout for their 512-pixel-wide maps that the GBA uses.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#65841 - gs2phateon - Fri Jan 06, 2006 1:58 am

Umm, I guess the problem I'm having is pretty hard to explain. I'll just start with one thing first. What is happening is that every other row is off maybe about 2 tiles. I also tried making a 512x512 map.

For example a straight line that should look like:
|
|
|
|
|

Ends up looking like:
|
xx|
|
xx|
|

(pretend the x's are the missing tiles)

#66509 - pure_ev1l - Wed Jan 11, 2006 2:08 pm

its easy. I have only been programing for GBA for 4 days now, and I have made my own map editor with infinite size capabilities with some good tools and a gba game that can play any size map with no (visible) loading

all you need to do is if u move 1 tile left load a line of tiles down the left side off screen....

the only limittation of it is the fact that I ran out of virtual memory on my comp trying to compile a map bigger than 1024*1024 tiles....

but if I would have been able to compile it, it would have played.

if what I'm saying applies to your problem then with a slight grudge I could part with my source code for dynamic loading of an infinite map?

#66547 - tepples - Wed Jan 11, 2006 10:00 pm

pure_ev1l wrote:
all you need to do is if u move 1 tile left load a line of tiles down the left side off screen....

And for an illustration of this, run any NES game in Nintendulator and look at the "nametables" (the NES term for maps).

Quote:
the only limittation of it is the fact that I ran out of virtual memory on my comp trying to compile a map bigger than 1024*1024 tiles

That's why you shouldn't output your maps to .c files. Instead, output them to .s files, as the assembler is much more efficient than the C compiler at handling large const arrays.

But wouldn't such a map (16 bits per tile, 1024 tiles wide, 1024 tiles tall) take half of a 32 Mbit ROM anyway?

Discussion of including assets in a GBA binary continues in this topic.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#90282 - king501 - Thu Jun 29, 2006 7:36 am

Of course, I?m planning to use TONC notes in a very near future, but right now I just would like to understand how to set a 512x512 map using Jharbour?s code source. Let?s suppose I would like to use a 512x512 background map, what should I add in this code?

Quote:
//create a pointer to background 0 tilemap buffer
unsigned short* bg0map =(unsigned short*)ScreenBaseBlock(28);

//set up background 0
REG_BG0CNT = BG_COLOR256 | TEXTBG_SIZE_256x256 |
(31 << SCREEN_SHIFT);

//set video mode 0 with background 0
SetMode(0 | BG0_ENABLE);

//copy the palette into the background palette memory
DMAFastCopy((void*)test_Palette, (void*)BGPaletteMem,
256, DMA_16NOW);

//copy the tile images into the tile memory
DMAFastCopy((void*)test_Tiles, (void*)CharBaseBlock(0),
57984/4, DMA_32NOW);

//copy the tile map into background 0
DMAFastCopy((void*)test_Map, (void*)bg0map, 512, DMA_32NOW);


so far I know that a screenblock is big enough for a 256x256 piece, and that 4 screenblocks are needed for a 512x512 map.

I tried many possibilities, but in vain. Could someone modify the above code source and adapt it for a 512x512 map? Making comparaison truly help me understanding stuff.

Thanks!

#90290 - Cearn - Thu Jun 29, 2006 9:35 am

  • Instead of TEXTBG_SIZE_256x256, use TEXTBG_SIZE_256x512.
  • Make sure that the map editor correctly divides the map into 4 screen base blocks (SBB). If not, be prepared to do it manually.
  • Put the map data into the screenblock(s) that you told the GBA you were going to use. I'm mentioning this because this isn't the case in the code you posted: bg0map=SBB 28, but REG_BG0CNT indicates SBB 31. Same goes for tile data, of course. Also, make sure that the map and tiles actually fit into BG-VRAM: starting your big map at SBBs 31 means ? of the map is actually in OBJ VRAM and funkyness ensues.
  • Should I mention possible alignment problems when you #include data and use 16 or 32 bit copies? Nah, I'll give it a miss this time.

Code:
// Move the useless casts that DMAFastCopy requires to the top
u16 *palsrc=  (u16*)test_Palette, *paldst=  (u16*)BGPaletteMem;
u16 *tilesrc= (u16*)test_Tiles,   *tiledst= (u16*)CharBaseBlock(0);
u16 *mapsrc=  (u16*)test_Map,     *mapdst=  (u16*)ScreenBaseBlock(28);

REG_BG0CNT= BG_COLOR256 | TEXTBG_SIZE_512x512 | (28<<SCREEN_SHIFT) | (0<<CHAR_SHIFT);
REG_DISPCNT= 0 | BG0_ENABLE;

// Copy stuff via DMA16 (or DMA32, your choice)
// Replace 'foo_Size' with the real sizes in bytes.
DMAFastCopy(palsrc, paldst, pal_Size/2, DMA_16NOW);
DMAFastCopy(tilesrc, tiledst, tile_Size/2, DMA_16NOW);
DMAFastCopy(mapsrc, mapdst, map_Size/2, DMA_16NOW);

#90347 - king501 - Thu Jun 29, 2006 8:35 pm

My head is going to blow up. I?m a slow learner :| Sometime I can understand things pretty quickly, and sometime it seems to be totally impossible.

Cearn, I don?t know if you will accept this, but is it possible for you to make me a small zipped program with the minimal defines, minimal functions so I can just focus my attention to what is really required to use a 512x512 map?

Sometime learning with little chunk of code is really helpful?

I?m trying to learn from TONC (it?s your website, right?), but it?s quite hard for a guy like me to learn from multiple big source files and track down every piece of code to understand the basic.

Anyone else wanting to help could be appreciated too.

#90364 - Cearn - Thu Jun 29, 2006 10:34 pm

The size of the background is determined by the two top bits of REG_BGxCNT; (0<<14) means a 256x256p map, (3<<14) means a 512x512p map. In the code you have these are defined as TEXTBG_SIZE_256x256 and TEXTBG_SIZE_512x512, respectively, so when setting REG_BG0CNT use the second one instead of the first and BAM! instant 512x512 map.

Well, mostly. Even though that would make the bg a 512 by 512 map, you'd still need 3 more screenblocks worth of map-data. And in your case you can't put that data after sbb 31 because that's where the VRAM of objects starts. So you'll have to use another sbb instead. 28 for example.

Just create a few easily discernible tiles, and make each of the screenblocks that make up the 512x512 map use those tiles. Load it up in VBA, look at the tile and map viewers and see if you can see the pattern.

king501 wrote:
but it?s quite hard for a guy like me to learn from multiple big source files and track down every piece of code to understand the basic.

this about as minimal as I'd care to get. Any more and I'm really down to raw hex on everything :P.

#90368 - king501 - Thu Jun 29, 2006 11:09 pm

THANKS Cearn!! It's too bad I couldn't use a bigger font for thanking you!! haha

Now I'm really getting the logic behind all this.

#90426 - king501 - Fri Jun 30, 2006 6:12 am

All things considered, even though that I understand more clearly how screenblocks work now, this part confuses me a little;

Code:
// Four tiles, one for each screenblock of the 64x64t map
TILE testTiles[4]=
{
    {{ 0x11111111, 0x0111FF11, 0x011F11F1, 0x011F11F1,
      0x011F11F1, 0x0111FF11, 0x01111111, 0x00000001  }},
    {{ 0x22222222, 0x0222F222, 0x0222FF22, 0x0222F222,
      0x0222F222, 0x022FFF22, 0x02222222, 0x00000002  }},
    {{ 0x33333333, 0x033FFF33, 0x03F33333, 0x033F3333,
      0x0333F333, 0x03FFFF33, 0x03333333, 0x00000003  }},
    {{ 0x44444444, 0x044FFF44, 0x04F44444, 0x044FF444,
      0x04F44444, 0x044FFF44, 0x04444444, 0x00000004  }}
};


How was it possible for you to draw four 8x8 tiles using only 8 elements per array? Isn?t an 8x8 tile supposed to use an array of 64 elements (64 pixels)?

#90434 - DekuTree64 - Fri Jun 30, 2006 6:39 am

king501 wrote:
How was it possible for you to draw four 8x8 tiles using only 8 elements per array? Isn?t an 8x8 tile supposed to use an array of 64 elements (64 pixels)?

Yep, but each pixel is only 4 bits, and each element in that array is 32 bits, so there are 8 pixels in each element. Also notice that each hex digit has 16 possible values, which happens to correspond to 4 bits, so basically each digit is a pixel.

You can arrange them vertically like this for a more clear view of each tile:
Code:
TILE testTiles[4]=
{
    {{ 0x11111111,
       0x0111FF11,
       0x011F11F1,
       0x011F11F1,
       0x011F11F1,
       0x0111FF11,
       0x01111111,
       0x00000001  }},
...

It will actually appear horizontally flipped from that in the game, because numbers go most-significant to least-significant, but it's still a handy way to 'draw' tiles in code :)
_________________
___________
The best optimization is to do nothing at all.
Therefore a fully optimized program doesn't exist.
-Deku

#90448 - king501 - Fri Jun 30, 2006 7:32 am

I would have never guessed it by myself... Thanks!

This part almost sounds like the DaVinci Code :P

#90544 - tepples - Fri Jun 30, 2006 7:24 pm

king501 wrote:
This part almost sounds like the DaVinci Code :P

If you turn Mona Lisa into a GBA tile set, then it's really the Da Vinci Code :-)
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#90594 - king501 - Sat Jul 01, 2006 4:30 am

There's something else I'm not quite sure...

Code:
typedef unsigned char  u8,  byte;
typedef unsigned short u16, hword;
typedef unsigned int   u32, word;

typedef signed char  s8;
typedef signed short s16;
typedef signed int   s32;

typedef struct { u32 data[8];  } TILE;

typedef TILE     CHARBLOCK[512];
typedef u16   SCREENBLOCK[1024];


this line;

typedef TILE CHARBLOCK[512];

if I understand well, it's a new type size? so it's 512 * 32 (u32 from TILE structure)?

and 512*32 = 16 334 (16kb), the size needed for a Char Base Block?

#90631 - Cearn - Sat Jul 01, 2006 11:21 am

Aye, that's exactly it.

The reason behind the TILE struct and CHARBLOCK typedef is that I can have the whole of VRAM mapped as a double-indexed array, which would be tile_mem. tile_mem[cbb][tl] is the tile tl of charblock cbb, which you can either assign a tile to directly (as done in the demo code), or take the address of (&tile_mem[cbb][tl]) and pass to memcpy etc for larger copies. You can do something similar with macros if you like, but actually imposing a memory map over the whole thing feels more natural to me. Just as long as you're not entering tile and screen entry addresses manually.

Leetle more ...

#91295 - king501 - Thu Jul 06, 2006 4:06 am

Can you tell me if I am right?

1 tile = 32bytes?

so we can enter a total of 512 tiles (16384 bytes / 32 bytes) in 1 Char Block?

#91299 - tepples - Thu Jul 06, 2006 4:16 am

king501 wrote:
Can you tell me if I am right?

1 tile = 32bytes?

Correct in 16 colors.

Quote:
so we can enter a total of 512 tiles (16384 bytes / 32 bytes) in 1 Char Block?

A background in a 16-color tiled mode can refer to tiles in one Char Block and the one following it, for a total of 1024.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#91313 - king501 - Thu Jul 06, 2006 7:53 am

so we cannot use 3 char blocks to load graphics tiles and use the 8 last screen blocks only for tile entries?

#91348 - tepples - Thu Jul 06, 2006 4:51 pm

king501 wrote:
so we cannot use 3 char blocks to load graphics tiles and use the 8 last screen blocks only for tile entries?

You can set each background at its own Char Block, but a single background can see only 1024 of the 2048 tiles.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.