From 2771564b94696f9fe8f27a118dc5f0f1eb9e15a2 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Sat, 3 Oct 2020 15:36:26 +0300 Subject: [PATCH] Add instanced_indexed_mesh class --- libs/gfx/include/psemek/gfx/mesh.hpp | 188 +++++++++++++++++++++++++-- libs/gfx/source/mesh.cpp | 79 +++++++++++ todo.md | 3 +- 3 files changed, 254 insertions(+), 16 deletions(-) diff --git a/libs/gfx/include/psemek/gfx/mesh.hpp b/libs/gfx/include/psemek/gfx/mesh.hpp index 7a40a699..9929520e 100644 --- a/libs/gfx/include/psemek/gfx/mesh.hpp +++ b/libs/gfx/include/psemek/gfx/mesh.hpp @@ -389,6 +389,18 @@ namespace psemek::gfx void check_vertex_size(std::size_t vertex_size, std::size_t stride); void check_instance_size(std::size_t instance_size, std::size_t stride); + static std::size_t index_size(GLenum type) + { + switch (type) + { + case gl::UNSIGNED_BYTE: return 1; + case gl::UNSIGNED_SHORT: return 2; + case gl::UNSIGNED_INT: return 4; + } + assert(false); + return 0; + } + } struct mesh @@ -617,7 +629,7 @@ namespace psemek::gfx assert(first + count <= count_); gl::BindVertexArray(array_); - gl::DrawElements(primitive_type_, count, index_type_, reinterpret_cast(0) + first * index_size(index_type_)); + gl::DrawElements(primitive_type_, count, index_type_, reinterpret_cast(0) + first * detail::index_size(index_type_)); } GLsizei index_count() const @@ -643,18 +655,6 @@ namespace psemek::gfx GLenum primitive_type_; indexed_mesh(int); - - static std::size_t index_size(GLenum type) - { - switch (type) - { - case gl::UNSIGNED_BYTE: return 1; - case gl::UNSIGNED_SHORT: return 2; - case gl::UNSIGNED_INT: return 4; - } - assert(false); - return 0; - } }; struct instanced_mesh @@ -786,7 +786,7 @@ namespace psemek::gfx GLsizei instance_count() const { - return count_; + return instance_count_; } GLenum primitive_type() const @@ -810,4 +810,164 @@ namespace psemek::gfx instanced_mesh(int); }; + struct instanced_indexed_mesh + : drawable + { + static instanced_indexed_mesh null(); + + instanced_indexed_mesh(); + instanced_indexed_mesh(instanced_indexed_mesh &&); + instanced_indexed_mesh(instanced_indexed_mesh const &) = delete; + + instanced_indexed_mesh & operator = (instanced_indexed_mesh &&); + instanced_indexed_mesh & operator = (instanced_indexed_mesh const &) = delete; + + ~instanced_indexed_mesh(); + + template + void setup() + { + gl::BindVertexArray(array_); + + gl::BindBuffer(gl::ARRAY_BUFFER, buffer_); + stride_ = detail::instanced_mesh_vertex_setup::setup(); + + gl::BindBuffer(gl::ARRAY_BUFFER, instance_buffer_); + instance_stride_ = detail::instanced_mesh_instance_setup::setup(); + + gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_); + } + + template + void load(Vertex const * vertices, std::size_t vertex_count, Index const * indices, std::size_t index_count, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW) + { + detail::check_vertex_size(sizeof(Vertex), stride_); + + switch (primitive_type) + { + case gl::LINES: + if ((index_count % 2) != 0) throw std::runtime_error("Index count for GL_LINES should be a multiple of 2"); + break; + case gl::TRIANGLES: + if ((index_count % 3) != 0) throw std::runtime_error("Index count for GL_TRIANGLES should be a multiple of 3"); + break; + default: + break; + } + + gl::BindBuffer(gl::ARRAY_BUFFER, buffer_); + gl::BufferData(gl::ARRAY_BUFFER, vertex_count * sizeof(Vertex), vertices, usage); + gl::BindBuffer(gl::ARRAY_BUFFER, index_buffer_); + gl::BufferData(gl::ARRAY_BUFFER, index_count * sizeof(Index), indices, usage); + + count_ = index_count; + index_type_ = detail::gl_type_v; + primitive_type_ = primitive_type; + } + + template + void load(std::vector const & vertices, std::vector const & indices, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW) + { + load(vertices.data(), vertices.size(), indices.data(), indices.size(), primitive_type, usage); + } + + template + void load(Vertex const * vertices, std::size_t vertex_count, geom::simplex const * simplices, std::size_t simplex_count, GLenum usage = gl::STREAM_DRAW) + { + static_assert(sizeof(geom::simplex) == (N + 1) * sizeof(Index)); + + GLenum primitive_type; + + if constexpr (N == 0) + { + primitive_type = gl::POINTS; + } + else if constexpr (N == 1) + { + primitive_type = gl::LINES; + } + else if constexpr (N == 2) + { + primitive_type = gl::TRIANGLES; + } + else + { + static_assert("unknown primitive type"); + } + + load(vertices, vertex_count, reinterpret_cast(simplices), simplex_count * (N + 1), primitive_type, usage); + } + + template + void load(std::vector const & vertices, std::vector> const & simplices, GLenum usage = gl::STREAM_DRAW) + { + load(vertices.data(), vertices.size(), simplices.data(), simplices.size(), usage); + } + + template + void load_instance(Instance const * instances, std::size_t count, GLenum usage = gl::STREAM_DRAW) + { + detail::check_instance_size(sizeof(Instance), instance_stride_); + + gl::BindBuffer(gl::ARRAY_BUFFER, instance_buffer_); + gl::BufferData(gl::ARRAY_BUFFER, count * sizeof(Instance), instances, usage); + instance_count_ = count; + } + + template + void load_instance(std::vector const & instances, GLenum usage = gl::STREAM_DRAW) + { + load_instance(instances.data(), instances.size(), usage); + } + + void draw() const override + { + draw(0, count_, instance_count_); + } + + void draw(GLsizei first, GLsizei count, GLsizei instance_count) const + { + assert(first + count <= count_); + assert(instance_count <= instance_count_); + + if (count == 0) return; + if (instance_count == 0) return; + + gl::BindVertexArray(array_); + gl::DrawElementsInstanced(primitive_type_, count, index_type_, reinterpret_cast(0) + detail::index_size(index_type_) * first, instance_count); + } + + GLsizei index_count() const + { + return count_; + } + + GLsizei instance_count() const + { + return instance_count_; + } + + GLenum primitive_type() const + { + return primitive_type_; + } + + private: + GLuint array_; + GLuint buffer_; + GLuint index_buffer_; + GLuint instance_buffer_; + + GLsizei count_ = 0; + GLsizei instance_count_ = 0; + GLenum index_type_ = 0; + + std::size_t stride_ = 0; + std::size_t instance_stride_ = 0; + + GLenum primitive_type_; + + instanced_indexed_mesh(int); + }; + } diff --git a/libs/gfx/source/mesh.cpp b/libs/gfx/source/mesh.cpp index 02741672..e55ec563 100644 --- a/libs/gfx/source/mesh.cpp +++ b/libs/gfx/source/mesh.cpp @@ -231,4 +231,83 @@ namespace psemek::gfx instance_buffer_ = 0; } + instanced_indexed_mesh instanced_indexed_mesh::null() + { + return instanced_indexed_mesh(0); + } + + instanced_indexed_mesh::instanced_indexed_mesh() + { + gl::GenVertexArrays(1, &array_); + gl::GenBuffers(1, &buffer_); + gl::GenBuffers(1, &index_buffer_); + gl::GenBuffers(1, &instance_buffer_); + } + + instanced_indexed_mesh::instanced_indexed_mesh(instanced_indexed_mesh && other) + { + array_ = other.array_; + buffer_ = other.buffer_; + instance_buffer_ = other.instance_buffer_; + count_ = other.count_; + instance_count_ = other.instance_count_; + stride_ = other.stride_; + instance_stride_ = other.instance_stride_; + primitive_type_ = other.primitive_type_; + + other.array_ = 0; + other.buffer_ = 0; + other.instance_buffer_ = 0; + other.count_ = 0; + other.instance_count_ = 0; + other.stride_ = 0; + other.instance_stride_ = 0; + } + + instanced_indexed_mesh & instanced_indexed_mesh::operator = (instanced_indexed_mesh && other) + { + if (this == &other) + return *this; + + gl::DeleteVertexArrays(1, &array_); + gl::DeleteBuffers(1, &buffer_); + gl::DeleteBuffers(1, &index_buffer_); + gl::DeleteBuffers(1, &instance_buffer_); + + array_ = other.array_; + buffer_ = other.buffer_; + instance_buffer_ = other.instance_buffer_; + count_ = other.count_; + instance_count_ = other.instance_count_; + stride_ = other.stride_; + instance_stride_ = other.instance_stride_; + primitive_type_ = other.primitive_type_; + + other.array_ = 0; + other.buffer_ = 0; + other.instance_buffer_ = 0; + other.count_ = 0; + other.instance_count_ = 0; + other.stride_ = 0; + other.instance_stride_ = 0; + + return *this; + } + + instanced_indexed_mesh::~instanced_indexed_mesh() + { + gl::DeleteVertexArrays(1, &array_); + gl::DeleteBuffers(1, &buffer_); + gl::DeleteBuffers(1, &index_buffer_); + gl::DeleteBuffers(1, &instance_buffer_); + } + + instanced_indexed_mesh::instanced_indexed_mesh(int) + { + array_ = 0; + buffer_ = 0; + index_buffer_ = 0; + instance_buffer_ = 0; + } + } diff --git a/todo.md b/todo.md index 579cd1b0..3db8f253 100644 --- a/todo.md +++ b/todo.md @@ -1,4 +1,3 @@ -* Design affine transforms in geom & use them instead of matrices when appropriate * Add more pixmap fonts * Design ui system * Add color utilities @@ -7,4 +6,4 @@ * gfx: design & implement simple rendering pipelines * pcg: add clean Generator, Sampler & Pixmap processor concepts, uniformize interfaces, be type & dimension agnostic when possible * pcg: add more vector & point distributions -* pcg: make template fractal generator, replace fractal_perlin with it +* gfx: unify 4 mesh classes somehow