/*====================ÉCOLE POLYTECHNIQUE DE MONTRÉAL============================

	NOM DU FICHIER :CBande.cpp

	DESCRIPTION :	Implémentation des fonctions de l'objet dérivé Bande

	AUTEUR : Martin Bisson, Anne-Marie Buki, Mylene Denis & Jean-Francois Pérusse

	DATE DE CRÉATION : 2004-3-16

	MISES À JOUR :

===============================================================================*/
#include "CBande.h"
#include <GL/glut.h>
#include <cmath>
#ifndef M_PI
#define M_PI (3.14159265358979323846264338327950288419716939937510)
#endif


CPngTexture CBande::TextureBande;


/*------------------------------------------------------------------
  Fonction :	CBande::CBande

  Description :	Constructeur

  Paramètres :
	 const CVector3f& posi : Position de la bande
	 type_jeuobjet Type : Type de bande (orientation)
	 float w : Largeur de la bande
	 float h : Hauteur de la bande

  Valeur retournée :	Aucune (constructeur) : 

  Par : 2004-3-16 Martin Bisson, Anne-Marie Buki, Mylene Denis & Jean-Francois Pérusse
  MAJ: 
------------------------------------------------------------------*/
CBande::CBande(const CVector3f& posi, type_jeuobjet Type, float w, float h)
  : CObjet(posi, Type)
{
  width = w;
  height = h;
}


/*------------------------------------------------------------------
  Fonction :	CBande::AfficheGL

  Description :	Affiche la bande en OpenGL

  Paramètres :

  Valeur retournée :	void : 

  Par : 2004-3-16 Martin Bisson, Anne-Marie Buki, Mylene Denis & Jean-Francois Pérusse
  MAJ: 
------------------------------------------------------------------*/
void CBande::AfficheGL() const
{  
  glEnable(GL_TEXTURE_2D);
  glColor3f(1,1,1);

  glBindTexture(GL_TEXTURE_2D, TextureBande.GetID());

  glPushMatrix();
  glTranslatef(Pos.GetPosX(), Pos.GetPosY(), 0);
  glRotatef(angle(), 0, 0, -1);
  glScalef(width / TAILLE_TUILE / 2, height / TAILLE_TUILE / 2, 1);

  glBegin(GL_QUADS);
    glNormal3f(0,0,1);
    glTexCoord2i(0, 1); glVertex3f(-1,-1,BANDE_HEIGHT);
    glTexCoord2i(1, 1); glVertex3f( 1,-1,BANDE_HEIGHT);
    glTexCoord2i(1, 0); glVertex3f( 1, 1,BANDE_HEIGHT);
    glTexCoord2i(0, 0); glVertex3f(-1, 1,BANDE_HEIGHT);
  glEnd();

  glBegin(GL_QUADS);
    glNormal3f(0,-1,0);
    glTexCoord2i(0, 1); glVertex3f(-1,-1,0);
    glTexCoord2i(1, 1); glVertex3f( 1,-1,0);
    glTexCoord2i(1, 0); glVertex3f( 1, -1,BANDE_HEIGHT);
    glTexCoord2i(0, 0); glVertex3f(-1, -1,BANDE_HEIGHT);
  glEnd();
  
  glBegin(GL_QUADS);
    glNormal3f(1,0,0);
    glTexCoord2i(0, 1); glVertex3f( 1,-1,0);
    glTexCoord2i(1, 1); glVertex3f( 1, 1,0);
    glTexCoord2i(1, 0); glVertex3f( 1, 1,BANDE_HEIGHT);
    glTexCoord2i(0, 0); glVertex3f( 1, -1,BANDE_HEIGHT);
  glEnd();
  
  glBegin(GL_QUADS);
    glNormal3f(0,1,0);
    glTexCoord2i(0, 1); glVertex3f(1,1,0);
    glTexCoord2i(1, 1); glVertex3f(-1, 1,0);
    glTexCoord2i(1, 0); glVertex3f(-1, 1,BANDE_HEIGHT);
    glTexCoord2i(0, 0); glVertex3f(1, 1,BANDE_HEIGHT);
  glEnd();
  
  glBegin(GL_QUADS);
    glNormal3f(-1,0,0);
    glTexCoord2i(0, 1); glVertex3f(-1,1,0);
    glTexCoord2i(1, 1); glVertex3f( -1,-1,0);
    glTexCoord2i(1, 0); glVertex3f( -1, -1,BANDE_HEIGHT);
    glTexCoord2i(0, 0); glVertex3f(-1, 1,BANDE_HEIGHT);
  glEnd();
  
  glPopMatrix();

  glDisable(GL_TEXTURE_2D);
}


/*------------------------------------------------------------------
  Fonction :	CBande::isCollision

  Description :	Détermine si la balle va faire une collision avec la bande

  Paramètres :
	 CBalle *balle : 

  Valeur retournée :	bool : Si la collision s'est fait

  Par : 2004-3-16 Martin Bisson, Anne-Marie Buki, Mylene Denis & Jean-Francois Pérusse
  MAJ: 
------------------------------------------------------------------*/
bool CBande::isCollision(CBalle *balle) const
{
  CVector3f BallePos;
  CVector3f BalleVit;

  bool Collision = false;
  CVector3f VectColli;

  // On fait une rotation de la vitesse et de la position 
  // pour revenir dans une base simple

  float lesin = sin(angle() * M_PI / 180.0f );
  float lecos = cos(angle() * M_PI / 180.0f );

  BalleVit.setX(balle->getDirection().GetPosX()*lecos - 
		balle->getDirection().GetPosY()*lesin);
  BalleVit.setY(balle->getDirection().GetPosX()*lesin + 
		balle->getDirection().GetPosY()*lecos);

  CVector3f NewPos = balle->getPos() - Pos;
  
  BallePos.setX(NewPos.GetPosX()*lecos - NewPos.GetPosY()*lesin);
  BallePos.setY(NewPos.GetPosX()*lesin + NewPos.GetPosY()*lecos);
  // Vérification de la "bounding box"
  if ( (BallePos.GetPosX() >   width / 2 / TAILLE_TUILE + balle->getRayon()/TAILLE_TUILE) ||
       (BallePos.GetPosX() < - width / 2 / TAILLE_TUILE - balle->getRayon()/TAILLE_TUILE) ||
       (BallePos.GetPosY() >   height / 2 / TAILLE_TUILE + balle->getRayon()/TAILLE_TUILE) ||
       (BallePos.GetPosY() < - height / 2 / TAILLE_TUILE - balle->getRayon()/TAILLE_TUILE) )
    return false; // Pas de collision

  // Vérification de la collision avec les coins
  CVector3f lecoin;

  lecoin.setX((width / 2 / TAILLE_TUILE) * BallePos.GetPosX() / fabs(BallePos.GetPosX()));
  lecoin.setY((height / 2 / TAILLE_TUILE) * BallePos.GetPosY() / fabs(BallePos.GetPosY()));

  if ( (BallePos - lecoin) * (BallePos - lecoin) < (balle->getRayon()/TAILLE_TUILE) * (balle->getRayon()/TAILLE_TUILE))
    {
      // Collision avec le coin
      Collision = true;
      VectColli = BallePos - lecoin;
    }
  else
    {
      //Vérification de la collision avec la bande
      if (fabs(BallePos.GetPosY()) < fabs(lecoin.GetPosY()))
	VectColli.setX( - BalleVit.GetPosY() / fabs(BalleVit.GetPosY()));
      else
	VectColli.setX(0);

      if (fabs(BallePos.GetPosX()) < fabs(lecoin.GetPosX()))
	VectColli.setY( - BalleVit.GetPosX() / fabs(BalleVit.GetPosX()));
      else
	VectColli.setY(0);

      if (VectColli.GetPosX() == 0 && VectColli.GetPosY() == 0)
	return false;
      else
	Collision = true;
    }

  if (Collision)
    {
      balle->Recule();

      CVector3f Vcolli, Vconst;
      Vcolli = BalleVit >> VectColli;
      Vconst = BalleVit - Vcolli;
      BalleVit = balle->getCoefRestitution() * (Vconst - Vcolli);

      CVector3f NewVit;

      NewVit.setX(BalleVit.GetPosX() * lecos +
		  BalleVit.GetPosY() * lesin);
      NewVit.setY(BalleVit.GetPosX() * (-lesin) +
		  BalleVit.GetPosY() * lecos);

      balle->setDirection(NewVit);
      return true;
    }
  else
    {
      return false;
    }
}


/*------------------------------------------------------------------
  Fonction :	CBande::ChargeTextures

  Description :	Charge la texture de la bande

  Paramètres :

  Valeur retournée :	bool : Si le chargement s'est fait

  Par : 2004-3-16 Martin Bisson, Anne-Marie Buki, Mylene Denis & Jean-Francois Pérusse
  MAJ: 
------------------------------------------------------------------*/
bool CBande::ChargeTextures()
{
  return (TextureBande.LoadPNG("editeur/images/bande.png") != 0);
}


/*------------------------------------------------------------------
  Fonction :	CBande::DechargeTextures

  Description :	Décharge la texture de la bande

  Paramètres :

  Valeur retournée :	bool : Vrai

  Par : 2004-3-16 Martin Bisson, Anne-Marie Buki, Mylene Denis & Jean-Francois Pérusse
  MAJ: 
------------------------------------------------------------------*/
bool CBande::DechargeTextures()
{
  TextureBande.Unload();
  return true;
}
