#include "Surface3D.h"

Surface3D::Surface3D(float tailleX, float tailleY, std::string const fichierImage, float multi)
:m_texture( new Texture(fichierImage) ), m_textID( m_texture->getID() ),
 m_vboID(0), m_tailleVerticesBytes(18*sizeof(float)), m_tailleCoordTextureBytes(12*sizeof(float)), m_vaoID(0)
{
    // Vertices
    tailleX /= 2;
    tailleY /= 2;
    float vertices[] = {-tailleX, 0.0, -tailleY,   tailleX, 0.0, -tailleY,   tailleX, 0.0, tailleY,   // Triangle 1
                        -tailleX, 0.0, -tailleY,   -tailleX, 0.0, tailleY,   tailleX, 0.0, tailleY};  // Triangle 2
    for (int i(0); i<18; i++)
        m_vertices[i] = vertices[i];

    // Coordonnées de texture
    if (multi == 0.0f)
        multi = 1.0;
    float multiX, multiY;
    multiX = multiY = multi;
    if (tailleX < tailleY)
        multiX *= tailleX/tailleY;
    else if (tailleY < tailleX)
        multiY *= tailleY/tailleX;

    float coordTexture[] = {0, 0,   multiX, 0,   multiX, multiY,     // Triangle 1
                            0, 0,   0, multiY,   multiX, multiY};    // Triangle 2
    for (int i(0); i<12; i++)
        m_coordTexture[i] = coordTexture[i];

    // Chargement automatique
    charger();
}

Surface3D::Surface3D(float tailleX, float tailleY, GLuint samplerID, float multi)
:m_texture( 0x0 ), m_textID( samplerID ),
 m_vboID(0), m_tailleVerticesBytes(18*sizeof(float)), m_tailleCoordTextureBytes(12*sizeof(float)), m_vaoID(0)
{
    // Vertices
    tailleX /= 2;
    tailleY /= 2;
    float vertices[] = {-tailleX, 0.0, -tailleY,   tailleX, 0.0, -tailleY,   tailleX, 0.0, tailleY,   // Triangle 1
                        -tailleX, 0.0, -tailleY,   -tailleX, 0.0, tailleY,   tailleX, 0.0, tailleY};  // Triangle 2
    for (int i(0); i<18; i++)
        m_vertices[i] = vertices[i];

    // Coordonnées de texture
    if (multi == 0.0f)
        multi = 1.0;
    float multiX, multiY;
    multiX = multiY = multi;
    if (tailleX < tailleY)
        multiX *= tailleX/tailleY;
    else if (tailleY < tailleX)
        multiY *= tailleY/tailleX;
    float coordTexture[] = {0, 0,   multiX, 0,   multiX, multiY,     // Triangle 1
                            0, 0,   0, multiY,   multiX, multiY};    // Triangle 2
    for (int i(0); i<12; i++)
        m_coordTexture[i] = coordTexture[i];

    // Chargement automatique
    charger();
}

Surface3D::~Surface3D()
{
    // Destruction du VBO
    glDeleteBuffers(1, &m_vboID);

    // Destruction du VAO
    glDeleteVertexArrays(1, &m_vaoID);

    // Destruction de la texture
    if ( m_texture ) delete m_texture;
}

void Surface3D::charger()
{
    /// Chargement Vertex Buffer Object
    // Destruction d'un éventuel ancien VBO
    if(glIsBuffer(m_vboID) == GL_TRUE)
        glDeleteBuffers(1, &m_vboID);

    // Génération de l'ID
    glGenBuffers(1, &m_vboID);

    // Verrouillage du VBO
    glBindBuffer(GL_ARRAY_BUFFER, m_vboID);

        // Allocation de la mémoire vidéo
        glBufferData(GL_ARRAY_BUFFER, m_tailleVerticesBytes + m_tailleCoordTextureBytes, 0, GL_STATIC_DRAW);

        // Transfert des données
        glBufferSubData(GL_ARRAY_BUFFER, 0, m_tailleVerticesBytes, m_vertices);
        glBufferSubData(GL_ARRAY_BUFFER, m_tailleVerticesBytes, m_tailleCoordTextureBytes, m_coordTexture);

    // Déverrouillage de l'objet
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    /// Chargement Vertex Array Object
    // Destruction d'un éventuel ancien VAO
    if(glIsVertexArray(m_vaoID) == GL_TRUE)
        glDeleteVertexArrays(1, &m_vaoID);

    // Génération de l'ID du VAO
    glGenVertexArrays(1, &m_vaoID);

    // Verrouillage du VAO
    glBindVertexArray(m_vaoID);

        // Verrouillage du VBO
        glBindBuffer(GL_ARRAY_BUFFER, m_vboID);

            // Accès aux vertices dans la mémoire vidéo
            glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
            glEnableVertexAttribArray(0);

            // Accès aux coordonnées de texture dans la mémoire vidéo
            glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(m_tailleVerticesBytes));
            glEnableVertexAttribArray(2);

        // Déverrouillage du VBO
        glBindBuffer(GL_ARRAY_BUFFER, 0);


    // Déverrouillage du VAO
    glBindVertexArray(0);
}

void Surface3D::afficher( glm::mat4 pmv, Shader const &shad )
{
    // Verouillage VAO
    glBindVertexArray(m_vaoID);

        // Envoi des matrices
        glUniformMatrix4fv(glGetUniformLocation(shad.getProgramID(), "pmv"), 1, GL_FALSE, glm::value_ptr(pmv));

        // Verrouillage de la texture
        glBindTexture(GL_TEXTURE_2D, m_textID);

        // Rendu
        glDrawArrays(GL_TRIANGLES, 0, 6);

        // Déverrouillage de la texture
        glBindTexture(GL_TEXTURE_2D, 0);

    // Déverrouillage du VAO
    glBindVertexArray(0);
}