BLT-With-Graphics-Template/include/blt/gfx/model.h

241 lines
7.3 KiB
C
Raw Normal View History

2023-12-27 01:10:53 -05:00
/*
* <Short Description>
* Copyright (C) 2023 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_WITH_GRAPHICS_MODEL_H
#define BLT_WITH_GRAPHICS_MODEL_H
#include <blt/math/vectors.h>
#include <vector>
#include <blt/gfx/gl_includes.h>
2023-12-27 22:04:33 -05:00
#include <variant>
2023-12-28 00:10:02 -05:00
#include <array>
2023-12-28 13:05:04 -05:00
#include <blt/std/hashmap.h>
2023-12-27 01:10:53 -05:00
namespace blt::gfx
{
2024-04-11 20:40:28 -04:00
struct vbo_t_owner;
class static_dynamic_array;
class vertex_array;
2023-12-27 01:10:53 -05:00
2023-12-28 03:49:00 -05:00
struct vbo_t
{
2024-04-11 20:40:28 -04:00
friend vbo_t_owner;
friend vertex_array;
friend static_dynamic_array;
private:
GLuint bufferID_ = 0;
GLsizeiptr size_ = 0;
GLint buffer_type = 0;
GLint memory_type = 0;
public:
void create(GLint type = GL_ARRAY_BUFFER);
void bind() const;
void unbind() const;
void allocate(GLsizeiptr size, GLint mem_type = GL_STATIC_DRAW, const void* data = nullptr);
template<typename T>
void allocate(GLsizeiptr size, const T* data, GLint mem_type = GL_STATIC_DRAW)
{
allocate(size, mem_type, static_cast<const void*>(data));
}
void sub_update(GLsizeiptr offset, GLsizeiptr size, void* data) const;
void update(GLsizeiptr size, void* data);
void destroy();
};
struct ssbo_t : public vbo_t
{
public:
inline void create()
{
vbo_t::create(GL_SHADER_STORAGE_BUFFER);
}
};
struct ebo_t : public vbo_t
{
public:
inline void create()
{
vbo_t::create(GL_ELEMENT_ARRAY_BUFFER);
}
2023-12-28 03:49:00 -05:00
};
2024-01-08 21:12:31 -05:00
struct vbo_t_owner
{
vbo_t vbo;
vbo_t_owner() = default;
explicit vbo_t_owner(vbo_t vbo): vbo(vbo)
{}
2024-01-11 11:49:48 -05:00
vbo_t* operator->()
{
2024-01-08 21:12:31 -05:00
return &vbo;
}
~vbo_t_owner()
{
if (!vbo.bufferID_)
return;
vbo.destroy();
vbo.unbind();
}
};
2023-12-28 00:10:02 -05:00
/**
* Since most VAOs will not use more than 8 VBOs it makes no sense to heap allocate memory to store them
* This class is used to make that easier to handle
*/
2023-12-27 22:04:33 -05:00
class static_dynamic_array
{
public:
using vbo_type = std::shared_ptr<vbo_t_owner>;
2023-12-27 22:04:33 -05:00
private:
static constexpr size_t DATA_SIZE = 8;
2024-01-08 21:12:31 -05:00
using array_t = std::array<vbo_type, DATA_SIZE>;
std::variant<array_t, vbo_type*> data_;
2023-12-27 22:04:33 -05:00
size_t size_ = DATA_SIZE;
2023-12-28 03:49:00 -05:00
size_t max = 0;
2023-12-28 00:10:02 -05:00
void swap();
2023-12-28 13:05:04 -05:00
2023-12-27 22:04:33 -05:00
public:
2023-12-28 00:10:02 -05:00
static_dynamic_array();
2023-12-27 22:04:33 -05:00
static_dynamic_array(const static_dynamic_array& copy) = delete;
2023-12-28 03:49:00 -05:00
static_dynamic_array(static_dynamic_array&& move) noexcept = default;
2023-12-27 22:04:33 -05:00
static_dynamic_array& operator=(const static_dynamic_array& copy) = delete;
2023-12-28 03:49:00 -05:00
static_dynamic_array& operator=(static_dynamic_array&& move) noexcept = default;
2023-12-28 00:10:02 -05:00
2024-01-08 21:12:31 -05:00
vbo_type& operator[](size_t index);
2023-12-27 22:04:33 -05:00
2023-12-28 13:05:04 -05:00
[[nodiscard]] inline size_t used() const noexcept
{
2023-12-28 03:49:00 -05:00
return max;
}
2023-12-27 22:04:33 -05:00
~static_dynamic_array()
{
2024-01-08 21:12:31 -05:00
if (std::holds_alternative<vbo_type*>(data_))
delete[] std::get<vbo_type*>(data_);
2023-12-27 22:04:33 -05:00
}
};
/**
* basic VAO class.
*/
2023-12-28 13:05:36 -05:00
class vertex_array
2023-12-27 22:04:33 -05:00
{
private:
GLuint vaoID;
2023-12-28 03:49:00 -05:00
static_dynamic_array VBOs;
2024-03-23 19:52:57 -04:00
blt::hashset_t<GLuint> used_attributes;
2023-12-28 13:05:04 -05:00
vbo_t element;
void handle_vbo(const vbo_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
2024-01-11 11:49:48 -05:00
2023-12-27 22:04:33 -05:00
public:
2023-12-28 13:05:36 -05:00
vertex_array();
2023-12-28 13:05:04 -05:00
2023-12-28 13:05:36 -05:00
vertex_array(const vertex_array&) = delete;
2023-12-28 13:05:04 -05:00
2023-12-28 13:05:36 -05:00
vertex_array(vertex_array&&) = delete;
2023-12-28 13:05:04 -05:00
2023-12-28 13:05:36 -05:00
vertex_array& operator=(const vertex_array&) = delete;
2023-12-28 13:05:04 -05:00
2023-12-28 13:05:36 -05:00
vertex_array& operator=(vertex_array&&) = delete;
2023-12-28 13:05:04 -05:00
/**
* This function takes ownership of the underlying VBO (GPU side). It will be freed when the basic vertex array is deleted
* @param vbo vbo to bind to this attribute
* @param attribute_number attribute number to bind to
* @param coordinate_size size of the data (number of
* @param type type of data
* @param stride how many bytes this data takes (for the entire per-vertex data structure) 0 will assume packed data
2023-12-28 16:14:12 -05:00
* This is in effect how many bytes until the next block of data
2023-12-28 13:05:04 -05:00
* @param offset offset into the data structure to where the data is stored
* @return a shared pointer to the stored vbo. used for chaining VAOs with multiple shared VBOs
2023-12-28 13:05:04 -05:00
*/
static_dynamic_array::vbo_type bindVBO(const vbo_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
2024-01-11 11:49:48 -05:00
// same as the other bind method except you provide the shared reference.
void bindVBO(const static_dynamic_array::vbo_type& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
2023-12-28 13:05:04 -05:00
2023-12-28 16:14:12 -05:00
inline void bindElement(const vbo_t& vbo)
{
bind();
element = vbo;
vbo.bind();
unbind();
}
inline vbo_t& getElement()
{
return element;
}
2023-12-28 13:05:04 -05:00
/**
* Returns a non-owning reference to a vbo allowing for updating the VBO
* The VBO is considered invalid if its ID is 0
*/
inline vbo_t& operator[](size_t index)
2024-04-12 00:10:29 -04:00
{
return getBuffer(index);
}
inline vbo_t& getBuffer(size_t index)
2023-12-28 13:05:04 -05:00
{
2024-01-08 21:12:31 -05:00
return VBOs[index]->vbo;
2023-12-28 13:05:04 -05:00
}
2024-01-08 21:12:31 -05:00
inline void bind() const
2023-12-28 13:05:04 -05:00
{
glBindVertexArray(vaoID);
}
2023-12-28 16:14:12 -05:00
static inline void unbind()
{
glBindVertexArray(0);
}
2024-01-11 11:49:48 -05:00
static inline std::shared_ptr<vbo_t_owner> createSharedVBO(const vbo_t& vbo)
{
return std::make_shared<vbo_t_owner>(vbo);
}
2023-12-28 13:05:36 -05:00
~vertex_array();
2023-12-27 22:04:33 -05:00
};
2023-12-27 01:10:53 -05:00
}
#endif //BLT_WITH_GRAPHICS_MODEL_H