Remove gfx::vertex, setup meshes using attributes directly

This commit is contained in:
Nikita Lisitsa 2020-08-28 11:15:49 +03:00
parent f69fb7299e
commit 0424bae480
3 changed files with 73 additions and 114 deletions

View file

@ -19,6 +19,9 @@ namespace psemek::gfx
struct normalized struct normalized
{}; {};
struct skip
{};
template <typename Attrib> template <typename Attrib>
struct attrib_traits; struct attrib_traits;
@ -132,111 +135,62 @@ namespace psemek::gfx
static constexpr GLboolean normalized = gl::TRUE_; static constexpr GLboolean normalized = gl::TRUE_;
}; };
template <typename ... Attribs>
struct vertex
{
static constexpr std::size_t size = (0 + ... + sizeof(typename attrib_traits<Attribs>::attrib_type));
using attribs = std::tuple<Attribs...>;
using attrib_types = std::tuple<typename attrib_traits<Attribs>::attrib_type...>;
template <std::size_t I>
static constexpr std::size_t offset()
{
return offset_impl(std::make_index_sequence<I>{});
}
template <std::size_t I>
auto & get()
{
using T = std::tuple_element_t<I, attrib_types>;
return *reinterpret_cast<T *>(reinterpret_cast<char *>(&storage) + offset<I>());
}
template <std::size_t I>
auto const & get() const
{
using T = std::tuple_element_t<I, attrib_types>;
return *reinterpret_cast<T const *>(reinterpret_cast<char const *>(&storage) + offset<I>());
}
vertex() = default;
vertex(vertex const & other)
{
copy_impl(std::make_index_sequence<sizeof...(Attribs)>{}, other);
}
vertex (typename attrib_traits<Attribs>::attrib_type const & ... args)
{
construct_impl(std::make_index_sequence<sizeof...(Attribs)>{}, args...);
}
vertex & operator = (vertex const & other)
{
if (this != &other) copy_impl(std::make_index_sequence<sizeof...(Attribs)>{}, other);
return *this;
}
std::aligned_storage_t<size, std::max(std::initializer_list<std::size_t>{alignof(Attribs)...})> storage;
private:
template <std::size_t ... Is>
static constexpr std::size_t offset_impl(std::index_sequence<Is...>)
{
return (0 + ... + sizeof(std::tuple_element_t<Is, attrib_types>));
}
template <std::size_t ... Is>
void construct_impl(std::index_sequence<Is...>, typename attrib_traits<Attribs>::attrib_type const & ... args)
{
((get<Is>() = args), ...);
}
template <std::size_t ... Is>
void copy_impl(std::index_sequence<Is...>, vertex const & other)
{
((get<Is>() = other.get<Is>()), ...);
}
};
namespace detail namespace detail
{ {
template <std::size_t ... Is> template <typename Attr>
void enable_attribs(std::index_sequence<Is...>) std::size_t attr_size()
{ {
int x[] { ((void) gl::EnableVertexAttribArray(Is), 0) ... }; if constexpr (std::is_same_v<Attr, skip>)
(void) x;
}
template <typename Vertex, std::size_t I>
void attrib_pointer()
{ {
using traits = attrib_traits<std::tuple_element_t<I, typename Vertex::attribs>>; return 0;
gl::VertexAttribPointer(I, traits::size, traits::type, traits::normalized, sizeof(Vertex), reinterpret_cast<char const *>(Vertex::template offset<I>()));
} }
else
template <typename Vertex, std::size_t ... Is>
void attrib_pointers(std::index_sequence<Is...>)
{ {
int x[] { ((void) attrib_pointer<Vertex, Is>(), 0) ... }; return sizeof(Attr);
(void) x; }
} }
template <typename Vertex>
struct mesh_setup;
template <typename ... Attribs> template <typename ... Attribs>
struct mesh_setup<vertex<Attribs...>> struct mesh_setup;
{
static void setup()
{
using indices = std::make_index_sequence<sizeof...(Attribs)>;
enable_attribs(indices{}); template <>
attrib_pointers<vertex<Attribs...>>(indices{}); struct mesh_setup<>
{
static std::size_t setup()
{
return 0;
}
static void setup_impl(int, std::size_t, std::size_t)
{}
};
template <typename Attr1, typename ... Attribs>
struct mesh_setup<Attr1, Attribs...>
{
static std::size_t setup()
{
std::size_t const stride = (0 + ... + attr_size<Attribs>());
setup_impl(0, 0, stride);
return stride;
}
static void setup_impl(int index, std::size_t offset, std::size_t stride)
{
if constexpr (std::is_same_v<Attr1, skip>)
{
mesh_setup<Attribs...>::setup_impl(index + 1, offset, stride);
}
else
{
using traits = attrib_traits<Attr1>;
gl::EnableVertexAttribArray(index);
gl::VertexAttribPointer(index, traits::size, traits::type, traits::normalized, stride, reinterpret_cast<char const *>(offset));
mesh_setup<Attribs...>::setup_impl(index + 1, offset + attr_size<Attr1>(), stride);
}
} }
}; };
@ -279,20 +233,21 @@ namespace psemek::gfx
~mesh(); ~mesh();
template <typename Vertex> template <typename ... Attribs>
void setup() void setup()
{ {
static_assert(sizeof(Vertex) == Vertex::size);
gl::BindVertexArray(array_); gl::BindVertexArray(array_);
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_); gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
detail::mesh_setup<Vertex>::setup(); stride_ = detail::mesh_setup<Attribs...>::setup();
} }
template <typename Vertex> template <typename Vertex>
void load(std::vector<Vertex> const & vertices, GLenum usage = gl::STREAM_DRAW) void load(std::vector<Vertex> const & vertices, GLenum usage = gl::STREAM_DRAW)
{ {
if (sizeof(Vertex) != stride_)
throw std::runtime_error("Vertex size not equal to sum of attribute sizes");
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_); gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
gl::BufferData(gl::ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), usage); gl::BufferData(gl::ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), usage);
@ -318,6 +273,8 @@ namespace psemek::gfx
GLsizei count_ = 0; GLsizei count_ = 0;
std::size_t stride_ = 0;
mesh(int); mesh(int);
}; };
@ -334,13 +291,13 @@ namespace psemek::gfx
~indexed_mesh(); ~indexed_mesh();
template <typename Vertex> template <typename ... Attribs>
void setup() void setup()
{ {
gl::BindVertexArray(array_); gl::BindVertexArray(array_);
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_); gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
detail::mesh_setup<Vertex>::setup(); stride_ = detail::mesh_setup<Attribs...>::setup();
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_); gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_);
} }
@ -348,6 +305,9 @@ namespace psemek::gfx
template <typename Vertex, typename Index> template <typename Vertex, typename Index>
void load(std::vector<Vertex> const & vertices, std::vector<Index> const & indices, GLenum usage = gl::STREAM_DRAW) void load(std::vector<Vertex> const & vertices, std::vector<Index> const & indices, GLenum usage = gl::STREAM_DRAW)
{ {
if (sizeof(Vertex) != stride_)
throw std::runtime_error("Vertex size not equal to sum of attribute sizes");
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_); gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
gl::BufferData(gl::ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), usage); gl::BufferData(gl::ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), usage);
gl::BindBuffer(gl::ARRAY_BUFFER, index_buffer_); gl::BindBuffer(gl::ARRAY_BUFFER, index_buffer_);
@ -378,6 +338,8 @@ namespace psemek::gfx
GLsizei count_ = 0; GLsizei count_ = 0;
GLenum index_type_ = 0; GLenum index_type_ = 0;
std::size_t stride_ = 0;
indexed_mesh(int); indexed_mesh(int);
}; };

View file

@ -7,15 +7,13 @@ namespace psemek::gfx
{ {
indexed_mesh m; indexed_mesh m;
using vertex = gfx::vertex<geom::point<float, 2>>; std::vector<geom::point<float, 2>> vertices(4);
std::vector<vertex> vertices(4);
std::vector<std::uint8_t> indices(6); std::vector<std::uint8_t> indices(6);
vertices[0].get<0>() = {-1.f, -1.f}; vertices[0] = {-1.f, -1.f};
vertices[1].get<0>() = { 1.f, -1.f}; vertices[1] = { 1.f, -1.f};
vertices[2].get<0>() = {-1.f, 1.f}; vertices[2] = {-1.f, 1.f};
vertices[3].get<0>() = { 1.f, 1.f}; vertices[3] = { 1.f, 1.f};
indices[0] = 0; indices[0] = 0;
indices[1] = 1; indices[1] = 1;
@ -24,7 +22,7 @@ namespace psemek::gfx
indices[4] = 1; indices[4] = 1;
indices[5] = 3; indices[5] = 3;
m.setup<vertex>(); m.setup<geom::point<float, 2>>();
m.load(vertices, indices, gl::STATIC_DRAW); m.load(vertices, indices, gl::STATIC_DRAW);
return m; return m;

View file

@ -1,4 +1,3 @@
* Remove gfx::vertex, setup mesh using attributes directly
* Design affine transforms in geom & use them instead of matrices when appropriate * Design affine transforms in geom & use them instead of matrices when appropriate
* Implement pixmap font rendering * Implement pixmap font rendering
* Create a simple generic primive painter * Create a simple generic primive painter