minetest/irr/src/CGLTFMeshFileLoader.h
2024-12-12 15:33:08 +01:00

170 lines
4.4 KiB
C++

// Minetest
// SPDX-License-Identifier: LGPL-2.1-or-later
#pragma once
#include "SkinnedMesh.h"
#include "IMeshLoader.h"
#include "IReadFile.h"
#include "irrTypes.h"
#include "path.h"
#include "S3DVertex.h"
#include "tiniergltf.hpp"
#include <functional>
#include <cstddef>
#include <tuple>
#include <vector>
namespace irr
{
namespace scene
{
class CGLTFMeshFileLoader : public IMeshLoader
{
public:
CGLTFMeshFileLoader() noexcept {};
bool isALoadableFileExtension(const io::path &filename) const override;
IAnimatedMesh *createMesh(io::IReadFile *file) override;
private:
template <typename T>
static T rawget(const char *ptr);
template <class T>
class Accessor
{
struct BufferSource
{
const char *ptr;
std::size_t byteStride;
};
using Source = std::variant<BufferSource, std::vector<T>, std::tuple<>>;
public:
static Accessor sparseIndices(
const tiniergltf::GlTF &model,
const tiniergltf::AccessorSparseIndices &indices,
const std::size_t count);
static Accessor sparseValues(
const tiniergltf::GlTF &model,
const tiniergltf::AccessorSparseValues &values,
const std::size_t count,
const std::size_t defaultByteStride);
static Accessor base(
const tiniergltf::GlTF &model,
std::size_t accessorIdx);
static Accessor make(const tiniergltf::GlTF &model, std::size_t accessorIdx);
static constexpr tiniergltf::Accessor::Type getType();
static constexpr tiniergltf::Accessor::ComponentType getComponentType();
std::size_t getCount() const { return count; }
T get(std::size_t i) const;
private:
Accessor(const char *ptr, std::size_t byteStride, std::size_t count) :
source(BufferSource{ptr, byteStride}), count(count) {}
Accessor(std::vector<T> vec, std::size_t count) :
source(vec), count(count) {}
Accessor(std::size_t count) :
source(std::make_tuple()), count(count) {}
// Directly from buffer, sparse, or default-initialized
const Source source;
const std::size_t count;
};
template <typename... Ts>
using AccessorVariant = std::variant<Accessor<Ts>...>;
template <std::size_t N, typename... Ts>
using ArrayAccessorVariant = std::variant<Accessor<std::array<Ts, N>>...>;
template <std::size_t N>
using NormalizedValuesAccessor = ArrayAccessorVariant<N, u8, u16, f32>;
template <std::size_t N>
static NormalizedValuesAccessor<N> createNormalizedValuesAccessor(
const tiniergltf::GlTF &model,
const std::size_t accessorIdx);
template <std::size_t N, bool validate = true>
static std::array<f32, N> getNormalizedValues(
const NormalizedValuesAccessor<N> &accessor,
const std::size_t i);
class MeshExtractor
{
public:
MeshExtractor(tiniergltf::GlTF &&model,
SkinnedMeshBuilder *mesh) noexcept
: m_gltf_model(std::move(model)), m_irr_model(mesh) {};
/* Gets indices for the given mesh/primitive.
*
* Values are return in Irrlicht winding order.
*/
std::optional<std::vector<u16>> getIndices(
const tiniergltf::MeshPrimitive &primitive) const;
std::optional<std::vector<video::S3DVertex>> getVertices(
const tiniergltf::MeshPrimitive &primitive) const;
std::size_t getMeshCount() const;
std::size_t getPrimitiveCount(const std::size_t meshIdx) const;
void load();
const std::unordered_set<std::string> &getWarnings() {
return warnings;
}
private:
const tiniergltf::GlTF m_gltf_model;
SkinnedMeshBuilder *m_irr_model;
std::vector<std::function<void()>> m_mesh_loaders;
std::vector<SkinnedMesh::SJoint *> m_loaded_nodes;
std::unordered_set<std::string> warnings;
void warn(const std::string &warning) {
warnings.insert(warning);
}
void copyPositions(const std::size_t accessorIdx,
std::vector<video::S3DVertex>& vertices) const;
void copyNormals(const std::size_t accessorIdx,
std::vector<video::S3DVertex>& vertices) const;
void copyTCoords(const std::size_t accessorIdx,
std::vector<video::S3DVertex>& vertices) const;
void addPrimitive(const tiniergltf::MeshPrimitive &primitive,
const std::optional<std::size_t> skinIdx,
SkinnedMesh::SJoint *parent);
void deferAddMesh(const std::size_t meshIdx,
const std::optional<std::size_t> skinIdx,
SkinnedMesh::SJoint *parentJoint);
void loadNode(const std::size_t nodeIdx, SkinnedMesh::SJoint *parentJoint);
void loadNodes();
void loadSkins();
void loadAnimation(const std::size_t animIdx);
};
tiniergltf::GlTF parseGLTF(io::IReadFile *file);
};
} // namespace scene
} // namespace irr