#include "ogl4_texture_fbo.h"
#include "ogl4_texture.h"
#include <memory.h>
#include <GL/gl.h>

namespace sleek
{
    namespace driver
    {
        template<>
        ogl4_texture_fbo<false>::ogl4_texture_fbo(fbo *o, math::vec2i size, u32 a, u32 fmt) noexcept
            : identifier(o), attachment(a), framebuffer(*(GLuint*)o->getHardwareLink()), format(fmt)
        {
            glGenTextures(1, &gl);
            glBindTexture(GL_TEXTURE_2D, gl);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexImage2D(
                GL_TEXTURE_2D, 0,
                ogl4_texture_componantes[fmt-1],
                size.x, size.y, 0,
                ogl4_texture_format[fmt-1],
                ogl4_texture_type[fmt-1], 0
            );
        }

        template<>
        ogl4_texture_fbo<true>::ogl4_texture_fbo(fbo *o, math::vec2i size, u32 a, u32 fmt) noexcept
            : identifier(o), attachment(a), framebuffer(*(GLuint*)o->getHardwareLink()), format(fmt)
        {
            glGenTextures(1, &gl);
            glTextureParameteriEXT(gl, GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
            glTextureParameteriEXT(gl, GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
            glTextureParameteriEXT(gl, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            glTextureParameteriEXT(gl, GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTextureImage2DEXT(
                gl, GL_TEXTURE_2D, 0,
                ogl4_texture_componantes[fmt-1],
                size.x, size.y, 0,
                ogl4_texture_format[fmt-1],
                ogl4_texture_type[fmt-1], 0
            );
        }

        template<bool i>
        ogl4_texture_fbo<i>::~ogl4_texture_fbo() noexcept
        {
            glDeleteTextures(1, &gl);
        }

        template<bool i>
        void* ogl4_texture_fbo<i>::getHardwareLink() const noexcept
        {
            GLuint *tmp = (GLuint*)&gl;
            return tmp;
        }


        template <bool dsa>
        void ogl4_texture_fbo<dsa>::resize(const math::vec2i &size) noexcept
        {
            this->~ogl4_texture_fbo<dsa>();
            new (this) ogl4_texture_fbo<dsa>((fbo*)owner, size, attachment, format);
        }

        template<bool i>
        void ogl4_texture_fbo<i>::bind() noexcept
        {
            glBindTexture(GL_TEXTURE_2D, gl);
        }

        template<bool i>
        void ogl4_texture_fbo<i>::unbind() noexcept
        {
            glBindTexture(GL_TEXTURE_2D, 0);
        }

        template<>
        void ogl4_texture_fbo<false>::update() noexcept
        {
            glFramebufferTexture2DEXT(
                GL_FRAMEBUFFER_EXT,
                attachment,
                GL_TEXTURE_2D, gl, 0
            );
        }

        template<>
        void ogl4_texture_fbo<true>::update() noexcept
        {
            glNamedFramebufferTexture2DEXT(
                framebuffer,
                attachment,
                GL_TEXTURE_2D, gl, 0
            );
        }
    }
}