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_base;
template <bool IsInstanced, bool InstanceSetup>
struct mesh_setup_base<IsInstanced, InstanceSetup>
struct mesh_setup_result
{
static std::size_t setup()
{
return 0;
}
static void setup_impl(int, std::size_t, std::size_t)
{}
std::size_t stride;
std::size_t max_index;
};
template <bool IsInstanced, bool InstanceSetup, typename Attr1, typename ... Attribs>
struct mesh_setup_base<IsInstanced, InstanceSetup, Attr1, Attribs...>
template <bool InstanceSetup, typename ... 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();
setup_impl(0, 0, stride);
return stride;
return {0, 0};
}
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>)
{
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)
{
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)
{
static_assert("cannot use instanced attribute for non-instanced mesh");
}
else if constexpr (!IsInstanced || (is_instanced<Attr1>::value == InstanceSetup))
else if constexpr (is_instanced<Attr1>::value == InstanceSetup)
{
using attr = typename remove_instanced<Attr1>::type;
@ -324,7 +328,7 @@ namespace psemek::gfx
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
{
@ -336,7 +340,7 @@ namespace psemek::gfx
gl::EnableVertexAttribArray(index);
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
@ -345,24 +349,39 @@ namespace psemek::gfx
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
{
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>
using mesh_setup = mesh_setup_base<false, false, Attribs...>;
using mesh_vertex_setup = mesh_setup_base<false, 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>
using instanced_mesh_instance_setup = mesh_setup_base<true, true, Attribs...>;
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;
template <typename T>
struct gl_type;
@ -433,24 +452,6 @@ namespace psemek::gfx
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
@ -549,6 +550,8 @@ namespace psemek::gfx
GLenum primitive_type_;
GLenum index_type_;
std::size_t max_attribute_index_ = 0;
};
mesh_info info_;
@ -559,16 +562,23 @@ namespace psemek::gfx
{
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();
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 (!instance_buffer_) instance_buffer_ = buffer{};
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_.max_attribute_index_ = std::max(info_.max_attribute_index_, instance_setup.max_index);
}
else
{