/**************************************************************************
ANIMATION : 10 éléments graphiques bougent à l'écran
            avec 3 formes et 2 comportements
            (rebond simple ou changement de direction au hasard)

            Par rapport au 1_0 on a juste ajouté
            des champs à la structure et quelques
            lignes dans les sous programmes

            MAIN ET PROTTYPES IDENTIQUES AU 1_0
       ( plus d'intervention sur le programme principal
         pour modifier des aspects de "détails" )
**************************************************************************/


#include <allegro.h>
#include <time.h>

// Nombre d'acteurs fixe :
//    le tableau d'acteurs sera déclaré et utilisé en "automatique"
//    t_acteur tab[NACTEUR];

// Une constante est nécessaire car on ne peut pas
// (en principe en C standard) utiliser une taille variable
// pour déclarer un tableau automatique.
#define NACTEUR 10


/****************************/
/*     STRUCTURE ACTEUR     */
/*  devra aller dans un .h  */
/****************************/

// données personnelles de chaque acteur qui se déplace
typedef struct acteur
{
    // coordonnée (du coin sup. gauche)
    int posx, posy;

    // vecteur deplacement
    int depx, depy;

    // tailles : horizontal/vertical
    int tx,ty;

    // couleur de l'élément graphique
    int couleur;

    // type :   0 rectangle   1 ellipse   2 triangle
    //          ( codes arbitraires : convention )
    int type;

    // comportement :   0 inertie     1 inertie + changements aléatoires
    //                  ( codes arbitraires : convention )
    int comportement;

} t_acteur;


/*****************************/
/*     PROTOTYPES            */
/*  devront aller dans un .h */
/*****************************/

// Allouer et initialiser un acteur
t_acteur * creerActeur();

// Remplir un tableau avec des acteurs créés
void remplirTabActeurs(t_acteur * tab[NACTEUR]);


// Actualiser un acteur (bouger ...)
void actualiserActeur(t_acteur *acteur);

// Gérer l'évolution de l'ensemble des acteurs
void actualiserTabActeurs(t_acteur * tab[NACTEUR]);


// Dessiner un acteur sur une bitmap bmp
void dessinerActeur(BITMAP *bmp, t_acteur *acteur);

// Dessiner l'ensemble des acteurs sur une bitmap bmp
void dessinerTabActeurs(BITMAP *bmp,t_acteur * tab[NACTEUR]);


/******************************************/
/* PROGRAMME PRINCIPAL                    */
/* initialisation puis boucle d'animation */
/******************************************/

int main()
{
    // Le tableau regroupant tous les acteurs
    // c'est un tableau de pointeurs sur structures t_acteurs
    t_acteur * mesActeurs[NACTEUR];

    // BITMAP servant de buffer d'affichage (double buffer)
    BITMAP *page;

    // On va utiliser du hasard
    srand(time(NULL));

    // Lancer allegro et le mode graphique
    allegro_init();
    install_keyboard();

    set_color_depth(desktop_color_depth());
    if (set_gfx_mode(GFX_AUTODETECT_WINDOWED,800,600,0,0)!=0)
    {
        allegro_message("prb gfx mode");
        allegro_exit();
        exit(EXIT_FAILURE);
    }


    // CREATION DU BUFFER D'AFFICHAGE à la taille de l'écran
    page=create_bitmap(SCREEN_W,SCREEN_H);
    clear_bitmap(page);


    // Initialisation aléatoire des paramètres des acteurs :
    // remplir le tableau avec des acteurs alloués et initialisés
    remplirTabActeurs(mesActeurs);


    // Boucle d'animation (pas d'interaction)
    while (!key[KEY_ESC])
    {
        // 1) EFFACER POSITIONs ACTUELLEs SUR LE BUFFER
        //    ON EFFACE TOUT LE BUFFER ! (c'est plus simple)
        clear_bitmap(page);

         // 2) DETERMINER NOUVELLEs POSITIONs
        actualiserTabActeurs(mesActeurs);

        // 3) AFFICHAGE NOUVELLEs POSITIONs SUR LE BUFFER
        dessinerTabActeurs(page,mesActeurs);

        // 4) AFFICHAGE DU BUFFER MIS A JOUR A L'ECRAN
        blit(page,screen,0,0,0,0,SCREEN_W,SCREEN_H);

        // 5) ON FAIT UNE PETITE PAUSE à chaque fois sinon ça va trop vite...
        rest(20);
    }

    return 0;
}
END_OF_MAIN();


/************************************************/
/*     DEFINITIONS DES SOUS-PROGRAMMES          */
/*  devront aller dans un autre .c : acteurs.c  */
/************************************************/


// Allouer et initialiser (aléatoirement) un acteur
t_acteur * creerActeur()
{
    // pointeur sur l'acteur qui sera créé (et retourné)
    t_acteur *acteur;

    // Création (allocation)
    acteur = (t_acteur *)malloc(1*sizeof(t_acteur));

    // Initialisation

    acteur->tx = rand()%40+40;
    acteur->ty = rand()%40+40;

    // Position aléatoire (on tient compte de la taille...)
    acteur->posx = rand()%(SCREEN_W - acteur->tx);
    acteur->posy = rand()%(SCREEN_H - acteur->ty);

    // Vitesse aléatoire symétrique
    // avec composantes horizontales et verticales non nulles
    do
    {
        acteur->depx = rand()%21-10;
        acteur->depy = rand()%21-10;
    } while (acteur->depx==0 || acteur->depy==0);

    // Type au hasard 0, 1, 2
    acteur->type = rand()%3;

    // Comportement au hasard (0 ou 1)
    acteur->comportement = rand()%2;

    // Pour mieux visualiser on associe 2 domiantes couleurs distinctes
    // aux 2 comportement (mais ce n'est pas obligé)
    if ( acteur->comportement == 0 )
        acteur->couleur = makecol(rand()%64+196,rand()%40+40,rand()%40+40);
    else
        acteur->couleur = makecol(rand()%40+40,rand()%64+196,rand()%40+40);

    // on retourne cet acteur fraichement créé
    // ( en fait on retourne le POINTEUR sur lui )
    return acteur;
}

// Remplir un tableau avec des (pointeurs sur) acteurs créés
void remplirTabActeurs(t_acteur * tab[NACTEUR])
{
    int i;

    // On "accroche" NACTEUR nouveaux acteurs
    // à chaque case du tableau
    for (i=0;i<NACTEUR;i++)
        tab[i]=creerActeur();
}


// Actualiser un acteur (bouger ...)
void actualiserActeur(t_acteur *acteur)
{

    // prise en compte comportement
    // ( proba de changement de déplacement seulement si comportement 1 )
    if ( acteur->comportement == 1 ){
        // Une chance sur 20
        if ( rand()%20==0 ){
            // Nouveau vecteur déplacement
            acteur->depx = rand()%11-5;
            acteur->depy = rand()%11-5;
        }
    }

    // contrôle des bords : ici on décide de rebondir sur les bords
    if  (  ( acteur->posx < 0 && acteur->depx < 0 ) ||
           ( acteur->posx + acteur->tx > SCREEN_W && acteur->depx > 0) )
        acteur->depx = -acteur->depx;

    if  (  ( acteur->posy < 0 && acteur->depy < 0 ) ||
           ( acteur->posy + acteur->ty > SCREEN_H && acteur->depy > 0) )
        acteur->depy = -acteur->depy;

    // calculer nouvelle position
    // nouvelle position = position actuelle + deplacement
    acteur->posx = acteur->posx + acteur->depx;
    acteur->posy = acteur->posy + acteur->depy;
}

// Gérer l'évolution de l'ensemble des acteurs
void actualiserTabActeurs(t_acteur * tab[NACTEUR])
{
    int i;

    for (i=0;i<NACTEUR;i++)
        actualiserActeur(tab[i]);

}


// Dessiner un acteur sur une bitmap bmp
void dessinerActeur(BITMAP *bmp, t_acteur *acteur)
{
    // Prise en compte du type
    // 0 rectangle   1 ellipse   2 triangle
    switch(acteur->type)
    {
        case 0:
            rectfill(bmp,acteur->posx,acteur->posy,acteur->posx+acteur->tx,acteur->posy+acteur->ty,acteur->couleur);
            break;
        case 1:
            ellipsefill(bmp,acteur->posx+acteur->tx/2,acteur->posy+acteur->ty/2,acteur->tx/2,acteur->ty/2,acteur->couleur);
            break;
        case 2:
            triangle(bmp,acteur->posx,acteur->posy+acteur->ty,acteur->posx+acteur->tx/2,acteur->posy,acteur->posx+acteur->tx,acteur->posy+acteur->ty,acteur->couleur);
            break;
    }

}

// Dessiner sur une bitmap l'ensemble des acteurs
void dessinerTabActeurs(BITMAP *bmp,t_acteur * tab[NACTEUR])
{
    int i;

    for (i=0;i<NACTEUR;i++)
        dessinerActeur(bmp,tab[i]);

}