diff --git a/libs/gfx/include/psemek/gfx/mesh.hpp b/libs/gfx/include/psemek/gfx/mesh.hpp index 9bc167dc..ddbdc418 100644 --- a/libs/gfx/include/psemek/gfx/mesh.hpp +++ b/libs/gfx/include/psemek/gfx/mesh.hpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -277,23 +278,75 @@ namespace psemek::gfx } template - void load(std::vector 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 + void load(std::vector const & vertices, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW) + { + load(vertices.data(), vertices.size(), primitive_type, usage); + } + + template + void load(geom::simplex const * simplices, std::size_t count, GLenum usage = gl::STREAM_DRAW) + { + static_assert(sizeof(geom::simplex) == (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(simplices), count * (N + 1), primitive_type, usage); + } + + template + void load(std::vector> 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 - void load(std::vector const & vertices, std::vector 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; + primitive_type_ = primitive_type; } - void draw(GLenum mode) const + template + void load(std::vector const & vertices, std::vector const & indices, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW) + { + load(vertices.data(), vertices.size(), indices.data(), indices.size(), primitive_type, usage); + } + + template + void load(geom::simplex 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) == (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(simplices), simplex_count * (N + 1), indices, index_count, primitive_type, usage); + } + + template + void load(std::vector> const & simplices, std::vector 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); }; diff --git a/libs/gfx/source/painter.cpp b/libs/gfx/source/painter.cpp index c317ec63..9701c431 100644 --- a/libs/gfx/source/painter.cpp +++ b/libs/gfx/source/painter.cpp @@ -424,24 +424,24 @@ namespace psemek::gfx void painter::render(geom::matrix 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(); } }