/*
		BOUGER DE NOMBREUSES FORMES EN PARALLELE :					
		METHODE DU DOUBLE BUFFER
*/
//#define ALLEGRO_STATICLINK
#include <allegro.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);\
}

// macro pour simplifier l'écriture de rand()%quelque chose
#define irand(n) (rand()%(n))

// Une énumération plutôt que trois #define
enum{rectang, triang,cercle};

// structure qui rassemble tous les attributs d'une forme et définition 
//(typedef) d'un type "FORME" équivalent à cette structure
typedef struct FORME{
	int type;		//rectang,triang,cercle
	int x,y;		//position
	int tx,ty;		//taille
	int dx,dy;		//deplacement
	int couleur;
}FORME;

// le nombre total des formes
#define NB_FORMES	1000

// déclarations des 4 fonctions du programme
void initialisation_formes	(FORME*f);
void mouvement_formes		(FORME*f);
void assemble_formes		(FORME*f, BITMAP* bmp);
void degrade_pas_variable	(PALETTE pal);
/*********************************************************
*********************************************************/
void initialisation_formes(FORME*f)
{ 
	  f->type = rand()%3;
	  f->x = rand()%ECRAN_X;
	  f->y = rand()%ECRAN_Y;
	  f->tx = (rand()%56)+5;
	  f->ty = (rand()%56)+5;
	  f->dx = (rand()%11)-5;
	  f->dy = (rand()%11)-5;
	  f->couleur = rand()%256;
}
/*********************************************************
Modifier les coordonnées d'une forme en fonction de ses 
valeurs de déplacement (dx et dy)
Contrôler les bords (rebond en cas de collision)
*********************************************************/
void mouvement_formes(FORME*f)
{
   f->x += f->dx;
   f->y += f->dy;
   
   if ( ((f->x <= 0) && (f->dx < 0))||((f->x >= ECRAN_X) && (f->dx > 0))) 
      f->dx = -f->dx;
      
   if (((f->y <= 0) && (f->dy < 0))||((f->y >= ECRAN_Y) && (f->dy > 0))) 
      f->dy = -f->dy;
}
/*********************************************************
Afficher une forme dans une bitmap en fonction de son type
*********************************************************/
void assemble_formes(FORME*f, BITMAP* bmp)
{
   switch(f->type){
      case rectang :
		 rectfill( bmp,	f->x, f->y, f->x+f->tx, f->y+f->ty, f->couleur);
         break;

      case triang :
		 triangle( bmp,	f->x, f->y, f->x+f->tx, f->y,f->x+f->tx/2 ,f->y-f->ty, 
						f->couleur);
         break;

      case cercle :
		  circlefill( bmp, f->x, f->y, f->ty, f->couleur);	
         break;
	}
}
/*********************************************************
Fabriquer un dégradé de couleur dans une palette 
*********************************************************/
void degrade_pas_variable(PALETTE pal)
{
int i,rouge,pr,vert,pv,bleu,pb;

	pal[0].r=pal[0].g=pal[0].b=0;
	
	rouge = irand(54)+5;
	pr = irand(11)-5;
	vert = irand(54)+5;
	pv = irand(11)-5;
	bleu = irand(54)+5;
	pb = irand(11)-5;

	for(i=1;i<256;i++){
		//rouge
		rouge += pr;
		pal[i].r = rouge;
		if( rouge <=ABS(pr) || rouge >= 63-ABS(pr))
			pr*=-1;
		// vert
		vert += pv;
		if( vert <=ABS(pv) || vert >= 63-ABS(pv))
			pv*=-1;
		pal[i].g = vert;
		// bleu
		bleu +=pb;
		if( bleu <=ABS(pb) || bleu >= 63-ABS(pb))
			pb*=-1;
		pal[i].b = bleu;
	}
	set_palette(pal);
}
/*********************************************************
*********************************************************/
int main()
{
// tools
int i;

// un tableau de pointeurs de FORMES
FORME* TAB[NB_FORMES];

//  2 bitmaps de mémoire vidéo
BITMAP*page;

// une palette de couleurs
PALETTE pal;

   allegro_init();
   install_keyboard();
   srand(time(NULL));
   if (set_gfx_mode(MODE, ECRAN_X, ECRAN_Y, 0, 0) != 0) 
      ERREUR("gfx mode");
   // initialisation palette
   degrade_pas_variable(pal);
   
   // créer deux bitmaps de mémoire vidéo  
   page = create_bitmap(ECRAN_X, ECRAN_Y);
   if (!page) 
      ERREUR("creation bitmap");
      
   // Malloc des poiteurs FORME* du tableau TAB et initialisation de 
   // chaque FORME via la fonction d'initialisation
   for ( i = 0; i <NB_FORMES; i++){
      TAB[i] = (FORME*)malloc(sizeof(FORME));
      initialisation_formes(TAB[i]);
   }
   // boucle d'événements, test d'arrêt = presser echapp
   do{
      // 1 effacement du buffer
      clear_bitmap(page);
      // 2 modification des positions de chaque forme
      // et affichage de chaque forme dans le buffer
      for ( i = 0; i <NB_FORMES; i++){
		
         mouvement_formes(TAB[i]);
	     assemble_formes(TAB[i], page);
      }
      // 3 affichage du buffer à l'écran
      blit(page,screen,0,0,0,0,page->w,page->h);
	  // bidouille en attendant mieux pour ralentir la vitesse
	  rest(20);
	  //Changer la palette de couleurs
	  if(key[KEY_ENTER])
	     degrade_pas_variable(pal);
   }while( !key[KEY_ESC] );
   
   // sortie boucle évent, nettoyage mémoire allouée 
   destroy_bitmap(page);
   for (i=0; i< NB_FORMES; i++)
      free(TAB[i]);
   
   exit(EXIT_SUCCESS);
}
END_OF_MAIN();
/*********************************************************
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"
*********************************************************/
