Refactor gltf_mesh
This commit is contained in:
parent
514f4006ef
commit
437714288b
2 changed files with 118 additions and 63 deletions
|
|
@ -1,40 +1,30 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <psemek/gfx/buffer.hpp>
|
|
||||||
#include <psemek/gfx/array.hpp>
|
|
||||||
#include <psemek/gfx/gltf_parser.hpp>
|
#include <psemek/gfx/gltf_parser.hpp>
|
||||||
|
#include <psemek/gfx/drawable.hpp>
|
||||||
|
#include <psemek/gfx/texture.hpp>
|
||||||
#include <psemek/util/span.hpp>
|
#include <psemek/util/span.hpp>
|
||||||
|
|
||||||
#include <optional>
|
#include <functional>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace psemek::gfx
|
namespace psemek::gfx
|
||||||
{
|
{
|
||||||
|
|
||||||
struct gltf_mesh
|
struct gltf_mesh
|
||||||
{
|
{
|
||||||
struct mesh
|
struct primitive
|
||||||
{
|
{
|
||||||
struct primitive
|
gfx::drawable * drawable;
|
||||||
{
|
std::optional<std::size_t> material;
|
||||||
gfx::array vao;
|
|
||||||
std::optional<std::size_t> material;
|
|
||||||
std::size_t index_count;
|
|
||||||
std::size_t index_offset;
|
|
||||||
GLenum index_type;
|
|
||||||
|
|
||||||
void draw() const;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<primitive> primitives;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<gfx::buffer> buffers;
|
virtual gltf_asset::material const & material(std::size_t index) const = 0;
|
||||||
|
virtual gfx::texture_2d const & texture(std::size_t index) const = 0;
|
||||||
|
virtual util::span<primitive const> mesh(std::string_view name) const = 0;
|
||||||
|
|
||||||
std::unordered_map<std::string, mesh> meshes;
|
virtual ~gltf_mesh() {}
|
||||||
|
|
||||||
gltf_mesh() = default;
|
|
||||||
gltf_mesh(gltf_asset const & asset, std::vector<util::span<char const>> const & buffers);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<gltf_mesh> make_gltf_mesh(gltf_asset const & asset, std::function<std::vector<char>(std::string const &)> uri_loader);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,132 @@
|
||||||
#include <psemek/gfx/gltf_mesh.hpp>
|
#include <psemek/gfx/gltf_mesh.hpp>
|
||||||
|
#include <psemek/gfx/array.hpp>
|
||||||
|
#include <psemek/gfx/buffer.hpp>
|
||||||
|
#include <psemek/util/hstring.hpp>
|
||||||
|
#include <psemek/io/memory_stream.hpp>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
namespace psemek::gfx
|
namespace psemek::gfx
|
||||||
{
|
{
|
||||||
|
|
||||||
void gltf_mesh::mesh::primitive::draw() const
|
namespace
|
||||||
{
|
{
|
||||||
vao.bind();
|
|
||||||
gl::DrawElements(gl::TRIANGLES, index_count, index_type, reinterpret_cast<void const *>(index_offset));
|
|
||||||
}
|
|
||||||
|
|
||||||
gltf_mesh::gltf_mesh(gltf_asset const & asset, std::vector<util::span<char const>> const & buffers)
|
struct drawable_impl
|
||||||
{
|
: drawable
|
||||||
if (buffers.size() != asset.buffers.size())
|
|
||||||
throw std::runtime_error("wrong number of glTF buffers");
|
|
||||||
|
|
||||||
for (auto buffer : buffers)
|
|
||||||
this->buffers.emplace_back().load(buffer.data(), buffer.size(), gl::STATIC_DRAW);
|
|
||||||
|
|
||||||
for (auto const & node : asset.nodes)
|
|
||||||
{
|
{
|
||||||
auto & target_mesh = meshes[node.name];
|
gfx::array vao;
|
||||||
|
std::size_t index_count;
|
||||||
|
std::size_t index_offset;
|
||||||
|
GLenum index_type;
|
||||||
|
|
||||||
auto const & mesh = asset.meshes[node.mesh];
|
void draw() const override
|
||||||
|
|
||||||
for (auto const & primitive : mesh.primitives)
|
|
||||||
{
|
{
|
||||||
auto & target_primitive = target_mesh.primitives.emplace_back();
|
vao.bind();
|
||||||
target_primitive.material = primitive.material;
|
gl::DrawElements(gl::TRIANGLES, index_count, index_type, reinterpret_cast<void const *>(index_offset));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
target_primitive.vao.bind();
|
struct gltf_mesh_impl
|
||||||
|
: gltf_mesh
|
||||||
|
{
|
||||||
|
gltf_mesh_impl(gltf_asset const & asset, std::function<std::vector<char>(std::string const &)> uri_loader);
|
||||||
|
|
||||||
|
gltf_asset::material const & material(std::size_t index) const override
|
||||||
|
{
|
||||||
|
return materials_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx::texture_2d const & texture(std::size_t index) const override
|
||||||
|
{
|
||||||
|
return textures_[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
util::span<primitive const> mesh(std::string_view name) const override
|
||||||
|
{
|
||||||
|
return meshes_.at(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<gltf_asset::material> materials_;
|
||||||
|
std::vector<gfx::texture_2d> textures_;
|
||||||
|
std::vector<gfx::buffer> buffers_;
|
||||||
|
std::vector<std::unique_ptr<drawable_impl>> drawables_;
|
||||||
|
std::unordered_map<util::hstring, std::vector<primitive>> meshes_;
|
||||||
|
};
|
||||||
|
|
||||||
|
gltf_mesh_impl::gltf_mesh_impl(gltf_asset const & asset, std::function<std::vector<char>(std::string const &)> uri_loader)
|
||||||
|
{
|
||||||
|
materials_ = asset.materials;
|
||||||
|
|
||||||
|
for (auto const & buffer : asset.buffers)
|
||||||
|
{
|
||||||
|
auto data = uri_loader(buffer.uri);
|
||||||
|
buffers_.emplace_back().load(data.data(), data.size(), gl::STATIC_DRAW);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const & texture : asset.textures)
|
||||||
|
{
|
||||||
|
auto data = uri_loader(texture.uri);
|
||||||
|
auto & target = textures_.emplace_back();
|
||||||
|
target.load(gfx::read_png(io::memory_istream(data.data(), data.data() + data.size())));
|
||||||
|
target.linear_mipmap_filter();
|
||||||
|
target.anisotropy();
|
||||||
|
target.generate_mipmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const & node : asset.nodes)
|
||||||
|
{
|
||||||
|
auto & target_mesh = meshes_[node.name];
|
||||||
|
|
||||||
|
auto const & mesh = asset.meshes[node.mesh];
|
||||||
|
|
||||||
|
for (auto const & primitive : mesh.primitives)
|
||||||
{
|
{
|
||||||
auto const & indices_accessor = asset.accessors[primitive.indices];
|
drawables_.push_back(std::make_unique<drawable_impl>());
|
||||||
auto const & indices_view = asset.buffer_views[indices_accessor.buffer_view];
|
auto & drawable = *drawables_.back();
|
||||||
|
|
||||||
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, this->buffers[indices_view.buffer].id());
|
drawable.vao.bind();
|
||||||
target_primitive.index_offset = indices_view.offset;
|
|
||||||
target_primitive.index_type = indices_accessor.component_type;
|
|
||||||
target_primitive.index_count = indices_accessor.count;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<GLuint, std::optional<std::size_t>> attributes[3] =
|
{
|
||||||
{
|
auto const & indices_accessor = asset.accessors[primitive.indices];
|
||||||
{0, primitive.position},
|
auto const & indices_view = asset.buffer_views[indices_accessor.buffer_view];
|
||||||
{1, primitive.normal},
|
|
||||||
{2, primitive.texcoord},
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto const & attribute : attributes)
|
gl::BindBuffer(gl::ELEMENT_ARRAY_BUFFER, buffers_[indices_view.buffer].id());
|
||||||
{
|
drawable.index_offset = indices_view.offset;
|
||||||
if (!attribute.second) continue;
|
drawable.index_type = indices_accessor.component_type;
|
||||||
|
drawable.index_count = indices_accessor.count;
|
||||||
|
}
|
||||||
|
|
||||||
auto const & accessor = asset.accessors[*attribute.second];
|
std::pair<GLuint, std::optional<std::size_t>> attributes[3] =
|
||||||
auto const & view = asset.buffer_views[accessor.buffer_view];
|
{
|
||||||
|
{0, primitive.position},
|
||||||
|
{1, primitive.normal},
|
||||||
|
{2, primitive.texcoord},
|
||||||
|
};
|
||||||
|
|
||||||
gl::BindBuffer(gl::ARRAY_BUFFER, this->buffers[view.buffer].id());
|
for (auto const & attribute : attributes)
|
||||||
gl::EnableVertexAttribArray(attribute.first);
|
{
|
||||||
gl::VertexAttribPointer(attribute.first, accessor.type, accessor.component_type, accessor.normalized, 0, reinterpret_cast<void const *>(view.offset));
|
if (!attribute.second) continue;
|
||||||
|
|
||||||
|
auto const & accessor = asset.accessors[*attribute.second];
|
||||||
|
auto const & view = asset.buffer_views[accessor.buffer_view];
|
||||||
|
|
||||||
|
gl::BindBuffer(gl::ARRAY_BUFFER, buffers_[view.buffer].id());
|
||||||
|
gl::EnableVertexAttribArray(attribute.first);
|
||||||
|
gl::VertexAttribPointer(attribute.first, accessor.type, accessor.component_type, accessor.normalized, 0, reinterpret_cast<void const *>(view.offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
target_mesh.push_back({&drawable, primitive.material});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<gltf_mesh> make_gltf_mesh(gltf_asset const & asset, std::function<std::vector<char>(std::string const &)> uri_loader)
|
||||||
|
{
|
||||||
|
return std::make_unique<gltf_mesh_impl>(asset, std::move(uri_loader));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue