#include "FrameBuffer.h"

// Constructeurs et Destructeur
FrameBuffer::FrameBuffer() : m_id(0), m_largeur(0), m_hauteur(0), m_colorBuffers(0), m_depthBufferID(0), m_stencil(false)
{}

FrameBuffer::FrameBuffer(int largeur, int hauteur, bool stencil)
: m_id(0), m_largeur(largeur), m_hauteur(hauteur), m_colorBuffers(0), m_depthBufferID(0), m_stencil(stencil)
{}


FrameBuffer::FrameBuffer(const FrameBuffer &frameBufferACopier)
{
    // Copie de la largeur, de la hauteur et du booléen
    m_largeur = frameBufferACopier.m_largeur;
    m_hauteur = frameBufferACopier.m_hauteur;
    m_stencil = frameBufferACopier.m_stencil;

    // Chargement de la copie du Frame Buffer
    charger();
}

FrameBuffer::~FrameBuffer()
{
    // Destruction des buffers
    glDeleteFramebuffers(1, &m_id);
    glDeleteRenderbuffers(1, &m_depthBufferID);
}

// Méthodes
bool FrameBuffer::charger()
{
    // Vérification d'un éventuel ancien FBO
    if(glIsFramebuffer(m_id) == GL_TRUE)
    {
        // Destruction du Frame Buffer
        glDeleteFramebuffers(1, &m_id);
    }

    // Génération d'un id
    glGenFramebuffers(1, &m_id);

    // Verrouillage du Frame Buffer
    glBindFramebuffer(GL_FRAMEBUFFER, m_id);

        // Création du Color Buffer
        Texture* colorBuffer(new Texture(m_largeur, m_hauteur));
        colorBuffer->create();

        // Ajout au tableau
        m_colorBuffers.push_back(colorBuffer);

        // Création du Depth Buffer et du Stencil Buffer (si besoin)
        if(m_stencil == true)
            creerRenderBuffer(m_depthBufferID, GL_DEPTH24_STENCIL8);
        else
            creerRenderBuffer(m_depthBufferID, GL_DEPTH_COMPONENT24);

        // Association du Color Buffer
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_colorBuffers[0]->getID(), 0);

        // Création du Depth Buffer et du Stencil Buffer (si besoin)
        if(m_stencil == true)
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_depthBufferID);
        else
            glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, m_depthBufferID);

        // Vérification de l'intégrité du FBO
        if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
        {
            // Libération des buffers
            glDeleteFramebuffers(1, &m_id);
            glDeleteRenderbuffers(1, &m_depthBufferID);

            // Affichage d'un message d'erreur et retour de la valeur false
            std::cout << "Erreur : le FBO est mal construit" << std::endl;
            return false;
        }

    // Déverrouillage du Frame Buffer
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // Si tout s'est bien passé, on renvoie la valeur true
    return true;
}

void FrameBuffer::creerRenderBuffer(GLuint &id, GLenum formatInterne)
{
    // Destruction d'un éventuel ancien Render Buffer
    if(glIsRenderbuffer(id) == GL_TRUE)
        glDeleteRenderbuffers(1, &id);

    // Génération de l'identifiant
    glGenRenderbuffers(1, &id);

    // Verrouillage
    glBindRenderbuffer(GL_RENDERBUFFER, id);

        // Configuration du Render Buffer
        glRenderbufferStorage(GL_RENDERBUFFER, formatInterne, m_largeur, m_hauteur);

    // Déverrouillage
    glBindRenderbuffer(GL_RENDERBUFFER, 0);
}

// Getters
GLuint FrameBuffer::getID() const
{
    return m_id;
}

Texture* FrameBuffer::getColorBuffer(unsigned int index)
{
    return m_colorBuffers[index];
}

int FrameBuffer::getLargeur() const
{
    return m_largeur;
}

int FrameBuffer::getHauteur() const
{
    return m_hauteur;
}
