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.

Beginners > New to the Scene - Big map question

#68554 - Chaotic Harmony - Wed Jan 25, 2006 5:53 pm

Hi - I'm new to the GBA Dev scene. I've only been coding on it for about a week, so far I've just about managed to get sprites working and 128x128 tiled backgrounds. I've got a question about how to go about making bigger backgrounds than that.

Some background: I decided to get started by porting a simple game I made years ago to the GBA - a game I originally made in Qbasic, called "The Hunt".

[Images not permitted - Click here to view it] <- Screenshot
Click here to download (about 100KB, works in DOS and Windows) <- Game

It's a pretty simple game - nothing more that a few sprites, a scrolling background and some collision detection. Unfortunately, I've run into one technical problem - the game's map size is about 1500x20 (there's no vertical scrolling, just one big horizonal level).

Anyway, no doubt it's probably really easy to do, but I'm having trouble with making big maps. If I try to make a map buffer of even 32x32 tiles (256x256), I get an error from the comilper, saying something like that it's too big. It seems that I'm restricted to an array of 16x16, so I must be doing something wrong somewhere...

So basically I just want to know - how do you get really big arrays working? Do I have to split the map up and feed it into the tile memory? Am I doing something wrong? Is there an easier way to do it?

(I don't have the code on me right now, but I can bring it in tomorrow if nessicary... I'm hoping this is a kinda trivial problem that I can fix with one line...)
_________________
http://www.distractionware.com

#68565 - poslundc - Wed Jan 25, 2006 6:45 pm

When you say 32x32 tiles, do you mean 32x32 indices (single numbers) or a 32x32 set of 8x8 BGR pixel values?

If it's the latter, then you're definitely going to run out of memory. You only have 32K of fast (default) RAM, and an array of that size would consume 128K. You need to store your tiles in the ROM as const data, and load them directly into VRAM.

Dan.

#68572 - Chaotic Harmony - Wed Jan 25, 2006 7:42 pm

It's the former, I'm afraid... Both the map and the tiles are defined as unsigned chars.

What about this storing tiles in ROM as const data thing though? I haven't come across it before...
_________________
http://www.distractionware.com

#68774 - Chaotic Harmony - Thu Jan 26, 2006 7:13 pm

I still need a solution, and I've got my code with me today!

Alright, so stripping it down to what's absolutely essential:

Code:

#include "gba\gba.h"
#include "graphics\cars.h"

u8 tileSet[8*8*3] = {1,1,1,1,1,1,1,1,
                               1,1,1,1,1,1,1,1,
                               1,1,1,1,1,1,1,1,
                               1,1,1,1,1,1,1,1,
                               1,1,1,1,1,1,1,1,
                               1,1,1,1,1,1,1,1,
                               1,1,1,1,1,1,1,1,
                               1,1,1,1,1,1,1,1,

                               2,2,2,2,2,2,2,2,
                               2,2,2,2,2,2,2,2,
                               2,2,2,2,2,2,2,2,
                               2,2,2,2,2,2,2,2,
                               2,2,2,2,2,2,2,2,
                               2,2,2,2,2,2,2,2,
                               2,2,2,2,2,2,2,2,
                               2,2,2,2,2,2,2,2,

                               3,3,3,3,3,3,3,3,
                               3,3,3,3,3,3,3,3,
                               3,3,3,3,3,3,3,3,
                               3,3,3,3,3,3,3,3,
                               3,3,3,3,3,3,3,3,
                               3,3,3,3,3,3,3,3,
                               3,3,3,3,3,3,3,3,
                               3,3,3,3,3,3,3,3};

u8 map[16*16] = {
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
        1,0,3,0,3,0,3,3,3,0,3,0,0,0,0,1,
        1,0,3,0,3,0,3,0,0,0,3,0,0,0,0,1,
        1,0,3,3,3,0,3,3,0,0,3,0,0,0,0,1,
        1,0,3,0,3,0,3,0,0,0,3,0,0,0,0,1,
        1,0,3,0,3,0,3,3,3,0,3,3,3,0,0,1,
        1,0,0,0,3,0,0,0,0,3,0,0,0,0,0,1,
        1,0,0,0,3,0,0,0,3,0,3,0,0,0,0,1,
        1,0,0,0,3,0,0,0,3,0,3,0,0,0,0,1,
        1,0,0,0,3,0,0,0,3,0,3,0,0,0,0,1,
        1,0,0,0,3,3,3,0,0,3,0,0,0,0,0,1,
        1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
        1,0,2,2,2,2,2,2,2,2,2,2,2,2,0,1,
        1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,
        1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};


That's how I'm defining my tiles and my 16x16 map. It's just a test until I can get the thing working.

Now here's how I'm implementing it:

Code:

// ---- In main:
        u16* vramMap = (u16*)SCREEN_BASE_BLOCK(31);
        u16* vramTiles = (u16*)MAP_BASE_BLOCK(0);
        u16* mapP = (u16*)map;
        u16* tileSetP = (u16*)tileSet;

        REG_DISPCNT = MODE_2 | BG2_ENABLE | OBJ_ENABLE | OBJ_MAP_1D;
        BGPaletteMem[0] = RGB16(0,0,0);
        BGPaletteMem[1] = RGB16(0,8,16);
        BGPaletteMem[2] = RGB16(0,16,31);
        BGPaletteMem[3] = RGB16(31,0,0);

        //Initilise the Tiles
        for(i=0; i<16*16/2; i++) vramMap[i] = mapP[i];
        for(i=0; i<8*8*3/2; i++) vramTiles[i] = tileSetP[i];

        REG_BG2CNT = BG_COLOR_256 | ROTBG_SIZE_128x128
                   | (31 << SCREEN_SHIFT) | (0 << CHAR_SHIFT);


Now, all this works perfectly. But say I go back to my "map" array, and change that to map[32*32] (and fill it out appropriatly), I get these error messages from the compiler, even if I leave all the other code untouched.

Code:

arm-elf-gcc -I./ -Igba -mthumb-interwork -mthumb -O2 -Wall -c hunt.c -o hunt.o
arm-elf-gcc -specs=gba.specs -mthumb-interwork -mthumb  hunt.o graphics/cars.o
-o hunt.elf
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .data is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram0 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram1 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram2 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram3 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram4 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram5 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram6 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram7 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram8 is not within region iwram
f:\coding\devkitpro\devkitarm\bin\..\lib\gcc\arm-elf\4.0.2\..\..\..\..\arm-elf\bin\ld.exe:
address 0x30082f0 of hunt.elf section .iwram9 is not within region iwram
"make": *** [hunt.elf] Error 1


It seems that that array is just too big for the game. Why is this? I'm new to this, so I don't know what I'm doing wrong...

I suspect I've got a "variable size" problem somewhere with the pointers, but when I fiddle around with them it messes up the display. This is the only way I've managed to get it working.

Any advice?
_________________
http://www.distractionware.com

#68776 - poslundc - Thu Jan 26, 2006 7:27 pm

Is the array in cars.h declared as const?

If not, it's going into IWRAM, and most likely blowing your stack.

Regardless, there's no reason (at least with your current design) for you to keep your map[] and tileSet[] in RAM, and it's a bad architecture to pursue on the GBA. They should be moved into ROM by declaring them const as well, and then copied directly from there into VRAM.

Dan.

#68777 - wintermute - Thu Jan 26, 2006 7:29 pm

The GBA has 256K of ewram, 32K of iwram and 32M of ROM.

With the default crtls initialised data goes into iwram,

Data which will not be changed should be placed in ROM by declaring the arrays as const. This will include all your graphics data and probably all your maps.

#68784 - Chaotic Harmony - Thu Jan 26, 2006 7:48 pm

Ah, I see... I didn't know about that, thanks :) I'll give that a try when I get home.
_________________
http://www.distractionware.com

#68812 - tepples - Thu Jan 26, 2006 10:18 pm

poslundc wrote:
there's no reason (at least with your current design) for you to keep your map[] and tileSet[] in RAM, and it's a bad architecture to pursue on the GBA.

Unless you want to make your program compatible with MBV2, XBOO, or GBA Movie Player. For this you use the "multiboot" setup file (-specs=gba_mb.specs), which automatically moves everything that would get put in ROM into EWRAM.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#68937 - Chaotic Harmony - Fri Jan 27, 2006 2:18 pm

This fixed it - thanks a million!

I'll post more questions here when I inevitably have them.
_________________
http://www.distractionware.com

#69390 - Chaotic Harmony - Mon Jan 30, 2006 2:33 pm

Work on the game is progressing quite well - I've posted a screenshot and a ROM of what I've got done so far on my website:

http://www.distractionware.com/?p=43

Still quite a bit to do, but I think it's coming along quite nicely.
_________________
http://www.distractionware.com

#69748 - Chaotic Harmony - Wed Feb 01, 2006 5:31 pm

I've got another problem - I was wondering if anyone could help.

Basically, while I managed to get a scrolling background working in ROT mode, I need a few extra tiles, so I've started converting to TEXT mode. The only thing is, I can't get the map to display, and I can't see what I'm doing wrong. I think I might be moving the screen data into vram in the wrong way, but I don't know how.

Here's the code, stripped down to what's relavent:

Code:

#include "gba\gba.h"
#include "graphics\cars.h"
#include "graphics\tiles.h"
#include "data\roaddata.h"

u8 screenmap[32*32];


Just including all the graphics and defining a buffer to hold the screenblock entries.

Code:

void PlotTile(int x, int y, int t){
  x = x<<1; y = y<<6; t=t<<2;
        screenmap[x+y]=t;
        screenmap[x+y+1]=t + 1;
        screenmap[x+y+32]=t + 2;
        screenmap[x+y+33]=t + 3;
}


I'm using 16x16 tiles, so I use this function to plot the 8x8 tiles onto the screenmap buffer. There's probably a better way to do it, but it works ok...

Code:

//in main
        u16* vramMap = (u16*)SCREEN_BASE_BLOCK(20);
        u16* vramTiles = (u16*)MAP_BASE_BLOCK(0);
        u16* screenmapP = (u16*)screenmap;

        REG_DISPCNT = MODE_0 | BG0_ENABLE | OBJ_ENABLE | OBJ_MAP_1D;

        //Filling Screenmap...
        for(j=0; j<10; j++){
          for(i=0; i<16; i++){
                  PlotTile(i,j, map[xpos+i+(800*j))]); //Where 800 is the width of the map.
          }
  }


        for(i=0; i<512; i++) vramMap[i] = screenmapP[i]; //32*32/2
        for(i=0; i<9600; i++) vramTiles[i] = tilesData[i]; //8*8*256/2
        for(i=0; i<256; i++) BGPaletteMem[i] = tilesPalette[i];

        REG_BG0CNT = BG_COLOR_256 | TEXTBG_SIZE_256x256 |
                     (20 << SCREEN_SHIFT) | (0 << CHAR_SHIFT);


I just get garbage on the screen when I do this. Any ideas why?
_________________
http://www.distractionware.com

#69750 - poslundc - Wed Feb 01, 2006 5:54 pm

Chaotic Harmony wrote:
I just get garbage on the screen when I do this. Any ideas why?


Text maps are not the same thing as rotational maps. Read a tutorial or look at the spec to see how text backgrounds are formatted.

Dan.

#69752 - Chaotic Harmony - Wed Feb 01, 2006 6:06 pm

Oh - so basically text maps take up twice as much memory?

I'm not at my home computer right now, so I can't try it out - just to be sure, will this adjustment work? (or have I got the wrong idea?)

Code:

for(i=0; i<512; i++){
   vramMap[i*2] = 0;
   vramMap[(i*2)+1] = screenmapP[i];
}

//instead of
for(i=0; i<512; i++) vramMap[i] = screenmapP[i]; //32*32/2


_________________
http://www.distractionware.com

#69781 - poslundc - Wed Feb 01, 2006 9:01 pm

The short answer is you're still going to have problems because vramMap is a u16 pointer and screenmapP is a u8 pointer, so your code is not correctly copying from one to the other.

Fix this problem, but a tip when doing so: upgrade both to u16 rather than down to u8, because VRAM has a special hardware quirk that makes 8-bit reads and writes work incorrectly.

Dan.

#69788 - Chaotic Harmony - Wed Feb 01, 2006 10:18 pm

That makes sense - I'll give it a try later. Thanks!
_________________
http://www.distractionware.com

#69795 - tepples - Wed Feb 01, 2006 10:59 pm

Chaotic Harmony wrote:
Oh - so basically text maps take up twice as much memory?

Yes, but the tile data for a text background might take less memory because it's allowed to be 4 bit per pixel.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#69858 - Cearn - Thu Feb 02, 2006 1:05 pm

Chaotic Harmony wrote:
Oh - so basically text maps take up twice as much memory?

No .. well yes, but also no. Text maps are formatted differently than affine maps, and one of those differences happens to be that the screen entries are twice as big.

Chaotic Harmony wrote:
I'm not at my home computer right now, so I can't try it out - just to be sure, will this adjustment work? (or have I got the wrong idea?)
Code:
for(i=0; i<512; i++){
   vramMap[i*2] = 0;
   vramMap[(i*2)+1] = screenmapP[i];
}

//instead of
for(i=0; i<512; i++) vramMap[i] = screenmapP[i]; //32*32/2

No that won't work, for a number of reasons. Firstly, screenmapP is a (u16*) pointer to a map that has 8bit screen entries. (poslundc, screenmap is (u8*), screenmapP is (u16*)). When you start copying this to vramMap, you'll still compose one text screen entry (u16) out of two affine screen entries (u8), which is exactly why you're getting garbage now. The only difference with what you have now is that you'll also have zeroed out gaps between everything because of "vramMap[i*2]= 0;".

Text screen entries (SE) are 2 bytes long; their contents are a tile index plus extras. Affine screen entries (ASE) are 1 byte long, and only have a tile index. Which is exactly what you have now. So what you need to do is take that tile index of the ASE and use it to make SEs. You're close to doing that, just not quite there.
Code:
// u16 *vramMap;
// u8  *screenmap;
for(i=0; i<32*32; i++)
    vramMap[i] = screenmap[i];

The implicit type-conversion between u8 and u16 take care of the format difference. This code gets rid of the garbage, but as the whole point was to be able to use more tiles, you'll have to create maps with more than 8 bits/entry anyway.

poslundc wrote:
because VRAM has a special hardware quirk that makes 8-bit reads and writes work incorrectly.

That's only for writes. Byte-reads work fine.

#69862 - Chaotic Harmony - Thu Feb 02, 2006 2:26 pm

Well, I've got it working - thanks for the help everyone. This has been pretty educational!

I've got the text mode working (once I realised that you need to use 16bits instead of 8 for text mode, it became pretty obvious why what I was doing wouldn't work... doh) - I have more problems, but I've got an idea of how to approach it.

Incidently, here's what I've managed to accomplish so far:

{Click to download the ROM (68KB)}

Considering I didn't know the first thing about GBA programming only a fortnight ago, I'm pretty chuffed with it :)
_________________
http://www.distractionware.com