diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index efc4599..4612212 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -4,23 +4,18 @@
-
-
-
-
-
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a12bd91..76081bf 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
-project(gpu-particles VERSION 0.0.10)
+project(gpu-particles VERSION 0.0.11)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
diff --git a/include/vbo.h b/include/vbo.h
index b7dcfa1..bb35434 100644
--- a/include/vbo.h
+++ b/include/vbo.h
@@ -30,6 +30,10 @@ namespace blt::gfx
namespace detail
{
+ /**
+ * So long as this class is called from vbo.bind(), it is always valid to chain any internal functions.
+ * This system is designed to be foolproof, so don't get too clever
+ */
class vbo_context_t
{
public:
@@ -47,27 +51,45 @@ namespace blt::gfx
vbo_context_t& unbind();
- vbo_context_t& reserve(GLsizeiptr size, GLint mem_type);
+ /**
+ * Reserves a chunk of GPU memory for future use
+ */
+ vbo_context_t& resize(GLsizeiptr size, GLint mem_type);
- vbo_context_t& reserve(const size_t size, const GLint mem_type)
+ /**
+ * Reserves a chunk of GPU memory for future use
+ */
+ vbo_context_t& resize(const size_t size, const GLint mem_type)
{
- return reserve(static_cast(size), mem_type);
+ return resize(static_cast(size), mem_type);
}
- vbo_context_t& upload(size_t size, void* ptr, GLint mem_type);
+ /**
+ * Uploads a chunk of memory to the GPU. If the existing VBO has enough space, the memory will be reused.
+ */
+ vbo_context_t& upload(size_t size, const void* ptr, GLint mem_type);
- template
+ /**
+ * Uploads a chunk of memory to the GPU. If the existing VBO has enough space, the memory will be reused.
+ */
+ template , bool> = true>
vbo_context_t& upload(const size_t size, T* ptr, const GLint mem_type)
{
return upload(size, static_cast(ptr), mem_type);
}
+ /**
+ * Updates an internal segment of the VBO. This function will never reallocate.
+ */
vbo_context_t& update(size_t offset, size_t size, const void* ptr);
- template
- vbo_context_t& update(size_t offset, const size_t size, T* ptr)
+ /**
+ * Updates an internal segment of the VBO. This function will never reallocate.
+ */
+ template , bool> = true>
+ vbo_context_t& update(const size_t offset, const size_t size, T* ptr)
{
- return upload(offset, size, static_cast(ptr));
+ return update(offset, size, static_cast(ptr));
}
private:
@@ -102,12 +124,26 @@ namespace blt::gfx
return *this;
}
+ /**
+ * Changes the internal buffer type of this VBO
+ */
GLuint change_type(const GLuint type)
{
return std::exchange(this->buffer_type, type);
}
- [[nodiscard]] auto bind();
+ /**
+ * This function binds the VBO to the current buffer_type slot and returns an object which allows you to modify or use this VBO.
+ * This allows you to use the VBO without worrying about whether an operation is valid in this context.
+ * As so long as you use this object in line, or without binding other VBOs to the same buffer_type
+ * (violating the contracts this function attempts to create) then all functions on the associated object are valid to call.
+ */
+ [[nodiscard]] detail::vbo_context_t bind();
+
+ [[nodiscard]] auto native_handle() const
+ {
+ return vboID;
+ }
~unique_vbo_t()
{
@@ -139,8 +175,17 @@ namespace blt::gfx
class unique_ubo_t : public unique_vbo_t
{
public:
- unique_ubo_t(): unique_vbo_t{GL_UNIFORM_BUFFER}
- {}
+ explicit unique_ubo_t(const i32 location): unique_vbo_t{GL_UNIFORM_BUFFER}
+ {set_location(location);}
+
+ void set_location(i32 new_location);
+
+ [[nodiscard]] i32 get_location() const
+ {
+ return location;
+ }
+ private:
+ i32 location = 0;
};
}
diff --git a/src/vbo.cpp b/src/vbo.cpp
index 92c9822..64f2da2 100644
--- a/src/vbo.cpp
+++ b/src/vbo.cpp
@@ -26,17 +26,17 @@ namespace blt::gfx
vbo_context_t& vbo_context_t::bind()
{
BLT_CONTRACT(vbo.vboID, "Expected VBO to have an assoicated VBO ID!");
- glBindBuffer(vbo.type, *vbo.vboID);
+ glBindBuffer(vbo.buffer_type, *vbo.vboID);
return *this;
}
vbo_context_t& vbo_context_t::unbind()
{
- glBindBuffer(vbo.type, 0);
+ glBindBuffer(vbo.buffer_type, 0);
return *this;
}
- vbo_context_t& vbo_context_t::reserve(const GLsizeiptr size, const GLint mem_type)
+ vbo_context_t& vbo_context_t::resize(const GLsizeiptr size, const GLint mem_type)
{
vbo.size = size;
vbo.memory_type = mem_type;
@@ -44,9 +44,9 @@ namespace blt::gfx
return *this;
}
- vbo_context_t& vbo_context_t::upload(const size_t size, void* ptr, const GLint mem_type)
+ vbo_context_t& vbo_context_t::upload(const size_t size, const void* ptr, const GLint mem_type)
{
- if (mem_type != vbo.memory_type || vbo.size < size)
+ if (mem_type != vbo.memory_type || static_cast(vbo.size) < size)
{
vbo.size = static_cast(size);
vbo.memory_type = mem_type;
@@ -65,9 +65,16 @@ namespace blt::gfx
}
}
- auto unique_vbo_t::bind()
+ detail::vbo_context_t unique_vbo_t::bind()
{
BLT_CONTRACT(glfwGetCurrentContext() != nullptr, "Expected active OpenGL context!");
return detail::vbo_context_t{*this};
}
+
+ void unique_ubo_t::set_location(const i32 new_location)
+ {
+ BLT_CONTRACT(native_handle().has_value(), "Expected UBO to have an associated buffer! (You are probably calling this on a moved-from value)");
+ location = new_location;
+ glBindBufferBase(GL_UNIFORM_BUFFER, location, *native_handle());
+ }
}