#include "graphics/opengl/buffer.hpp"
#include <memory>

using namespace kuiper::gl;

buffer::s_ptr buffer::make(GLenum target) noexcept {
    GLuint name = 0;
    glGenBuffers(1, &name);

    if (!name)
        return nullptr;

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

void buffer::destroy() noexcept {
    if (m_id)
        glDeleteBuffers(1, &m_id);

    return;
}

void buffer::bind() const noexcept {
    return glBindBuffer(m_target, m_id);
}

void buffer::bind_to_location(std::uint32_t location) const noexcept {
    return glBindBufferBase(m_target, location, m_id);
}

void buffer::upload(GLenum usage, std::size_t size, const void* data) noexcept {
    m_size = size;

    bind();

    return glBufferData(m_target, static_cast<GLsizeiptr>(size), data, usage);
}

void buffer::update(std::size_t offset, std::size_t size, const void* data) noexcept {
    bind();

    return glBufferSubData(m_target, static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), data);
}

void buffer::set_vertex_attrib(std::uint32_t index,
                               std::size_t   size,
                               GLenum        type,
                               std::size_t   stride,
                               std::size_t   offset,
                               bool          normalised) noexcept {
    bind();

    return glVertexAttribPointer(index,
                                 static_cast<GLint>(size),
                                 type,
                                 normalised,
                                 static_cast<GLsizei>(stride),
                                 reinterpret_cast<const void*>(offset));
}
