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 skip
{};
template <typename Attrib>
struct attrib_traits;
@ -132,111 +135,62 @@ namespace psemek::gfx
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
{
template <std::size_t ... Is>
void enable_attribs(std::index_sequence<Is...>)
template <typename Attr>
std::size_t attr_size()
{
int x[] { ((void) gl::EnableVertexAttribArray(Is), 0) ... };
(void) x;
}
template <typename Vertex, std::size_t I>
void attrib_pointer()
if constexpr (std::is_same_v<Attr, skip>)
{
using traits = attrib_traits<std::tuple_element_t<I, typename Vertex::attribs>>;
gl::VertexAttribPointer(I, traits::size, traits::type, traits::normalized, sizeof(Vertex), reinterpret_cast<char const *>(Vertex::template offset<I>()));
return 0;
}
template <typename Vertex, std::size_t ... Is>
void attrib_pointers(std::index_sequence<Is...>)
else
{
int x[] { ((void) attrib_pointer<Vertex, Is>(), 0) ... };
(void) x;
return sizeof(Attr);
}
}
template <typename Vertex>
struct mesh_setup;
template <typename ... Attribs>
struct mesh_setup<vertex<Attribs...>>
{
static void setup()
{
using indices = std::make_index_sequence<sizeof...(Attribs)>;
struct mesh_setup;
enable_attribs(indices{});
attrib_pointers<vertex<Attribs...>>(indices{});
template <>
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);
}
}
};
@ -274,25 +228,26 @@ namespace psemek::gfx
mesh(mesh &&);
mesh(mesh const &) = delete;
mesh & operator =(mesh &&);
mesh & operator =(mesh const &) = delete;
mesh & operator = (mesh &&);
mesh & operator = (mesh const &) = delete;
~mesh();
template <typename Vertex>
template <typename ... Attribs>
void setup()
{
static_assert(sizeof(Vertex) == Vertex::size);
gl::BindVertexArray(array_);
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
detail::mesh_setup<Vertex>::setup();
stride_ = detail::mesh_setup<Attribs...>::setup();
}
template <typename Vertex>
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::BufferData(gl::ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), usage);
@ -318,6 +273,8 @@ namespace psemek::gfx
GLsizei count_ = 0;
std::size_t stride_ = 0;
mesh(int);
};
@ -334,13 +291,13 @@ namespace psemek::gfx
~indexed_mesh();
template <typename Vertex>
template <typename ... Attribs>
void setup()
{
gl::BindVertexArray(array_);
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_);
}
@ -348,6 +305,9 @@ namespace psemek::gfx
template <typename Vertex, typename Index>
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::BufferData(gl::ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), usage);
gl::BindBuffer(gl::ARRAY_BUFFER, index_buffer_);
@ -378,6 +338,8 @@ namespace psemek::gfx
GLsizei count_ = 0;
GLenum index_type_ = 0;
std::size_t stride_ = 0;
indexed_mesh(int);
};

View file

@ -7,15 +7,13 @@ namespace psemek::gfx
{
indexed_mesh m;
using vertex = gfx::vertex<geom::point<float, 2>>;
std::vector<vertex> vertices(4);
std::vector<geom::point<float, 2>> vertices(4);
std::vector<std::uint8_t> indices(6);
vertices[0].get<0>() = {-1.f, -1.f};
vertices[1].get<0>() = { 1.f, -1.f};
vertices[2].get<0>() = {-1.f, 1.f};
vertices[3].get<0>() = { 1.f, 1.f};
vertices[0] = {-1.f, -1.f};
vertices[1] = { 1.f, -1.f};
vertices[2] = {-1.f, 1.f};
vertices[3] = { 1.f, 1.f};
indices[0] = 0;
indices[1] = 1;
@ -24,7 +22,7 @@ namespace psemek::gfx
indices[4] = 1;
indices[5] = 3;
m.setup<vertex>();
m.setup<geom::point<float, 2>>();
m.load(vertices, indices, gl::STATIC_DRAW);
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
* Implement pixmap font rendering
* Create a simple generic primive painter