/*
        ANIMATION A PARTIR DE SPRITE - ANIMATION DE PLUSIEURS SEQUENCES 
        SIMULTANEMENT
*/

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

#define ECRAN_X	800
#define ECRAN_Y	600
#define MODE    GFX_AUTODETECT_WINDOWED
#define ERREUR(msg) {\
   set_gfx_mode(GFX_TEXT,0,0,0,0);\
   allegro_message("erreur ligne %d, fichier %s: %s\n",__LINE__, __FILE__,msg);\
   allegro_exit();\
   exit(EXIT_FAILURE);\
}

#define NB_IMAGE      64    // nombre total d'images de l'animation météorite
#define NB_MAX        50    // nombre de sequences d'animation
#define NB_STARS      300   // quelques étoiles


// généralisation controle du sprite 
typedef struct SPRITE{
    // le deplacement
    int x,y;         // position
    int tx,ty;       // taille
    int px,py;        // pas du deplacement
    int xwait,ywait; // pour retard avancement en x et y
    int xcmpt,ycmpt; // pour compter le retard
    // l'image
    int courant;     // l'image courante
    int nb_image;   // le nombre max des images de l'animation
    int dir;        // sens de l'animation (à reculons ou avancer)
    int tmps;       // pour compter le temps d'affichage de l'image
    int maxtmps;    // temps maxi pour chaque image
    
}t_sprite ;

typedef struct stars{
   int x,y;
   int r,g,b;
}t_stars;

BITMAP* recup_sprites(  BITMAP*scr, int w, int h, int startx, int starty,
                        int col, int i);
void avance(t_sprite *s);
void cntl_bords(t_sprite *s);
/******************************************************************************
*******************************************************************************/
int main()
{
t_sprite *s[NB_MAX];
t_stars etoile[NB_STARS];

BITMAP *page,*tmp,*im[NB_IMAGE];
int i,c;

   allegro_init();
   install_keyboard(); 
   srand(time(NULL));
     
   set_color_depth(16);
   if (set_gfx_mode(MODE, ECRAN_X, ECRAN_Y, 0, 0) != 0) 
      ERREUR(allegro_error);
   
   // récup de l'image qui contient tout
   tmp=load_bitmap("asteroid.bmp",NULL);
   if (!tmp)
      ERREUR("creation image temporaire image");
   
   // récupération des 64 images de l'animation dans le tableau im[]
   // remarque : finalement il y a une seule animation mais des entées 
   // différentes seront attribuées à chaque sequence. 
   for (i=0;i<NB_IMAGE;i++){
     im[i]=recup_sprites(tmp,64,64,0,0,8,i);
     if (!im[i])
        ERREUR("recup images");
   }
   // l'image tmp n'est plus utile en mémoire
   destroy_bitmap(tmp);   
   
   // création buffer
   page=create_bitmap(SCREEN_W,SCREEN_H);
   if (!page)
      ERREUR("creation buffer")  
   
   // initialisation de chaque séquence d'animation, les sprites
   for (i=0;i<NB_MAX;i++){
      s[i]=(t_sprite*)malloc(sizeof(t_sprite));
      s[i]->x=rand()%(SCREEN_W-im[0]->w);
      s[i]->y=rand()%(SCREEN_H-im[0]->h);
      s[i]->tx=im[0]->w;
      s[i]->ty=im[0]->h;
      s[i]->xwait=rand()%2+1;
      s[i]->ywait=rand()%2+1;
      s[i]->xcmpt=0;
      s[i]->ycmpt=0;
      s[i]->px=(rand()%11)-5;
      s[i]->py= rand()%2+4;
      // une entrée différente dans l'animation pour chaque sequence
      s[i]->courant=rand()%NB_IMAGE;  
      s[i]->nb_image=NB_IMAGE-1;
      s[i]->tmps=0;
      s[i]->maxtmps=rand()%3+1;
      s[i]->dir=1;
   }   
   
   // quelques étoiles au hasard
   for (i=0; i<NB_STARS;i++){
       etoile[i].x=rand()%SCREEN_W;
       etoile[i].y=rand()%SCREEN_H;
       etoile[i].b=etoile[i].g=etoile[i].r=rand()%255;
   }   
   while (!key[KEY_ESC]){
      // effacer buffer
      clear_bitmap(page);
      
      // quelques étoiles au hasard
      for (i=0; i<NB_STARS;i++){
         c=makecol(etoile[i].r,etoile[i].g,etoile[i].b);
         putpixel(page,etoile[i].x,etoile[i].y,c);
         if (rand()%3001>2300){
            if (etoile[i].r>0){
               etoile[i].r--;
               etoile[i].g--;
               etoile[i].b--; 
            } 
            else{ 
               etoile[i].x=rand()%SCREEN_W;
               etoile[i].y=rand()%SCREEN_H; 
               etoile[i].b=etoile[i].g=etoile[i].r=rand()%255;
            }    
         }
      }     
         
      // pour chaque sprite
      for (i=0;i<NB_MAX;i++){
         // avancer
         avance(s[i]); 
         // controler bords (écran circulair)
         cntl_bords(s[i]);
         // affichage image courante de l'anime
         draw_sprite(page,im[s[i]->courant],s[i]->x,s[i]->y);   
      }
      //affichage ecran
      blit(page,screen,0,0,0,0,SCREEN_W,SCREEN_H);
      rest(10);  
      
   }
   
   destroy_bitmap(page);
   for (i=0;i<NB_IMAGE;i++)
      destroy_bitmap(im[i]);
   for (i=0;i<NB_MAX;i++)
      free(s[i]);
      
   return 0;
   
}
END_OF_MAIN();
/******************************************************************************
*******************************************************************************/
BITMAP* recup_sprites(  BITMAP*scr, // bitmap origine
                        int w, int h, // taille element
                        int startx, int starty, // à partir de 
                        int col, int i)// nombre de colones, élément i
{
BITMAP *bmp;
int x,y;
     
   bmp=create_bitmap(w,h);
   if (bmp!=NULL){
      x= startx+(i%col)*w;    
      y= starty+(i/col)*h; 
      blit(scr,bmp,x,y,0,0,w,h);     
   }    
   return bmp;
}
/******************************************************************************
*******************************************************************************/
void avance(t_sprite *s)
{
int res;
   // petit compte pour retard avance en x
   s->xcmpt=(++s->xcmpt)%s->xwait;
   if (!s->xcmpt)
      s->x+=s->px;
   // idem en y
   s->ycmpt=(++s->ycmpt)%s->ywait;
   if (!s->ycmpt)
      s->y+=s->py;
   
   // compte pour affichage image
   s->tmps=(++s->tmps)%s->maxtmps;
   if (!s->tmps){
      s->courant+=s->dir;
      s->courant=(s->courant<0) ? s->nb_image : s->courant;
      s->courant=(s->courant>s->nb_image) ? 0 : s->courant;
   }        
}
/******************************************************************************
*******************************************************************************/
void cntl_bords(t_sprite *s)
{
   // controle mouvement x
   if (s->x+s->tx<0){
      s->x=SCREEN_W-1;
      s->px=(rand()%4+1)*-1;
      
   }
   else if (s->x>SCREEN_W){
      s->x= -(s->tx);
      s->px=rand()%4+1;
   }      
   
   // controle mouvement y
   if (s->y+s->ty<0){
      s->y=SCREEN_H-1;
      s->py=(rand()%4+1)*-1;
      
   }
   else if (s->y>SCREEN_H){
      s->y= -(s->ty);
      s->py=rand()%4+1;
   }      
}
/******************************************************************************
RAPPEL LINKAGE lib static :
pour dev :
dans menu : Projet/otpions du projet/paramètres/éditeur de liens , là, 
copier la liste suivante :
  -lalleg_s -lgdi32 -lwinmm -lole32 -ldxguid -ldinput -lddraw -ldsound
et dans la colonne "compilateur" à gauche de l'éditeur de liens copier
  -DALLEGRO_STATICLINK
cliquer "OK"
*******************************************************************************/

