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 > oam

#59015 - ninogenio - Fri Oct 28, 2005 12:57 am

i was wondering if any one has a oam example or knows of a ds oam tut i used oam on the gba before but im not quite sure how the ds works with oam sprites also can oam sprites be done in 16 bit color. cheers for any help.

#59042 - Mollusk - Fri Oct 28, 2005 11:15 am

The OAM works the same as the gba OAM... but doubled, one for each screen.

You can get some info here : http://www.drunkencoders.com/documents/DS/ndslib.htm#_Sprite_Data
or here http://neimod.com/dstek/

You can also have 16 bit sprites, but from what I've tested, they must be 128 pixels large (even if you only use a 8x8 sprite), so that takes up a lot of memory, I guess... Check the first link for info on how to do a 16 bit sprite (I think it's putting the object mode to 3 (0 - normal, 1 - alpha, 2 - window, 3 - 16 bit, if I remember correctly)
_________________
PAlib official forum : http://www.palib.info
PAlib official tutorials: http://www.palib.info/wiki
Updates, help, code examples, tutorials, etc...

#59781 - ninogenio - Fri Nov 04, 2005 2:28 am

after quite a lengthy play with sprites tonight ive got this which im pretty sure is close but the grahpics get scrambled quite badly i realize the problem my spritewell line of sprites really are 126/7 18 by ten high now im trying to drop these into a 32 by 32 sprite and i dont know how to get it to move down a line when it hits the end of the eighteen pixels.

Code:
#include <nds.h>
#include "fat_driver/gbamp_cf.c" 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <nds/arm9/console.h>
#include "tiles.h"


#define NUM_SPRITES 128   

sSpriteEntry OAMCopy[128];

typedef struct
{
   int x,y;
   int dx, dy;
   sSpriteEntry* oam;   
   int gfxID;
}Sprite;


void MoveSprite(Sprite* sp)
{
   sp->oam->attribute[1] &= 0xFE00;
   sp->oam->attribute[1] |= (sp->x & 0x01FF);
 
   sp->oam->attribute[0] &= 0xFF00;
   sp->oam->attribute[0] |= (sp->y & 0x00FF);
}


void initOAM(void)
{
   int i;

   for(i = 0; i < 128; i++)
        {
      OAMCopy[i].attribute[0] = ATTR0_DISABLED;
   }   
}

void updateOAM(void)
{
   unsigned int i;
   
   for(i = 0; i < 128 * sizeof(sSpriteEntry) / 4 ; i++)
   {
      ((uint32*)OAM)[i] = ((uint32*)OAMCopy)[i];
   }
}

void draw_map(u16);
void levelloader(u16 level_no);
void read_width_height(u16);


u16 instr(char* ,char* ,u16);
void readline(char* ,char** );
void readfile(char* ,char** );
char* mid(char* ,u16 ,u16 );
u16 len(char*);
void closefile(char*);

u16* vram;

typedef struct{
     u16 height;
     u16 width;
     u16 tilewidth;
     u16 tileheight;
     u16 counter;
}LEVEL;

LEVEL levels[60];
u16 map[50][50];
u16 anim[50][50];

u16 background[256*192];
u16 obj_number;

Sprite sprites[NUM_SPRITES];

int main(){

       

        powerON(POWER_ALL);

   irqInit();
   irqSet(IRQ_VBLANK,0);
        WAIT_CR=0xe800;
        vramSetMainBanks(   VRAM_A_MAIN_SPRITE,        //A and B maped consecutivly as sprite memory
                        VRAM_B_MAIN_SPRITE,        //this gives us 256KB which is the max
                        VRAM_C_MAIN_BG_0x6000000,  //map C to background memory
                        VRAM_D_LCD                 //not using D
                        );
   
        //set the video mode
        videoSetMode(  MODE_0_2D |
                       DISPLAY_SPR_ACTIVE |    //turn on sprites
                       DISPLAY_BG0_ACTIVE |    //turn on background 0
                       DISPLAY_SPR_1D |        //this is used when in tile mode
                       DISPLAY_SPR_1D_BMP      //and this in bitmap mode
                     );
       
        initOAM();
        for (int x=0; x<126*10 ; x++)
                 SPRITE_GFX[x]=tiles[x]|BIT(15);
        levelloader(1);
        draw_map(1);

        while(1)
        {
                swiWaitForVBlank();
                updateOAM();   
        }

   return(0);
}

void levelloader(u16 level_no)
{
            read_width_height(level_no);
            char* filein;
            char fname[128];
            u16 x=0;
            u16 point_index_t_or_f=0;
            sprintf(fname, "/BREAK_OUT_MANIA/levels/level%d.txt", level_no);
            readfile(fname,&filein);

            char* point_index;
            char* maps;
            readline(filein,&maps);
            free(maps);
            readline(filein,&maps);
            free(maps);
            for(int yx=0 ; yx<levels[level_no].height ; yx++)
            {
                    readline(filein,&maps);
                    x=0;

                    for(int ix=0 ; ix<levels[level_no].width ; ix++)
                    {
                            point_index=mid(maps,x,instr(maps,",",x));

                            if (len(point_index)>1) point_index_t_or_f=1;
                            else point_index_t_or_f=0;

                            if (point_index_t_or_f)
                            {
                                  map[ix][yx]=atol(mid(maps,x,1));
                                  anim[ix][yx]=atol(mid(point_index,2,3));
                                  x=x+3+1;
                            }
                            else
                            {
                                  map[ix][yx]=0;
                                  x=x+1+1;
                            }
                    }
                    free(maps);
             }
             closefile(filein);

             levels[level_no].counter=0;
             for (int yx=1 ; yx<levels[level_no].height ; yx++)
             {
                     for (int ix=1 ; ix<levels[level_no].width ; ix++)
                     {
                              if (anim[ix][yx]>0) levels[level_no].counter=levels[level_no].counter+1;
                     }
             }
}



void draw_map(u16 level_no)
{
        obj_number=0;
        for (int yx=0 ; yx<levels[level_no].height ; yx++)
        {
                 for (int xx=0 ; xx<levels[level_no].width;xx++)
                 {
                          if (anim[xx][yx]>0)
                          {
                              //random place and speed
                         sprites[obj_number].x = xx*levels[level_no].tileheight;
                         sprites[obj_number].y = yx*levels[level_no].tilewidth;
   
                         sprites[obj_number].oam = &OAMCopy[obj_number];
                         sprites[obj_number].gfxID = anim[xx][yx];
   
                         //set up our sprites OAM entry attributes
                         sprites[obj_number].oam->attribute[0] = ATTR0_BMP; 
                         sprites[obj_number].oam->attribute[1] = ATTR1_SIZE_32;
                         sprites[obj_number].oam->attribute[2] = ATTR2_ALPHA(1)|sprites[obj_number].gfxID;

                              MoveSprite(&sprites[obj_number]);
                              obj_number++;                               

                          }
                 }
        }
}


void read_width_height(u16 level_no)
{
         u16 position;
         char* filein;
         char* line;

         char fname[128];
         sprintf(fname, "/BREAK_OUT_MANIA/levels/level%d.txt", level_no);
         readfile(fname,&filein);

         readline(filein,&line);
         position=instr(line,",",0);
         
         levels[level_no].tilewidth=atol(mid(line,0,position));
         levels[level_no].tileheight=atol(mid(line,position+1,len(line)));
         free(line);

         readline(filein,&line);

         position=instr(line,",",0);

         levels[level_no].width=atol(mid(line,0,position));
         levels[level_no].height=atol(mid(line,position+1,len(line)));
         free(line);
         closefile(filein);
}




u16 instr(char* name,char* seek_char,u16 startpos)
{
    char *start = name+startpos;
    return (u16) (strstr(start, seek_char)-start);
}

u16 start_pos;
u16 end_pos;
void readline(char* filehandle,char** buffer)
{
        start_pos=end_pos;
        u16 temp_instr_point=instr(filehandle,"\n",start_pos);
        if (temp_instr_point)
        {
                  end_pos=end_pos+temp_instr_point;
                  filehandle[end_pos]='\0';
                 
                 *buffer=(char*) malloc (end_pos-start_pos+1);
                  strncpy(*buffer, filehandle+start_pos, temp_instr_point+1);
                  end_pos++;
         }
}

void readfile(char* filename,char** filein)
{
        FAT_InitFiles();
        int handle = FAT_fopen(filename, "r"); 
        int size=FAT_GetFileSize();
        *filein = (char*) malloc (size+1);
        for (int x=0 ; x<size ;x++)
        {
            (*filein)[x]=FAT_fgetc(handle);
        }
        FAT_fclose(handle);
}

void closefile(char* filename)
{
     
        free(filename);
        end_pos=0;
        start_pos=0;
}

char tmp[200];
char* mid(char *src, u16 pos, u16 siz)
{
        strncpy(tmp, src+pos, siz);
        tmp[siz]='\0';
        return tmp;
}

u16 len(char* stri)
{
       return strlen(stri);
}

void draw_text(char* dtext,u16 tst,u16 ist)
{
         for (int xst=0 ; xst<len(dtext) ; xst++)
                  draw_anim_image(vram , text , tst+(xst*8) , ist , 8 , 8 , (u16)dtext[xst]-32 , 632);
}


if you guys could help that would be really great as ive been trying to get this working for quite a while and i think im pretty close.

#59789 - Joat - Fri Nov 04, 2005 3:23 am

There isn't any way to make a 32x32 sprite render only 18x10 pixels without padding that data out to 32x32 (although there is a 32x16 size, which will waste less space). If you want to stretch 18x10 out to 32x32, you can do that, although using rot/scale hardware won't look as good as doing it beforehand in your art package.

I'm not certain if this is what you're trying to do however. If not, please clarify.
_________________
Joat
http://www.bottledlight.com

#59821 - chishm - Fri Nov 04, 2005 9:28 am

A bit off topic, but that include:
ninogenio wrote:
Code:
#include "fat_driver/gbamp_cf.c"
really should be including the header. This will cause all manner of problems otherwise.
That is, use:
Code:
#include "fat_driver/gbamp_cf.h"

You just have to make sure you include the fat_driver directory in the list of source directories.
_________________
http://chishm.drunkencoders.com
http://dldi.drunkencoders.com

#59843 - ninogenio - Fri Nov 04, 2005 2:35 pm

yes thank chrism i do it the correct way in my full game this was just a little test proggy i can enlarge the sprites to 32x16 thats no problem but can i then use the hardware to scale the sprite down to 18*10 and how might i modify the above code to correctly set 32x16 sprites.

#59867 - ninogenio - Fri Nov 04, 2005 8:42 pm

ive now drawn my sprites 32x32x7 in paint and it still isnt working the 32x32 sprite it shows is all scrambled.also how do i get to diffrent tiles in sprite_gfx just say i wanted to assign sprite 2 the second tile in sprite_gfx.

Code:
#include <nds.h>
#include "fat_driver/gbamp_cf.c" 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "jpeg_lib/gba-jpeg.h"
#include "jpeg_lib/gba-jpeg-decode.c"
#include <nds/arm9/console.h>
#include "tiles.h"
#include "text.h"
#include "bat.h"

#define NUM_SPRITES 128   

sSpriteEntry OAMCopy[128];

typedef struct
{
   int x,y;
   int dx, dy;
   sSpriteEntry* oam;   
   int gfxID;
}Sprite;


void MoveSprite(Sprite* sp)
{
   sp->oam->attribute[1] &= 0xFE00;
   sp->oam->attribute[1] |= (sp->x & 0x01FF);
 
   sp->oam->attribute[0] &= 0xFF00;
   sp->oam->attribute[0] |= (sp->y & 0x00FF);
}


void initOAM(void)
{
   int i;

   for(i = 0; i < 128; i++)
        {
      OAMCopy[i].attribute[0] = ATTR0_DISABLED;
   }   
}

void updateOAM(void)
{
   unsigned int i;
   
   for(i = 0; i < 128 * sizeof(sSpriteEntry) / 4 ; i++)
   {
      ((uint32*)OAM)[i] = ((uint32*)OAMCopy)[i];
   }
}

void grab_a_graphic(char* filename,u16* buffer,u16 width,u16 height);
void drawgraphic(u16* buffer,u16* image,u16 width,u16 height,u16 x_pos,u16 y_pos);
void draw_map(u16);
void levelloader(u16 level_no);
void read_width_height(u16);
void draw_anim_image(u16* buffer,u16* image,u16 width,u16 height,u16 tilewidth,u16 tileheight,u16 frame_no,u16 obj_width);
void draw_text(char* dtext,u16 tst,u16 ist);

u16 instr(char* ,char* ,u16);
void readline(char* ,char** );
void readfile(char* ,char** );
char* mid(char* ,u16 ,u16 );
u16 len(char*);
void closefile(char*);

u16* vram;

typedef struct{
     u16 height;
     u16 width;
     u16 tilewidth;
     u16 tileheight;
     u16 counter;
}LEVEL;

LEVEL levels[60];
u16 map[50][50];
u16 anim[50][50];

u16 background[256*192];
u16 obj_number;

Sprite sprites[NUM_SPRITES];

int main(){

       

        powerON(POWER_ALL);

   irqInit();
   irqSet(IRQ_VBLANK,0);
        WAIT_CR=0xe800;
        vramSetMainBanks(   VRAM_A_MAIN_SPRITE,        //A and B maped consecutivly as sprite memory
                        VRAM_B_MAIN_SPRITE,        //this gives us 256KB which is the max
                        VRAM_C_MAIN_BG_0x6000000,  //map C to background memory
                        VRAM_D_LCD                 //not using D
                        );
   
        //set the video mode
        videoSetMode(  MODE_0_2D |
                       DISPLAY_SPR_ACTIVE |    //turn on sprites
                       DISPLAY_BG0_ACTIVE |    //turn on background 0
                       DISPLAY_SPR_1D |        //this is used when in tile mode
                       DISPLAY_SPR_1D_BMP      //and this in bitmap mode
                     );
        //videoSetModeSub(MODE_0_2D|DISPLAY_SPR_ACTIVE|DISPLAY_BG0_ACTIVE|DISPLAY_SPR_1D|DISPLAY_SPR_1D_BMP);
         //vramSetMainBanks(VRAM_A_LCD, VRAM_B_LCD, VRAM_C_SUB_BG, VRAM_D_SUB_SPRITE);
     
        //vram=VRAM_A;

        initOAM();
        for (int x=0; x<224*32 ; x++)
                 SPRITE_GFX[x]=tiles[x]|BIT(15);
        levelloader(1);
        draw_map(1);

       
       

        //draw_text("NINO IS THE GREATEST!!",10,10);
        while(1)
        {
                swiWaitForVBlank();
                updateOAM();   
        }

   return(0);
}

void grab_a_graphic(char* filename , u16* buffer , u16 width , u16 height)
{
        FAT_InitFiles();
        int handle = FAT_fopen(filename, "r"); 
        int size=FAT_GetFileSize();
        char* text = (char*) malloc (size+1);
       
        while (!FAT_feof(handle))
        {
               FAT_fread((void*)text, size, 1, handle);
               
        }
        FAT_fclose(handle);

        //now decompress image and drop it in an array
        WAIT_CR &= ~0x80;
        JPEG_DecompressImage((const unsigned char*)text , buffer , width , height);
        WAIT_CR |= 0x80;
        free(text);
}

void drawgraphic(u16* buffer,u16* image,u16 width,u16 height,u16 x_pos,u16 y_pos)
{
       buffer += y_pos * SCREEN_WIDTH + x_pos;
       for(int i = 0; i < height; ++i)
       {
               u16* line = buffer + (SCREEN_WIDTH * i);
               u16* color= image + (width * i);
               for(int j = 0; j < width; ++j)
               {
                      *line++ = (*color++)|BIT(15);
               }
       }
}


void draw_anim_image(u16* buffer,u16* image,u16 width,u16 height,u16 tilewidth,u16 tileheight,u16 frame_no,u16 obj_width)
{
       buffer += height * SCREEN_WIDTH + width;
       image += tilewidth*frame_no;
       for(int i = 0; i < tileheight; ++i)
       {
               u16* line = buffer + (SCREEN_WIDTH * i);
               u16* color= image + (obj_width * i);
               for(int j = 0; j < tilewidth; ++j)
               {
                      *line++ = (*color++)|BIT(15);
               }
       }
}


void levelloader(u16 level_no)
{
            read_width_height(level_no);
            char* filein;
            char fname[128];
            u16 x=0;
            u16 point_index_t_or_f=0;
            sprintf(fname, "/BREAK_OUT_MANIA/levels/level%d.txt", level_no);
            readfile(fname,&filein);

            char* point_index;
            char* maps;
            readline(filein,&maps);
            free(maps);
            readline(filein,&maps);
            free(maps);
            for(int yx=0 ; yx<levels[level_no].height ; yx++)
            {
                    readline(filein,&maps);
                    x=0;

                    for(int ix=0 ; ix<levels[level_no].width ; ix++)
                    {
                            point_index=mid(maps,x,instr(maps,",",x));

                            if (len(point_index)>1) point_index_t_or_f=1;
                            else point_index_t_or_f=0;

                            if (point_index_t_or_f)
                            {
                                  map[ix][yx]=atol(mid(maps,x,1));
                                  anim[ix][yx]=atol(mid(point_index,2,3));
                                  x=x+3+1;
                            }
                            else
                            {
                                  map[ix][yx]=0;
                                  x=x+1+1;
                            }
                    }
                    free(maps);
             }
             closefile(filein);

             levels[level_no].counter=0;
             for (int yx=1 ; yx<levels[level_no].height ; yx++)
             {
                     for (int ix=1 ; ix<levels[level_no].width ; ix++)
                     {
                              if (anim[ix][yx]>0) levels[level_no].counter=levels[level_no].counter+1;
                     }
             }
}



void draw_map(u16 level_no)
{
        obj_number=0;
        for (int yx=0 ; yx<1/*levels[level_no].height*/ ; yx++)
        {
                 for (int xx=0 ; xx<1/*levels[level_no].width*/;xx++)
                 {
                          if (anim[xx][yx]>0)
                          {
                              //random place and speed
                         sprites[obj_number].x = xx*levels[level_no].tileheight;
                         sprites[obj_number].y = yx*levels[level_no].tilewidth;
   
                         sprites[obj_number].oam = &OAMCopy[obj_number];
                         sprites[obj_number].gfxID = 0;//anim[xx][yx];
   
                         //set up our sprites OAM entry attributes
                         sprites[obj_number].oam->attribute[0] = ATTR0_BMP; 
                         sprites[obj_number].oam->attribute[1] = ATTR1_SIZE_32;
                         sprites[obj_number].oam->attribute[2] = ATTR2_ALPHA(1)|sprites[obj_number].gfxID;

                              MoveSprite(&sprites[obj_number]);
                              obj_number++;                               

                          }
                 }
        }
}


void read_width_height(u16 level_no)
{
         u16 position;
         char* filein;
         char* line;

         char fname[128];
         sprintf(fname, "/BREAK_OUT_MANIA/levels/level%d.txt", level_no);
         readfile(fname,&filein);

         readline(filein,&line);
         position=instr(line,",",0);
         
         levels[level_no].tilewidth=atol(mid(line,0,position));
         levels[level_no].tileheight=atol(mid(line,position+1,len(line)));
         free(line);

         readline(filein,&line);

         position=instr(line,",",0);

         levels[level_no].width=atol(mid(line,0,position));
         levels[level_no].height=atol(mid(line,position+1,len(line)));
         free(line);
         closefile(filein);
}




u16 instr(char* name,char* seek_char,u16 startpos)
{
    char *start = name+startpos;
    return (u16) (strstr(start, seek_char)-start);
}

u16 start_pos;
u16 end_pos;
void readline(char* filehandle,char** buffer)
{
        start_pos=end_pos;
        u16 temp_instr_point=instr(filehandle,"\n",start_pos);
        if (temp_instr_point)
        {
                  end_pos=end_pos+temp_instr_point;
                  filehandle[end_pos]='\0';
                 
                 *buffer=(char*) malloc (end_pos-start_pos+1);
                  strncpy(*buffer, filehandle+start_pos, temp_instr_point+1);
                  end_pos++;
         }
}

void readfile(char* filename,char** filein)
{
        FAT_InitFiles();
        int handle = FAT_fopen(filename, "r"); 
        int size=FAT_GetFileSize();
        *filein = (char*) malloc (size+1);
        for (int x=0 ; x<size ;x++)
        {
            (*filein)[x]=FAT_fgetc(handle);
        }
        FAT_fclose(handle);
}

void closefile(char* filename)
{
     
        free(filename);
        end_pos=0;
        start_pos=0;
}

char tmp[200];
char* mid(char *src, u16 pos, u16 siz)
{
        strncpy(tmp, src+pos, siz);
        tmp[siz]='\0';
        return tmp;
}

u16 len(char* stri)
{
       return strlen(stri);
}

void draw_text(char* dtext,u16 tst,u16 ist)
{
         for (int xst=0 ; xst<len(dtext) ; xst++)
                  draw_anim_image(vram , text , tst+(xst*8) , ist , 8 , 8 , (u16)dtext[xst]-32 , 632);
}

#59915 - ninogenio - Sat Nov 05, 2005 1:56 pm

thanks very much guys :(

#60001 - LOst? - Sun Nov 06, 2005 5:26 am

ninogenio wrote:
thanks very much guys :(


I suggest you test your graphics data directly from the ROM, and if it is not scrambled, then you know where to locate the problem.

Normally if graphics are scrambled:
1) You try to write to the VRAM using bytes instead of words. Simply use a (u16*) pointer to the const u8 graphics.

2) You have choosen a tile base bank that is being overwritten by the map base, or something else.

3) You have put the sprite settings to 16 colors when you use 256 color graphics, or reverse.


If you have all these things working, then it is problably your fat reading code, or your graphics are corrupted from the beginning.
_________________
Exceptions are fun

#60043 - ninogenio - Sun Nov 06, 2005 5:50 pm

the graphics arent corrupted there in 16bit bmp format and i put them in spritegfx as a 1d array.im pretty sure my problem is coming from here.

sprites[obj_number].gfxID = anim[xx][yx];

as what i do is say i want my sprite to have the second graphic in sprite gfx i would do this but i dont think it looks right.

sprites[obj_number].gfxID = 2;