Refactor meshes: single unified mesh class

This commit is contained in:
Nikita Lisitsa 2020-10-04 17:22:38 +03:00
parent 726b8486c7
commit e9af93b747
8 changed files with 294 additions and 818 deletions

View file

@ -173,9 +173,9 @@ struct cloud_app
std::vector<geom::point<float, 3>> bbox_vertices;
std::vector<geom::segment<std::uint32_t>> bbox_edges;
gfx::indexed_mesh bbox_mesh;
gfx::mesh bbox_mesh;
gfx::indexed_mesh slice_mesh;
gfx::mesh slice_mesh;
gfx::mesh light_mesh;
std::vector<geom::vector<float, 3>> dirs;

View file

@ -99,7 +99,7 @@ private:
gfx::program program_{vertex_source, fragment_source};
gfx::instanced_mesh mesh_;
gfx::mesh mesh_;
gfx::texture_2d texture_;
gfx::texture_2d noise_texture_;
@ -229,7 +229,6 @@ void candle_renderer::render(geom::camera const & camera, float time)
texture_.bind();
gl::ActiveTexture(gl::TEXTURE1);
noise_texture_.bind();
(void)time;
mesh_.draw();
}

View file

@ -173,10 +173,10 @@ struct grass_app
pcg::perlin<float, 2> density;
gfx::program ground_program{ground_vs, ground_fs};
gfx::indexed_mesh ground_mesh;
gfx::mesh ground_mesh;
gfx::program grass_program{grass_vs, grass_fs};
gfx::indexed_mesh grass_mesh;
gfx::mesh grass_mesh;
gfx::texture_1d grass_texture;
gfx::program grass_slice_program{grass_slice_vs, grass_slice_fs};

View file

@ -5,6 +5,6 @@
namespace psemek::gfx
{
indexed_mesh const & fullscreen_quad();
mesh const & fullscreen_quad();
}

View file

@ -2,6 +2,8 @@
#include <psemek/gfx/gl.hpp>
#include <psemek/gfx/drawable.hpp>
#include <psemek/gfx/array.hpp>
#include <psemek/gfx/buffer.hpp>
#include <psemek/geom/vector.hpp>
#include <psemek/geom/point.hpp>
@ -386,10 +388,7 @@ namespace psemek::gfx
template <typename T>
static constexpr GLenum gl_type_v = gl_type<T>::value;
void check_vertex_size(std::size_t vertex_size, std::size_t stride);
void check_instance_size(std::size_t instance_size, std::size_t stride);
static std::size_t index_size(GLenum type)
inline std::size_t index_size(GLenum type)
{
switch (type)
{
@ -401,573 +400,277 @@ namespace psemek::gfx
return 0;
}
template <std::size_t N>
GLenum get_primitive_type()
{
if constexpr (N == 0)
{
return gl::POINTS;
}
else if constexpr (N == 1)
{
return gl::LINES;
}
else if constexpr (N == 2)
{
return gl::TRIANGLES;
}
else
{
static_assert("unknown primitive type");
}
}
inline std::optional<std::size_t> get_primitive_type_vertex_count(GLenum type)
{
switch (type)
{
case gl::LINES:
return 2;
case gl::TRIANGLES:
return 3;
default:
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
* Supports both indexed & non-indexed rendering
* Supports both instanced & non-instanced rendering
* Checks vertex & instance size, may throw on load
* Strong exception guarantees
*/
struct mesh
: drawable
{
static mesh null();
mesh();
mesh() = default;
mesh(mesh &&);
mesh(mesh const &) = delete;
mesh & operator = (mesh &&);
mesh(mesh const &) = delete;
mesh & operator = (mesh const &) = delete;
~mesh();
template <typename ... Attribs>
void setup()
{
gl::BindVertexArray(array_);
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
void setup();
stride_ = detail::mesh_setup<Attribs...>::setup();
}
// Non-indexed vertex data
template <typename Vertex>
void load(Vertex const * vertices, std::size_t count, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW)
{
detail::check_vertex_size(sizeof(Vertex), stride_);
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;
}
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
gl::BufferData(gl::ARRAY_BUFFER, count * sizeof(Vertex), vertices, usage);
count_ = count;
primitive_type_ = primitive_type;
}
void load(Vertex const * vertices, std::size_t count, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW);
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);
}
void load(std::vector<Vertex> const & vertices, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW);
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);
}
void load(geom::simplex<Vertex, N> const * simplices, std::size_t count, GLenum usage = gl::STREAM_DRAW);
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 load(std::vector<geom::simplex<Vertex, N>> const & simplices, GLenum usage = gl::STREAM_DRAW);
void draw() const override
{
draw(0, count_);
}
void draw(GLsizei first, GLsizei count) const
{
assert(first + count <= count_);
if (count == 0) return;
gl::BindVertexArray(array_);
gl::DrawArrays(primitive_type_, first, count);
}
GLsizei count() const
{
return count_;
}
GLenum primitive_type() const
{
return primitive_type_;
}
private:
GLuint array_;
GLuint buffer_;
GLsizei count_ = 0;
std::size_t stride_ = 0;
GLenum primitive_type_;
mesh(int);
};
struct indexed_mesh
: drawable
{
static indexed_mesh null();
indexed_mesh();
indexed_mesh(indexed_mesh &&);
indexed_mesh(indexed_mesh const &) = delete;
indexed_mesh & operator =(indexed_mesh &&);
indexed_mesh & operator =(indexed_mesh const &) = delete;
~indexed_mesh();
template <typename ... Attribs>
void setup()
{
gl::BindVertexArray(array_);
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
stride_ = detail::mesh_setup<Attribs...>::setup();
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_);
}
// Indexed vertex data
template <typename Vertex, typename Index>
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)
{
detail::check_vertex_size(sizeof(Vertex), stride_);
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;
}
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 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);
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);
}
void load(std::vector<Vertex> const & vertices, std::vector<Index> const & indices, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW);
template <typename Vertex, typename Index, std::size_t N>
void load(Vertex const * vertices, std::size_t vertex_count, geom::simplex<Index, N> const * simplices, std::size_t simplex_count, GLenum usage = gl::STREAM_DRAW)
{
static_assert(sizeof(geom::simplex<Index, N>) == (N + 1) * sizeof(Index));
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(vertices, vertex_count, reinterpret_cast<Index const *>(simplices), simplex_count * (N + 1), primitive_type, usage);
}
void load(Vertex const * vertices, std::size_t vertex_count, geom::simplex<Index, N> const * simplices, std::size_t simplex_count, GLenum usage = gl::STREAM_DRAW);
template <typename Vertex, typename Index, std::size_t N>
void load(std::vector<Vertex> const & vertices, std::vector<geom::simplex<Index, N>> const & simplices, GLenum usage = gl::STREAM_DRAW)
{
load(vertices.data(), vertices.size(), simplices.data(), simplices.size(), usage);
}
void load(std::vector<Vertex> const & vertices, std::vector<geom::simplex<Index, N>> const & simplices, GLenum usage = gl::STREAM_DRAW);
void draw() const override
{
draw(0, count_);
}
void draw(GLsizei first, GLsizei count) const
{
if (count == 0) return;
assert(first + count <= count_);
gl::BindVertexArray(array_);
gl::DrawElements(primitive_type_, count, index_type_, reinterpret_cast<char const *>(0) + first * detail::index_size(index_type_));
}
GLsizei index_count() const
{
return count_;
}
GLenum primitive_type() const
{
return primitive_type_;
}
private:
GLuint array_;
GLuint buffer_;
GLuint index_buffer_;
GLsizei count_ = 0;
GLenum index_type_ = 0;
std::size_t stride_ = 0;
GLenum primitive_type_;
indexed_mesh(int);
};
struct instanced_mesh
: drawable
{
static instanced_mesh null();
instanced_mesh();
instanced_mesh(instanced_mesh &&);
instanced_mesh(instanced_mesh const &) = delete;
instanced_mesh & operator = (instanced_mesh &&);
instanced_mesh & operator = (instanced_mesh const &) = delete;
~instanced_mesh();
template <typename ... Attribs>
void setup()
{
gl::BindVertexArray(array_);
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
stride_ = detail::instanced_mesh_vertex_setup<Attribs...>::setup();
gl::BindBuffer(gl::ARRAY_BUFFER, instance_buffer_);
instance_stride_ = detail::instanced_mesh_instance_setup<Attribs...>::setup();
}
template <typename Vertex>
void load(Vertex const * vertices, std::size_t count, GLenum primitive_type, GLenum usage = gl::STREAM_DRAW)
{
detail::check_vertex_size(sizeof(Vertex), stride_);
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;
}
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
gl::BufferData(gl::ARRAY_BUFFER, count * sizeof(Vertex), vertices, usage);
count_ = count;
primitive_type_ = primitive_type;
}
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);
}
// Instance data
template <typename Instance>
void load_instance(Instance const * instances, std::size_t count, GLenum usage = gl::STREAM_DRAW)
{
detail::check_instance_size(sizeof(Instance), instance_stride_);
gl::BindBuffer(gl::ARRAY_BUFFER, instance_buffer_);
gl::BufferData(gl::ARRAY_BUFFER, count * sizeof(Instance), instances, usage);
instance_count_ = count;
}
void load_instance(Instance const * instances, std::size_t count, GLenum usage = gl::STREAM_DRAW);
template <typename Instance>
void load_instance(std::vector<Instance> const & instances, GLenum usage = gl::STREAM_DRAW)
{
load_instance(instances.data(), instances.size(), usage);
}
void load_instance(std::vector<Instance> const & instances, GLenum usage = gl::STREAM_DRAW);
void draw() const override
{
draw(0, count_, instance_count_);
}
// Info
void draw(GLsizei first, GLsizei count, GLsizei instance_count) const
{
assert(first + count <= count_);
assert(instance_count <= instance_count_);
bool is_indexed() const { return info_.indexed_; }
bool is_instanced() const { return info_.instanced_; }
if (count == 0) return;
if (instance_count == 0) return;
std::size_t vertex_count() const { return info_.vertex_count_; }
std::size_t index_count() const { return info_.index_count_; }
std::size_t instance_count() const { return info_.instance_count_; }
gl::BindVertexArray(array_);
gl::DrawArraysInstanced(primitive_type_, first, count, instance_count);
}
std::size_t count() const; // total vertex count = number of vertex shader executions
GLsizei count() const
{
return count_;
}
GLenum primitive_type() const { return info_.primitive_type_; }
GLenum index_type() const { return info_.index_type_; }
GLsizei instance_count() const
{
return instance_count_;
}
// Drawing commands
GLenum primitive_type() const
{
return primitive_type_;
}
void draw() const override;
void draw(std::size_t first, std::size_t count, std::size_t instance_count = 0) const;
private:
GLuint array_;
GLuint buffer_;
GLuint instance_buffer_;
array array_;
buffer vertex_buffer_ = buffer::null();
buffer index_buffer_ = buffer::null();
buffer instance_buffer_ = buffer::null();
GLsizei count_ = 0;
GLsizei instance_count_ = 0;
struct mesh_info
{
bool indexed_ = false;
bool instanced_ = false;
std::size_t vertex_count_ = 0;
std::size_t index_count_ = 0;
std::size_t instance_count_ = 0;
std::size_t stride_ = 0;
std::size_t instance_stride_ = 0;
GLenum primitive_type_;
instanced_mesh(int);
GLenum index_type_;
};
struct instanced_indexed_mesh
: drawable
{
static instanced_indexed_mesh null();
instanced_indexed_mesh();
instanced_indexed_mesh(instanced_indexed_mesh &&);
instanced_indexed_mesh(instanced_indexed_mesh const &) = delete;
instanced_indexed_mesh & operator = (instanced_indexed_mesh &&);
instanced_indexed_mesh & operator = (instanced_indexed_mesh const &) = delete;
~instanced_indexed_mesh();
mesh_info info_;
};
template <typename ... Attribs>
void setup()
void mesh::setup()
{
gl::BindVertexArray(array_);
array_.bind();
gl::BindBuffer(gl::ARRAY_BUFFER, buffer_);
stride_ = detail::instanced_mesh_vertex_setup<Attribs...>::setup();
if (!vertex_buffer_) vertex_buffer_ = buffer{};
vertex_buffer_.bind();
info_.stride_ = detail::instanced_mesh_vertex_setup<Attribs...>::setup();
gl::BindBuffer(gl::ARRAY_BUFFER, instance_buffer_);
instance_stride_ = detail::instanced_mesh_instance_setup<Attribs...>::setup();
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();
info_.instanced_ = true;
}
else
{
info_.instance_stride_ = 0;
info_.instanced_ = false;
}
}
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_);
template <typename Vertex>
void mesh::load(Vertex const * vertices, std::size_t count, GLenum primitive_type, GLenum usage)
{
assert(info_.stride_ == sizeof(Vertex));
if (auto n = detail::get_primitive_type_vertex_count(primitive_type); n)
assert((count % (*n)) == 0);
assert(vertex_buffer_);
vertex_buffer_.load(vertices, count, usage);
info_.vertex_count_ = count;
info_.index_count_ = 0;
info_.indexed_ = false;
info_.primitive_type_ = primitive_type;
}
template <typename Vertex>
void mesh::load(std::vector<Vertex> const & vertices, GLenum primitive_type, GLenum usage)
{
load(vertices.data(), vertices.size(), primitive_type, usage);
}
template <typename Vertex, std::size_t N>
void mesh::load(geom::simplex<Vertex, N> const * simplices, std::size_t count, GLenum usage)
{
static_assert(sizeof(Vertex) * (N + 1) == sizeof(simplices[0]));
load(reinterpret_cast<Vertex const *>(simplices), count * (N + 1), detail::get_primitive_type<N>(), usage);
}
template <typename Vertex, std::size_t N>
void mesh::load(std::vector<geom::simplex<Vertex, N>> const & simplices, GLenum usage)
{
load(simplices.data(), simplices.size(), usage);
}
template <typename Vertex, typename Index>
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)
void mesh::load(Vertex const * vertices, std::size_t vertex_count, Index const * indices, std::size_t index_count, GLenum primitive_type, GLenum usage)
{
detail::check_vertex_size(sizeof(Vertex), stride_);
assert(info_.stride_ == sizeof(Vertex));
switch (primitive_type)
if (auto n = detail::get_primitive_type_vertex_count(primitive_type); n)
assert((index_count % (*n)) == 0);
assert(vertex_buffer_);
if (!index_buffer_)
{
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;
index_buffer_ = buffer{};
array_.bind();
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_.id());
}
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;
vertex_buffer_.load(vertices, vertex_count, usage);
index_buffer_.load(indices, index_count, usage);
info_.vertex_count_ = vertex_count;
info_.index_count_ = index_count;
info_.indexed_ = true;
info_.primitive_type_ = primitive_type;
info_.index_type_ = detail::gl_type_v<Index>;
}
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)
void mesh::load(std::vector<Vertex> const & vertices, std::vector<Index> const & indices, GLenum primitive_type, GLenum usage)
{
load(vertices.data(), vertices.size(), indices.data(), indices.size(), primitive_type, usage);
}
template <typename Vertex, typename Index, std::size_t N>
void load(Vertex const * vertices, std::size_t vertex_count, geom::simplex<Index, N> const * simplices, std::size_t simplex_count, GLenum usage = gl::STREAM_DRAW)
void mesh::load(Vertex const * vertices, std::size_t vertex_count, geom::simplex<Index, N> const * simplices, std::size_t simplex_count, GLenum usage)
{
static_assert(sizeof(geom::simplex<Index, N>) == (N + 1) * sizeof(Index));
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(vertices, vertex_count, reinterpret_cast<Index const *>(simplices), simplex_count * (N + 1), primitive_type, usage);
static_assert(sizeof(Index) * (N + 1) == sizeof(simplices[0]));
load(vertices, vertex_count, reinterpret_cast<Index const *>(simplices), (N + 1) * simplex_count, detail::get_primitive_type<N>(), usage);
}
template <typename Vertex, typename Index, std::size_t N>
void load(std::vector<Vertex> const & vertices, std::vector<geom::simplex<Index, N>> const & simplices, GLenum usage = gl::STREAM_DRAW)
void mesh::load(std::vector<Vertex> const & vertices, std::vector<geom::simplex<Index, N>> const & simplices, GLenum usage)
{
load(vertices.data(), vertices.size(), simplices.data(), simplices.size(), usage);
}
template <typename Instance>
void load_instance(Instance const * instances, std::size_t count, GLenum usage = gl::STREAM_DRAW)
void mesh::load_instance(Instance const * instances, std::size_t count, GLenum usage)
{
detail::check_instance_size(sizeof(Instance), instance_stride_);
assert(info_.instance_stride_ == sizeof(Instance));
gl::BindBuffer(gl::ARRAY_BUFFER, instance_buffer_);
gl::BufferData(gl::ARRAY_BUFFER, count * sizeof(Instance), instances, usage);
instance_count_ = count;
assert(instance_buffer_);
instance_buffer_.load(instances, count, usage);
info_.instance_count_ = count;
}
template <typename Instance>
void load_instance(std::vector<Instance> const & instances, GLenum usage = gl::STREAM_DRAW)
void mesh::load_instance(std::vector<Instance> const & instances, GLenum usage)
{
load_instance(instances.data(), instances.size(), usage);
}
void draw() const override
{
draw(0, count_, instance_count_);
}
void draw(GLsizei first, GLsizei count, GLsizei instance_count) const
{
assert(first + count <= count_);
assert(instance_count <= instance_count_);
if (count == 0) return;
if (instance_count == 0) return;
gl::BindVertexArray(array_);
gl::DrawElementsInstanced(primitive_type_, count, index_type_, reinterpret_cast<char const *>(0) + detail::index_size(index_type_) * first, instance_count);
}
GLsizei index_count() const
{
return count_;
}
GLsizei instance_count() const
{
return instance_count_;
}
GLenum primitive_type() const
{
return primitive_type_;
}
private:
GLuint array_;
GLuint buffer_;
GLuint index_buffer_;
GLuint instance_buffer_;
GLsizei count_ = 0;
GLsizei instance_count_ = 0;
GLenum index_type_ = 0;
std::size_t stride_ = 0;
std::size_t instance_stride_ = 0;
GLenum primitive_type_;
instanced_indexed_mesh(int);
};
}

View file

@ -3,9 +3,9 @@
namespace psemek::gfx
{
static indexed_mesh create_fullscreen_quad()
static mesh create_fullscreen_quad()
{
indexed_mesh m;
mesh m;
std::vector<geom::point<float, 2>> vertices(4);
std::vector<std::uint8_t> indices(6);
@ -28,9 +28,9 @@ namespace psemek::gfx
return m;
}
indexed_mesh const & fullscreen_quad()
mesh const & fullscreen_quad()
{
static indexed_mesh m = create_fullscreen_quad();
static mesh m = create_fullscreen_quad();
return m;
}

View file

@ -5,309 +5,83 @@
namespace psemek::gfx
{
namespace detail
{
void check_vertex_size(std::size_t vertex_size, std::size_t stride)
{
if (vertex_size != stride)
throw std::runtime_error(util::to_string("Vertex size (", vertex_size, ") not equal to sum of attribute sizes (", stride, ")"));
}
void check_instance_size(std::size_t instance_size, std::size_t stride)
{
if (instance_size != stride)
throw std::runtime_error(util::to_string("Instance size (", instance_size, ") not equal to sum of instanced attribute sizes (", stride, ")"));
}
}
mesh mesh::null()
{
return mesh(0);
}
mesh::mesh()
{
gl::GenVertexArrays(1, &array_);
gl::GenBuffers(1, &buffer_);
}
mesh::mesh(mesh && other)
: array_{std::move(other.array_)}
, vertex_buffer_{std::move(other.vertex_buffer_)}
, index_buffer_{std::move(other.index_buffer_)}
, instance_buffer_{std::move(other.instance_buffer_)}
, info_{other.info_}
{
array_ = other.array_;
buffer_ = other.buffer_;
count_ = other.count_;
stride_ = other.stride_;
primitive_type_ = other.primitive_type_;
other.array_ = 0;
other.buffer_ = 0;
other.count_ = 0;
other.stride_ = 0;
other.info_ = mesh_info{};
}
mesh & mesh::operator =(mesh && other)
mesh & mesh::operator = (mesh && other)
{
if (this == &other) return *this;
if (array_)
{
gl::DeleteVertexArrays(1, &array_);
gl::DeleteBuffers(1, &buffer_);
}
array_ = other.array_;
buffer_ = other.buffer_;
count_ = other.count_;
stride_ = other.stride_;
primitive_type_ = other.primitive_type_;
other.array_ = 0;
other.buffer_ = 0;
other.count_ = 0;
other.stride_ = 0;
array_ = std::move(other.array_);
vertex_buffer_ = std::move(other.vertex_buffer_);
index_buffer_ = std::move(other.index_buffer_);
instance_buffer_ = std::move(other.instance_buffer_);
info_ = other.info_;
other.info_ = mesh_info{};
return *this;
}
mesh::~mesh()
void mesh::draw() const
{
gl::DeleteVertexArrays(1, &array_);
gl::DeleteBuffers(1, &buffer_);
draw(0, is_indexed() ? index_count() : vertex_count(), instance_count());
}
mesh::mesh(int)
void mesh::draw(std::size_t first, std::size_t count, std::size_t instance_count) const
{
array_ = 0;
buffer_ = 0;
if (is_indexed())
{
assert(first + count <= index_count());
if (is_instanced())
{
assert(instance_count <= this->instance_count());
if (count != 0 && instance_count != 0)
{
array_.bind();
gl::DrawElementsInstanced(primitive_type(), count, index_type(), reinterpret_cast<char const *>(detail::index_size(index_type()) * first), instance_count);
}
indexed_mesh indexed_mesh::null()
{
return indexed_mesh(0);
}
indexed_mesh::indexed_mesh()
else
{
gl::GenVertexArrays(1, &array_);
gl::GenBuffers(1, &buffer_);
gl::GenBuffers(1, &index_buffer_);
if (count != 0)
{
array_.bind();
gl::DrawElements(primitive_type(), count, index_type(), reinterpret_cast<char const *>(detail::index_size(index_type()) * first));
}
indexed_mesh::indexed_mesh(indexed_mesh && other)
{
array_ = other.array_;
buffer_ = other.buffer_;
index_buffer_ = other.index_buffer_;
count_ = other.count_;
index_type_ = other.index_type_;
stride_ = other.stride_;
primitive_type_ = other.primitive_type_;
other.array_ = 0;
other.buffer_ = 0;
other.index_buffer_ = 0;
other.count_ = 0;
other.index_type_ = 0;
other.stride_ = 0;
}
indexed_mesh & indexed_mesh::operator =(indexed_mesh && other)
{
if (this == &other) return *this;
if (array_)
{
gl::DeleteVertexArrays(1, &array_);
gl::DeleteBuffers(1, &buffer_);
gl::DeleteBuffers(1, &index_buffer_);
}
array_ = other.array_;
buffer_ = other.buffer_;
index_buffer_ = other.index_buffer_;
count_ = other.count_;
index_type_ = other.index_type_;
stride_ = other.stride_;
primitive_type_ = other.primitive_type_;
other.array_ = 0;
other.buffer_ = 0;
other.index_buffer_ = 0;
other.count_ = 0;
other.index_type_ = 0;
other.stride_ = 0;
return *this;
}
indexed_mesh::~indexed_mesh()
else
{
gl::DeleteVertexArrays(1, &array_);
gl::DeleteBuffers(1, &buffer_);
gl::DeleteBuffers(1, &index_buffer_);
}
assert(first + count <= vertex_count());
indexed_mesh::indexed_mesh(int)
if (is_instanced())
{
array_ = 0;
buffer_ = 0;
index_buffer_ = 0;
}
assert(instance_count <= this->instance_count());
instanced_mesh instanced_mesh::null()
if (count != 0 && instance_count != 0)
{
return instanced_mesh(0);
array_.bind();
gl::DrawArraysInstanced(primitive_type(), first, count, instance_count);
}
instanced_mesh::instanced_mesh()
{
gl::GenVertexArrays(1, &array_);
gl::GenBuffers(1, &buffer_);
gl::GenBuffers(1, &instance_buffer_);
}
instanced_mesh::instanced_mesh(instanced_mesh && other)
else
{
array_ = other.array_;
buffer_ = other.buffer_;
instance_buffer_ = other.instance_buffer_;
count_ = other.count_;
instance_count_ = other.instance_count_;
stride_ = other.stride_;
instance_stride_ = other.instance_stride_;
primitive_type_ = other.primitive_type_;
other.array_ = 0;
other.buffer_ = 0;
other.instance_buffer_ = 0;
other.count_ = 0;
other.instance_count_ = 0;
other.stride_ = 0;
other.instance_stride_ = 0;
if (count != 0)
{
array_.bind();
gl::DrawArrays(primitive_type(), first, count);
}
instanced_mesh & instanced_mesh::operator = (instanced_mesh && other)
{
if (this == &other)
return *this;
gl::DeleteVertexArrays(1, &array_);
gl::DeleteBuffers(1, &buffer_);
gl::DeleteBuffers(1, &instance_buffer_);
array_ = other.array_;
buffer_ = other.buffer_;
instance_buffer_ = other.instance_buffer_;
count_ = other.count_;
instance_count_ = other.instance_count_;
stride_ = other.stride_;
instance_stride_ = other.instance_stride_;
primitive_type_ = other.primitive_type_;
other.array_ = 0;
other.buffer_ = 0;
other.instance_buffer_ = 0;
other.count_ = 0;
other.instance_count_ = 0;
other.stride_ = 0;
other.instance_stride_ = 0;
return *this;
}
instanced_mesh::~instanced_mesh()
{
gl::DeleteVertexArrays(1, &array_);
gl::DeleteBuffers(1, &buffer_);
gl::DeleteBuffers(1, &instance_buffer_);
}
instanced_mesh::instanced_mesh(int)
{
array_ = 0;
buffer_ = 0;
instance_buffer_ = 0;
}
instanced_indexed_mesh instanced_indexed_mesh::null()
{
return instanced_indexed_mesh(0);
}
instanced_indexed_mesh::instanced_indexed_mesh()
{
gl::GenVertexArrays(1, &array_);
gl::GenBuffers(1, &buffer_);
gl::GenBuffers(1, &index_buffer_);
gl::GenBuffers(1, &instance_buffer_);
}
instanced_indexed_mesh::instanced_indexed_mesh(instanced_indexed_mesh && other)
{
array_ = other.array_;
buffer_ = other.buffer_;
instance_buffer_ = other.instance_buffer_;
count_ = other.count_;
instance_count_ = other.instance_count_;
stride_ = other.stride_;
instance_stride_ = other.instance_stride_;
primitive_type_ = other.primitive_type_;
other.array_ = 0;
other.buffer_ = 0;
other.instance_buffer_ = 0;
other.count_ = 0;
other.instance_count_ = 0;
other.stride_ = 0;
other.instance_stride_ = 0;
}
instanced_indexed_mesh & instanced_indexed_mesh::operator = (instanced_indexed_mesh && other)
{
if (this == &other)
return *this;
gl::DeleteVertexArrays(1, &array_);
gl::DeleteBuffers(1, &buffer_);
gl::DeleteBuffers(1, &index_buffer_);
gl::DeleteBuffers(1, &instance_buffer_);
array_ = other.array_;
buffer_ = other.buffer_;
instance_buffer_ = other.instance_buffer_;
count_ = other.count_;
instance_count_ = other.instance_count_;
stride_ = other.stride_;
instance_stride_ = other.instance_stride_;
primitive_type_ = other.primitive_type_;
other.array_ = 0;
other.buffer_ = 0;
other.instance_buffer_ = 0;
other.count_ = 0;
other.instance_count_ = 0;
other.stride_ = 0;
other.instance_stride_ = 0;
return *this;
}
instanced_indexed_mesh::~instanced_indexed_mesh()
{
gl::DeleteVertexArrays(1, &array_);
gl::DeleteBuffers(1, &buffer_);
gl::DeleteBuffers(1, &index_buffer_);
gl::DeleteBuffers(1, &instance_buffer_);
}
instanced_indexed_mesh::instanced_indexed_mesh(int)
{
array_ = 0;
buffer_ = 0;
index_buffer_ = 0;
instance_buffer_ = 0;
}
}

View file

@ -94,8 +94,8 @@ namespace psemek::gfx
gfx::program program{vertex_source, fragment_source};
gfx::program text_program{text_vertex_source, text_fragment_source};
gfx::indexed_mesh mesh;
gfx::indexed_mesh text_mesh;
gfx::mesh mesh;
gfx::mesh text_mesh;
std::vector<vertex> vertices;
std::vector<std::uint32_t> indices;