#include <mygba.h>
#include "dma.h"
#include "ecran.h"
#include "touches.h"

//Dans le dossier Res: un tileset, une palette et une map!
#include "Res/Tower.til.c"
#include "Res/Tower.pal.c"
#include "Res/Tower.map.c"

//Copie un morceau de Tower_map sur ScreenBlock 31 avec l'offset défini par defilX et defilY.
void CopieMap(int defilX, int defilY);
#define REG_GREENSWAP *(volatile unsigned short*) 0x4000002

int main(void)         {
    int defilX, defilY;                         //Défilement en X et en Y
    
    //On va utiliser le mode 0 et activer le BG0.
    REG_DISPCNT=1<<8;
    //Et maintenant, il faut paramétrer le BG0. J'utilise le mode palette 256 couleurs
    //(bit 7) et le screenblock 31 (bits 8 à 12).
    REG_BG0CNT=1<<7|31<<8;
    REG_GREENSWAP=1;

    //Copie du tileset vers le charblock 0.
    CopieObjet(Tower_tiles,CharBaseBlock(0));
    //Copie la palette (Tower_palette) vers la palette physique.
    CopieObjet(Tower_palette,Palette);
    
    //Initialisation des variables
    defilX=defilY=0;                         //Initialise le défilement au sommet à gauche
    

    //Boucle principale. Sur GBA, contrairement au PC, tous les programmes/jeux tournent
    //en boucle, et ne se terminent jamais. C'est le joueur qui choisira quand le terminer
    //en plaçant l'interrupteur sur "Off". Mais là, on n'a pas à s'en soucier puisque
    //ce procédé est mécanique et non logiciel :)
    while(1)        {
        //Dans un premier temps, je vais vérifier quelles touches sont appuyées et
        //déplacer l'écran en fonction de cela.

        /*
            1) Test des touches
            --------------------
            REG_TOUCHES contient l'état des touches (1 si pressées, 0 sinon). Pour tester
            l'état d'une seule touche, il faut effectuer un ET bit à bit qui mettra à zéro
            les bits qui ne nous intéressent pas. Par exemple:
            Etat de REG_TOUCHES: 11 1001 0001 1110
            Masque TOUCHE_START: 00 0000 0000 1000
            Résultat d'un AND:   00 0000 0000 1000 -> START est pressé!
        */

        /*
            2) Déplacement à l'écran
            ------------------------
            Rappelez-vous que les coordonnées x,y sont définies ainsi:
            0 --------------- x ------------------> max
            |
            |
            |
            y
            |
            |
            |
            V
            max                                      x max et y max
            Ceci explique donc les modifications de defilX et defilY en fonction des touches
            appuyées.
            Les positions maximales et minimales sont également vérifiées pour éviter de
            sortir de la map. Peut-être arriverez-vous à déterminer la formule qui me
            permet de trouver ces valeurs?
        */

        if (REG_TOUCHES&TOUCHE_DROITE && defilX<(64-30)*8)
            defilX++;
        if (REG_TOUCHES&TOUCHE_GAUCHE && defilX>0)
            defilX--;
        if (REG_TOUCHES&TOUCHE_BAS && defilY<(32-20)*8)
            defilY++;
        if (REG_TOUCHES&TOUCHE_HAUT && defilY>0)
            defilY--;

        /*
            Copie d'un morceau de map
            -------------------------
            
            L'écran fait 240x160 pixels, soit 30x20 pixels. Mais on doit laisser une
            mosaïque de marge en haut et en bas, car si l'écran est défilé, on va voir
            partiellement la mosaïque d'en dessus, et partiellement celle d'en dessous.
            L'écran fera donc 31x21 mosaïques à ce moment-là (dont deux qui ne seront pas
            complètes).
            Et comme la taille de la map est limitée, on ne peut la copier complètement
            d'un coup. C'est pourquoi j'extrais un morceau de la grande map (64x32)
            correspondant à ce dont on a besoin sur l'écran (31x21).
        */
        
        CopieMap(defilX,defilY);

        /*
            Defilement
            ----------
            Le défilement nécessaire est partiellement effectué par CopieMap. En effet,
            pour un offset de 16 pixels par exemple, CopieMap ne copiera qu'à partir du
            bloc n° 2 (un bloc faisant 8x8 pixels). Comme vous ne verrez pas les blocs 0
            et 1, mais le 2 au sommet de l'écran, cela vous donnera l'impression que
            l'écran a défilé de deux blocs, soit de 16 pixels).
            Mais le défilement résiduel (chaque mosaïque faisant 8 pixels, on ne peut pas
            trouver d'unité plus basse que celle-ci lors de la copie du morceau de map)
            est effectué par le matériel, grâce aux registres ci-dessous.
        */
        REG_BG0HOFS=defilX%8;
        REG_BG0VOFS=defilY%8;


        //Il faut toujours se synchroniser avec le balayage vertical, sinon le programme
        //ira beaucoup trop vite!
        AttendVSync();
    }
    
    return 0;
}


void CopieMap(int defilX, int defilY)         {
    int i,j;                                    //Index de boucle
    unsigned short (*Map)[32];                  //Située sur un screenblock

    /*
        Le défilement donné par defilX et defilY est défini au pixel près. Mais dans notre
        cas, il doit être effectué à la mosaïque près. Le défilement supplémentaire à
        l'intérieur des mosaïques est fait par le matériel à l'intérieur de la boucle
        principale.
    */
    defilX/=8, defilY/=8;

    //On va copier la map sur le screenblock 31 puisque BG0CNT est configuré ainsi.
    Map=ScreenBaseBlock(31);

    //Pour la copie, une boucle for fera l'affaire.
    for (j=0;j<21;j++)
        for (i=0;i<31;i++)
            Map[j][i]=Tower_map[defilY+j][defilX+i];
}


/* END OF FILE */

