#ifndef GLTEXTURE2D_HPP_
#define GLTEXTURE2D_HPP_


#include <string>
#include <utility>

#include <globject.hpp>
#include <gltexturend.hpp>


/// Class

class GLTexture2D : public GLTextureND<2>
{
public:

    /// Special member functions

    explicit GLTexture2D(
        std::string object_label,
        Size        size,
        GLenum      internal_format = GL_RGBA8,
        GLenum      wrap            = GL_REPEAT,
        GLenum      min_filter      = GL_LINEAR_MIPMAP_LINEAR,
        GLenum      mag_filter      = GL_LINEAR
    );

    /// Core

    GLTexture2D static const & empty();

    /// TGA

    GLTexture2D static tga_read(
        Path const & path,
        GLenum       format          = GL_BGRA,
        GLenum       internal_format = GL_SRGB8_ALPHA8,
        GLenum       wrap            = GL_REPEAT,
        GLenum       min_filter      = GL_LINEAR_MIPMAP_LINEAR,
        GLenum       mag_filter      = GL_LINEAR
    );

    void tga_write(
        Path const & path,
        GLenum       format = GL_BGRA
    ) const;

private:

    /// Core

    void virtual data_(
        void const * data,
        GLenum       target,
        GLenum       format,
        GLenum       type
    ) override;
};


/// Special member functions

inline GLTexture2D::GLTexture2D(
    std::string object_label,
    Size        size,
    GLenum      internal_format,
    GLenum      wrap,
    GLenum      min_filter,
    GLenum      mag_filter
)
:
    GLTextureND(
        std::move(object_label),
        GL_TEXTURE_2D,
        GL_TEXTURE_BINDING_2D,
        GL_MAX_TEXTURE_SIZE,
        size,
        internal_format,
        wrap,
        min_filter,
        mag_filter
    )
{
    try
    {
        glTexImage2D(
            target_, 0,
            (GLint)internal_format,
            size[0], size[1], 0,
            GL_RED, GL_UNSIGNED_BYTE, nullptr
        );
        check_error_(glGetError());
    }
    catch (...)
    {
        fail_action_("create");
    }
}

/// Core

inline GLTexture2D const & GLTexture2D::empty()
{
    return empty_<GLTexture2D>();
}

inline void GLTexture2D::data_(
    void const * data,
    GLenum       target,
    GLenum       format,
    GLenum       type
)
{
    glTexSubImage2D(
        target, 0,
        0, 0,
        size()[0], size()[1],
        format, type, data
    );
}


#endif // GLTEXTURE2D_HPP_