Redesign gfx::mesh: stores primitive type, supports loading from pointers & simplices (deduces primitive type in the latter case)

This commit is contained in:
Nikita Lisitsa 2020-09-24 12:45:25 +03:00
parent 5d44efa2ea
commit 8877f6dedd
2 changed files with 137 additions and 18 deletions

View file

@ -4,6 +4,7 @@
#include <psemek/geom/vector.hpp>
#include <psemek/geom/point.hpp>
#include <psemek/geom/simplex.hpp>
#include <cstddef>
#include <tuple>
@ -277,23 +278,75 @@ namespace psemek::gfx
}
template <typename Vertex>
void load(std::vector<Vertex> const & vertices, GLenum usage = gl::STREAM_DRAW)
void load(Vertex const * vertices, std::size_t count, GLenum primitive_type, 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);
switch (primitive_type)
{
case gl::LINES:
if ((count % 2) != 0) throw std::runtime_error("Vertex count for GL_LINES should be a multiple of 2");
break;
case gl::TRIANGLES:
if ((count % 3) != 0) throw std::runtime_error("Vertex count for GL_TRIANGLES should be a multiple of 3");
break;
default:
break;
}
count_ = vertices.size();
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
gl::BufferData(gl::ARRAY_BUFFER, count * sizeof(Vertex), vertices, usage);
count_ = count;
primitive_type_ = primitive_type;
}
void draw(GLenum mode) const
template <typename Vertex>
void load(std::vector<Vertex> const & vertices, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW)
{
load(vertices.data(), vertices.size(), primitive_type, usage);
}
template <typename Vertex, std::size_t N>
void load(geom::simplex<Vertex, N> const * simplices, std::size_t count, GLenum usage = gl::STREAM_DRAW)
{
static_assert(sizeof(geom::simplex<Vertex, N>) == (N + 1) * sizeof(Vertex));
GLenum primitive_type;
if constexpr (N == 0)
{
primitive_type = gl::POINTS;
}
else if constexpr (N == 1)
{
primitive_type = gl::LINES;
}
else if constexpr (N == 2)
{
primitive_type = gl::TRIANGLES;
}
else
{
static_assert("unknown primitive type");
}
load(reinterpret_cast<Vertex const *>(simplices), count * (N + 1), primitive_type, usage);
}
template <typename Vertex, std::size_t N>
void load(std::vector<geom::simplex<Vertex, N>> const & simplices, GLenum usage = gl::STREAM_DRAW)
{
load(simplices.data(), simplices.size(), usage);
}
void draw() const
{
if (count_ == 0) return;
gl::BindVertexArray(array_);
gl::DrawArrays(mode, 0, count_);
gl::DrawArrays(primitive_type_, 0, count_);
}
GLsizei count() const
@ -301,6 +354,11 @@ namespace psemek::gfx
return count_;
}
GLenum primitive_type() const
{
return primitive_type_;
}
private:
GLuint array_;
GLuint buffer_;
@ -309,6 +367,8 @@ namespace psemek::gfx
std::size_t stride_ = 0;
GLenum primitive_type_;
mesh(int);
};
@ -337,26 +397,78 @@ 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)
void load(Vertex const * vertices, std::size_t vertex_count, Index const * indices, std::size_t index_count, GLenum primitive_type, 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_);
gl::BufferData(gl::ARRAY_BUFFER, indices.size() * sizeof(Index), indices.data(), usage);
switch (primitive_type)
{
case gl::LINES:
if ((index_count % 2) != 0) throw std::runtime_error("Index count for GL_LINES should be a multiple of 2");
break;
case gl::TRIANGLES:
if ((index_count % 3) != 0) throw std::runtime_error("Index count for GL_TRIANGLES should be a multiple of 3");
break;
default:
break;
}
count_ = indices.size();
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
gl::BufferData(gl::ARRAY_BUFFER, vertex_count * sizeof(Vertex), vertices, usage);
gl::BindBuffer(gl::ARRAY_BUFFER, index_buffer_);
gl::BufferData(gl::ARRAY_BUFFER, index_count * sizeof(Index), indices, usage);
count_ = index_count;
index_type_ = detail::gl_type_v<Index>;
primitive_type_ = primitive_type;
}
void draw(GLenum mode) const
template <typename Vertex, typename Index>
void load(std::vector<Vertex> const & vertices, std::vector<Index> const & indices, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW)
{
load(vertices.data(), vertices.size(), indices.data(), indices.size(), primitive_type, usage);
}
template <typename Vertex, std::size_t N, typename Index>
void load(geom::simplex<Vertex, N> const * simplices, std::size_t simplex_count, Index const * indices, std::size_t index_count, GLenum usage = gl::STREAM_DRAW)
{
static_assert(sizeof(geom::simplex<Vertex, N>) == (N + 1) * sizeof(Vertex));
GLenum primitive_type;
if constexpr (N == 0)
{
primitive_type = gl::POINTS;
}
else if constexpr (N == 1)
{
primitive_type = gl::LINES;
}
else if constexpr (N == 2)
{
primitive_type = gl::TRIANGLES;
}
else
{
static_assert("unknown primitive type");
}
load(reinterpret_cast<Vertex const *>(simplices), simplex_count * (N + 1), indices, index_count, primitive_type, usage);
}
template <typename Vertex, std::size_t N, typename Index>
void load(std::vector<geom::simplex<Vertex, N>> const & simplices, std::vector<Index> const & indices, GLenum usage = gl::STREAM_DRAW)
{
load(simplices.data(), simplices.size(), indices.data(), indices.size(), usage);
}
void draw() const
{
if (count_ == 0) return;
gl::BindVertexArray(array_);
gl::DrawElements(mode, count_, index_type_, nullptr);
gl::DrawElements(primitive_type_, count_, index_type_, nullptr);
}
GLsizei count() const
@ -364,6 +476,11 @@ namespace psemek::gfx
return count_;
}
GLenum primitive_type() const
{
return primitive_type_;
}
private:
GLuint array_;
GLuint buffer_;
@ -374,6 +491,8 @@ namespace psemek::gfx
std::size_t stride_ = 0;
GLenum primitive_type_;
indexed_mesh(int);
};

View file

@ -424,24 +424,24 @@ namespace psemek::gfx
void painter::render(geom::matrix<float, 4, 4> const & transform)
{
impl().mesh.load(impl().vertices, impl().indices, gl::STREAM_DRAW);
impl().mesh.load(impl().vertices, impl().indices, gl::TRIANGLES, gl::STREAM_DRAW);
impl().vertices.clear();
impl().indices.clear();
impl().text_mesh.load(impl().text_vertices, impl().text_indices, gl::STREAM_DRAW);
impl().text_mesh.load(impl().text_vertices, impl().text_indices, gl::TRIANGLES, gl::STREAM_DRAW);
impl().text_vertices.clear();
impl().text_indices.clear();
impl().program.bind();
impl().program["u_transform"] = transform;
impl().mesh.draw(gl::TRIANGLES);
impl().mesh.draw();
impl().text_program.bind();
impl().text_program["u_transform"] = transform;
impl().text_program["u_texture"] = 0;
impl().text_program["u_texture_size"] = impl().font_texture.size();
impl().font_texture.bind();
impl().text_mesh.draw(gl::TRIANGLES);
impl().text_mesh.draw();
}
}