Refactor mesh setup & properly disable old attribs on re-setup

This commit is contained in:
Nikita Lisitsa 2020-10-04 17:35:21 +03:00
parent e9af93b747
commit d807d5c74b

View file

@ -267,46 +267,50 @@ namespace psemek::gfx
} }
}; };
template <bool IsInstanced, bool InstanceSetup, typename ... Attribs> struct mesh_setup_result
struct mesh_setup_base;
template <bool IsInstanced, bool InstanceSetup>
struct mesh_setup_base<IsInstanced, InstanceSetup>
{ {
static std::size_t setup() std::size_t stride;
{ std::size_t max_index;
return 0;
}
static void setup_impl(int, std::size_t, std::size_t)
{}
}; };
template <bool IsInstanced, bool InstanceSetup, typename Attr1, typename ... Attribs> template <bool InstanceSetup, typename ... Attribs>
struct mesh_setup_base<IsInstanced, InstanceSetup, Attr1, Attribs...> struct mesh_setup_base;
template <bool InstanceSetup>
struct mesh_setup_base<InstanceSetup>
{ {
static std::size_t setup() static mesh_setup_result setup()
{ {
std::size_t const stride = stride_helper<InstanceSetup, Attr1, Attribs...>::stride(); return {0, 0};
setup_impl(0, 0, stride);
return stride;
} }
static void setup_impl(int index, std::size_t offset, std::size_t stride) static std::size_t setup_impl(std::size_t index, std::size_t, std::size_t)
{
return index;
}
};
template <bool InstanceSetup, typename Attr1, typename ... Attribs>
struct mesh_setup_base<InstanceSetup, Attr1, Attribs...>
{
static mesh_setup_result setup()
{
std::size_t const stride = stride_helper<InstanceSetup, Attr1, Attribs...>::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<Attr1, skip>) if constexpr (std::is_same_v<Attr1, skip>)
{ {
mesh_setup_base<IsInstanced, InstanceSetup, Attribs...>::setup_impl(index + 1, offset, stride); return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + 1, offset, stride);
} }
else if constexpr (is_padding<Attr1>::value) else if constexpr (is_padding<Attr1>::value)
{ {
mesh_setup_base<IsInstanced, InstanceSetup, Attribs...>::setup_impl(index, offset + Attr1::size, stride); return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index, offset + Attr1::size, stride);
} }
else if constexpr (!IsInstanced && is_instanced<Attr1>::value) else if constexpr (is_instanced<Attr1>::value == InstanceSetup)
{
static_assert("cannot use instanced attribute for non-instanced mesh");
}
else if constexpr (!IsInstanced || (is_instanced<Attr1>::value == InstanceSetup))
{ {
using attr = typename remove_instanced<Attr1>::type; using attr = typename remove_instanced<Attr1>::type;
@ -324,7 +328,7 @@ namespace psemek::gfx
gl::VertexAttribDivisor(index + row, 1); gl::VertexAttribDivisor(index + row, 1);
} }
mesh_setup_base<IsInstanced, InstanceSetup, Attribs...>::setup_impl(index + attr::rows, offset + attr_size<Attr1>(), stride); return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + attr::rows, offset + attr_size<Attr1>(), stride);
} }
else else
{ {
@ -336,7 +340,7 @@ namespace psemek::gfx
gl::EnableVertexAttribArray(index); gl::EnableVertexAttribArray(index);
gl::VertexAttribPointer(index, traits::size, traits::type, traits::normalized, stride, reinterpret_cast<char const *>(offset)); gl::VertexAttribPointer(index, traits::size, traits::type, traits::normalized, stride, reinterpret_cast<char const *>(offset));
mesh_setup_base<IsInstanced, InstanceSetup, Attribs...>::setup_impl(index + 1, offset + attr_size<Attr1>(), stride); return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + 1, offset + attr_size<Attr1>(), stride);
} }
} }
else else
@ -345,24 +349,39 @@ namespace psemek::gfx
if constexpr (is_matrix<attr>::value) if constexpr (is_matrix<attr>::value)
{ {
mesh_setup_base<IsInstanced, InstanceSetup, Attribs...>::setup_impl(index + attr::rows, offset, stride); return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + attr::rows, offset, stride);
} }
else else
{ {
mesh_setup_base<IsInstanced, InstanceSetup, Attribs...>::setup_impl(index + 1, offset, stride); return mesh_setup_base<InstanceSetup, Attribs...>::setup_impl(index + 1, offset, stride);
} }
} }
} }
}; };
template <typename ... Attribs> template <typename ... Attribs>
using mesh_setup = mesh_setup_base<false, false, Attribs...>; using mesh_vertex_setup = mesh_setup_base<false, Attribs...>;
template <typename ... Attribs> template <typename ... Attribs>
using instanced_mesh_vertex_setup = mesh_setup_base<true, false, Attribs...>; using mesh_instance_setup = mesh_setup_base<true, Attribs...>;
template <typename ... Attribs> template <typename ... Args>
using instanced_mesh_instance_setup = mesh_setup_base<true, true, Attribs...>; struct has_instanced_attribs_impl
: std::false_type
{};
template <typename T, typename ... Args>
struct has_instanced_attribs_impl<T, Args...>
: has_instanced_attribs_impl<Args...>
{};
template <typename T, typename ... Args>
struct has_instanced_attribs_impl<instanced<T>, Args...>
: std::true_type
{};
template <typename ... Args>
constexpr bool has_instanced_attribs = has_instanced_attribs_impl<Args...>::value;
template <typename T> template <typename T>
struct gl_type; struct gl_type;
@ -433,24 +452,6 @@ namespace psemek::gfx
return std::nullopt; return std::nullopt;
} }
} }
template <typename ... Args>
struct has_instanced_attribs_impl
: std::false_type
{};
template <typename T, typename ... Args>
struct has_instanced_attribs_impl<T, Args...>
: has_instanced_attribs_impl<Args...>
{};
template <typename T, typename ... Args>
struct has_instanced_attribs_impl<instanced<T>, Args...>
: std::true_type
{};
template <typename ... Args>
constexpr bool has_instanced_attribs = has_instanced_attribs_impl<Args...>::value;
} }
/* A generic mesh class /* A generic mesh class
@ -549,6 +550,8 @@ namespace psemek::gfx
GLenum primitive_type_; GLenum primitive_type_;
GLenum index_type_; GLenum index_type_;
std::size_t max_attribute_index_ = 0;
}; };
mesh_info info_; mesh_info info_;
@ -559,16 +562,23 @@ namespace psemek::gfx
{ {
array_.bind(); array_.bind();
for (std::size_t i = 0; i < info_.max_attribute_index_; ++i)
gl::DisableVertexAttribArray(i);
if (!vertex_buffer_) vertex_buffer_ = buffer{}; if (!vertex_buffer_) vertex_buffer_ = buffer{};
vertex_buffer_.bind(); vertex_buffer_.bind();
info_.stride_ = detail::instanced_mesh_vertex_setup<Attribs...>::setup(); auto vertex_setup = detail::mesh_vertex_setup<Attribs...>::setup();
info_.stride_ = vertex_setup.stride;
info_.max_attribute_index_ = vertex_setup.max_index;
if constexpr (detail::has_instanced_attribs<Attribs...>) if constexpr (detail::has_instanced_attribs<Attribs...>)
{ {
if (!instance_buffer_) instance_buffer_ = buffer{}; if (!instance_buffer_) instance_buffer_ = buffer{};
instance_buffer_.bind(); instance_buffer_.bind();
info_.instance_stride_ = detail::instanced_mesh_instance_setup<Attribs...>::setup(); auto instance_setup = detail::mesh_instance_setup<Attribs...>::setup();
info_.instance_stride_ = instance_setup.stride;
info_.instanced_ = true; info_.instanced_ = true;
info_.max_attribute_index_ = std::max(info_.max_attribute_index_, instance_setup.max_index);
} }
else else
{ {