/*********************************************************************************************************
                                                Les sprites
    Les sprites, aussi appelés objets, sont de petites images qu'on utilise pour tout ce qui bouge.
    Bien que l'arrière-plan soit en général fixe, les objets eux sont très animés et peuvent se déplacer
    n'importe où. La GBA offre un support matériel pour 128 sprites. Ce qui signifie qu'elle dessinera
    directement ces petits lutins en utilisant les effets avec lesquels on les paramètrés. Mais attention,
    le support matériel ne simplifie pas la gestion des objets, il permet juste d'économiser un peu de CPU.
*********************************************************************************************************/

//On garde l'OAM en cache
TypeSprite IN_EWRAM MonOAM[128];
//Pour les rotations/zooms.
pRotData rotData = (pRotData)MonOAM;

//Arguments pour les tailles. Il y en a deux, un pour la forme (0=carré, 1=aplati, 2=vertical)
#define TAILLE_8x8 0,0
#define TAILLE_16x16 0,1
#define TAILLE_32x32 0,2
#define TAILLE_64x64 0,3

#define TAILLE_64x32 1,3

//Crée un nouvel objet
#define CreeObjet(obj_number,char_number,xpos,ypos,obj_mode,obj_shape,obj_size,color_mode,pal_number,prio_to_bg,vflip,hflip,mosaic,rotation,rotation_no,dblsize) \
                        \
                        MonOAM[obj_number].attribut0= \
                        (obj_shape<<14)  | \
                        (color_mode<<13) | \
                        (mosaic<<12)     | \
                        (obj_mode<<10)   | \
                        (rotation<<8)    | \
                        (dblsize<<9)     | \
                        (ypos); \
                        \
                        MonOAM[obj_number].attribut1= \
                        (obj_size<<14)   |\
                        (vflip<<13)      |\
                        (hflip<<12)      |\
                        (rotation_no<<9) |\
                        (xpos);\
                        \
                        MonOAM[obj_number].attribut2= \
                        (pal_number<<12) |\
                        (prio_to_bg<<10) |\
                        (char_number);


//Place l'objet en question aux positions XY. Cela ne modifie pas les autres attributs du sprites
#define PlaceObjetXY(obj_number,xpos,ypos)\
                        MonOAM[obj_number].attribut1 &= 0xFE00;\
                        MonOAM[obj_number].attribut1 |= (xpos);\
                        MonOAM[obj_number].attribut0 &= 0xFF00;\
                        MonOAM[obj_number].attribut0 |= (ypos);

//Détruit le sprite (il ne sera plus visible)
#define DetruitObjet(obj_number)\
                        MonOAM[obj_number].attribut0 = 240;\
                        MonOAM[obj_number].attribut1 = 160;\
                        MonOAM[obj_number].attribut2 = 0;

//Active ou désactive le retournement horizontal ou vertical
#define RetourneObjetH_Oui(obj_number)\
                        MonOAM[obj_number].attribut1 |= 0x1000;

#define RetourneObjetH_Non(obj_number)\
                        MonOAM[obj_number].attribut1 &= ~0x1000;

#define RetourneObjetV_Oui(obj_number)\
                        MonOAM[obj_number].attribut1 |= 0x2000;

#define RetourneObjetV_Non(obj_number)\
                        MonOAM[obj_number].attribut1 &= ~0x2000;

//Change le numéro de tile de l'objet en question.
#define ChangeTileObjet(obj_number,char_number)\
                        ({ MonOAM[obj_number].attribut2 &= 0xFC00;\
                        MonOAM[obj_number].attribut2 |= char_number; })


//Petit moteur de sprites. Entasse simplement les sprites dans la mémoire vidéo et copies les tiles dont
//ils ont besoin.
int objetsUtilises;
int n_tile;

//Contient les données (nombre de sprites/tiles) utilisées jusqu'à maintenant.
typedef struct      {
    int nbreObjetsDeBase;
    int nbreTilesDeBase;
} SPRITE_PARAM;

//Initialise le système de sprites
void InitSprites()      {
    memset(pOAM,0,sizeof(pOAM));
    objetsUtilises=0;
    n_tile=32;
}

//Crée un nouvel objet en utilisant des paramètres standard.
void CreeObjetStandard(unsigned short tiles, unsigned short palette, unsigned short forme, unsigned short taille)        {
    if (objetsUtilises>=127)        //Mémoire déjà pleine?
        return;
    objetsUtilises++;               //Et un objet de plus, un!
    CreeObjet(objetsUtilises,  //Numéro d'objet
    tiles,                  //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
    240,                    //Position X initiale
    160,                    //Position Y initiale
    0,                      //Mode (alpha-blend)
    forme,                  //Forme (0=carrée)
    taille,                 //Taille
    0,                      //Mode palette (1=256 couleurs, 0=16 couleurs)
    palette,                //Numéro de palette si 16 couleurs
    2,                      //Priorité
    0,                      //Retournement vertical
    0,                      //Retournement horizontal
    0,                      //Mode mosaïque (?)
    0,                      //Rotation
    0,                      //N° de rotation
    0);                     //Double-taille (pour rotation)
}

//Fonction spéciale qui crée la boîte de dialogue transparente
void CreeBoite(unsigned short tiles, unsigned short forme, unsigned short taille)        {
    if (objetsUtilises>=127)
        return;
    objetsUtilises++;
    //Création de Mario
    CreeObjet(objetsUtilises,  //Numéro d'objet
    tiles,                  //Numéro de mosaïque (3), <<2 car 16x16 (*4) et <<1 car mode 8 bits (*2)
    240,                    //Position X initiale
    160,                    //Position Y initiale
    1,                      //Mode (alpha-blend)
    forme,                  //Forme (0=carrée)
    taille,                 //Taille
    1,                      //Mode palette (1=256 couleurs, 0=16 couleurs)
    0,                      //Numéro de palette si 16 couleurs
    2,                      //Priorité
    0,                      //Retournement vertical
    0,                      //Retournement horizontal
    0,                      //Mode mosaïque (?)
    1,                      //Rotation
    0,                      //N° de rotation
    1);                     //Double-taille (pour rotation)
}

//Pour le système de sprites. Ajoute un nouveau sprite (les tiles contenues à adr_sprites seront copiées
//à la prochaine VBLANK).
unsigned int AjouteSprite(const unsigned char *adr_sprite, unsigned short taille)        {
    int i;
    CopieDMA((void*)adr_sprite,CharBaseBlock(4)+n_tile,taille>>2,DMA_16im);
    i=n_tile;
    n_tile+=taille;
    return i>>5;
}

//Sauvegarde des paramètres du moteur de sprites
void SauveSpriteParam(SPRITE_PARAM *s)     {
    s->nbreObjetsDeBase=objetsUtilises;
    s->nbreTilesDeBase=n_tile;
}

//Restauration des paramètres du moteur de sprites
void RestoreSpriteParam(SPRITE_PARAM *s, BOOL remplissage)     {
    u32 i;
    objetsUtilises=s->nbreObjetsDeBase;
    n_tile=s->nbreTilesDeBase;
    for (i=objetsUtilises+1;i<128;i++)
        DetruitObjet(i);
}

//Déplace un objet avec support des positions négatives jusqu'à -64 seulement
void PlaceObjetEx(u32 no_objet, s32 x, s32 y)       {
    if (x<0 && x>-64)
        x=512+x;
    if (y<0 && y>-64)
        y=256+y;
    PlaceObjetXY(no_objet,x,y);
}



