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 > Beginner OAM problems (SOLVED)

#148894 - rook02 - Fri Jan 11, 2008 7:13 pm

Okay, I'm not sure what I'm doing wrong. I've been trying to see how exactly the OAM works, so that I'll be able to just throw in arrays of pixel data in it. However, I can't even seem to load a small 8x8 sprite into it correctly.

The sprite displays, but it's broken in vertical lines or something.

Here's what I did after doing initOAM();

Code:

   int index = 0;
   oam[index].attribute[0] = ATTR0_COLOR_256 | ATTR0_ROTSCALE;
   oam[index].attribute[1] = ATTR1_ROTDATA(0) | ATTR1_SIZE_8;
   oam[index].attribute[2] = 0;

   const unsigned short palette[2]=
   {
      0x001,0x01F,
   };

   const unsigned char test[64]=
   {
      0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
      0x01,0x01,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
      0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x01,0x01,
      0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
   };

   dmaCopy ( palette, SPRITE_PALETTE, 2 * sizeof ( unsigned short ) );
   dmaCopy ( test, &SPRITE_GFX[0 * 16], 64 * sizeof ( unsigned char ));

   swiWaitForVBlank();
   updateOAM();


What did I miss here? Any help would be appreciated.


Last edited by rook02 on Fri Jan 25, 2008 8:03 pm; edited 1 time in total

#148895 - eKid - Fri Jan 11, 2008 7:23 pm

What is initOAM()?

#148900 - theoxylo - Fri Jan 11, 2008 7:45 pm

eKid wrote:
What is initOAM()?


I think he means from patatersoft 6.0 http://patatersoft.info/manual_online.html#id2534738, cut and pasted here:

Code:
void initOAM(tOAM * oam) {
    /*
     * For all 128 sprites on the DS, disable and clear any attributes they
     * might have. This prevents any garbage from being displayed and gives
     * us a clean slate to work with.
     */
    for (int i = 0; i < SPRITE_COUNT; i++) {
        oam->spriteBuffer[i].attribute[0] = ATTR0_DISABLED;
        oam->spriteBuffer[i].attribute[1] = 0;
        oam->spriteBuffer[i].attribute[2] = 0;
    }
    for (int i = 0; i < MATRIX_COUNT; i++) {
        /* If you look carefully, you'll see this is that affine trasformation
         * matrix again. We initialize it to the identity matrix, as we did
         * with backgrounds
         */
        oam->matrixBuffer[i].hdx = 1 << 8;
        oam->matrixBuffer[i].hdy = 0;
        oam->matrixBuffer[i].vdx = 0;
        oam->matrixBuffer[i].vdy = 1 << 8;
    }

    /* Be sure to wait for vblank before trying to update the OAM. */
    swiWaitForVBlank();
    updateOAM(oam);
}

#148901 - Cearn - Fri Jan 11, 2008 7:57 pm

The initOAM() found in the libnds examples do not set the OAM affine matrices. Without that matrix affine sprites (ATTR0_ROTSCALE or ATTR0_ROTSCALE_DOUBLE) will just use the center pixel's color for the whole sprite (see also tonc : affine objects). Use the initOAM() version theoxylo pasted.

#148902 - eKid - Fri Jan 11, 2008 8:00 pm

Ah, okay, thanks.
I still can't pinpoint the problem with the current information :(. More source code please :P
The first snippet posted looks correct, the problem must be elsewhere.

edit: oops 1 post too late

#148914 - tepples - Fri Jan 11, 2008 10:27 pm

Perhaps if you do it without rot/scale, it might be easier to figure things out.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.

#148934 - rook02 - Sat Jan 12, 2008 6:12 am

Sadly, there isn't much else as this is mostly test code.

This is how I set up my writable copy of the OAM:

Code:
   SpriteEntry oam[128];
   SpriteRotation *spriteRotation = (SpriteRotation*)oam;

   int i;
   for (i = 0; i < 128; i++) {
      oam[i].attribute[0] = ATTR0_DISABLED;
      oam[i].attribute[1] = 0;
      oam[i].attribute[2] = 0;
   }
   for (i = 0; i < 32; i++) {
      spriteRotation[i].hdx = 1<<8;
      spriteRotation[i].hdy = 0;
      spriteRotation[i].vdx = 0;
      spriteRotation[i].vdy = 1<<8;
   }
   swiWaitForVBlank();
   updateOAM ( oam );


And here's. the updateOAM code:
Code:
void updateOAM( SpriteEntry * oam )
{
   DC_FlushAll();
   dmaCopy(oam, OAM, 128*sizeof(SpriteEntry));
}


And the VRAM banks are configured the way they are in the Patatersoft manual. That's about it. :|

#148935 - eKid - Sat Jan 12, 2008 6:22 am

That code looks correct, may I see your whole main() function? The problem is most likely in there. Also, a screenshot of the broken sprite might help.

#148938 - rook02 - Sat Jan 12, 2008 6:39 am

That's about it, really, but I guess there's no harm in posting the whole thing..

Code:
int main ()
{
   powerON(POWER_ALL_2D);

   irqInit();
   irqSet(IRQ_VBLANK, 0);
   lcdMainOnBottom();

   vramSetMainBanks(VRAM_A_MAIN_BG_0x06000000,
                     VRAM_B_MAIN_BG_0x06020000,
                     VRAM_C_SUB_BG_0x06200000,
                     VRAM_D_LCD);

   vramSetBankE(VRAM_E_MAIN_SPRITE);

   /*  Set the video mode on the main screen. */
   videoSetMode(MODE_5_2D | // Set the graphics mode to Mode 5
                 DISPLAY_BG2_ACTIVE | // Enable BG2 for display
                 DISPLAY_BG3_ACTIVE | // Enable BG3 for display
                 DISPLAY_SPR_ACTIVE | // Enable sprites for display
                 DISPLAY_SPR_1D       // Enable 1D tiled sprites
                 );

   /*  Set the video mode on the sub screen. */
   videoSetModeSub(MODE_5_2D | // Set the graphics mode to Mode 5
                    DISPLAY_BG3_ACTIVE); // Enable BG3 for display
               */
   videoSetModeSub(MODE_0_2D | DISPLAY_BG0_ACTIVE);
   consoleDemoInit();

   swiWaitForVBlank();

   SpriteEntry oam[128];
   SpriteRotation *spriteRotation = (SpriteRotation*)oam;

   int i;
   for (i = 0; i < 128; i++) {
      oam[i].attribute[0] = ATTR0_DISABLED;
      oam[i].attribute[1] = 0;
      oam[i].attribute[2] = 0;
   }
   for (i = 0; i < 32; i++) {
      spriteRotation[i].hdx = 1<<8;
      spriteRotation[i].hdy = 0;
      spriteRotation[i].vdx = 0;
      spriteRotation[i].vdy = 1<<8;
   }
   swiWaitForVBlank();
   updateOAM ( oam );

   int index = 0;

   oam[index].attribute[0] = ATTR0_COLOR_256 | ATTR0_ROTSCALE;
   oam[index].attribute[1] = ATTR1_ROTDATA(0) | ATTR1_SIZE_8;
   oam[index].attribute[2] = 0;


   const unsigned short palette[2]=
   {
      0x001,0x01F,
   };

   const unsigned char test[64]=
   {
      0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
      0x01,0x01,0x00,0x01,0x01,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
      0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x01,0x01,
      0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,0x01,
   };

   dmaCopy ( palette, SPRITE_PALETTE, 2 * sizeof ( unsigned short ) );
   dmaCopy ( test, &SPRITE_GFX[0 * 16], 64 * sizeof ( unsigned char ));

   swiWaitForVBlank();
   updateOAM();

}


It looks like this:
http://i254.photobucket.com/albums/hh92/rookthedemokid/nogba.png

#148940 - eKid - Sat Jan 12, 2008 7:33 am

I found the problem.
updateOAM uses dma to copy the sprites to OAM memory. But DMA cannot transfer data from the arm9 stack space. You are declaring 'oam' inside the main function, so its going into the stack space.
The garbled sprite that you saw is just a bunch of uninitialized 16-color sprites (the OAM memory never got updated).
To fix this, either move 'oam' outside of the main function to global memory, or change the dmaCopy in updateOAM to a software copy:
Code:
void updateOAM( SpriteEntry * oam )
{
   DC_FlushAll();
   int i;
   for( i = 0; i < 128*(sizeof(SpriteEntry)/2); i++ )
   {
      OAM[i] = ((u16*)oam)[i];
   }
}

#148941 - rook02 - Sat Jan 12, 2008 8:04 am

Ahh... I never would've figured that one out myself. Thanks. :D