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 > sprite rotation problem.

#152898 - ben0bi - Sat Mar 22, 2008 11:14 am

i copy/pasted some tutorial code and created a simple sprite engine for me.

now the problem is, rotating the first sprite affects ALL sprites while rotating the "second" sprite does not work.

i do not know what memory magic i (again) have to use, to make this work.

short: i can only rotate the first sprite, all other sprites are rotated in the same direction. it changes ALL sprites, not only the ones with the same picture....

here is my code, it is much again, but i really dont know where to search for this rotating stuff:

Code:


a=new CSpriteImageInfo; a->Initialize(orangeShuttleTilesLen,orangeShuttleTiles,orangeShuttlePalLen,orangeShuttlePal,OBJSIZE_64);
b=new CSpriteImageInfo; b->Initialize(moonTilesLen,moonTiles,moonPalLen,moonPal,OBJSIZE_32);


int shuttleId=m_Sprites.CreateSprite(a,10,10,300);
int shuttleId2=m_Sprites.CreateSprite(a,100,10,100);
int moonId=m_Sprites.CreateSprite(b,50,10,100);

------------------------------------------------------------------

typedef struct{
   bool used;
    int oamId;
    int width;
    int height;
    int angle;
    SpriteEntry * entry;
} SpriteInfo;

class CSpriteImageInfo
{
protected:
   static int               m_iNEXTTILEMEMADRESS;
   int                     m_iTilesLen;
   int                     m_iPalLen;
   int                     m_iTileMemAdress;

   const unsigned int         *m_pTiles;

   const short unsigned int   *m_pPalette;
   tObjSize               m_objectSize;

public:
   void CreateMemAdress()                  
   {
      m_iTileMemAdress=m_iNEXTTILEMEMADRESS;
      m_iNEXTTILEMEMADRESS+=m_iTilesLen / OAM_BYTES_PER_16_COLOR_TILE;
   }
   static int GetNextAvailableMemAdress(void)   {return m_iNEXTTILEMEMADRESS;};
   int GetMemAdress(void)                  {return m_iTileMemAdress;};
   int GetTilesLen(void)                  {return m_iTilesLen;};
   int GetPalLen(void)                     {return m_iPalLen;};
   tObjSize GetObjSize(void)               {return m_objectSize;};
   const unsigned int *GetTiles(void)         {return m_pTiles;};
   const short unsigned int *GetPalette(void)   {return m_pPalette;};
   
   CSpriteImageInfo()
   {
      Initialize(0,NULL,0,NULL,OBJSIZE_8);
      m_iTileMemAdress=-1;
   }

   void Initialize(int imageLen,const unsigned int *imagePtr, int imagePalLen,const short unsigned int *imagePalette,tObjSize objSize)
   {
      m_iTilesLen=imageLen;
      m_pTiles=imagePtr;
      m_iPalLen=imagePalLen;
      m_pPalette=imagePalette;
      m_objectSize=objSize;
   }
};
   int CreateSprite(CSpriteImageInfo *Image, int posX, int posY, int angle)
   {
      // eventually load the image/s to OAM if this has not happened before.
      int iImageMemAdress=imageLoadToOAM(Image);
      ////// first search an entry to use.
      int emptyOAMID = -1;
      for(int i=0;i<SPRITE_COUNT;i++)
      {
         if(!m_SpriteInfo[i].used)
         {
            emptyOAMID=i;
            break;
         }
      }
      //// found an entry.
      if(emptyOAMID!=-1)
      {
         printf("C\n");
         int width=0;
         int height=0;
         switch(Image->GetObjSize())
         {
            case OBJSIZE_8:
               width=height=8;
               break;
            case OBJSIZE_16:
               width=height=16;
               break;
            case OBJSIZE_32:
               width=height=32;
               break;
            case OBJSIZE_64:
               width=height=64;
               break;
         }
         SpriteInfo * sprInfo = &m_SpriteInfo[emptyOAMID];
         SpriteEntry * OAMEntry = &oam->spriteBuffer[emptyOAMID];

         /* Initialize sprite info struct */
         sprInfo->used=true;
         sprInfo->oamId = emptyOAMID;
         sprInfo->width = width;
         sprInfo->height = height;
         sprInfo->angle = angle;
         sprInfo->entry = OAMEntry;

          /*
         *  Configure attribute 0.
         *
         *  OBJCOLOR_16 will make a 16-color sprite. We specify that we want an
         *  affine sprite (via isRotoscale) here because we would like to rotate
         *  the ship.
         */
         OAMEntry->posY = posY;
         OAMEntry->posX = posX;
         OAMEntry->isRotoscale = true;
         /* This assert is a check to see a matrix is available to store the affine
         * transformation matrix for this sprite. Of course, you don't have to have
         * the matrix id match the affine id, but if you do make them match, this
         * assert can be helpful. */
         assert(!OAMEntry->isRotoscale || (sprInfo->oamId < MATRIX_COUNT));
         OAMEntry->rsDouble = false;
         OAMEntry->objMode = OBJMODE_NORMAL;
         OAMEntry->isMosaic = false;
         OAMEntry->colMode = OBJCOLOR_16;
         OAMEntry->objShape = OBJSHAPE_SQUARE;
         /*
         *  Configure attribute 1.
         *
         *  rsMatrixId refers to the location of affine transformation matrix. We
         *  set it to a location computed with a macro. OBJSIZE_64, in our case
         *  since we are making a square sprite, creates a 64x64 sprite.
         */
         OAMEntry->rsMatrixIdx = ATTR1_ROTDATA(sprInfo->oamId);
         OAMEntry->objSize = Image->GetObjSize();//OBJSIZE_32;//OBJSIZE_64;

         /*
         *  Configure attribute 2.
         *
         *  Configure which tiles the sprite will use, which priority layer it will
         *  be placed onto, which palette the sprite should use, and whether or not
         *  to show the sprite.
         */
         OAMEntry->tileIdx = iImageMemAdress;
         OAMEntry->objPriority = OBJPRIORITY_0;
         OAMEntry->objPal = sprInfo->oamId;

         /* Rotate the sprite */
         spriteRotate(&oam->matrixBuffer[sprInfo->oamId], sprInfo->angle);

         /*************************************************************************/

         /* Copy over the sprite palette */
         dmaCopyHalfWords(OAM_SPRITE_DMA_CHANNEL,
                     Image->GetPalette(),
                     &SPRITE_PALETTE[sprInfo->oamId *
                                     OAM_COLORS_PER_PALETTE],
               Image->GetPalLen());
         
         printf("-------------------------------\n");
         printf("OAM ID: %i/%i (real)\n", emptyOAMID,sprInfo->oamId);
         printf("TileMem    : %08x\nNextTileMem: %08x\n",Image->GetMemAdress(),Image->GetNextAvailableMemAdress());
         return emptyOAMID;
      }
      return -1;
   };


   // returns the mem adress of the picture and sets it in the given struct.
   // returns the same adress as bevore if it was loaded before.
   int imageLoadToOAM(CSpriteImageInfo *Image)
   {
      if(Image->GetMemAdress()==-1)
      {
         printf("Not Existing\n");
         // load the image to OAM.
         /* Copy the sprite graphics to sprite graphics memory */
         Image->CreateMemAdress();
         dmaCopyHalfWords(OAM_SPRITE_DMA_CHANNEL,
               Image->GetTiles(),
                     &SPRITE_GFX[Image->GetMemAdress() * OAM_MAINSPR_OFFSET_MULTIPLIER],
                     Image->GetTilesLen());
      }
      return Image->GetMemAdress();
   }


void CSpriteEngine::spriteRotate(SpriteRotation *spriteRotation, u16 angle)
{
   s16 s = SIN[angle & OAM_SPRITE_ANGLE_MASK]>>4;
   s16 c = COS[angle & OAM_SPRITE_ANGLE_MASK]>>4;

   spriteRotation->hdx=c;
   spriteRotation->hdy=s;
   spriteRotation->vdx=-s;
   spriteRotation->vdy=c;
}

#152901 - Cearn - Sat Mar 22, 2008 12:02 pm

ben0bi wrote:
i copy/pasted some tutorial code and created a simple sprite engine for me.

now the problem is, rotating the first sprite affects ALL sprites while rotating the "second" sprite does not work.

i do not know what memory magic i (again) have to use, to make this work.

short: i can only rotate the first sprite, all other sprites are rotated in the same direction. it changes ALL sprites, not only the ones with the same picture....

here is my code, it is much again, but i really dont know where to search for this rotating stuff:

Code:

         OAMEntry->rsMatrixIdx = ATTR1_ROTDATA(sprInfo->oamId);

The ATTRx_ macros should only be used for full 16-bit attributes, not the named bitfields. Most of the macros shift the parameter so that it can be ORred into the attribute. With bitfields this shifting is done automatically ; you just write the number directly. If you use the shifted form for a bitfield, you'd probably get 0 as the result.

Code:
objId= 1;                       // Object index 1
mtxId= ATTR1_ROTDATA(objId);    // mtxId= 1<<9 = 0x0200
obj->rsMatrixIdx= mtxId;        // Set object's matrix id to (0x0200&31) = 0.
                                //   Oops.


Also, be aware that there are only 32 matrices, but 128 object slots.

ben0bi wrote:
here is my code, it is much again, but i really dont know where to search for this rotating stuff:
Much of the NDS is similar or identical to the GBA. For overlapping parts, read Tonc. For everything else, go to GBATek. If you're completely new, the GBA might be a better starting point, as the tools and tutorials are more mature.

ben0bi wrote:
Code:

         switch(Image->GetObjSize())
         {
            case OBJSIZE_8:
               width=height=8;
               break;
            case OBJSIZE_16:
               width=height=16;
               break;
            case OBJSIZE_32:
               width=height=32;
               break;
            case OBJSIZE_64:
               width=height=64;
               break;
         }

Note that this code will only work for square objects. For tall and wide objects, not only will the width and height be different, but the number in the OBJ_SIZE_ macro won't correspond to the actual dimensions. A better strategy to get the object's pixel sizes would be to create a look-up table and simply look them up, rather than use a switch-block.

Code:
// Usage:
// oam_sizes[shape][size][0] is width
// oam_sizes[shape][size][1] is height
const u8 oam_sizes[3][4][2]=
{
    { { 8, 8}, {16,16}, {32,32}, {64,64} },
    { {16, 8}, {32, 8}, {32,16}, {64,32} },
    { { 8,16}, { 8,32}, {16,32}, {32,64} },
};

#152916 - silent_code - Sat Mar 22, 2008 4:58 pm

benobi, cearn's the man!
but if you'd like, send me your code, i'll setup my nds dev env. today and check it out. i remember having odd sprite rotations myself (shearing and the like), but that was due to sh***y tutorials! tonc really gets it to the point.

again, if you'd like, i pm'ed you an offer to help. :^)