/*****************************************************************************
 *
 *  Copyright (C) 2003 Cédric Brégardis <cedric.bregardis@free.fr>
 *
 *  This file is part of BRIQUOLO
 *
 *  BRIQUOLO is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  BRIQUOLO is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with BRIQUOLO; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *****************************************************************************/
#ifndef MOGL_AFFICHEUR
#define MOGL_AFFICHEUR

#include <map>
#include <list>
#include <set>
#include "MOGL_MatriceTransformation.h"
#include "MOGL_Camera.h"
#include "MOGL_Texture.h"
#include "MOGL_Triangle.h"
#include "MOGL_TriangleOmbre.h"
#include "MOGL_Strip.h"

using namespace std;

struct MOGL_Struct_Triangle2D
{
        float x[2],y[2];
        float r,g,b,a;
        MOGL_Texture * texture;
};

class MOGL_NoeudOpenGL;

/**
   Reçoit les polygones ayant subit la phase de <i>TnL</i> et destiné à les aficher pendant la phase effective d'<i>affichage</i>.
   Cette classe gère aussi des abonnements de certaines listes de polygones qui sont liés à un pointeur vers une matrice de transformation
   et qui sont destinés à être afficher chaque fois (d'où l'abonnement...).
*/
class MOGL_Afficheur
{
    // **** Types locaux à la classe ****
        
    struct MOGL_Struct_TableauTextureObjet
    {
        int NbPoint;
        bool * DessinerBord;
        MOGL_Struct_Couleur * CouleurBord;
        unsigned int * TailleBord;
        MOGL_MatriceTransformation * Matrice;
        GLfloat * TabPoint;
        GLfloat * TabNormale;
        GLfloat * TabTexture;
    };

    struct MOGL_Struct_LumiereOmbre
    {
        bool VecteurEstDirection;
        MOGL_Struct_Vecteur Vecteur;
    };
        
    typedef map <int, MOGL_Struct_TableauTextureObjet> MOGL_Map_TableauxTriangle;
    typedef MOGL_Map_TableauxTriangle::iterator MOGL_ItMap_TableauxTriangle;

    typedef map <MOGL_Texture *, MOGL_Map_TableauxTriangle> MOGL_Map_TextureTriangles;
    typedef MOGL_Map_TextureTriangles::iterator MOGL_ItMap_TextureTriangles;

    typedef map <int, MOGL_Struct_TableauTextureObjet> MOGL_Map_TableauxStrip;
    typedef MOGL_Map_TableauxStrip::iterator MOGL_ItMap_TableauxStrip;

    typedef map <MOGL_Texture *, MOGL_Map_TableauxStrip> MOGL_Map_TextureStrips;
    typedef MOGL_Map_TextureStrips::iterator MOGL_ItMap_TextureStrips;

    typedef list<MOGL_Struct_Vecteur> MOGL_List_Vecteur;
    typedef MOGL_List_Vecteur::iterator MOGL_ItList_Vecteur;

    typedef list <MOGL_Triangle> MOGL_Liste_Triangle;
    typedef MOGL_Liste_Triangle::const_iterator MOGL_ItListe_Triangle;

    typedef list<MOGL_TriangleOmbre> MOGL_List_TriangleOmbre;
    typedef MOGL_List_TriangleOmbre::iterator MOGL_ItList_TriangleOmbre;

    typedef list <MOGL_Strip> MOGL_Liste_Strip;
    typedef MOGL_Liste_Strip::const_iterator MOGL_ItListe_Strip;

    typedef list <MOGL_Struct_LumiereOmbre> MOGL_Liste_LumiereOmbre;
    typedef MOGL_Liste_LumiereOmbre::iterator MOGL_ItListe_LumiereOmbre;

    typedef map<unsigned int, MOGL_MatriceTransformation *> MOGL_Map_EntierMatrice;
    typedef MOGL_Map_EntierMatrice::iterator MOGL_ItMap_EntierMatrice;

    struct MOGL_Struct_Image
    {
        MOGL_Struct_Image(MOGL_Texture * p_Texture, float p_X, float p_Y, float p_Z,
                          float p_TailleX, float p_TailleY, const MOGL_Struct_Couleur & p_Couleur):
          texture(p_Texture), x(p_X), y(p_Y), z(p_Z), tailleX(p_TailleX), tailleY(p_TailleY), couleur(p_Couleur)
        {
        }

        MOGL_Texture * texture;
        float x,y,z;
        float tailleX, tailleY;
        MOGL_Struct_Couleur couleur;
    };

    struct MOGL_Struct_Flare
    {
        MOGL_Struct_Flare(MOGL_Texture * p_Texture, float p_Position, float p_X, float p_Y, float p_Z,
                          float p_Taille, const MOGL_Struct_Couleur & p_Couleur):
          texture(p_Texture), position(p_Position), x(p_X), y(p_Y), z(p_Z), taille(p_Taille), couleur(p_Couleur)
        {
        }

        MOGL_Texture * texture;
        float position;
        float x,y,z;
        float taille;
        MOGL_Struct_Couleur couleur;
    };

    typedef multimap <float, MOGL_Struct_Image> MOGL_Multimap_ProfondeurImage;
    typedef MOGL_Multimap_ProfondeurImage::iterator MOGL_ItMultimap_ProfondeurImage;

    typedef list<MOGL_Struct_Image> MOGL_Liste_Image;
    typedef MOGL_Liste_Image::iterator MOGL_ItListe_Image;
        
    typedef list<MOGL_Struct_Flare> MOGL_Liste_Flare;
    typedef MOGL_Liste_Flare::iterator MOGL_ItListe_Flare;

    typedef set<MOGL_NoeudOpenGL *> MOGL_Set_NoeudOpenGL;
    typedef MOGL_Set_NoeudOpenGL::iterator MOGL_ItSet_NoeudOpenGL;
    // **********************************

  protected:
    void _AfficherAbonnementsOpaque(bool p_AvecNormalTexture);
    void _AfficherBordAbonnementsOpaque();
    void _AfficherAbonnementsNonOpaque(bool p_AvecNormalTexture);
    //void _AfficherParticules();
    void _AfficherOmbre();
    void _AfficherImageOpaque();
    void _AfficherImageNonOpaque();
    void _AfficherLensFlare();

    void _GetProjectionPoint(const MOGL_Struct_Vecteur & p_Point, const MOGL_Struct_Vecteur & p_Direction, float * p_PointResultat);
    void _FabriqueQuadrilatere(float * p_TabQuadri, const MOGL_Struct_Vecteur & p_Vecteur, bool p_VecteurEstDirection,
    const MOGL_Struct_Vecteur & p_Point1, const MOGL_Struct_Vecteur & p_Point2);
        
    int _DernierIdentifiantObjet;
    MOGL_Map_TextureTriangles _MapTabTriangle;
    MOGL_Map_TextureStrips _MapTabStrip;
        
    MOGL_List_Vecteur _ListPoint;
        
    MOGL_Camera * _Camera;
    MOGL_MatriceTransformation _MatriceCamera, _MatriceInvCamera;

    MOGL_List_TriangleOmbre _ListeTriangleOmbre;
    MOGL_Liste_LumiereOmbre _ListeLumiereOmbre;

    MOGL_Multimap_ProfondeurImage _MultimapImage;
    MOGL_Multimap_ProfondeurImage _MultimapImageTailleFixe;
    MOGL_Liste_Image _ListeImage;
    MOGL_Liste_Image _ListeImageTailleFixe;

    MOGL_Liste_Flare _ListeFlare;
    MOGL_Liste_Flare _ListeFlareTailleFixe;

    MOGL_Set_NoeudOpenGL _SetNoeudOpenGL;

    bool _DessinerBord;
    unsigned int _TailleBord;
        
    unsigned int _Largeur, _Hauteur;
        
    float _ptX, _ptY, _ptZ;
    bool _ActiverLumiere;

    float _zMin, _zMax;
        
  public:
    /**
       Constructeur.
    */
    MOGL_Afficheur();

    /**
       Destrcueteur.
    */
    ~MOGL_Afficheur();
        
    /**
       Provoque la remise à zéro des structures temproraires d'affichage. Doit être appelé avant chaque <i>TnL</i>
    */
    void DebutTnL();

    /**
       Permet d'abonner une liste de triangles associés à une même texture.
       @param p_Texture : pointeur vers la texture.
       @param p_Matrice : pointeur vers la matrice de transformation lié à cet ensemble de triangle.
       Si <i>null</i>, alors les points fournis sont déjà transformés
       @param p_NbPoint : nombre de points (qui correspondent à <i>p_NbPoint</i>/3).
       @param p_TabPoints : tableau des points des triangles (de taille 3*p_NbPoint)
       @param p_TabNormale : tableau des normales aux points des triangles (de taille 3*p_NbPoint)
       @param p_TabTexture : tableau des coordonnées de texture des points (de taille 2*p_NbPoint)
    */
    int AbonnerTriangle(MOGL_Texture * p_Texture, MOGL_MatriceTransformation * p_Matrice,int p_NbPoint, bool * p_DessinerBord,
                        MOGL_Struct_Couleur * p_CouleurBord, unsigned int * p_TailleBord,
                        GLfloat * p_TabPoints, GLfloat * p_TabNormale, GLfloat * p_TabTexture);

    /**
       Permet d'abonner un liste de triangles associés à une même texture qui est sous la forme d'un <i>strip</i>.
       @param p_Texture : pointeur vers la texture.
       @param p_Matrice : pointeur vers la matrice de transformation lié à cet ensemble de triangle.
       Si <i>null</i>, alors les points fournis sont déjà transformés
       @param p_NbPoint : nombre de points (qui correspondent à <i>p_NbPoint</i>-2).
       @param p_TabPoints : tableau des points des triangles (de taille 3*p_NbPoint)
       @param p_TabNormale : tableau des normales aux points des triangles (de taille 3*p_NbPoint)
       @param p_TabTexture : tableau des coordonnées de texture des points (de taille 2*p_NbPoint)
    */
    int AbonnerStrip(MOGL_Texture * p_Texture, MOGL_MatriceTransformation * p_Matrice,int p_NbPoint, bool * p_DessinerBord,
                     MOGL_Struct_Couleur * p_CouleurBord, unsigned int * p_TailleBord,
                     GLfloat * p_TabPoints, GLfloat * p_TabNormale, GLfloat * p_TabTexture);

    /**
       Désabonne une liste de triangle préalablement abonné avec
       AbonnerTriangle(MOGL_Texture *, MOGL_MatriceTransformation *,int, GLfloat *,     GLfloat *, GLfloat *).
       @param p_Texture : texture de l'abonnement.
       @param p_Identifiant : numéro d'identifiant de l'abonnement.
    */
    bool DesabonnerTriangle(MOGL_Texture * p_Texture, int p_Identifiant);

    /**
       Désabonne une liste de triangle, qui est sous la forme d'un strip, préalablement abonné avec
       AbonnerStrip(MOGL_Texture *, MOGL_MatriceTransformation *,int, GLfloat *, GLfloat *, GLfloat *).
       @param p_Texture : texture de l'abonnement.
       @param p_Identifiant : numéro d'identifiant de l'abonnement.
    */
    bool DesabonnerStrip(MOGL_Texture * p_Texture, int p_Identifiant);

    /**
       Permet d'ajouter des triangles à la liste des triangles projecteur d'ombre.
    */
    void AjouterTriangleOmbre(const MOGL_List_TriangleOmbre & p_ListeTriangle);

    /**
       Permet d'ajouter des triangles à la liste des triangles projecteur d'ombre.
    */
    void AjouterTriangleOmbre(const MOGL_Liste_Triangle & p_ListeTriangle);

    /**
       Permet d'ajouter un triangle projecteur d'ombre
    */
    void AjouterTriangleOmbre(const MOGL_TriangleOmbre & p_Triangle);

    /**
       Permet d'ajouter une source de lumière qui projete une ombre.
       @param p_Vecteur : voir <i>p_VecteurEstDirection</i>
       @param p_VecteurEstDirection : <i>false</i> indique que le vecteur indique la position de la lumière
       (pour les lumières omnidirectionnelles), <i>true</i> indique que le vecteur est la direction de la
       lumière (pour les lumières directionnelles.
    */
    void AjouterLumiereOmbre(const MOGL_Struct_Vecteur & p_Vecteur, bool p_VecteurEstDirection);
        
    /**
       Envoie à OpenGL tous les triangles à afficher qui sont opaques. D'abord les abonnements, puis les particules.
    */
    void AfficherOpaque();

    /**
       Envoie à OpenGL tous les triangles à afficher qui ne sont pas opaques. D'abord les abonnements, puis les particules.
    */
    void AfficherNonOpaque();

    /**
       Définit la caméra
       @param p_Camera : la caméra
    */
    void SetCamera(MOGL_Camera * p_Camera);

    /**
       Permet de récupérer la caméra courante associée à l'afficheur
       @return Pointeur vers la caméra.
    */
    MOGL_Camera * GetCamera() const;
        
    /**
       Permet de récupérer la matrice de transformation correspondant à la caméra
       return Référence vers la matrice de transformation. C'est une constante !
    */
    const MOGL_MatriceTransformation & GetMatriceCamera() const;

    /**
       Permet de récupérer l'inverse de la matrice de transformation correspondant à la caméra
       return Référence vers la matrice de transformation. C'est une constante !
    */
    const MOGL_MatriceTransformation & GetMatriceInvCamera() const;

    /**
       Permet d'indiquer s'il faut dessiner les bords des objets. Le bord correspond au "détourage"
       style <i>bande déssinée</i>
       @param p_Val : true -> déssiner les bords, false -> ne pas déssiner les bords
    */
    void DessinerBord(bool p_Val);

    /**
       Permet de définir la taille en pixels du bord.
       @param p_Taille : taille en pixels
       @sa DessinerBord()
    */
    void SetTailleBord(unsigned int p_Taille);

    /**
       Permet de définir les dimension de la fenêtre.
    */
    void SetDimension(unsigned int p_Largeur, unsigned int p_Hauteur);
    /**
       Permet de récupérer les dimensiosn de la fenêtre
    */
    void GetDimension(unsigned int & p_Largeur, unsigned int & p_Hauteur);

    /**
       Permet d'activer ou désactiver la gestion des lumières
    */
    void ActiverLumiere(bool p_Activation);

    /**
       Permet d'ajouter un point.
    */
    void AjouterPoint(MOGL_Struct_Vecteur p_Point);

    /**
       Permet d'ajouter une image. Aussi connu sous le nom de <i>billboard</i>. L'image va être
       affichée de manière à être toujours face à la caméra. Sa taille va varier selon sa distance par rapport
       à la caméra.
       @param p_Texture : pointeur vers le MOGL_Texture correspondant à l'image.
       @param p_X : position en X du centre de l'image.
       @param p_Y : position en Y du centre de l'image.
       @param p_Z : position en Z du centre de l'image.
       @param p_TailleX : largeur de l'image.
       @param p_TailleY : hauteur de l'image.
       @param p_Couleur : couleur.
       @sa AjouterImageTailleFixe
    */
    void AjouterImage(MOGL_Texture * p_Texture, float p_X, float p_Y, float p_Z,
                      float p_TailleX, float p_TailleY, const MOGL_Struct_Couleur & p_Couleur);

    /**
       Permet d'ajouter une image dont la taille ne varie pas selon la distance.
       Aussi connu sous le nom de <i>billboard</i>. L'image va être
       affichée de manière à être toujours face à la caméra.
       à la caméra.
       @param p_Texture : pointeur vers le MOGL_Texture correspondant à l'image.
       @param p_X : position en X du centre de l'image.
       @param p_Y : position en Y du centre de l'image.
       @param p_Z : position en Z du centre de l'image.
       @param p_TailleX : largeur de l'image (pourcentage de la largeur de la fenêtre, par exemple 25 correpond au quart de la largeur).
       @param p_TailleY : hauteur de l'image (pourcentage de la hauteur de la fenêtre, par exemple 25 correpond au quart de la hauteur).
       Si la valeur est négative alors la hauteur de l'image sera égale à la largeur.
       @param p_Couleur : couleur.
       @sa AjouterImage
    */
    void AjouterImageTailleFixe(MOGL_Texture * p_Texture, float p_X, float p_Y, float p_Z,
                                float p_TailleX, float p_TailleY, const MOGL_Struct_Couleur & p_Couleur);

    /**
       Permet d'ajouter une partie d'une lens flare.
       Il n'est affiché que si l'origine n'est pas masqué.
       @param p_Texture : texture à utiliser.
       @param p_Position : position de la partie du lens flare. Doit être compris entre 0 et 1. 1 correspond à l'origine du lens flare
       (donc la source de lumière) et 0 correspond au centre de l'écran. Les autres valeurs sont ditribuées
       linéairement entres ces deux positions.
       @param p_OrigineX : coordonnée X de l'origine du lens flare (donc la source de lumière correspondante).
       @param p_OrigineY : coordonnée Y de l'origine du lens flare (donc la source de lumière correspondante).
       @param p_OrigineZ : coordonnée Z de l'origine du lens flare (donc la source de lumière correspondante).
       @param p_Taille : taille.
       @param p_Couleur : couleur à utiliser lors du plaquage de texture.
    */
    void AjouterPartieLensFlare(MOGL_Texture * p_Texture, float p_Position,
                                float p_OrigineX, float p_OrigineY, float p_OrigineZ,
                                float p_Taille, const MOGL_Struct_Couleur & p_Couleur);
        
    /**
       Permet d'ajouter une partie d'une lens flare dont la taille ne varie pas selon la distance.
       Il n'est affiché que si l'origine n'est pas masqué.
       @param p_Texture : texture à utiliser.
       @param p_Position : position de la partie du lens flare. Doit être compris entre 0 et 1. 1 correspond à l'origine du lens flare
       (donc la source de lumière) et 0 correspond au centre de l'écran. Les autres valeurs sont ditribuées
       linéairement entres ces deux positions.
       @param p_OrigineX : coordonnée X de l'origine du lens flare (donc la source de lumière correspondante).
       @param p_OrigineY : coordonnée Y de l'origine du lens flare (donc la source de lumière correspondante).
       @param p_OrigineZ : coordonnée Z de l'origine du lens flare (donc la source de lumière correspondante).
       @param p_Taille : taille (pourcentage de la largeur de la fenêtre, ainsi une valeur de 25 correspond au
       quart de la largeur de la fenêtre).
       @param p_Couleur : couleur à utiliser lors du plaquage de texture.
    */
    void AjouterPartieLensFlareTailleFixe(MOGL_Texture * p_Texture, float p_Position,
                                          float p_OrigineX, float p_OrigineY, float p_OrigineZ,
                                          float p_Taille, const MOGL_Struct_Couleur & p_Couleur);
        
    /**
       Permet d'ajouter un MOGL_NoeudOpenGL.
       @param p_NoeudOpenGL : noeud à ajouter.
     */
    void AjouterNoeudOpenGL(MOGL_NoeudOpenGL * p_NoeudOpenGL);

    /**
       Permet de retirer un MOGL_NoeudOpenGL.
       @param p_NoeudOpenGL : noeud à retirer.
       @return <i>true</i> si le MOGL_NoeudOpenGL a bien été trouvé et retiré, <i>false</i> sinon.
     */
    bool RetirerNoeudOpenGL(MOGL_NoeudOpenGL * p_NoeudOpenGL);

};


#endif
