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 > another scrolling question

#70919 - ion - Thu Feb 09, 2006 3:53 pm

Hi all,

Q1.
Newbie to the game. have a basic scrolling question. I've loaded up 2 bgs and now I want to scroll ala parallax. From looking around I've seen there are 2 ways a)scroll them different speeds and b)using HBlank.

I'm working on a college project , it's fairly basic. I know you can use these methods but how would one go about it?

Q2.
I've created a 16*16 sprite and converted with Usenti (hopefully with the right settings). It's a basic example where I'm loading in the sprite and display it on the screen.
I use this routine to use DMA (I know tonc says not to use it but it's just a basic sample so not too worried).

Code:
void DMAFastCopy(void* source, void* dest, u32 count, u32 mode)
{
   if (mode == DMA_16NOW || mode == DMA_32NOW)
   {
      REG_DMA3SAD = (unsigned int)source;
      REG_DMA3DAD = (unsigned int)dest;
      REG_DMA3CNT = count | mode;
   }
}


I understand what mode means but what about count? if my ship_1.c file contains this:

Code:
const unsigned short ship_1Tiles[128]=
{
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,
   0x0000,0x0000,0x0000,0x0000,0x0000,0x0000,0xF300,0xF1F3,
........}


then what count should I pass to the DMAFastCopy routine. Likewise for a 256 color palette. My backgrounds use the same routine and work fine. The sprite is not displaying at all.

Q.3
When converted with usenti I get a ship_1.h. here are the contents.

Code:
#define ship_1PalLen 512
extern const unsigned short ship_1Pal[256];

#define ship_1TilesLen 256
extern const unsigned short ship_1Tiles[128];


Why is the ship tiles len define 256 and not 128? is that 256 bytes? why would I need to know that when I'm doing the copying with DMA in 16 or 32bit mode.

Thanks in advance guys.
ION

#70932 - ion - Thu Feb 09, 2006 4:22 pm

alright well here's a picture of tile mem in VBA which clearly shows the ship tiles are there. maybe it's an OAM entry problem.. any ideas?

[Images not permitted - Click here to view it]

ION

#70942 - ion - Thu Feb 09, 2006 4:50 pm

oh man I'm such an eejit... I was forgetting to call update_oam() to copy oam to memory.. Oh well. any answers for the other questions?

ION

#70955 - ScottLininger - Thu Feb 09, 2006 6:09 pm

I'm not sure what questions you still have. Could you post again with just the questions remaining?

In general, I recommend getting your code working *without* DMA at first, with a simple FOR or WHILE loop to copy your data around. Then once that's working, you can turn on the DMA and help isolate any problems.

-Scott

#70969 - Cearn - Thu Feb 09, 2006 8:26 pm

ion wrote:
Code:
#define ship_1PalLen 512
extern const unsigned short ship_1Pal[256];

#define ship_1TilesLen 256
extern const unsigned short ship_1Tiles[128];

The size of an array depends on the number of array elements, and the size of a single element. A byte is, well 1, byte long, short is 2 bytes, int is 4 bytes. So if you have data of a given length, n bytes, you'll have n elements in a byte array, n/2 for a short array and n/4 for an int array. The fooLen #define always gives the number of bytes, but the array type of foo may change.

ion wrote:
I use this routine to use DMA (I know tonc says not to use it but it's just a basic sample so not too worried).

Code:

void DMAFastCopy(void* source, void* dest, u32 count, u32 mode)
{
   if (mode == DMA_16NOW || mode == DMA_32NOW)
   {
      REG_DMA3SAD = (unsigned int)source;
      REG_DMA3DAD = (unsigned int)dest;
      REG_DMA3CNT = count | mode;
   }
}

I think you may have misread, I'm fine with DMA (well, mostly: it can muck up interrupts so I use something else these days). Or maybe I wrote it down wrong. Still, there are more useful DMA functions than this though. For starters, removing the if may be useful.

Anyway, the DMA count is always the number of chunks you need copied. The chunk size depends on whether you use 16bit or 32bit DMA. Divide the byte-count by 2 or 4, respectively.

As for the parallax scrolling: the basic idea is to move things that are further away at a lower speed. Basically, something if you're moving at velocity v, things that are a distance z away move at v/z. You may want to use fixed numbers for the distances and related calculations. And a division LUT. Don't have any specific example I can point you to, though.

#71957 - ion - Wed Feb 15, 2006 5:09 pm

thanks guys. sorry took so long to get back to you.

regarding the scrolling question would updating the scrolling offsets at VBlank suffice or would I need to use HBlank.

#71959 - Cearn - Wed Feb 15, 2006 5:19 pm

That really depends on the kind of parallax you want. You you just need a 2 or 3 layer parallax, extra backgrounds + offsetting at VBlank should be enough. If you want to go for more layers or you've run out of BGs, you'll have to do some HBlank interrupting. It's really up to you here.

#72101 - ion - Thu Feb 16, 2006 1:03 pm

Cheers Cearn.

I'm just doing basic 2 background parallax. I've got it working with this god-ugly hacky code:

Code:
       //Update foreground
      bg0_x += 50;
      if(bg0_x > (256 * 100))
      {
         bg0_x = 0;
      }

      //Update background
      bg1_x += 25;
      if(bg1_x > (256 * 100))
      {
         bg1_x = 0;
      }
      
      REG_BG0HOFS = (bg0_x / 100);
      REG_BG1HOFS = (bg1_x / 100);


Of course I realise it's not the best method but hey it's for a project, it works, and I'm running out of time. I guess I'll still have to learn Fixed Point for projectiles and collisions.. do I?

ION

#72102 - Cearn - Thu Feb 16, 2006 1:27 pm

ion wrote:

Code:
... 100s...

Of course I realise it's not the best method but hey it's for a project, it works, and I'm running out of time. I guess I'll still have to learn Fixed Point for projectiles and collisions.. do I?

Should work.

Fixed point isn't so hard by the way. It's just like working in percentages/decimals only in hex. That is, using 0x100 instead of 100 (in the case of .8 fixeds). Just watch out for shifting (hexa)decimal points in multiplying and dividing. Just like you would in standard decimal mults and divs. Fixed points can be used for much more that just projectiles -- anything that might use floats can be replaced with fixeds.

Btw, you don't have to do the boundary tests: tile-mode background wrap around. Just mask of the final 8 bits ... or not because the GBA will probably do that for you anyway.

Code:

// a #define for the scrolling speed == good idea
// You're trying half-pixel movement/frame right?
// 50/100 = 1/2 = 128/256
#define SCROLL_SPEED 128

bg0_x += SCROLL_SPEED;
bg1_x += SCROLL_SPEED/2;

// assuming bg0_x, bg1_x are already .8 fixeds
REG_BG0HOFS= (bg0_x>>8)&255;
REG_BG1HOFS= (bg1_x>>8)&255;

#72109 - ion - Thu Feb 16, 2006 2:24 pm

cheers again for the reply. I've stuck in your code to test it out. It seems the background skips every couple of frames. would it have something to do with my if statements?


Code:
       if(bg0_x > (256 * 100))
      {
         bg0_x = 0;
      }
      if(bg1_x > (256 * 100))
      {
         bg1_x = 0;
      }


actually when I removed the if(s) the problem disappeared. is this because you're ANDing &255 i.e. (bg0_x>>8)&255 or is that just masking out the .8 fractional part?

I'm sorry for all the questions (although this is the beginners forum).

#72111 - Cearn - Thu Feb 16, 2006 2:51 pm

ion wrote:
cheers again for the reply. I've stuck in your code to test it out. It seems the background skips every couple of frames. would it have something to do with my if statements?


Code:
       if(bg0_x > (256 * 100))
      {
         bg0_x = 0;
      }
      if(bg1_x > (256 * 100))
      {
         bg1_x = 0;
      }


Were you using those ifs with the code I showed? That would be bad because I used proper .8 fixeds (1/256 fractions) while these ifs use percentages (1/100 fractions). Mixing them would mean mixing different kinds of fractions without correcting for the difference, which is always a bad idea. If you really want to keep those ifs, you'd have to test against 256*256, not 256*100.

If time permits it, resize all percentages to use proper fixed point math. Computers don't handle the decimal system particularly well, powers of two are much better. That way you can use AND instead of % and shifts instead of division. The compiler will even do it for you.

ion wrote:
actually when I removed the if(s) the problem disappeared. is this because you're ANDing &255 i.e. (bg0_x>>8)&255 or is that just masking out the .8 fractional part?

That's the AND yes. Like I said, tiled backgrounds wrap around, at 256 so everything is modulo 256 == AND 255. Or 512 and mod 512 if you're using the wide backgrounds, but you get the idea.

You can safely lose the ifs and use AND 255 instead. It's faster, shorter and actually a little safer too.

#72115 - ion - Thu Feb 16, 2006 3:14 pm

cheers man. one other question:

Code:
oam_set_attribute( ship, (OAM_COLOR_256 | OAM_MODE_NORMAL | OAM_SQUARE),
                  OAM_SIZE_16, (tl_id | OAM_PRIORITY(1)) );


I use this function to set up my sprite (I'm bulding my own basic library cos my projects is all about learning gba technology/techniques). My bgs are left as is regarding priority thus bg0 is higher priority than bg1 (according to cowbite). tl_id is the tile id for the current ships frame of animation. I think the OAM_PRIORITY(n) is from tonc (although I can't remember). should calling this function not set display priority behind bg0 and in front of bg1? cos it's not....

ION

#72120 - Cearn - Thu Feb 16, 2006 3:48 pm

ion wrote:
My bgs are left as is regarding priority thus bg0 is higher priority than bg1 (according to cowbite). ... Should calling OAM_PRIORITY not set display priority behind bg0 and in front of bg1? cos it's not....

And it shouldn't.

There are two things at work here. One is priority and the other, for lack of a better word, is bg/obj order. Priority is what you set in the bits of attr2 and REG_BGxCNT. Order is the numbering of the bgs or objs themselves. These are not the same.

By default, the priority of everything is 0. The bits for priority is zero after all. Within a given priority, the bgs and objs are drawn in order (or rather, reverse order: higher numbers are drawn first, leaving lower bgs/objs ar the front). In the same priority, objs/bgs are layered from front to back as
OAM0-OAM127-BG0-BG3. To get different orders (say, bgs in front of sprites), you'd have to up the priority of everything that would normally go in front of it. In your case, what should work is bg0=prio0, the rest prio1.

There is a problem with mixing backgrounds and sprites of different priorities. I'm not sure how to explain this best, but it comes down to that it's best to you should not put a bg between sprites that have conflicting orders and priorities. For example: oam1/prio0 - bg0/prio0 - oam0/prio1 would give artifacts, but oam0/prio0 - bg0/prio0 - oam1/prio1 would be ok. See GBATek:?ttr2 for more on this.

#72132 - poslundc - Thu Feb 16, 2006 4:57 pm

I've heard a lot about this problem but never actually seen it... is it only when the conflicting OBJs overlap? Is a BG required to make it happen? What kind of an artifact does it create? Where is the GPU's algorithm failing to take it correctly into account?

Dan.

#72136 - ion - Thu Feb 16, 2006 5:07 pm

ok well that makes alot more sense. since a sprite takes priority over a bg then setting bg0 to prio0 and everything else to prio1 then bg0 will always be displayed above everything else. ok think I got that. now...

Code:
oam_set_attribute( ship, (OAM_COLOR_256 | OAM_MODE_NORMAL | OAM_SQUARE),
                  OAM_SIZE_16, (tl_id) | OAM_PRIORITY(1) );

I've set up the two bgs as you said and call this but still my ship is being displayed on top of bg0. in OAM viewer in VBA my ships priority is 0. should not (tl_id) | OAM_PRIORITY(1) correctly setup the priority using the this macro (it just shifts the priority like 1 << 10).

#72138 - Cearn - Thu Feb 16, 2006 5:13 pm

poslundc wrote:
I've heard a lot about this problem but never actually seen it... is it only when the conflicting OBJs overlap? Is a BG required to make it happen? What kind of an artifact does it create? Where is the GPU's algorithm failing to take it correctly into account?

Dan.

Cool, I found it again.
http://forum.gbadev.org/viewtopic.php?t=3502
Try the demo that's linked to and select the first option in the menu. The text is sprites and shows through the overlapping background.

#72139 - Cearn - Thu Feb 16, 2006 5:17 pm

ion wrote:

I've set up the two bgs as you said and call this but still my ship is being displayed on top of bg0. In OAM viewer in VBA my ships priority is 0. Should not (tl_id) | OAM_PRIORITY(1) correctly setup the priority using the this macro (it just shifts the priority like 1 << 10).

Should have worked. Maybe you're unsetting it somewhere else? Block out all the other code and check. Don't forget to still update to the real OAM of course.

#72140 - ion - Thu Feb 16, 2006 5:19 pm

sorry sorry sorry... weird but my code is working now... anyway. I think this thread has ran it's course so thanks a million for the help. on to the enemies now...

ION