psemek/libs/gfx/source/mesh.cpp

154 lines
3.3 KiB
C++

#include <psemek/gfx/mesh.hpp>
#include <psemek/util/to_string.hpp>
namespace psemek::gfx
{
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_}
{
other.info_ = mesh_info{};
}
mesh & mesh::operator = (mesh && other)
{
if (this == &other) return *this;
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;
}
void mesh::bind() const
{
array_.bind();
}
void mesh::setup(attribs_description const & attribs)
{
assert(!attribs.attribs.empty());
bind();
for (std::size_t i = 0; i < info_.max_attribute_index_; ++i)
gl::DisableVertexAttribArray(i);
std::size_t max_index = 0;
bool instanced = false;
std::size_t stride = 0;
std::size_t instance_stride = 0;
for (auto const & a : attribs.attribs)
{
max_index = std::max<std::size_t>(max_index, a.index);
if (a.divisor == 0)
{
stride = a.stride;
}
else
{
assert(a.divisor == 1);
instance_stride = a.stride;
instanced = true;
}
}
info_.max_attribute_index_ = max_index;
info_.stride_ = stride;
info_.instance_stride_ = instance_stride;
info_.instanced_ = instanced;
if (!vertex_buffer_) vertex_buffer_ = buffer{};
vertex_buffer_.bind();
for (auto const & a : attribs.attribs)
{
if (a.divisor != 0) continue;
gl::EnableVertexAttribArray(a.index);
gl::VertexAttribPointer(a.index, a.size, a.type, a.normalized, a.stride, a.pointer);
}
if (instanced)
{
if (!instance_buffer_) instance_buffer_ = buffer{};
instance_buffer_.bind();
for (auto const & a : attribs.attribs)
{
if (a.divisor == 0) continue;
gl::EnableVertexAttribArray(a.index);
gl::VertexAttribPointer(a.index, a.size, a.type, a.normalized, a.stride, a.pointer);
gl::VertexAttribDivisor(a.index, a.divisor);
}
}
}
void mesh::draw() const
{
draw(0, is_indexed() ? index_count() : vertex_count(), instance_count());
}
void mesh::draw(std::size_t first, std::size_t count, std::size_t instance_count) const
{
if (is_indexed())
{
assert(first + count <= index_count());
if (is_instanced())
{
assert(instance_count <= this->instance_count());
if (count != 0 && instance_count != 0)
{
bind();
gl::DrawElementsInstanced(primitive_type(), count, index_type(), reinterpret_cast<char const *>(detail::index_size(index_type()) * first), instance_count);
}
}
else
{
if (count != 0)
{
bind();
gl::DrawElements(primitive_type(), count, index_type(), reinterpret_cast<char const *>(detail::index_size(index_type()) * first));
}
}
}
else
{
assert(first + count <= vertex_count());
if (is_instanced())
{
assert(instance_count <= this->instance_count());
if (count != 0 && instance_count != 0)
{
bind();
gl::DrawArraysInstanced(primitive_type(), first, count, instance_count);
}
}
else
{
if (count != 0)
{
bind();
gl::DrawArrays(primitive_type(), first, count);
}
}
}
}
}