From 440fa3777ec11fdd04205e97d19f9ef24bfd2e2d Mon Sep 17 00:00:00 2001 From: lisyarus Date: Fri, 23 Oct 2020 12:10:11 +0300 Subject: [PATCH] Refactor attribute specification: move to a separate file + standalone function for use in vertices --- libs/gfx/include/psemek/gfx/attribs.hpp | 380 ++++++++++++++++++++++ libs/gfx/include/psemek/gfx/mesh.hpp | 400 +----------------------- libs/gfx/source/mesh.cpp | 62 ++++ 3 files changed, 453 insertions(+), 389 deletions(-) create mode 100644 libs/gfx/include/psemek/gfx/attribs.hpp diff --git a/libs/gfx/include/psemek/gfx/attribs.hpp b/libs/gfx/include/psemek/gfx/attribs.hpp new file mode 100644 index 00000000..e2d91997 --- /dev/null +++ b/libs/gfx/include/psemek/gfx/attribs.hpp @@ -0,0 +1,380 @@ +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include + +namespace psemek::gfx +{ + + struct attrib_description + { + GLuint index; + GLint size; + GLenum type; + GLboolean normalized; + GLsizei stride; + void const * pointer; + GLuint divisor; + }; + + using attribs_description = std::vector; + + template + struct normalized + { + using type = T; + }; + + // skips a single attribute index + struct skip + {}; + + // skips bytes in the vertex + template + struct padding + { + static constexpr std::size_t size = N; + }; + + // instance attribute, for instanced meshes only + template + struct instanced + { + using type = T; + }; + + template + attribs_description make_attribs_description(); + + namespace detail + { + + template + struct attrib_traits; + + template <> + struct attrib_traits + { + using attrib_type = std::uint8_t; + + static constexpr GLint size = 1; + static constexpr GLenum type = gl::UNSIGNED_BYTE; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template <> + struct attrib_traits + { + using attrib_type = std::int8_t; + + static constexpr GLint size = 1; + static constexpr GLenum type = gl::BYTE; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template <> + struct attrib_traits + { + using attrib_type = std::uint16_t; + + static constexpr GLint size = 1; + static constexpr GLenum type = gl::UNSIGNED_SHORT; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template <> + struct attrib_traits + { + using attrib_type = std::int16_t; + + static constexpr GLint size = 1; + static constexpr GLenum type = gl::SHORT; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template <> + struct attrib_traits + { + using attrib_type = std::uint32_t; + + static constexpr GLint size = 1; + static constexpr GLenum type = gl::UNSIGNED_INT; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template <> + struct attrib_traits + { + using attrib_type = std::int32_t; + + static constexpr GLint size = 1; + static constexpr GLenum type = gl::INT; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template <> + struct attrib_traits + { + using attrib_type = float; + + static constexpr GLint size = 1; + static constexpr GLenum type = gl::FLOAT; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template <> + struct attrib_traits + { + using attrib_type = double; + + static constexpr GLint size = 1; + static constexpr GLenum type = gl::DOUBLE; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template + struct attrib_traits> + { + using attrib_type = std::array; + + static constexpr GLint size = N; + static constexpr GLenum type = attrib_traits::type; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template + struct attrib_traits> + { + using attrib_type = geom::vector; + + static constexpr GLint size = N; + static constexpr GLenum type = attrib_traits::type; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template + struct attrib_traits> + { + using attrib_type = geom::point; + + static constexpr GLint size = N; + static constexpr GLenum type = attrib_traits::type; + static constexpr GLboolean normalized = gl::FALSE_; + }; + + template + struct attrib_traits> + { + using attrib_type = geom::matrix; + }; + + template + struct attrib_traits> + { + using attrib_type = T; + + static constexpr GLint size = attrib_traits::size; + static constexpr GLenum type = attrib_traits::type; + static constexpr GLboolean normalized = gl::TRUE_; + }; + + template + struct attrib_traits> + { + using attrib_type = typename attrib_traits::attrib_type; + + static constexpr GLint size = attrib_traits::size; + static constexpr GLenum type = attrib_traits::type; + static constexpr GLboolean normalized = attrib_traits::normalized; + }; + + template + struct is_padding : std::false_type + {}; + + template + struct is_padding> : std::true_type + {}; + + template + struct is_instanced : std::false_type + {}; + + template + struct is_instanced> : std::true_type + {}; + + template + struct remove_instanced + { + using type = T; + }; + + template + struct remove_instanced> + { + using type = T; + }; + + template + struct is_matrix : std::false_type + {}; + + template + struct is_matrix> : std::true_type + {}; + + template + std::size_t attr_size() + { + if constexpr (std::is_same_v) + { + return 0; + } + else if constexpr (is_padding::value) + { + return Attr::size; + } + else + { + return sizeof(typename attrib_traits::attrib_type); + } + } + + template + struct stride_helper; + + template + struct stride_helper + { + static std::size_t stride() + { + return 0; + } + }; + + template + struct stride_helper + { + static std::size_t stride() + { + std::size_t s = 0; + if constexpr (is_instanced::value == Instance) + { + s = attr_size(); + } + return s + stride_helper::stride(); + } + }; + + template + struct make_attribs_description_impl; + + template + struct make_attribs_description_impl + { + static void make(attribs_description &) + {} + + static void make_impl(attribs_description &, std::size_t, std::size_t, std::size_t) + { } + }; + + template + struct make_attribs_description_impl + { + static void make(attribs_description & result) + { + std::size_t const stride = stride_helper::stride(); + make_impl(result, 0, 0, stride); + } + + static void make_impl(attribs_description & result, std::size_t index, std::size_t offset, std::size_t stride) + { + if constexpr (std::is_same_v) + { + make_attribs_description_impl::make_impl(result, index + 1, offset, stride); + } + else if constexpr (is_padding::value) + { + make_attribs_description_impl::make_impl(result, index, offset + Attr1::size, stride); + } + else if constexpr (is_instanced::value == Instance) + { + using attr = typename remove_instanced::type; + + if constexpr (is_matrix::value) + { + using T = typename attr::scalar_type; + using traits = attrib_traits>; + + for (std::size_t row = 0; row < attr::rows; ++row) + { + attrib_description attr; + attr.index = index + row; + attr.size = traits::size; + attr.type = traits::type; + attr.normalized = traits::normalized; + attr.stride = stride; + attr.pointer = reinterpret_cast(offset + row * attr::columns * sizeof(T)); + attr.divisor = Instance ? 1 : 0; + + result.push_back(attr); + } + + make_attribs_description_impl::make_impl(result, index + attr::rows, offset + attr_size(), stride); + } + else + { + + using traits = attrib_traits; + + attrib_description attr; + attr.index = index; + attr.size = traits::size; + attr.type = traits::type; + attr.normalized = traits::normalized; + attr.stride = stride; + attr.pointer = reinterpret_cast(offset); + attr.divisor = Instance ? 1 : 0; + + result.push_back(attr); + + make_attribs_description_impl::make_impl(result, index + 1, offset + attr_size(), stride); + } + } + else + { + using attr = typename remove_instanced::type; + + if constexpr (is_matrix::value) + { + make_attribs_description_impl::make_impl(result, index + attr::rows, offset, stride); + } + else + { + make_attribs_description_impl::make_impl(result, index + 1, offset, stride); + } + } + } + }; + + } + + template + attribs_description make_attribs_description() + { + attribs_description result; + detail::make_attribs_description_impl::make(result); + detail::make_attribs_description_impl::make(result); + return result; + } + +} diff --git a/libs/gfx/include/psemek/gfx/mesh.hpp b/libs/gfx/include/psemek/gfx/mesh.hpp index 68ecb040..f8ced8c5 100644 --- a/libs/gfx/include/psemek/gfx/mesh.hpp +++ b/libs/gfx/include/psemek/gfx/mesh.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -22,390 +23,32 @@ namespace psemek::gfx { - template - struct normalized - { - using type = T; - }; - - // skips a single attribute index - struct skip - {}; - - // skips bytes in the vertex - template - struct padding - { - static constexpr std::size_t size = N; - }; - - // instance attribute, for instanced meshes only - template - struct instanced - { - using type = T; - }; - - template - struct attrib_traits; - - template <> - struct attrib_traits - { - using attrib_type = std::uint8_t; - - static constexpr GLint size = 1; - static constexpr GLenum type = gl::UNSIGNED_BYTE; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template <> - struct attrib_traits - { - using attrib_type = std::int8_t; - - static constexpr GLint size = 1; - static constexpr GLenum type = gl::BYTE; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template <> - struct attrib_traits - { - using attrib_type = std::uint16_t; - - static constexpr GLint size = 1; - static constexpr GLenum type = gl::UNSIGNED_SHORT; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template <> - struct attrib_traits - { - using attrib_type = std::int16_t; - - static constexpr GLint size = 1; - static constexpr GLenum type = gl::SHORT; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template <> - struct attrib_traits - { - using attrib_type = std::uint32_t; - - static constexpr GLint size = 1; - static constexpr GLenum type = gl::UNSIGNED_INT; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template <> - struct attrib_traits - { - using attrib_type = std::int32_t; - - static constexpr GLint size = 1; - static constexpr GLenum type = gl::INT; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template <> - struct attrib_traits - { - using attrib_type = float; - - static constexpr GLint size = 1; - static constexpr GLenum type = gl::FLOAT; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template <> - struct attrib_traits - { - using attrib_type = double; - - static constexpr GLint size = 1; - static constexpr GLenum type = gl::DOUBLE; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template - struct attrib_traits> - { - using attrib_type = std::array; - - static constexpr GLint size = N; - static constexpr GLenum type = attrib_traits::type; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template - struct attrib_traits> - { - using attrib_type = geom::vector; - - static constexpr GLint size = N; - static constexpr GLenum type = attrib_traits::type; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template - struct attrib_traits> - { - using attrib_type = geom::point; - - static constexpr GLint size = N; - static constexpr GLenum type = attrib_traits::type; - static constexpr GLboolean normalized = gl::FALSE_; - }; - - template - struct attrib_traits> - { - using attrib_type = geom::matrix; - }; - - template - struct attrib_traits> - { - using attrib_type = T; - - static constexpr GLint size = attrib_traits::size; - static constexpr GLenum type = attrib_traits::type; - static constexpr GLboolean normalized = gl::TRUE_; - }; - - template - struct attrib_traits> - { - using attrib_type = typename attrib_traits::attrib_type; - - static constexpr GLint size = attrib_traits::size; - static constexpr GLenum type = attrib_traits::type; - static constexpr GLboolean normalized = attrib_traits::normalized; - }; - namespace detail { template - struct is_padding : std::false_type - {}; - - template - struct is_padding> : std::true_type - {}; - - template - struct is_instanced : std::false_type - {}; - - template - struct is_instanced> : std::true_type - {}; - - template - struct remove_instanced - { - using type = T; - }; - - template - struct remove_instanced> - { - using type = T; - }; - - template - struct is_matrix : std::false_type - {}; - - template - struct is_matrix> : std::true_type - {}; - - template - std::size_t attr_size() - { - if constexpr (std::is_same_v) - { - return 0; - } - else if constexpr (is_padding::value) - { - return Attr::size; - } - else - { - return sizeof(typename attrib_traits::attrib_type); - } - } - - template - struct stride_helper; - - template - struct stride_helper - { - static std::size_t stride() - { - return 0; - } - }; - - template - struct stride_helper - { - static std::size_t stride() - { - std::size_t s = 0; - if constexpr (is_instanced::value == InstanceSetup) - { - s = attr_size(); - } - return s + stride_helper::stride(); - } - }; - - struct mesh_setup_result - { - std::size_t stride; - std::size_t max_index; - }; - - template - struct mesh_setup_base; - - template - struct mesh_setup_base - { - static mesh_setup_result setup() - { - return {0, 0}; - } - - static std::size_t setup_impl(std::size_t index, std::size_t, std::size_t) - { - return index; - } - }; - - template - struct mesh_setup_base - { - static mesh_setup_result setup() - { - std::size_t const stride = stride_helper::stride(); - auto const max_index = setup_impl(0, 0, stride); - return {stride, max_index}; - } - - static std::size_t setup_impl(std::size_t index, std::size_t offset, std::size_t stride) - { - if constexpr (std::is_same_v) - { - return mesh_setup_base::setup_impl(index + 1, offset, stride); - } - else if constexpr (is_padding::value) - { - return mesh_setup_base::setup_impl(index, offset + Attr1::size, stride); - } - else if constexpr (is_instanced::value == InstanceSetup) - { - using attr = typename remove_instanced::type; - - if constexpr (is_matrix::value) - { - using T = typename attr::scalar_type; - using traits = attrib_traits>; - - for (std::size_t row = 0; row < attr::rows; ++row) - { - gl::EnableVertexAttribArray(index + row); - gl::VertexAttribPointer(index + row, traits::size, traits::type, traits::normalized, stride, reinterpret_cast(offset + row * attr::columns * sizeof(T))); - - if (InstanceSetup) - gl::VertexAttribDivisor(index + row, 1); - } - - return mesh_setup_base::setup_impl(index + attr::rows, offset + attr_size(), stride); - } - else - { - if (InstanceSetup) - gl::VertexAttribDivisor(index, 1); - - using traits = attrib_traits; - - gl::EnableVertexAttribArray(index); - gl::VertexAttribPointer(index, traits::size, traits::type, traits::normalized, stride, reinterpret_cast(offset)); - - return mesh_setup_base::setup_impl(index + 1, offset + attr_size(), stride); - } - } - else - { - using attr = typename remove_instanced::type; - - if constexpr (is_matrix::value) - { - return mesh_setup_base::setup_impl(index + attr::rows, offset, stride); - } - else - { - return mesh_setup_base::setup_impl(index + 1, offset, stride); - } - } - } - }; - - template - using mesh_vertex_setup = mesh_setup_base; - - template - using mesh_instance_setup = mesh_setup_base; - - template - struct has_instanced_attribs_impl - : std::false_type - {}; - - template - struct has_instanced_attribs_impl - : has_instanced_attribs_impl - {}; - - template - struct has_instanced_attribs_impl, Args...> - : std::true_type - {}; - - template - constexpr bool has_instanced_attribs = has_instanced_attribs_impl::value; - - template - struct gl_type; + struct index_type_to_gl_enum; template <> - struct gl_type + struct index_type_to_gl_enum { static constexpr GLenum value = gl::UNSIGNED_BYTE; }; template <> - struct gl_type + struct index_type_to_gl_enum { static constexpr GLenum value = gl::UNSIGNED_SHORT; }; template <> - struct gl_type + struct index_type_to_gl_enum { static constexpr GLenum value = gl::UNSIGNED_INT; }; template - static constexpr GLenum gl_type_v = gl_type::value; + static constexpr GLenum index_type_to_gl_enum_v = index_type_to_gl_enum::value; inline std::size_t index_size(GLenum type) { @@ -452,6 +95,7 @@ namespace psemek::gfx return std::nullopt; } } + } /* A generic mesh class @@ -471,6 +115,8 @@ namespace psemek::gfx mesh(mesh const &) = delete; mesh & operator = (mesh const &) = delete; + void setup(attribs_description const & attribs); + template void setup(); @@ -560,31 +206,7 @@ namespace psemek::gfx template void mesh::setup() { - array_.bind(); - - for (std::size_t i = 0; i < info_.max_attribute_index_; ++i) - gl::DisableVertexAttribArray(i); - - if (!vertex_buffer_) vertex_buffer_ = buffer{}; - vertex_buffer_.bind(); - auto vertex_setup = detail::mesh_vertex_setup::setup(); - info_.stride_ = vertex_setup.stride; - info_.max_attribute_index_ = vertex_setup.max_index; - - if constexpr (detail::has_instanced_attribs) - { - if (!instance_buffer_) instance_buffer_ = buffer{}; - instance_buffer_.bind(); - auto instance_setup = detail::mesh_instance_setup::setup(); - info_.instance_stride_ = instance_setup.stride; - info_.instanced_ = true; - info_.max_attribute_index_ = std::max(info_.max_attribute_index_, instance_setup.max_index); - } - else - { - info_.instance_stride_ = 0; - info_.instanced_ = false; - } + setup(make_attribs_description()); } template @@ -645,7 +267,7 @@ namespace psemek::gfx info_.index_count_ = index_count; info_.indexed_ = true; info_.primitive_type_ = primitive_type; - info_.index_type_ = detail::gl_type_v; + info_.index_type_ = detail::index_type_to_gl_enum_v; } template diff --git a/libs/gfx/source/mesh.cpp b/libs/gfx/source/mesh.cpp index 5ca89df6..2d61cbfd 100644 --- a/libs/gfx/source/mesh.cpp +++ b/libs/gfx/source/mesh.cpp @@ -29,6 +29,68 @@ namespace psemek::gfx return *this; } + void mesh::setup(attribs_description const & attribs) + { + assert(!attribs.empty()); + + array_.bind(); + + for (std::size_t i = 0; i < info_.max_attribute_index_; ++i) + gl::DisableVertexAttribArray(i); + + std::size_t max_index = 0; + bool instanced = false; + std::size_t stride = 0; + std::size_t instance_stride = 0; + + for (auto const & a : attribs) + { + max_index = std::max(max_index, a.index); + + if (a.divisor == 0) + { + stride = a.stride; + } + else + { + assert(a.divisor == 1); + instance_stride = a.stride; + instanced = true; + } + } + + info_.max_attribute_index_ = max_index; + info_.stride_ = stride; + info_.instance_stride_ = instance_stride; + info_.instanced_ = instanced; + + if (!vertex_buffer_) vertex_buffer_ = buffer{}; + vertex_buffer_.bind(); + + for (auto const & a : attribs) + { + if (a.divisor != 0) continue; + + gl::EnableVertexAttribArray(a.index); + gl::VertexAttribPointer(a.index, a.size, a.type, a.normalized, a.stride, a.pointer); + } + + if (instanced) + { + if (!instance_buffer_) instance_buffer_ = buffer{}; + instance_buffer_.bind(); + + for (auto const & a : attribs) + { + if (a.divisor == 0) continue; + + gl::EnableVertexAttribArray(a.index); + gl::VertexAttribPointer(a.index, a.size, a.type, a.normalized, a.stride, a.pointer); + gl::VertexAttribDivisor(a.index, a.divisor); + } + } + } + void mesh::draw() const { draw(0, is_indexed() ? index_count() : vertex_count(), instance_count());