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 > Really Basic BG Question

#153906 - Jinroh - Tue Apr 08, 2008 2:36 am

I have a BG that I'm displaying and I'm trying to scroll it, however when I change my camX and camY and put them in the BG_HOFS and BG_VOFS registers my map scrolls like an Insane Man.

Code:
typedef struct
{
   u16 *tileData; //Pointer To the Tile Data In VRAM
   u16 *mapData; //Pointer To the Map Data In VRAM
   u8 mosaic; //Enable Mosaic Effect
   u8 colourMode; //16 or 256
   u8 number; //The Background Number 0-3
   u16 size; //The Size of the Background 128x128 256x256 or 512x512
   u8 charBaseBlock; //Tell Which Character Base Block To Use
   u8 screenBaseBlock; //Tell Which Screen Base Block To Use
   u8 wrapAround; //Does The Map Wrap At Edges?
   s16 camX; //Map Camera X
   s16 camY; //Map Camera Y
   s32 rotX; //Rotation Cam X
   s32   rotY; //Rotation Cam Y
   s16 PA, PB, PC, PD; //Rotation Attributes
}Background;

Background BG;

void enableBG(Background *bg)
{
   u16 temp;

   bg->tileData = (u16*)CharBaseBlock(bg->charBaseBlock);
   bg->mapData = (u16*)ScreenBaseBlock(bg->screenBaseBlock);
   temp = bg->size | (bg->charBaseBlock << CHAR_SHIFT) |
      (bg->screenBaseBlock << SCREEN_SHIFT) | bg->colourMode |
         bg->mosaic;

   switch(bg->number)
   {
      case 0:
         REG_BG0CNT = temp;
         REG_DISPCNT |= BG0ENABLE;
         break;

      case 1:
         REG_BG1CNT = temp;
         REG_DISPCNT |= BG1ENABLE;
         break;

      case 2:
         REG_BG2CNT = temp;
         REG_DISPCNT |= BG2ENABLE;
         break;

      case 3:
         REG_BG3CNT = temp;
         REG_DISPCNT |= BG3ENABLE;
         break;
   }
}

void updateBG(Background *bg)
{
                //Just Assume It's not Rotational for now
   switch(bg->number)
   {
      case 0:
         REG_BG0HOFS = bg->camX;
         REG_BG0VOFS = bg->camY;
         break;

      case 1:
         REG_BG1HOFS = bg->camX;
         REG_BG1VOFS = bg->camY;
         break;

      case 2:
         REG_BG2HOFS = bg->camX;
         REG_BG2VOFS = bg->camY;
         break;

      case 3:
         REG_BG3HOFS = bg->camX;
         REG_BG3VOFS = bg->camY;
         break;
   }
}

....

BG.number = 2;
   BG.charBaseBlock = 0;
   BG.screenBaseBlock = 28;
   BG.colourMode = BG_COLOR256;
   BG.size = ROTBG_SIZE_256x256;
   BG.mosaic = BG_MOSAIC_ENABLE;
   BG.camX = 120;
   BG.camY = 80;

   int i = 0;
   
   enableBG(&BG);

   for(i = 0; i < 256; i++)
      BGPaletteMem[i] = CoolMap_cmap[i];

   u16 *tilePtr = (u16*)CoolMap_blockgfx;
   for(i = 0; i < (sizeof(CoolMap_blockgfx)/2); i++)
      BG.tileData[i] = tilePtr[i];

   for(int y = 0; y < 32; y++)
      for(int x = 0; x < 32; x++)
         BG.mapData[(y * 32) + x] = (u16)CoolMap_map[y][x];


I mean it looks like it's scrolling, but it is just waaaay too fast.

THANKS!
_________________
The lone Wolf howls, driven by pride he presses on. Knowing not where he goes, but only where he wants to be.
~Me~

#153909 - Dwedit - Tue Apr 08, 2008 5:29 am

You didn't post any of the code that moves the camera. You are waiting for vblank...right?
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#153930 - silent_code - Tue Apr 08, 2008 3:18 pm

hope you're using fixed point maths. ;^)

#153950 - Jinroh - Tue Apr 08, 2008 5:42 pm

Code:
while(1)
   {
      WaitForVBlank();
    
      //Wait Until The Screen Is Finished Drawing;
     if(KEY_DOWN(KEYDOWN))
        BG.camY++;

     if(KEY_DOWN(KEYUP))
        BG.camY--;

     if(KEY_DOWN(KEYLEFT))
        BG.camX--;

     if(KEY_DOWN(KEYRIGHT))
        BG.camX++;

     updateBG(&BG);
   }


Camera Movement Code.
_________________
The lone Wolf howls, driven by pride he presses on. Knowing not where he goes, but only where he wants to be.
~Me~

#153951 - eKid - Tue Apr 08, 2008 5:47 pm

What does your WaitForVBlank() look like? :)

#153954 - Jinroh - Tue Apr 08, 2008 5:54 pm

Code:
void WaitForVBlank()
{
   #define ScanlineCounter *(volatile u16*)0x4000006 //Counts through the vertical scanlines until we get a blank
   while(ScanlineCounter < 160){}
}


Here it is, thanks.
_________________
The lone Wolf howls, driven by pride he presses on. Knowing not where he goes, but only where he wants to be.
~Me~

#153956 - silent_code - Tue Apr 08, 2008 5:57 pm

and again... you're scrolling 60 pixel per second - that's fast!
use fixed point math instead!

that means you do an additional shift when assigning the new scroll values to the hw bg. no other changes needed. e.g. ">> 1" will half your scroll rate:
Code:
    REG_BG0HOFS = (bg->camX >> 1);
    REG_BG0VOFS = (bg->camY >> 1);

try that!

EDIT: fixed a dumb typo (per second instead of frame) ;^)


Last edited by silent_code on Tue Apr 08, 2008 7:19 pm; edited 1 time in total

#153957 - eKid - Tue Apr 08, 2008 5:59 pm

Theres your problem. That function will only wait until the vblank period, without checking if it was already in the vblank period. Add
Code:
while(ScanlineCounter >= 160){}

to the beginning of that function. (You're probably firing hundreds of times during the vblank period).

Also, polling the VCOUNT register like that really isn't recommended (it uses 100% cpu and eats up the battery). You should be using the SWI that waits for the VBlank interrupt. I'm not sure what setup you have so I can't explain more about that.

#153958 - Jinroh - Tue Apr 08, 2008 6:00 pm

Thanks a plenty for the advice. Will do the changes right quick.
_________________
The lone Wolf howls, driven by pride he presses on. Knowing not where he goes, but only where he wants to be.
~Me~

#153960 - Jinroh - Tue Apr 08, 2008 6:25 pm

VBLANK Fix Did the Trick Thanks Guys.
_________________
The lone Wolf howls, driven by pride he presses on. Knowing not where he goes, but only where he wants to be.
~Me~

#153974 - Dwedit - Tue Apr 08, 2008 8:57 pm

Don't poll the scanline counter. Use Libgba/Libnds's code to install an interrupt handler, then use the code from the library to wait for vblank.

Code:

irqInit();
irqEnable(IRQ_VBLANK);


then to wait for vblank:
Code:

VBlankIntrWait();  //on GBA
swiWaitForVBlank(); //on NDS


Why do it this way? These use the BIOS functions which switch the GBA into low power mode while it's waiting. The Scanline polling loop keeps using full power.
_________________
"We are merely sprites that dance at the beck and call of our button pressing overlord."

#154081 - Jinroh - Thu Apr 10, 2008 6:38 pm

Thanks Dwedit I figured I'd need an interrupt handler sooner or later for things like Sound, but VBLANKing is another good thing. Thanks.
_________________
The lone Wolf howls, driven by pride he presses on. Knowing not where he goes, but only where he wants to be.
~Me~