From dd3a242b4110552f9a9b9252d9abd28093e66d22 Mon Sep 17 00:00:00 2001 From: Brett Date: Thu, 12 Jun 2025 02:16:37 -0400 Subject: [PATCH] breaking change, new VAO/VBO. Updated renderers not tested. --- CMakeLists.txt | 2 +- include/blt/gfx/model.h | 243 -------- include/blt/gfx/renderer/batch_2d_renderer.h | 26 +- include/blt/gfx/renderer/font_renderer.h | 4 +- include/blt/gfx/renderer/postprocess.h | 6 +- include/blt/gfx/vbo.h | 12 +- src/blt/gfx/model.cpp | 155 ----- src/blt/gfx/renderer/batch_2d_renderer.cpp | 144 +++-- src/blt/gfx/renderer/font_renderer.cpp | 11 +- src/blt/gfx/renderer/postprocess.cpp | 573 ++++++++++--------- 10 files changed, 405 insertions(+), 771 deletions(-) delete mode 100644 include/blt/gfx/model.h delete mode 100644 src/blt/gfx/model.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1fe21e3..d017ba3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.25) include(FetchContent) -set(BLT_GRAPHICS_VERSION 2.0.11) +set(BLT_GRAPHICS_VERSION 3.0.0) set(BLT_GRAPHICS_TEST_VERSION 0.0.1) project(BLT_WITH_GRAPHICS VERSION ${BLT_GRAPHICS_VERSION}) diff --git a/include/blt/gfx/model.h b/include/blt/gfx/model.h deleted file mode 100644 index 2de89af..0000000 --- a/include/blt/gfx/model.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * - * 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 . - */ - -#ifndef BLT_WITH_GRAPHICS_MODEL_H -#define BLT_WITH_GRAPHICS_MODEL_H - -#include -#include -#include -#include -#include -#include - -namespace blt::gfx -{ - struct vbo_t_owner; - - class static_dynamic_array; - - class vertex_array_t; - - // vbo - struct vertex_buffer_t - { - friend vbo_t_owner; - friend vertex_array_t; - 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 - void allocate(GLsizeiptr size, const T* data, GLint mem_type = GL_STATIC_DRAW) - { - allocate(size, mem_type, static_cast(data)); - } - - void sub_update(GLsizeiptr offset, GLsizeiptr size, const void* data) const; - - void update(GLsizeiptr size, const void* data); - - void destroy(); - }; - - // ssbo - struct shader_buffer_t : public vertex_buffer_t - { - public: - inline void create() - { - vertex_buffer_t::create(GL_SHADER_STORAGE_BUFFER); - } - }; - - // ebo - struct element_buffer_t : public vertex_buffer_t - { - public: - inline void create() - { - vertex_buffer_t::create(GL_ELEMENT_ARRAY_BUFFER); - } - }; - - struct vbo_t_owner - { - vertex_buffer_t vbo; - - vbo_t_owner() = default; - - explicit vbo_t_owner(vertex_buffer_t vbo): vbo(vbo) - {} - - vertex_buffer_t* operator->() - { - return &vbo; - } - - ~vbo_t_owner() - { - if (!vbo.bufferID_) - return; - vbo.destroy(); - vbo.unbind(); - } - }; - - /** - * 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 - */ - class static_dynamic_array - { - public: - using vbo_type = std::shared_ptr; - private: - static constexpr size_t DATA_SIZE = 8; - using array_t = std::array; - std::variant data_; - size_t size_ = DATA_SIZE; - size_t max = 0; - - void swap(); - - public: - static_dynamic_array(); - - static_dynamic_array(const static_dynamic_array& copy) = delete; - - static_dynamic_array(static_dynamic_array&& move) noexcept = default; - - static_dynamic_array& operator=(const static_dynamic_array& copy) = delete; - - static_dynamic_array& operator=(static_dynamic_array&& move) noexcept = default; - - vbo_type& operator[](size_t index); - - [[nodiscard]] inline size_t used() const noexcept - { - return max; - } - - ~static_dynamic_array() - { - if (std::holds_alternative(data_)) - delete[] std::get(data_); - } - }; - - /** - * basic VAO class. - */ - class vertex_array_t - { - private: - GLuint vaoID; - static_dynamic_array VBOs; - blt::hashset_t used_attributes; - vertex_buffer_t element; - - void handle_vbo(const vertex_buffer_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset); - - public: - vertex_array_t(); - - vertex_array_t(const vertex_array_t&) = delete; - - vertex_array_t(vertex_array_t&&) = delete; - - vertex_array_t& operator=(const vertex_array_t&) = delete; - - vertex_array_t& operator=(vertex_array_t&&) = delete; - - /** - * 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 - * 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 - * @return a shared pointer to the stored vbo. used for chaining VAOs with multiple shared VBOs - */ - void bindVBO(const vertex_buffer_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset); - - // 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); - - inline void bindElement(const vertex_buffer_t& vbo) - { - bind(); - element = vbo; - vbo.bind(); - unbind(); - } - - inline vertex_buffer_t& getElement() - { - return element; - } - - /** - * Returns a non-owning reference to a vbo allowing for updating the VBO - * The VBO is considered invalid if its ID is 0 - */ - inline vertex_buffer_t& operator[](size_t index) - { - return getBuffer(index); - } - - inline vertex_buffer_t& getBuffer(size_t index) - { - return VBOs[index]->vbo; - } - - inline void bind() const - { - glBindVertexArray(vaoID); - } - - static inline void unbind() - { - glBindVertexArray(0); - } - - static inline static_dynamic_array::vbo_type make_vbo(const vertex_buffer_t& vbo) - { - return std::make_shared(vbo); - } - - ~vertex_array_t(); - }; - -} - -#endif //BLT_WITH_GRAPHICS_MODEL_H diff --git a/include/blt/gfx/renderer/batch_2d_renderer.h b/include/blt/gfx/renderer/batch_2d_renderer.h index 9b752d8..5e5c8a0 100644 --- a/include/blt/gfx/renderer/batch_2d_renderer.h +++ b/include/blt/gfx/renderer/batch_2d_renderer.h @@ -19,16 +19,16 @@ #ifndef BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H #define BLT_WITH_GRAPHICS_BATCH_2D_RENDERER_H -#include "blt/gfx/model.h" -#include "blt/gfx/shader.h" -#include "blt/gfx/framebuffer.h" -#include "blt/gfx/renderer/resource_manager.h" -#include "blt/gfx/renderer/postprocess.h" -#include -#include -#include #include #include +#include +#include +#include +#include "blt/gfx/framebuffer.h" +#include "blt/gfx/shader.h" +#include "blt/gfx/vao.h" +#include "blt/gfx/renderer/postprocess.h" +#include "blt/gfx/renderer/resource_manager.h" namespace blt::gfx { @@ -121,12 +121,12 @@ namespace blt::gfx struct draw_t { - std::unique_ptr vao; + std::optional vao; i32 count; }; [[nodiscard]] draw_t to_vertex_array() const; - size_t populate_vertex_array(vertex_array_t& va) const; + [[nodiscard]] size_t populate_vertex_array(const unique_vao_t& va) const; [[nodiscard]] std::vector calculate_vertices() const; @@ -254,9 +254,9 @@ namespace blt::gfx using object_container = hashmap_t>>; private: - std::unique_ptr square_vao; - std::unique_ptr line_vao; - std::unique_ptr curve_vao; + std::optional square_vao; + std::optional line_vao; + std::optional curve_vao; std::unique_ptr square_shader; std::unique_ptr point_shader; resource_manager& resources; diff --git a/include/blt/gfx/renderer/font_renderer.h b/include/blt/gfx/renderer/font_renderer.h index c66b20f..323aa36 100644 --- a/include/blt/gfx/renderer/font_renderer.h +++ b/include/blt/gfx/renderer/font_renderer.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -368,7 +368,7 @@ namespace blt::gfx font_generator_t& generator; std::string contents, font; - vertex_array_t vao{}; + unique_vao_t vao{}; std::vector renders; blt::vec2f position, bounds; blt::vec2f scale = DEFAULT_SCALE; diff --git a/include/blt/gfx/renderer/postprocess.h b/include/blt/gfx/renderer/postprocess.h index 89e355c..de2f936 100644 --- a/include/blt/gfx/renderer/postprocess.h +++ b/include/blt/gfx/renderer/postprocess.h @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -271,10 +271,10 @@ namespace blt::gfx private: pp_engine_t() = default; - pp_step_t& find_last_frame_buffer(size_t index); + pp_step_t& find_last_frame_buffer(size_t index) const; std::vector> steps; - std::unique_ptr screen_vao; + std::optional screen_vao{}; }; } diff --git a/include/blt/gfx/vbo.h b/include/blt/gfx/vbo.h index 9f58d3e..c16e97a 100644 --- a/include/blt/gfx/vbo.h +++ b/include/blt/gfx/vbo.h @@ -54,14 +54,6 @@ namespace blt::gfx */ 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. */ @@ -71,9 +63,9 @@ namespace blt::gfx * 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) + vbo_context_t& upload(const size_t size, const T* ptr, const GLint mem_type) { - return upload(size, static_cast(ptr), mem_type); + return upload(size, static_cast(ptr), mem_type); } /** diff --git a/src/blt/gfx/model.cpp b/src/blt/gfx/model.cpp deleted file mode 100644 index f3f9389..0000000 --- a/src/blt/gfx/model.cpp +++ /dev/null @@ -1,155 +0,0 @@ -/* - * - * 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 . - */ -#include -#include -#include "blt/logging/logging.h" - -namespace blt::gfx -{ - void static_dynamic_array::swap() - { - size_t next_size = blt::mem::next_byte_allocation(size_); - - auto* new_data = new vbo_type[next_size]; - - if (std::holds_alternative(data_)) - { - auto* ptr = std::get(data_); - for (size_t i = 0; i < size_; i++) - new_data[i] = ptr[i]; - delete[] ptr; - } else - { - auto data = std::get(data_); - for (size_t i = 0; i < DATA_SIZE; i++) - new_data[i] = data[i]; - } - data_ = new_data; - size_ = next_size; - } - - static_dynamic_array::static_dynamic_array() = default; - - static_dynamic_array::vbo_type& static_dynamic_array::operator[](size_t index) - { - if (index >= size_) - swap(); - max = std::max(index, max); - if (std::holds_alternative(data_)) - return std::get(data_)[index]; - else - return std::get(data_)[index]; - } - - /* - * ----------------------------------- - * vbo_t - * ----------------------------------- - */ - void vertex_buffer_t::create(GLint type) - { - glGenBuffers(1, &bufferID_); - buffer_type = type; - } - - void vertex_buffer_t::destroy() - { - // prevent multiple destroys of the same object, in cases of multi attribute binds - if (bufferID_ == 0) - return; - glDeleteBuffers(1, &bufferID_); - bufferID_ = 0; - } - - void vertex_buffer_t::allocate(GLsizeiptr size, GLint mem_type, const void* data) - { - bind(); - size_ = size; - glBufferData(buffer_type, size, data, mem_type); - memory_type = mem_type; - } - - void vertex_buffer_t::update(GLsizeiptr size, const void* data) - { - if (size <= size_) - sub_update(0, size, data); - else - allocate(size, memory_type, data); - size_ = size; - } - - void vertex_buffer_t::sub_update(GLsizeiptr offset, GLsizeiptr size, const void* data) const - { - bind(); - glBufferSubData(buffer_type, offset, size, data); - } - - void vertex_buffer_t::bind() const - { - glBindBuffer(buffer_type, bufferID_); - } - - void vertex_buffer_t::unbind() const - { - glBindBuffer(buffer_type, 0); - } - - /* - * ---------------------------- - * basic_vertex_array - * ---------------------------- - */ - - vertex_array_t::vertex_array_t(): vaoID(0) - { - glGenVertexArrays(1, &vaoID); - } - - vertex_array_t::~vertex_array_t() - { - // free all VBOs - for (size_t i = 0; i < VBOs.used(); i++) - VBOs[i] = nullptr; - element.destroy(); - // then free the vertex array - glDeleteVertexArrays(1, &vaoID); - } - - void vertex_array_t::bindVBO(const vertex_buffer_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset) - { - handle_vbo(vbo, attribute_number, coordinate_size, type, stride, offset); - VBOs[attribute_number] = make_vbo(vbo); - } - - void vertex_array_t::bindVBO(const static_dynamic_array::vbo_type& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset) - { - handle_vbo(vbo->vbo, attribute_number, coordinate_size, type, stride, offset); - VBOs[attribute_number] = vbo; - } - - void vertex_array_t::handle_vbo(const vertex_buffer_t& vbo, int attribute_number, int coordinate_size, GLenum type, int stride, long offset) - { - used_attributes.insert(attribute_number); - bind(); - vbo.bind(); - - glEnableVertexAttribArray(attribute_number); - glVertexAttribPointer(attribute_number, coordinate_size, type, GL_FALSE, stride < 0 ? 0 : stride, (void*) offset); - unbind(); - } -} \ No newline at end of file diff --git a/src/blt/gfx/renderer/batch_2d_renderer.cpp b/src/blt/gfx/renderer/batch_2d_renderer.cpp index 8042970..273dcea 100644 --- a/src/blt/gfx/renderer/batch_2d_renderer.cpp +++ b/src/blt/gfx/renderer/batch_2d_renderer.cpp @@ -23,22 +23,58 @@ float square_vertices[20] = { // positions // texture coords - 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right - 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right - -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left - -0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left + 0.5f, + 0.5f, + 0.0f, + 1.0f, + 1.0f, // top right + 0.5f, + -0.5f, + 0.0f, + 1.0f, + 0.0f, // bottom right + -0.5f, + -0.5f, + 0.0f, + 0.0f, + 0.0f, // bottom left + -0.5f, + 0.5f, + 0.0f, + 0.0f, + 1.0f // top left }; const unsigned int square_indices[6] = { - 0, 1, 3, // first triangle - 1, 2, 3 // second triangle + 0, + 1, + 3, // first triangle + 1, + 2, + 3 // second triangle }; float line_vertices[20] = { // positions // texture coords - 0.5f, 0.5f, 0.0f, 1.0f, 1.0f, // top right - 0.5f, -0.5f, 0.0f, 1.0f, 0.0f, // bottom right - -0.5f, -0.5f, 0.0f, 0.0f, 0.0f, // bottom left - -0.5f, 0.5f, 0.0f, 0.0f, 1.0f // top left + 0.5f, + 0.5f, + 0.0f, + 1.0f, + 1.0f, // top right + 0.5f, + -0.5f, + 0.0f, + 1.0f, + 0.0f, // bottom right + -0.5f, + -0.5f, + 0.0f, + 0.0f, + 0.0f, // bottom left + -0.5f, + 0.5f, + 0.0f, + 0.0f, + 1.0f // top left }; // 0, 1 (top right) @@ -51,23 +87,23 @@ namespace blt::gfx curve2d_mesh_data_t::draw_t curve2d_mesh_data_t::to_vertex_array() const { const auto vertices = calculate_vertices(); - auto vao = std::make_unique(); + auto vao = unique_vao_t{}; - vertex_buffer_t vertex_buffer; - vertex_buffer.create(); - vertex_buffer.allocate(static_cast(vertices.size() * sizeof(line_vertex_t)), vertices.data()); + unique_vbo_t vertex_buffer{GL_ARRAY_BUFFER}; + vertex_buffer.bind().upload(static_cast(vertices.size() * sizeof(line_vertex_t)), vertices.data(), GL_STATIC_DRAW); - const auto vb = vertex_array_t::make_vbo(vertex_buffer); - vao->bindVBO(vb, 0, 3, GL_FLOAT, sizeof(line_vertex_t), 0); - vao->bindVBO(vb, 1, 2, GL_FLOAT, sizeof(line_vertex_t), sizeof(vec3)); + const auto ctx = vao.configure(); + auto vbo = ctx.attach_vbo(std::move(vertex_buffer)); + vbo.attribute_ptr(0, 3, GL_FLOAT, sizeof(line_vertex_t), 0); + vbo.attribute_ptr(1, 2, GL_FLOAT, sizeof(line_vertex_t), sizeof(vec3)); return {std::move(vao), static_cast(vertices.size())}; } - size_t curve2d_mesh_data_t::populate_vertex_array(vertex_array_t& va) const + size_t curve2d_mesh_data_t::populate_vertex_array(const unique_vao_t& va) const { const auto vertices = calculate_vertices(); - va.getBuffer(0).update(static_cast(vertices.size() * sizeof(line_vertex_t)), vertices.data()); + va.get_attribute(0)->get().bind().upload(static_cast(vertices.size() * sizeof(line_vertex_t)), vertices.data(), GL_STATIC_DRAW); return vertices.size(); } @@ -210,47 +246,43 @@ namespace blt::gfx void batch_renderer_2d::create() { { - vertex_buffer_t vertices_vbo; - element_buffer_t indices_vbo; + unique_vbo_t vertices_vbo{GL_ARRAY_BUFFER}; + unique_ebo_t indices_vbo; - vertices_vbo.create(); - indices_vbo.create(); + vertices_vbo.bind().upload(sizeof(square_vertices), square_vertices, GL_STATIC_DRAW); + indices_vbo.bind().upload(sizeof(square_indices), square_indices, GL_STATIC_DRAW); - vertices_vbo.allocate(sizeof(square_vertices), square_vertices); - indices_vbo.allocate(sizeof(square_indices), square_indices); - - square_vao = std::make_unique(); - auto vb = vertex_array_t::make_vbo(vertices_vbo); - square_vao->bindVBO(vb, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); - square_vao->bindVBO(vb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); - square_vao->bindElement(indices_vbo); + square_vao = unique_vao_t{}; + const auto ctx = square_vao->configure(); + auto vbo = ctx.attach_vbo(std::move(vertices_vbo)); + vbo.attribute_ptr(0, 3, GL_FLOAT, 5 * sizeof(float), 0); + vbo.attribute_ptr(1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); + ctx.attach_vbo(std::move(indices_vbo)); } { - vertex_buffer_t vertices_vbo; - element_buffer_t indices_vbo; + unique_vbo_t vertices_vbo{GL_ARRAY_BUFFER}; + unique_ebo_t indices_vbo; - vertices_vbo.create(); - indices_vbo.create(); + vertices_vbo.bind().upload(sizeof(line_vertices), line_vertices, GL_DYNAMIC_DRAW); + indices_vbo.bind().upload(sizeof(square_indices), square_indices, GL_DYNAMIC_DRAW); - vertices_vbo.allocate(sizeof(line_vertices), line_vertices, GL_DYNAMIC_DRAW); - indices_vbo.allocate(sizeof(square_indices), square_indices, GL_DYNAMIC_DRAW); - - line_vao = std::make_unique(); - const auto vb = vertex_array_t::make_vbo(vertices_vbo); - line_vao->bindVBO(vb, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); - line_vao->bindVBO(vb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); - line_vao->bindElement(indices_vbo); + line_vao = unique_vao_t{}; + const auto ctx = line_vao->configure(); + auto vbo = ctx.attach_vbo(std::move(vertices_vbo)); + vbo.attribute_ptr(0, 3, GL_FLOAT, 5 * sizeof(float), 0); + vbo.attribute_ptr(1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); + ctx.attach_vbo(std::move(indices_vbo)); } { - curve_vao = std::make_unique(); + curve_vao = unique_vao_t{}; - vertex_buffer_t vertex_buffer; - vertex_buffer.create(); - vertex_buffer.allocate(0, GL_DYNAMIC_DRAW); + unique_vbo_t vertex_buffer{GL_ARRAY_BUFFER}; + vertex_buffer.bind().resize(0, GL_DYNAMIC_DRAW); - const auto vb = vertex_array_t::make_vbo(vertex_buffer); - curve_vao->bindVBO(vb, 0, 3, GL_FLOAT, sizeof(curve2d_mesh_data_t::line_vertex_t), 0); - curve_vao->bindVBO(vb, 1, 2, GL_FLOAT, sizeof(curve2d_mesh_data_t::line_vertex_t), sizeof(vec3)); + const auto ctx = curve_vao->configure(); + auto vbo = ctx.attach_vbo(std::move(vertex_buffer)); + vbo.attribute_ptr(0, 3, GL_FLOAT, sizeof(curve2d_mesh_data_t::line_vertex_t), 0); + vbo.attribute_ptr(1, 2, GL_FLOAT, sizeof(curve2d_mesh_data_t::line_vertex_t), sizeof(vec3)); } square_shader = shader_t::make_unique(shader_2d_textured_vert, shader_2d_textured_frag); @@ -340,9 +372,9 @@ namespace blt::gfx { engine->cleanup(); engine = nullptr; - square_vao = nullptr; - line_vao = nullptr; - curve_vao = nullptr; + square_vao.reset(); + line_vao.reset(); + curve_vao.reset(); square_shader = nullptr; point_shader = nullptr; } @@ -435,8 +467,8 @@ namespace blt::gfx mat4x4 empty_model; square_shader->setMatrix("model", empty_model); line_vao->bind(); - auto& buf = line_vao->getBuffer(0); - buf.bind(); + auto& buf = line_vao->get_attribute(0)->get(); + auto vbo = buf.bind(); for (auto& [texture, objects] : draw.complex_lines) { // resource manager handles the check for empty string @@ -479,7 +511,7 @@ namespace blt::gfx line_vertices[15] = top_left.x(); line_vertices[16] = top_left.y(); - buf.update(sizeof(line_vertices), line_vertices); + vbo.update(0, sizeof(line_vertices), line_vertices); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); draw.draw_count++; diff --git a/src/blt/gfx/renderer/font_renderer.cpp b/src/blt/gfx/renderer/font_renderer.cpp index edbee3a..4a4478e 100644 --- a/src/blt/gfx/renderer/font_renderer.cpp +++ b/src/blt/gfx/renderer/font_renderer.cpp @@ -328,12 +328,9 @@ namespace blt::gfx font_renderer_t::compiled_text_t::compiled_text_t(font_generator_t& generator): generator(generator) { - auto vbo = vertex_array_t::make_vbo({}); - vbo->vbo.create(); - vbo->vbo.bind(); - vbo->vbo.allocate(sizeof(float) * 6 * 4, GL_DYNAMIC_DRAW); - vao.bind(); - vao.bindVBO(vbo, 0, 4, GL_FLOAT, 4 * sizeof(float), 0); + unique_vbo_t vbo{GL_ARRAY_BUFFER}; + vbo.bind().resize(sizeof(float) * 6 * 4, GL_DYNAMIC_DRAW); + vao.configure().attach_vbo(std::move(vbo)).attribute_ptr(0, 4, GL_FLOAT, 4 * sizeof(float), 0); } void font_renderer_t::compiled_text_t::draw() @@ -433,7 +430,7 @@ namespace blt::gfx // BLT_TRACE("size: %ld %ld %ld", draw_count, vertices.size(), vertices.size() / 4); renders.emplace_back(last_texture, draw_start, draw_count); - vao.getBuffer(0).update(static_cast(vertices.size() * sizeof(float)), vertices.data()); + vao.get_attribute(0)->get().bind().update(0, static_cast(vertices.size() * sizeof(float)), vertices.data()); return *this; } diff --git a/src/blt/gfx/renderer/postprocess.cpp b/src/blt/gfx/renderer/postprocess.cpp index e31a507..b2762cf 100644 --- a/src/blt/gfx/renderer/postprocess.cpp +++ b/src/blt/gfx/renderer/postprocess.cpp @@ -27,295 +27,306 @@ #include #include -#define __EMSCRIPTEN__ +// #define __EMSCRIPTEN__ float full_screen_vertices[20] = { - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f, - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f -}; -const unsigned int full_screen_indices[6] = { - 0, 1, 3, - 1, 2, 3 + 1.0f, + 1.0f, + 0.0f, + 1.0f, + 1.0f, + 1.0f, + -1.0f, + 0.0f, + 1.0f, + 0.0f, + -1.0f, + -1.0f, + 0.0f, + 0.0f, + 0.0f, + -1.0f, + 1.0f, + 0.0f, + 0.0f, + 1.0f }; +const unsigned int full_screen_indices[6] = {0, 1, 3, 1, 2, 3}; -template +template bool once() { - static bool ran = true; - return std::exchange(ran, false); + static bool ran = true; + return std::exchange(ran, false); } namespace blt::gfx { - void pp_engine_t::create() - { - { - vertex_buffer_t vertices_vbo; - element_buffer_t indices_vbo; - - vertices_vbo.create(); - indices_vbo.create(); - - vertices_vbo.allocate(sizeof(full_screen_vertices), full_screen_vertices); - indices_vbo.allocate(sizeof(full_screen_indices), full_screen_indices); - - screen_vao = std::make_unique(); - auto vb = vertex_array_t::make_vbo(vertices_vbo); - screen_vao->bindVBO(vb, 0, 3, GL_FLOAT, 5 * sizeof(float), 0); - screen_vao->bindVBO(vb, 1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); - screen_vao->bindElement(indices_vbo); - } -#ifdef __EMSCRIPTEN__ - addStep(std::make_unique()); -#endif - for (auto& step : steps) - step->create(); - } - - pp_step_t& pp_engine_t::find_last_frame_buffer(size_t index) - { - for (i64 i = static_cast(index); i >= 0; i--) - { - if (steps[i]->requests(pp_request_t::BIND_BUFFER)) - return *steps[i]; - } - BLT_FATAL("We reached the end trying to find a previous frame buffer, unable to do so! Please ensure this in-place step has a framebuffer!"); - std::exit(1); - } - - void pp_engine_t::render() - { - screen_vao->bind(); - for (const auto& [index, step] : blt::enumerate(steps)) - { - if (index == 0) - continue; - auto& previous = find_last_frame_buffer(index - 1); - if (step->requests(pp_request_t::BIND_BUFFER)) - step->getBuffer().bind(); - else - previous.getBuffer().bind(); - if (step->requests(pp_request_t::CLEAR_BUFFER)) - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - step->draw(previous.getBuffer()); - if (step->hasShader()) - step->getShader().bind(); - render_quad(); - step->post_draw(previous.getBuffer()); - } - glBindTexture(GL_TEXTURE_2D, 0); - frame_buffer_t::unbind(); -#ifndef __EMSCRIPTEN__ + void pp_engine_t::create() + { + { + unique_vbo_t vertices_vbo{GL_ARRAY_BUFFER}; + unique_ebo_t indices_vbo; + + vertices_vbo.bind().upload(sizeof(full_screen_vertices), full_screen_vertices, GL_STATIC_DRAW); + indices_vbo.bind().upload(sizeof(full_screen_indices), full_screen_indices, GL_STATIC_DRAW); + + screen_vao = unique_vao_t{}; + const auto ctx = screen_vao->configure(); + auto vbo = ctx.attach_vbo(std::move(vertices_vbo)); + vbo.attribute_ptr(0, 3, GL_FLOAT, 5 * sizeof(float), 0); + vbo.attribute_ptr(1, 2, GL_FLOAT, 5 * sizeof(float), 3 * sizeof(float)); + ctx.attach_vbo(std::move(indices_vbo)); + } + #ifdef __EMSCRIPTEN__ + addStep(std::make_unique()); + #endif + for (const auto& step : steps) + step->create(); + } + + pp_step_t& pp_engine_t::find_last_frame_buffer(const size_t index) const + { + for (i64 i = static_cast(index); i >= 0; i--) + { + if (steps[i]->requests(pp_request_t::BIND_BUFFER)) + return *steps[i]; + } + BLT_FATAL("We reached the end trying to find a previous frame buffer, unable to do so! Please ensure this in-place step has a framebuffer!"); + std::exit(1); + } + + void pp_engine_t::render() + { + screen_vao->bind(); + for (const auto& [index, step] : blt::enumerate(steps)) + { + if (index == 0) + continue; + auto& previous = find_last_frame_buffer(index - 1); + if (step->requests(pp_request_t::BIND_BUFFER)) + step->getBuffer().bind(); + else + previous.getBuffer().bind(); + if (step->requests(pp_request_t::CLEAR_BUFFER)) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + step->draw(previous.getBuffer()); + if (step->hasShader()) + step->getShader().bind(); + render_quad(); + step->post_draw(previous.getBuffer()); + } + glBindTexture(GL_TEXTURE_2D, 0); + frame_buffer_t::unbind(); + #ifndef __EMSCRIPTEN__ steps.back()->getBuffer().blitToScreen(getWindowWidth(), getWindowHeight()); -#endif - } - - void pp_engine_t::cleanup() - { - screen_vao = nullptr; - for (auto& v : steps) - v = nullptr; - steps.clear(); - } - - std::unique_ptr pp_engine_t::createShader(std::string_view fragment, std::optional> engine) - { - std::unique_ptr shader; - if (engine) - { - shader = shader_t::make_unique(engine, shader_postprocess_vert, std::string(fragment)); - } else - { - template_engine_t templateEngine; - templateEngine.set("LAYOUT_STRING", ""); - shader = shader_t::make_unique(templateEngine, shader_postprocess_vert, std::string(fragment)); - } - shader->bindAttribute(0, "vertex"); - shader->bindAttribute(1, "uv_in"); - return shader; - } - - void pp_engine_t::bind() - { - steps.front()->getBuffer().bind(); - steps.front()->draw(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - } - - void pp_engine_t::render_quad() - { - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - } - - void pp_in_place_t::create() - { - template_engine_t engine; - engine.set("LAYOUT_STRING", "layout (location = ${IF(LAYOUT_LOCATION) { LAYOUT_LOCATION } ELSE { ~DISCARD }}) "); - engine.set("LAYOUT_LOCATION", std::to_string(static_cast(to) - static_cast(frame_buffer_t::attachment_t::COLOR0))); - shader_pass = pp_engine_t::createShader(shader_pp_screen_frag, engine); - draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight()); - } - - void pp_in_place_t::post_draw(frame_buffer_t& previous) - { -// draw_buffer.blitTexture(previous, 0, 0, 0, 0, GL_NEAREST, from, to); - handle_errors(); - previous.bind(); - GLenum buf[32]; - auto to_val = static_cast(to); - auto size = to_val - GL_COLOR_ATTACHMENT0; - for (GLenum i = 0; i < size; i++) - buf[i] = GL_NONE; - buf[size] = to_val; - glDrawBuffers(static_cast(size) + 1, buf); - glClear(GL_COLOR_BUFFER_BIT); - shader_pass->bind(); - glActiveTexture(GL_TEXTURE0); - draw_buffer.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); - pp_engine_t::render_quad(); - } - - void pp_in_place_t::draw(frame_buffer_t& previous) - { - draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); - glActiveTexture(GL_TEXTURE0); - previous.getTexture(from).bind(); - draw_buffer.bind(); - GLenum buf[]{static_cast(frame_buffer_t::attachment_t::COLOR0)}; - glDrawBuffers(1, buf); - glClear(GL_COLOR_BUFFER_BIT); - } - - void pp_to_screen_step_t::create() - { - shader = pp_engine_t::createShader(shader_pp_screen_frag); - } - - void pp_to_screen_step_t::draw(frame_buffer_t& previous) - { - glActiveTexture(GL_TEXTURE0); - previous.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); - GLenum buf[]{GL_BACK}; - glDrawBuffers(1, buf); - } - - void pp_render_target_t::create() - { - draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight()); - } - - void pp_render_target_t::draw() - { - draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); - GLenum buf[]{static_cast(frame_buffer_t::attachment_t::COLOR0)}; - glDrawBuffers(1, buf); - } - - void pp_outline_target_t::create() - { - draw_buffer.create(); - draw_buffer.bind(); - - auto* texture = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8); - draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0); - - auto* mask = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8); - draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1); - - render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, getWindowWidth(), getWindowHeight()); - draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL); - - if (!frame_buffer_t::validate()) - BLT_ERROR("Failed to create render texture framebuffer!"); - frame_buffer_t::unbind(); - } - - void pp_outline_target_t::draw() - { - draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); - const GLenum buffers[]{static_cast(frame_buffer_t::attachment_t::COLOR0), static_cast(frame_buffer_t::attachment_t::COLOR1)}; - glDrawBuffers(2, buffers); - } - - void pp_outline_step_t::create() - { - draw_buffer = frame_buffer_t::make_render_texture(getWindowHeight(), getWindowHeight()); - shader = pp_engine_t::createShader(shader_pp_outline_step_frag); - shader->setInt("albedo", 0); - shader->setInt("mask", 1); - } - - void pp_outline_step_t::draw(frame_buffer_t& previous) - { - draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); - glActiveTexture(GL_TEXTURE0); - previous.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); - glActiveTexture(GL_TEXTURE1); - previous.getTexture(frame_buffer_t::attachment_t::COLOR1).bind(); - shader->bind(); - //auto v = vec2(getWindowWidth(), getWindowHeight()) * (1.0 / blt::make_vec2(manager.getScale2D())); - //BLT_TRACE_STREAM << v << '\n'; - //shader->setVec2("viewportSize", static_cast(v.x()), static_cast(v.y())); - GLenum buf[]{static_cast(frame_buffer_t::attachment_t::COLOR0)}; - glDrawBuffers(1, buf); - } - - void pp_blur_step_inplace_t::create() - { - pp_in_place_t::create(); - shader = pp_engine_t::createShader(shader_gaussian_blur_frag); - } - - void pp_blur_step_inplace_t::draw(frame_buffer_t& previous) - { - pp_in_place_t::draw(previous); - shader->bind(); - //auto v = vec2(getWindowWidth(), getWindowHeight()) * (1.0 / blt::make_vec2(manager.getScale2D())); - auto v = vec2(getWindowWidth(), getWindowHeight()); - shader->setVec4i("size", {static_cast(v.x()), static_cast(v.y()), x_blur, y_blur}); - } - - void pp_multiplier_step_inplace_t::create() - { - pp_in_place_t::create(); - shader = pp_engine_t::createShader(shader_multiplier_frag); - } - - void pp_multiplier_step_inplace_t::draw(frame_buffer_t& previous) - { - pp_in_place_t::draw(previous); - shader->bind(); - shader->setVec4("multiplier", multiplier); - } - - void pp_overlay_blur_step_t::create() - { - pp_in_place_t::create(); - shader = pp_engine_t::createShader(shader_overlay_blur_frag); - } - - void pp_overlay_blur_step_t::draw(frame_buffer_t& previous) - { - pp_in_place_t::draw(previous); - shader->bind(); - auto v = vec2(getWindowWidth(), getWindowHeight()); - shader->setVec4i("size", {static_cast(v.x()), static_cast(v.y()), x_blur, y_blur}); - } - - void pp_mouse_highlight_step_t::create() - { - pp_in_place_t::create(); - shader = pp_engine_t::createShader(shader_highlight_frag); - } - - void pp_mouse_highlight_step_t::draw(frame_buffer_t& previous) - { - pp_in_place_t::draw(previous); - shader->bind(); - auto v = vec2(getWindowWidth(), getWindowHeight()); - shader->setVec4("mousePos", blt::make_vec4(blt::vec2{getMouseX(), v.y() - getMouseY()})); - shader->setVec4i("size", {static_cast(v.x()), static_cast(v.y()), 4, 4}); - } -} \ No newline at end of file + #endif + } + + void pp_engine_t::cleanup() + { + screen_vao.reset(); + for (auto& v : steps) + v = nullptr; + steps.clear(); + } + + std::unique_ptr pp_engine_t::createShader(std::string_view fragment, std::optional> engine) + { + std::unique_ptr shader; + if (engine) + { + shader = shader_t::make_unique(engine, shader_postprocess_vert, std::string(fragment)); + } else + { + template_engine_t templateEngine; + templateEngine.set("LAYOUT_STRING", ""); + shader = shader_t::make_unique(templateEngine, shader_postprocess_vert, std::string(fragment)); + } + shader->bindAttribute(0, "vertex"); + shader->bindAttribute(1, "uv_in"); + return shader; + } + + void pp_engine_t::bind() + { + steps.front()->getBuffer().bind(); + steps.front()->draw(); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + } + + void pp_engine_t::render_quad() + { + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); + } + + void pp_in_place_t::create() + { + template_engine_t engine; + engine.set("LAYOUT_STRING", "layout (location = ${IF(LAYOUT_LOCATION) { LAYOUT_LOCATION } ELSE { ~DISCARD }}) "); + engine.set("LAYOUT_LOCATION", std::to_string(static_cast(to) - static_cast(frame_buffer_t::attachment_t::COLOR0))); + shader_pass = pp_engine_t::createShader(shader_pp_screen_frag, engine); + draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight()); + } + + void pp_in_place_t::post_draw(frame_buffer_t& previous) + { + // draw_buffer.blitTexture(previous, 0, 0, 0, 0, GL_NEAREST, from, to); + handle_errors(); + previous.bind(); + GLenum buf[32]; + auto to_val = static_cast(to); + auto size = to_val - GL_COLOR_ATTACHMENT0; + for (GLenum i = 0; i < size; i++) + buf[i] = GL_NONE; + buf[size] = to_val; + glDrawBuffers(static_cast(size) + 1, buf); + glClear(GL_COLOR_BUFFER_BIT); + shader_pass->bind(); + glActiveTexture(GL_TEXTURE0); + draw_buffer.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); + pp_engine_t::render_quad(); + } + + void pp_in_place_t::draw(frame_buffer_t& previous) + { + draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); + glActiveTexture(GL_TEXTURE0); + previous.getTexture(from).bind(); + draw_buffer.bind(); + GLenum buf[]{static_cast(frame_buffer_t::attachment_t::COLOR0)}; + glDrawBuffers(1, buf); + glClear(GL_COLOR_BUFFER_BIT); + } + + void pp_to_screen_step_t::create() + { + shader = pp_engine_t::createShader(shader_pp_screen_frag); + } + + void pp_to_screen_step_t::draw(frame_buffer_t& previous) + { + glActiveTexture(GL_TEXTURE0); + previous.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); + GLenum buf[]{GL_BACK}; + glDrawBuffers(1, buf); + } + + void pp_render_target_t::create() + { + draw_buffer = frame_buffer_t::make_render_texture(getWindowWidth(), getWindowHeight()); + } + + void pp_render_target_t::draw() + { + draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); + GLenum buf[]{static_cast(frame_buffer_t::attachment_t::COLOR0)}; + glDrawBuffers(1, buf); + } + + void pp_outline_target_t::create() + { + draw_buffer.create(); + draw_buffer.bind(); + + auto* texture = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8); + draw_buffer.attachTexture(texture, frame_buffer_t::attachment_t::COLOR0); + + auto* mask = new texture_gl2D(getWindowWidth(), getWindowHeight(), GL_RGBA8); + draw_buffer.attachTexture(mask, frame_buffer_t::attachment_t::COLOR1); + + render_buffer_t depth_rbo = render_buffer_t::make_render_buffer(GL_DEPTH24_STENCIL8, getWindowWidth(), getWindowHeight()); + draw_buffer.attachRenderBuffer(depth_rbo, frame_buffer_t::attachment_t::DEPTH_STENCIL); + + if (!frame_buffer_t::validate()) + BLT_ERROR("Failed to create render texture framebuffer!"); + frame_buffer_t::unbind(); + } + + void pp_outline_target_t::draw() + { + draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); + const GLenum buffers[]{static_cast(frame_buffer_t::attachment_t::COLOR0), static_cast(frame_buffer_t::attachment_t::COLOR1)}; + glDrawBuffers(2, buffers); + } + + void pp_outline_step_t::create() + { + draw_buffer = frame_buffer_t::make_render_texture(getWindowHeight(), getWindowHeight()); + shader = pp_engine_t::createShader(shader_pp_outline_step_frag); + shader->setInt("albedo", 0); + shader->setInt("mask", 1); + } + + void pp_outline_step_t::draw(frame_buffer_t& previous) + { + draw_buffer.updateBuffersStorage(getWindowWidth(), getWindowHeight()); + glActiveTexture(GL_TEXTURE0); + previous.getTexture(frame_buffer_t::attachment_t::COLOR0).bind(); + glActiveTexture(GL_TEXTURE1); + previous.getTexture(frame_buffer_t::attachment_t::COLOR1).bind(); + shader->bind(); + //auto v = vec2(getWindowWidth(), getWindowHeight()) * (1.0 / blt::make_vec2(manager.getScale2D())); + //BLT_TRACE_STREAM << v << '\n'; + //shader->setVec2("viewportSize", static_cast(v.x()), static_cast(v.y())); + GLenum buf[]{static_cast(frame_buffer_t::attachment_t::COLOR0)}; + glDrawBuffers(1, buf); + } + + void pp_blur_step_inplace_t::create() + { + pp_in_place_t::create(); + shader = pp_engine_t::createShader(shader_gaussian_blur_frag); + } + + void pp_blur_step_inplace_t::draw(frame_buffer_t& previous) + { + pp_in_place_t::draw(previous); + shader->bind(); + //auto v = vec2(getWindowWidth(), getWindowHeight()) * (1.0 / blt::make_vec2(manager.getScale2D())); + auto v = vec2(getWindowWidth(), getWindowHeight()); + shader->setVec4i("size", {static_cast(v.x()), static_cast(v.y()), x_blur, y_blur}); + } + + void pp_multiplier_step_inplace_t::create() + { + pp_in_place_t::create(); + shader = pp_engine_t::createShader(shader_multiplier_frag); + } + + void pp_multiplier_step_inplace_t::draw(frame_buffer_t& previous) + { + pp_in_place_t::draw(previous); + shader->bind(); + shader->setVec4("multiplier", multiplier); + } + + void pp_overlay_blur_step_t::create() + { + pp_in_place_t::create(); + shader = pp_engine_t::createShader(shader_overlay_blur_frag); + } + + void pp_overlay_blur_step_t::draw(frame_buffer_t& previous) + { + pp_in_place_t::draw(previous); + shader->bind(); + auto v = vec2(getWindowWidth(), getWindowHeight()); + shader->setVec4i("size", {static_cast(v.x()), static_cast(v.y()), x_blur, y_blur}); + } + + void pp_mouse_highlight_step_t::create() + { + pp_in_place_t::create(); + shader = pp_engine_t::createShader(shader_highlight_frag); + } + + void pp_mouse_highlight_step_t::draw(frame_buffer_t& previous) + { + pp_in_place_t::draw(previous); + shader->bind(); + auto v = vec2(getWindowWidth(), getWindowHeight()); + shader->setVec4("mousePos", blt::make_vec4(blt::vec2{getMouseX(), v.y() - getMouseY()})); + shader->setVec4i("size", {static_cast(v.x()), static_cast(v.y()), 4, 4}); + } +}