Program Listing for File GLTFLoader.cpp¶
↰ Return to documentation for file (Source\AssetManager\Src\GLTFLoader.cpp
)
#include "AssetManager/GLTFLoader.h"
#include <cassert>
#include <sstream>
#include <boost/filesystem.hpp>
#include <GLTFSDK/IStreamReader.h>
#include <GLTFSDK/GLTFResourceReader.h>
#include <GLTFSDK/Deserialize.h>
#include "Log/Log.h"
#include "Utils/Macros.h"
#include "Memory/Allocator.h"
using namespace Microsoft::glTF; // NOLINT
namespace filesystem = boost::filesystem; // NOLINT
namespace Azura {
namespace {
// The glTF SDK is decoupled from all file I/O by the IStreamReader (and IStreamWriter)
// interface(s) and the C++ stream-based I/O library. This allows the glTF SDK to be used in
// sandboxed environments, such as WebAssembly modules and UWP apps, where any file I/O code
// must be platform or use-case specific.
class StreamReader : public IStreamReader {
public:
explicit StreamReader(filesystem::path pathBase)
: m_pathBase(std::move(pathBase)) {
assert(m_pathBase.has_root_path());
}
// Resolves the relative URIs of any external resources declared in the glTF manifest
std::shared_ptr<std::istream> GetInputStream(const std::string& filename) const override {
// In order to construct a valid stream:
// 1. The filename argument will be encoded as UTF-8 so use filesystem::u8path to
// correctly construct a path instance.
// 2. Generate an absolute path by concatenating m_pathBase with the specified filename
// path. The filesystem::operator/ uses the platform's preferred directory separator
// if appropriate.
// 3. Always open the file stream in binary mode. The glTF SDK will handle any text
// encoding issues for us.
auto streamPath = m_pathBase / filename;
auto stream = std::make_shared<std::ifstream>(streamPath.c_str(), std::ios_base::binary);
// Check if the stream has no errors and is ready for I/O operations
if (!stream || !(*stream)) {
throw std::runtime_error("Unable to create a valid input stream for uri: " + filename);
}
return stream;
}
private:
filesystem::path m_pathBase;
};
} // namespace
GLTFMeshInterface::GLTFMeshInterface(const String& manifest,
std::unique_ptr<const Microsoft::glTF::GLTFResourceReader> resourceReader)
: m_resourceReader(std::move(resourceReader)),
m_document(Deserialize(manifest)) {
}
std::vector<float> GLTFMeshInterface::GetPositionBuffer(U32 meshId,
U32 meshPrimitive,
U32& bufferSize,
U32& count) const {
const auto& primitive = GetMeshPrimitive(GetMesh(meshId), meshPrimitive);
const Accessor& accessor = m_document.accessors.Get(primitive.GetAttributeAccessorId("POSITION"));
const auto data = m_resourceReader->ReadBinaryData<float>(m_document, accessor);
count = U32(accessor.count);
bufferSize = U32(data.size() * sizeof(float));
return data;
}
std::vector<float> GLTFMeshInterface::
GetNormalBuffer(U32 meshId, U32 meshPrimitive, U32& bufferSize, U32& count) const {
const auto& primitive = GetMeshPrimitive(GetMesh(meshId), meshPrimitive);
const Accessor& accessor = m_document.accessors.Get(primitive.GetAttributeAccessorId("NORMAL"));
const auto data = m_resourceReader->ReadBinaryData<float>(m_document, accessor);
count = U32(accessor.count);
bufferSize = U32(data.size() * sizeof(float));
return data;
}
std::vector<float> GLTFMeshInterface::GetUVBuffer(U32 meshId, U32 meshPrimitive, U32& bufferSize, U32& count) const {
const auto& primitive = GetMeshPrimitive(GetMesh(meshId), meshPrimitive);
const Accessor& accessor = m_document.accessors.Get(primitive.GetAttributeAccessorId("TEXCOORD_0"));
const auto data = m_resourceReader->ReadBinaryData<float>(m_document, accessor);
count = U32(accessor.count);
bufferSize = U32(data.size() * sizeof(float));
return data;
}
std::vector<U32> GLTFMeshInterface::GetIndexBuffer(U32 meshId, U32 meshPrimitive, U32& bufferSize, U32& count) const {
const auto& primitive = GetMeshPrimitive(GetMesh(meshId), meshPrimitive);
const Accessor& accessor = m_document.accessors.Get(primitive.indicesAccessorId);
const std::vector<U32> data = [&]()
{
if (accessor.componentType == COMPONENT_UNSIGNED_SHORT) {
const auto u16Data = m_resourceReader->ReadBinaryData<U16>(m_document, accessor);
std::vector<U32> u32Data;
u32Data.reserve(u16Data.size());
for (const auto value : u16Data)
{
u32Data.push_back(U32(value));
}
return u32Data;
}
return m_resourceReader->ReadBinaryData<U32>(m_document, accessor);
}();
count = U32(accessor.count);
bufferSize = U32(data.size() * sizeof(U32));
return data;
}
const Microsoft::glTF::Mesh& GLTFMeshInterface::GetMesh(U32 idx) const {
return m_document.meshes[idx];
}
const Microsoft::glTF::MeshPrimitive& GLTFMeshInterface::GetMeshPrimitive(const Microsoft::glTF::Mesh& mesh, U32 idx) {
return mesh.primitives[idx];
}
GLTFMeshInterface GLTFLoader::LoadFromJSON(const String& assetName, AssetLocation location, const Log& log) {
UNUSED(location);
UNUSED(log); // Release Mode
filesystem::path filePath = filesystem::current_path() / filesystem::
path("Meshes/" + assetName + "/" + assetName + ".gltf");
LOG_DBG(log, LOG_LEVEL, "Loading Mesh: %s", filePath.c_str());
auto streamReader = std::make_unique<StreamReader>(filePath.parent_path());
const auto gltfStream = streamReader->GetInputStream(assetName + ".gltf");
auto resourceReader = std::make_unique<GLTFResourceReader>(std::move(streamReader));
std::stringstream manifestStream;
// Read the contents of the glTF file into a string using a std::stringstream
manifestStream << gltfStream->rdbuf();
const std::string manifest = manifestStream.str();
return GLTFMeshInterface(manifest, std::move(resourceReader));
}
} // namespace Azura