diff --git a/.idea/editor.xml b/.idea/editor.xml
index 5bf27ce..907ea1b 100644
--- a/.idea/editor.xml
+++ b/.idea/editor.xml
@@ -283,8 +283,11 @@
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 4612212..efc4599 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -4,18 +4,23 @@
+
+
+
+
+
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d317969..30b1d20 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.25)
-project(gpu-particles VERSION 0.0.15)
+project(gpu-particles VERSION 0.0.16)
option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
diff --git a/default.nix b/default.nix
index 8259cac..d69db8d 100644
--- a/default.nix
+++ b/default.nix
@@ -49,6 +49,7 @@ pkgs.mkShell
libGL
libGL.dev
glfw
+ libbacktrace
];
LD_LIBRARY_PATH="/run/opengl-driver/lib:/run/opengl-driver-32/lib";
}
diff --git a/include/vao.h b/include/vao.h
deleted file mode 100644
index 5ca4d91..0000000
--- a/include/vao.h
+++ /dev/null
@@ -1,188 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2024 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 .
- */
-
-#ifndef BLT_GFX_VAO_H
-#define BLT_GFX_VAO_H
-
-#include
-#include
-#include
-#include
-
-namespace blt::gfx
-{
- class unique_vao_t;
-
- namespace detail
- {
- struct vao_vbo_storage_t
- {
- std::unique_ptr vbo;
- std::optional> attribute_numbers;
-
- [[nodiscard]] bool is_element() const
- {
- return vbo->get_buffer_type() == GL_ELEMENT_ARRAY_BUFFER;
- }
-
- explicit vao_vbo_storage_t(unique_vbo_t&& vbo): vbo(std::make_unique(std::move(vbo)))
- {}
- };
-
- class vao_vbo_context_t
- {
- 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 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();
-
- vao_vbo_context_t attach_vbo(unique_vbo_t&& vbo) const;
- private:
- [[nodiscard]] bool is_bound() const;
-
- explicit vao_context_t(unique_vao_t& vao): vao(vao)
- {
- bind();
- }
-
- unique_vao_t& vao;
- };
- }
-
- class unique_vao_t
- {
- friend detail::vao_vbo_context_t;
- friend detail::vao_context_t;
-
- public:
- unique_vao_t(): vaoID(0)
- {
- glGenVertexArrays(1, &*vaoID);
- }
-
- unique_vao_t(const unique_vao_t&) = delete;
-
- unique_vao_t& operator=(const unique_vao_t&) = delete;
-
- unique_vao_t(unique_vao_t&& other) noexcept: vaoID(std::exchange(other.vaoID, std::nullopt))
- {}
-
- unique_vao_t& operator=(unique_vao_t&& other) noexcept
- {
- vaoID = std::exchange(other.vaoID, vaoID);
- return *this;
- }
-
- detail::vao_context_t bind();
-
- [[nodiscard]] std::optional> get_attribute(const u32 attribute) const
- {
- for (const auto& vbo_obj : vbo_list)
- {
- if (const auto attrs = vbo_obj.attribute_numbers)
- {
- if (attrs->contains(attribute))
- return *vbo_obj.vbo;
- }
- }
- return {};
- }
-
- [[nodiscard]] std::optional> get_buffer_type(const GLuint buffer_type) const
- {
- for (const auto& vbo_obj : vbo_list)
- {
- if (vbo_obj.vbo->get_buffer_type() == buffer_type)
- return *vbo_obj.vbo;
- }
- return {};
- }
-
- [[nodiscard]] std::optional> get_element() const
- {
- for (const auto& vbo_obj : vbo_list)
- {
- if (vbo_obj.is_element())
- return *vbo_obj.vbo;
- }
- return {};
- }
-
- ~unique_vao_t()
- {
- if (vaoID)
- glDeleteVertexArrays(1, &*vaoID);
- }
-
- private:
- std::optional vaoID;
- std::vector vbo_list;
- };
-}
-
-#endif //BLT_GFX_VAO_H
diff --git a/include/vbo.h b/include/vbo.h
deleted file mode 100644
index f387b3d..0000000
--- a/include/vbo.h
+++ /dev/null
@@ -1,216 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2024 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 .
- */
-
-#ifndef BLT_GFX_VBO_H
-#define BLT_GFX_VBO_H
-
-#include
-#include
-#include
-#include
-
-namespace blt::gfx
-{
- class unique_vbo_t;
-
- 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
- {
- 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)
- *
- * It is very unlikely that you need this method!
- */
- vbo_context_t& bind();
-
- vbo_context_t& unbind();
-
- /**
- * Reserves a chunk of GPU memory for future use
- */
- vbo_context_t& resize(GLsizeiptr size, 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 resize(static_cast(size), 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);
-
- /**
- * 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);
-
- /**
- * 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 update(offset, size, static_cast(ptr));
- }
-
- private:
- [[nodiscard]] bool is_bound() const;
-
- explicit vbo_context_t(unique_vbo_t& vbo): vbo(vbo)
- {
- bind();
- }
-
- unique_vbo_t& vbo;
- };
- }
-
- class unique_vbo_t
- {
- friend class detail::vbo_context_t;
-
- public:
- explicit unique_vbo_t(const GLuint type): vboID(0), buffer_type(type)
- {
- glGenBuffers(1, &*vboID);
- }
-
- unique_vbo_t(const unique_vbo_t&) = delete;
-
- unique_vbo_t& operator=(const unique_vbo_t&) = delete;
-
- unique_vbo_t(unique_vbo_t&& other) noexcept: vboID(std::exchange(other.vboID, std::nullopt)), buffer_type(other.buffer_type),
- size(other.size), memory_type(other.memory_type)
- {}
-
- unique_vbo_t& operator=(unique_vbo_t&& other) noexcept
- {
- vboID = std::exchange(other.vboID, vboID);
- buffer_type = std::exchange(other.buffer_type, buffer_type);
- size = std::exchange(other.size, size);
- memory_type = std::exchange(other.memory_type, memory_type);
- return *this;
- }
-
- /**
- * Changes the internal buffer type of this VBO
- */
- GLuint change_type(const GLuint type)
- {
- return std::exchange(this->buffer_type, type);
- }
-
- /**
- * 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.
- *
- * You can enable the flag BLT_DEBUG_CONTRACTS which will validate VBO bind state making most of ^ irrelevant
- */
- detail::vbo_context_t bind();
-
- [[nodiscard]] auto native_handle() const
- {
- return vboID;
- }
-
- [[nodiscard]] GLsizeiptr get_size() const
- {
- return size;
- }
-
- [[nodiscard]] GLint get_memory_type() const
- {
- return memory_type;
- }
-
- [[nodiscard]] GLuint get_buffer_type() const
- {
- return buffer_type;
- }
-
- ~unique_vbo_t()
- {
- if (vboID)
- glDeleteBuffers(1, &*vboID);
- }
-
- private:
- std::optional vboID;
- GLuint buffer_type;
- GLsizeiptr size = 0;
- GLint memory_type = 0;
- };
-
- class unique_ssbo_t : public unique_vbo_t
- {
- public:
- unique_ssbo_t(): unique_vbo_t{GL_SHADER_STORAGE_BUFFER}
- {}
- };
-
- class unique_ebo_t : public unique_vbo_t
- {
- public:
- unique_ebo_t(): unique_vbo_t{GL_ELEMENT_ARRAY_BUFFER}
- {}
- };
-
- class unique_ubo_t : public unique_vbo_t
- {
- public:
- 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;
- };
-}
-
-#endif //BLT_GFX_VBO_H
diff --git a/src/main.cpp b/src/main.cpp
index aa06639..9a5d392 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -14,16 +14,16 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+#include
+#include
+#include
#include
-#include "blt/gfx/renderer/resource_manager.h"
-#include "blt/gfx/renderer/batch_2d_renderer.h"
-#include "blt/gfx/renderer/camera.h"
#include
-#include
-#include
#include
#include
-#include
+#include "blt/gfx/renderer/batch_2d_renderer.h"
+#include "blt/gfx/renderer/camera.h"
+#include "blt/gfx/renderer/resource_manager.h"
constexpr blt::size_t PARTICLE_COUNT = 8192;
@@ -70,10 +70,9 @@ public:
unique_ebo_t alive_particles_ebo;
alive_particles_ebo.bind().upload(sizeof(blt::u32) * alive_particles.size(), alive_particles.data(), GL_DYNAMIC_DRAW);
- auto vao_ctx = particle_vao.bind();
+ const auto vao_ctx = particle_vao.configure();
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));
- vao_ctx.unbind();
}
void render()
@@ -84,7 +83,6 @@ public:
particle_shader->setInt("tex1", 0);
particle_shader->setInt("tex2", 1);
particle_vao.bind();
- // particle_vao.get_element()->get().bind();
glActiveTexture(GL_TEXTURE0);
resources.get("silly").value()->bind();
glActiveTexture(GL_TEXTURE1);
diff --git a/src/vao.cpp b/src/vao.cpp
deleted file mode 100644
index dc14483..0000000
--- a/src/vao.cpp
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- *
- * Copyright (C) 2025 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 .
- */
-#include
-#include
-#include
-#include
-
-namespace blt::gfx
-{
- #define ENSURE_CONTEXT_BOUND BLT_CONTRACT(glfwGetCurrentContext() != nullptr, "Expected active OpenGL context!")
-
- #if blt_debug_has_flag(BLT_DEBUG_CONTRACTS)
- GLuint bound_vao_id = 0;
- #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 (!vbo.attribute_numbers)
- vbo.attribute_numbers = hashset_t();
- if (!vbo.attribute_numbers->contains(attribute_number))
- vbo.attribute_numbers->insert(attribute_number);
- 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;
- return *this;
- }
-
- detail::vao_context_t& detail::vao_context_t::unbind() // NOLINT
- {
- ENSURE_CONTEXT_BOUND;
- glBindVertexArray(0);
- bound_vao_id = 0;
- return *this;
- }
-
- 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!)");
-
- auto& vbo_storage = vao.vbo_list.emplace_back(std::move(vbo));
- vbo_storage.vbo->bind();
- return vao_vbo_context_t{vao, vbo_storage};
- }
-
- bool detail::vao_context_t::is_bound() const
- {
- return *vao.vaoID == bound_vao_id;
- }
-
- detail::vao_context_t unique_vao_t::bind()
- {
- ENSURE_CONTEXT_BOUND;
- return detail::vao_context_t{*this};
- }
-}
diff --git a/src/vbo.cpp b/src/vbo.cpp
deleted file mode 100644
index 424b0b0..0000000
--- a/src/vbo.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- *
- * Copyright (C) 2025 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 .
- */
-#include
-#include
-#include
-#include
-
-namespace blt::gfx
-{
- #if blt_debug_has_flag(BLT_DEBUG_CONTRACTS)
- static hashmap_t bound_vbo_ids;
- #endif
-
- namespace detail
- {
- vbo_context_t& vbo_context_t::bind()
- {
- BLT_CONTRACT(vbo.vboID, "Expected VBO to have an associated VBO ID!");
- glBindBuffer(vbo.buffer_type, *vbo.vboID);
- #if blt_debug_has_flag(BLT_DEBUG_CONTRACTS)
- bound_vbo_ids[vbo.buffer_type] = *vbo.vboID;
- #endif
- return *this;
- }
-
- vbo_context_t& vbo_context_t::unbind()
- {
- glBindBuffer(vbo.buffer_type, 0);
- #if blt_debug_has_flag(BLT_DEBUG_CONTRACTS)
- bound_vbo_ids[vbo.buffer_type] = 0;
- #endif
- return *this;
- }
-
- vbo_context_t& vbo_context_t::resize(const GLsizeiptr size, const GLint mem_type)
- {
- BLT_CONTRACT(is_bound(), "Expected VBO to be bound before resizing!");
- vbo.size = size;
- vbo.memory_type = mem_type;
- glBufferData(vbo.buffer_type, size, nullptr, mem_type);
- return *this;
- }
-
- vbo_context_t& vbo_context_t::upload(const size_t size, const void* ptr, const GLint mem_type)
- {
- BLT_CONTRACT(is_bound(), "Expected VBO to be bound before uploading!");
- if (mem_type != vbo.memory_type || static_cast(vbo.size) < size)
- {
- vbo.size = static_cast(size);
- vbo.memory_type = mem_type;
- glBufferData(vbo.buffer_type, vbo.size, ptr, mem_type);
- } else
- {
- update(0, size, ptr);
- }
- return *this;
- }
-
- vbo_context_t& vbo_context_t::update(const size_t offset, const size_t size, const void* ptr)
- {
- BLT_CONTRACT(is_bound(), "Expected VBO to be bound before updating!");
- glBufferSubData(vbo.buffer_type, static_cast(offset), static_cast(size), ptr);
- return *this;
- }
-
- bool vbo_context_t::is_bound() const
- {
- #if blt_debug_has_flag(BLT_DEBUG_CONTRACTS)
- return bound_vbo_ids[vbo.buffer_type] == *vbo.vboID;
- #else
- return true;
- #endif
- }
- }
-
- 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());
- }
-}