#include "graphics/opengl/texture_array.hpp"
#include "graphics/opengl/texture.hpp"

using namespace kuiper::gl;

texture_array::s_ptr texture_array::make(GLenum target) noexcept {
    GLuint name = 0;

    glCreateTextures(target, 1, &name);

    if (!name)
        return nullptr;

    return std::make_shared<texture_array>(name, target);
}

void texture_array::destroy() noexcept {
    if (m_id) {
        glDeleteTextures(1, &m_id);
        m_id = 0;
    }

    return;
}

void texture_array::bind(std::uint32_t unit) const noexcept {
    return glBindTextureUnit(unit, m_id);
}

void texture_array::set_storage(GLenum        internal_fmt,
                                std::uint32_t width,
                                std::uint32_t height,
                                std::uint32_t depth) noexcept {
    constexpr GLsizei mip_levels = 1; // only allocating storage for level 0, call gen_mipmaps()

    glTextureStorage3D(m_id,
                       mip_levels,
                       internal_fmt,
                       static_cast<GLsizei>(width),
                       static_cast<GLsizei>(height),
                       static_cast<GLsizei>(depth));

    m_internal_fmt = internal_fmt;
    m_width        = width;
    m_height       = height;
    m_depth        = depth;

    return;
}

void texture_array::upload(std::uint32_t x_offset,
                           std::uint32_t y_offset,
                           std::uint32_t z_offset,
                           std::uint32_t width,
                           std::uint32_t height,
                           std::uint32_t depth,
                           GLenum        format,
                           GLenum        type,
                           const void*   data,
                           std::uint32_t mip_level) noexcept {
    return glTextureSubImage3D(m_id,
                               static_cast<GLint>(mip_level),
                               static_cast<GLint>(x_offset),
                               static_cast<GLint>(y_offset),
                               static_cast<GLint>(z_offset),
                               static_cast<GLsizei>(width),
                               static_cast<GLsizei>(height),
                               static_cast<GLsizei>(depth),
                               format,
                               type,
                               data);
}

void texture_array::gen_mipmaps() noexcept {
    return glGenerateTextureMipmap(m_id);
}

void texture_array::set_param(GLenum name, GLint param) noexcept {
    return glTextureParameteri(m_id, name, param);
}
