diff --git a/.idea/editor.xml b/.idea/editor.xml
index 907ea1b..5bf27ce 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -283,11 +283,8 @@
-
-
-
\ No newline at end of file
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 39685cc..cdd3275 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
-project(gpu-particles VERSION 0.0.12)
+project(gpu-particles VERSION 0.0.13)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
diff --git a/include/vao.h b/include/vao.h
index 0023744..9a2ee7e 100644
--- a/include/vao.h
+++ b/include/vao.h
@@ -32,7 +32,7 @@ namespace blt::gfx
struct vao_vbo_storage_t
{
std::unique_ptr vbo;
- u32 attribute_number = 0;
+ std::optional> attribute_numbers;
[[nodiscard]] bool is_element() const
{
@@ -47,21 +47,55 @@ namespace blt::gfx
{
friend class vao_context_t;
public:
+ vao_vbo_context_t(const vao_vbo_context_t& copy) = delete;
+ vao_vbo_context_t(vao_vbo_context_t&& move) = delete;
+ vao_vbo_context_t& operator=(const vao_vbo_context_t& copy) = delete;
+ vao_vbo_context_t& operator=(vao_vbo_context_t&& move) = delete;
+ /**
+ * This function takes ownership of the underlying VBO (GPU side). It will be freed when the basic vertex array is deleted
+ * @param attribute_number attribute number to bind to
+ * @param coordinate_size size of the data (number of elements, not the number of bytes)
+ * @param type GL_TYPE type of data
+ * @param stride how many bytes this data takes (for the entire per-vertex data structure) 0 will assume packed data
+ * This is in effect how many bytes until the next block of data
+ * @param offset offset into the data structure to where the data is stored
+ */
+ vao_vbo_context_t& attribute_ptr(int attribute_number, int coordinate_size, GLenum type, int stride, long offset);
+ vao_vbo_context_t& silence()
+ {
+ attributed = true;
+ return *this;
+ }
+
+ /**
+ * Useless function, but if it makes you feel better, feel free to use it.
+ */
+ vao_vbo_context_t& as_element()
+ {
+ return *this;
+ }
+
+ ~vao_vbo_context_t();
private:
vao_vbo_context_t(unique_vao_t& vao, vao_vbo_storage_t& vbo): vbo(vbo), vao(vao)
{}
vao_vbo_storage_t& vbo;
unique_vao_t& vao;
+ bool attributed = false;
};
class vao_context_t
{
friend vao_vbo_context_t;
- friend class unique_vao_t;
-
+ friend unique_vao_t;
public:
+ vao_context_t(const vao_context_t& copy) = delete;
+ vao_context_t(vao_context_t&& move) = delete;
+ vao_context_t& operator=(const vao_context_t& copy) = delete;
+ vao_context_t& operator=(vao_context_t&& move) = delete;
+
vao_context_t& bind();
vao_context_t& unbind();
diff --git a/include/vbo.h b/include/vbo.h
index 91cd0c2..e891f40 100644
--- a/include/vbo.h
+++ b/include/vbo.h
@@ -38,6 +38,10 @@ namespace blt::gfx
{
friend unique_vbo_t;
public:
+ vbo_context_t(const vbo_context_t& copy) = delete;
+ vbo_context_t(vbo_context_t&& move) = delete;
+ vbo_context_t& operator=(const vbo_context_t& copy) = delete;
+ vbo_context_t& operator=(vbo_context_t&& move) = delete;
/**
* By default, the VBO is bound when this class is constructed (this class should only be constructed through the VBO bind() method)
*
diff --git a/src/main.cpp b/src/main.cpp
index ff36a8a..8cc193b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,7 +24,6 @@
#include
#include
#include
-#include
constexpr blt::size_t PARTICLE_COUNT = 8192;
@@ -48,9 +47,7 @@ struct particle_t
}
};
-std::unique_ptr particle_vao;
-std::unique_ptr particle_vbo;
-std::unique_ptr alive_particles_ebo;
+std::optional particle_vao;
std::unique_ptr particle_shader;
std::vector alive_particles;
@@ -69,17 +66,16 @@ void init(const blt::gfx::window_data&)
alive_particles.push_back(i);
}
- particle_vbo = std::make_unique();
- particle_vbo->create(GL_ARRAY_BUFFER);
- particle_vbo->allocate(sizeof(particle_t) * particles.size(), GL_DYNAMIC_DRAW, particles.data());
+ unique_vbo_t particle_vbo(GL_ARRAY_BUFFER);
+ particle_vbo.bind().upload(sizeof(particle_t) * particles.size(), particles.data(), GL_DYNAMIC_DRAW);
- alive_particles_ebo = std::make_unique();
- alive_particles_ebo->create();
- alive_particles_ebo->allocate(sizeof(blt::u32) * alive_particles.size(), GL_DYNAMIC_DRAW, alive_particles.data());
+ unique_ebo_t alive_particles_ebo;
+ alive_particles_ebo.bind().upload(sizeof(blt::u32) * alive_particles.size(), alive_particles.data(), GL_DYNAMIC_DRAW);
- particle_vao = std::make_unique();
- particle_vao->bindVBO(*particle_vbo, 0, 2, GL_FLOAT, sizeof(particle_t), 0);
- particle_vao->bindElement(*alive_particles_ebo);
+ particle_vao = unique_vao_t();
+ const auto vao_ctx = particle_vao->bind();
+ vao_ctx.attach_vbo(std::move(particle_vbo)).attribute_ptr(0, 2, GL_FLOAT, sizeof(particle_t), 0);
+ vao_ctx.attach_vbo(std::move(alive_particles_ebo));
global_matrices.create_internals();
resources.load_resources();
@@ -99,6 +95,8 @@ void update(const blt::gfx::window_data& data)
void destroy(const blt::gfx::window_data&)
{
+ particle_vao.reset();
+ particle_shader.reset();
global_matrices.cleanup();
resources.cleanup();
renderer_2d.cleanup();
diff --git a/src/vao.cpp b/src/vao.cpp
index 352352a..bdbc1f3 100644
--- a/src/vao.cpp
+++ b/src/vao.cpp
@@ -22,14 +22,45 @@
namespace blt::gfx
{
- #define BLT_DEBUG_LEVEL BLT_DEBUG_CONTRACTS
+ #define ENSURE_CONTEXT_BOUND BLT_CONTRACT(glfwGetCurrentContext() != nullptr, "Expected active OpenGL context!")
#if blt_debug_has_flag(BLT_DEBUG_CONTRACTS)
- GLuint bound_vao_id;
+ GLuint bound_vao_id;
#endif
+ detail::vao_vbo_context_t& detail::vao_vbo_context_t::attribute_ptr(const int attribute_number, const int coordinate_size, const GLenum type,
+ const int stride, const long offset)
+ {
+ if (auto& vec = vbo.attribute_numbers)
+ {
+ for (const auto& v : *vec)
+ {
+ if (static_cast(v) == attribute_number)
+ goto use;
+ }
+ vec->push_back(attribute_number);
+ }
+ use:
+ glEnableVertexAttribArray(attribute_number);
+ glVertexAttribPointer(attribute_number, coordinate_size, type, GL_FALSE, stride < 0 ? 0 : stride, reinterpret_cast(offset));
+ attributed = true;
+ return *this;
+ }
+
+ detail::vao_vbo_context_t::~vao_vbo_context_t()
+ {
+ #if blt_debug_has_flag(BLT_DEBUG_CONTRACTS)
+ if (!(vbo.is_element() || attributed))
+ {
+ BLT_WARN("VBO is not an element array buffer or been assigned to an attribute, are you sure this is what you want?");
+ BLT_WARN("You can silence this warning by calling .silence()");
+ }
+ #endif
+ }
+
detail::vao_context_t& detail::vao_context_t::bind()
{
+ ENSURE_CONTEXT_BOUND;
BLT_CONTRACT(vao.vaoID, "Expected VAO to have an associated VAO ID!");
glBindVertexArray(*vao.vaoID);
bound_vao_id = *vao.vaoID;
@@ -45,6 +76,7 @@ namespace blt::gfx
detail::vao_vbo_context_t detail::vao_context_t::attach_vbo(unique_vbo_t&& vbo) const
{
+ ENSURE_CONTEXT_BOUND;
BLT_CONTRACT(vao.vaoID, "Expected VAO to have an associated VAO ID!");
BLT_CONTRACT(is_bound(), "Expected VAO to be bound before attaching VBO! (If you are using this API correctly, this has been done for you!)");
@@ -60,7 +92,7 @@ namespace blt::gfx
detail::vao_context_t unique_vao_t::bind()
{
- BLT_CONTRACT(glfwGetCurrentContext() != nullptr, "Expected active OpenGL context!");
+ ENSURE_CONTEXT_BOUND;
return detail::vao_context_t{*this};
}
}