mirror of
https://github.com/minetest/minetest.git
synced 2025-01-09 23:07:31 +01:00
170 lines
4.4 KiB
C++
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
|
|
|