#include "Texture.h"

// Constructeur
Texture::Texture() : m_id(0)
{

}

// Constructeur de copie
Texture::Texture(Texture const &textureACopier)
{
    //Rechargement de la même texture
    charger(textureACopier.m_chemin);
}

// Destructeur
Texture::~Texture()
{
    glDeleteTextures(1, &m_id);
}

//Opérateur =
Texture& Texture::operator=(Texture const &textureACopier)
{
    //Rechargement de la même texture
    charger(textureACopier.m_chemin);

    // Retour du pointeur *this
    return *this;
}

// Méthodes
bool Texture::charger(std::string fichierImage)
{
    //Attribution fichier image
    m_chemin = fichierImage;

    //Chargement
    SDL_Surface* imageInversee = SDL_LoadBMP(fichierImage.c_str());
    if(imageInversee == 0)
    {
        std::cout << "Erreur chargement texture : " << SDL_GetError() << std::endl;
        return false;
    }

    //Mettre l'image à l'endroit
    SDL_Surface* imageSDL = inverserPixels(imageInversee);
    SDL_FreeSurface(imageInversee);
    imageInversee = 0;

    // Destruction d'une éventuelle ancienne texture
    if(glIsTexture(m_id) == GL_TRUE)
        glDeleteTextures(1, &m_id);

    // Génération de l'ID
    glGenTextures(1, &m_id);

    // Verrouillage
    glBindTexture(GL_TEXTURE_2D, m_id);

    // Format de l'image
    GLenum formatInterne(0);
    GLenum format(0);

    // Détermination du format et du format interne pour les images à 3 composantes
    std::cout << "Texture format interne|ordre de l'image "<<fichierImage<<" : ";
    if(imageSDL->format->BytesPerPixel == 3)
    {
        // Format interne
        formatInterne = GL_RGB;
        std::cout << "GL_RGB|";

        // Format
        if(imageSDL->format->Rmask == 0xff){
            format = GL_RGB;
            std::cout << "GL_RGB";
        }
        else{
            format = GL_BGR;
            std::cout << "GL_BGR";
        }
    }

    // Détermination du format et du format interne pour les images à 4 composantes
    else if(imageSDL->format->BytesPerPixel == 4)
    {
        // Format interne
        formatInterne = GL_RGBA;
        std::cout << "GL_RGBA|";

        // Format
        if(imageSDL->format->Rmask == 0xff){
            format = GL_RGBA;
            std::cout << "GL_RGBA";
        }
        else{
            format = GL_BGRA;
            std::cout << "GL_BGRA";
        }
    }


    // Dans les autres cas, on arrête le chargement
    else
    {
        std::cout << "Erreur, format interne de l'image inconnu" ;//<< std::endl;
        SDL_FreeSurface(imageSDL);

        return false;
    }
    std::cout << std::endl;

    // Copie des pixels
    glTexImage2D(GL_TEXTURE_2D, 0, formatInterne, imageSDL->w, imageSDL->h, 0, format, GL_UNSIGNED_BYTE, imageSDL->pixels);

    // Application des filtres
    //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

    // Déverrouillage
    glBindTexture(GL_TEXTURE_2D, 0);

    // Fin de la méthode
    SDL_FreeSurface(imageSDL);
    return true;
}

GLuint Texture::getID() const
{
    return m_id;
}

SDL_Surface* Texture::inverserPixels(SDL_Surface *imageSource) const
{
    // Copie conforme de l'image source sans les pixels
    SDL_Surface *imageInversee = SDL_CreateRGBSurface(0, imageSource->w, imageSource->h, imageSource->format->BitsPerPixel, imageSource->format->Rmask,
                                                         imageSource->format->Gmask, imageSource->format->Bmask, imageSource->format->Amask);


    // Tableau intermédiaires permettant de manipuler les pixels
    unsigned char* pixelsSources = (unsigned char*) imageSource->pixels;
    unsigned char* pixelsInverses = (unsigned char*) imageInversee->pixels;


    // Inversion des pixels
    for(int i = 0; i < imageSource->h; i++)
    {
        for(int j = 0; j < imageSource->w * imageSource->format->BytesPerPixel; j++)
            pixelsInverses[(imageSource->w * imageSource->format->BytesPerPixel * (imageSource->h - 1 - i)) + j] = pixelsSources[(imageSource->w * imageSource->format->BytesPerPixel * i) + j];
    }


    // Retour de l'image inversée
    return imageInversee;
}