200 lines
4.8 KiB
C++
200 lines
4.8 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;
|
|
|
|
for (auto const & a : attribs.attribs)
|
|
{
|
|
max_index = std::max<std::size_t>(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::load_raw(void const * vertices, std::size_t vertex_size, std::size_t count, GLenum primitive_type, GLenum usage)
|
|
{
|
|
assert(info_.stride_ == vertex_size);
|
|
|
|
if (auto n = detail::get_primitive_type_vertex_count(primitive_type); n)
|
|
assert((count % (*n)) == 0);
|
|
|
|
assert(vertex_buffer_);
|
|
|
|
vertex_buffer_.load(vertices, vertex_size * count, usage);
|
|
info_.vertex_count_ = count;
|
|
info_.index_count_ = 0;
|
|
info_.indexed_ = false;
|
|
info_.primitive_type_ = primitive_type;
|
|
}
|
|
|
|
static std::size_t index_size(GLenum type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case gl::UNSIGNED_BYTE: return 1;
|
|
case gl::UNSIGNED_SHORT: return 2;
|
|
case gl::UNSIGNED_INT: return 4;
|
|
default: throw std::runtime_error("Unknown undex type");
|
|
}
|
|
}
|
|
|
|
void mesh::load_raw(void const * vertices, std::size_t vertex_size, std::size_t vertex_count,
|
|
void const * indices, GLenum index_type, std::size_t index_count,
|
|
GLenum primitive_type, GLenum usage)
|
|
{
|
|
assert(info_.stride_ == vertex_size);
|
|
|
|
if (auto n = detail::get_primitive_type_vertex_count(primitive_type); n)
|
|
assert((index_count % (*n)) == 0);
|
|
|
|
assert(vertex_buffer_);
|
|
|
|
if (!index_buffer_)
|
|
{
|
|
index_buffer_ = buffer{};
|
|
array_.bind();
|
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, index_buffer_.id());
|
|
}
|
|
vertex_buffer_.load(vertices, vertex_size * vertex_count, usage);
|
|
index_buffer_.load(indices, index_size(index_type) * index_count, usage);
|
|
info_.vertex_count_ = vertex_count;
|
|
info_.index_count_ = index_count;
|
|
info_.indexed_ = true;
|
|
info_.primitive_type_ = primitive_type;
|
|
info_.index_type_ = index_type;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|