#include #include 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; for (auto const & a : attribs.attribs) { max_index = std::max(max_index, a.index); if (a.divisor != 0) { assert(a.divisor == 1); instanced = true; } } info_.max_attribute_index_ = max_index; info_.stride_ = attribs.vertex_size; info_.instance_stride_ = attribs.instance_size; 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, attribs.vertex_size, 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, attribs.instance_size, 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(detail::index_size(index_type()) * first), instance_count); } } else { if (count != 0) { bind(); gl::DrawElements(primitive_type(), count, index_type(), reinterpret_cast(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); } } } } }