mirror of
https://github.com/luanti-org/luanti.git
synced 2025-06-27 16:36:03 +00:00
Improve glTF logging (#15274)
Also removes all animations but the first one from gltf_frog.gltf to address the corresponding warning. Catches some more possible exceptions (out of bounds, optional access) which might be caused by a broken model to properly log them.
This commit is contained in:
parent
6d7a519740
commit
c7938ce81c
4 changed files with 68 additions and 54 deletions
File diff suppressed because one or more lines are too long
|
@ -9,6 +9,7 @@
|
||||||
#include "IAnimatedMesh.h"
|
#include "IAnimatedMesh.h"
|
||||||
#include "IReadFile.h"
|
#include "IReadFile.h"
|
||||||
#include "irrTypes.h"
|
#include "irrTypes.h"
|
||||||
|
#include "irr_ptr.h"
|
||||||
#include "matrix4.h"
|
#include "matrix4.h"
|
||||||
#include "path.h"
|
#include "path.h"
|
||||||
#include "quaternion.h"
|
#include "quaternion.h"
|
||||||
|
@ -27,7 +28,6 @@
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
namespace irr {
|
namespace irr {
|
||||||
|
|
||||||
|
@ -341,40 +341,24 @@ bool SelfType::isALoadableFileExtension(
|
||||||
*/
|
*/
|
||||||
IAnimatedMesh* SelfType::createMesh(io::IReadFile* file)
|
IAnimatedMesh* SelfType::createMesh(io::IReadFile* file)
|
||||||
{
|
{
|
||||||
if (file->getSize() <= 0) {
|
const char *filename = file->getFileName().c_str();
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
std::optional<tiniergltf::GlTF> model = tryParseGLTF(file);
|
|
||||||
if (!model.has_value()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
if (model->extensionsRequired) {
|
|
||||||
os::Printer::log("glTF loader",
|
|
||||||
"model requires extensions, but we support none", ELL_ERROR);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(model->buffers.has_value()
|
|
||||||
&& model->bufferViews.has_value()
|
|
||||||
&& model->accessors.has_value()
|
|
||||||
&& model->meshes.has_value()
|
|
||||||
&& model->nodes.has_value())) {
|
|
||||||
os::Printer::log("glTF loader", "missing required fields", ELL_ERROR);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto *mesh = new CSkinnedMesh();
|
|
||||||
MeshExtractor parser(std::move(model.value()), mesh);
|
|
||||||
try {
|
try {
|
||||||
parser.load();
|
tiniergltf::GlTF model = parseGLTF(file);
|
||||||
} catch (std::runtime_error &e) {
|
irr_ptr<CSkinnedMesh> mesh(new CSkinnedMesh());
|
||||||
os::Printer::log("glTF loader", e.what(), ELL_ERROR);
|
MeshExtractor extractor(std::move(model), mesh.get());
|
||||||
mesh->drop();
|
try {
|
||||||
return nullptr;
|
extractor.load();
|
||||||
|
for (const auto &warning : extractor.getWarnings()) {
|
||||||
|
os::Printer::log(filename, warning.c_str(), ELL_WARNING);
|
||||||
}
|
}
|
||||||
if (model->images.has_value())
|
return mesh.release();
|
||||||
os::Printer::log("glTF loader", "embedded images are not supported", ELL_WARNING);
|
} catch (const std::runtime_error &e) {
|
||||||
return mesh;
|
os::Printer::log("error converting gltf to irrlicht mesh", e.what(), ELL_ERROR);
|
||||||
|
}
|
||||||
|
} catch (const std::runtime_error &e) {
|
||||||
|
os::Printer::log("error parsing gltf", e.what(), ELL_ERROR);
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void transformVertices(std::vector<video::S3DVertex> &vertices, const core::matrix4 &transform)
|
static void transformVertices(std::vector<video::S3DVertex> &vertices, const core::matrix4 &transform)
|
||||||
|
@ -730,6 +714,21 @@ void SelfType::MeshExtractor::loadAnimation(const std::size_t animIdx)
|
||||||
|
|
||||||
void SelfType::MeshExtractor::load()
|
void SelfType::MeshExtractor::load()
|
||||||
{
|
{
|
||||||
|
if (m_gltf_model.extensionsRequired)
|
||||||
|
throw std::runtime_error("model requires extensions, but we support none");
|
||||||
|
|
||||||
|
if (!(m_gltf_model.buffers.has_value()
|
||||||
|
&& m_gltf_model.bufferViews.has_value()
|
||||||
|
&& m_gltf_model.accessors.has_value()
|
||||||
|
&& m_gltf_model.meshes.has_value()
|
||||||
|
&& m_gltf_model.nodes.has_value())) {
|
||||||
|
throw std::runtime_error("missing required fields");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_gltf_model.images.has_value())
|
||||||
|
warn("embedded images are not supported");
|
||||||
|
|
||||||
|
try {
|
||||||
loadNodes();
|
loadNodes();
|
||||||
for (const auto &load_mesh : m_mesh_loaders) {
|
for (const auto &load_mesh : m_mesh_loaders) {
|
||||||
load_mesh();
|
load_mesh();
|
||||||
|
@ -737,13 +736,18 @@ void SelfType::MeshExtractor::load()
|
||||||
loadSkins();
|
loadSkins();
|
||||||
// Load the first animation, if there is one.
|
// Load the first animation, if there is one.
|
||||||
if (m_gltf_model.animations.has_value()) {
|
if (m_gltf_model.animations.has_value()) {
|
||||||
if (m_gltf_model.animations->size() > 1) {
|
if (m_gltf_model.animations->size() > 1)
|
||||||
os::Printer::log("glTF loader",
|
warn("multiple animations are not supported");
|
||||||
"multiple animations are not supported", ELL_WARNING);
|
|
||||||
}
|
|
||||||
loadAnimation(0);
|
loadAnimation(0);
|
||||||
m_irr_model->setAnimationSpeed(1);
|
m_irr_model->setAnimationSpeed(1);
|
||||||
}
|
}
|
||||||
|
} catch (const std::out_of_range &e) {
|
||||||
|
throw std::runtime_error(e.what());
|
||||||
|
} catch (const std::bad_optional_access &e) {
|
||||||
|
throw std::runtime_error(e.what());
|
||||||
|
}
|
||||||
|
|
||||||
m_irr_model->finalize();
|
m_irr_model->finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -905,15 +909,18 @@ void SelfType::MeshExtractor::copyTCoords(
|
||||||
/**
|
/**
|
||||||
* This is where the actual model's GLTF file is loaded and parsed by tiniergltf.
|
* This is where the actual model's GLTF file is loaded and parsed by tiniergltf.
|
||||||
*/
|
*/
|
||||||
std::optional<tiniergltf::GlTF> SelfType::tryParseGLTF(io::IReadFile* file)
|
tiniergltf::GlTF SelfType::parseGLTF(io::IReadFile* file)
|
||||||
{
|
{
|
||||||
const bool isGlb = core::hasFileExtension(file->getFileName(), "glb");
|
const bool isGlb = core::hasFileExtension(file->getFileName(), "glb");
|
||||||
auto size = file->getSize();
|
auto size = file->getSize();
|
||||||
if (size < 0) // this can happen if `ftell` fails
|
if (size < 0) // this can happen if `ftell` fails
|
||||||
return std::nullopt;
|
throw std::runtime_error("error reading file");
|
||||||
|
if (size == 0)
|
||||||
|
throw std::runtime_error("file is empty");
|
||||||
|
|
||||||
std::unique_ptr<char[]> buf(new char[size + 1]);
|
std::unique_ptr<char[]> buf(new char[size + 1]);
|
||||||
if (file->read(buf.get(), size) != static_cast<std::size_t>(size))
|
if (file->read(buf.get(), size) != static_cast<std::size_t>(size))
|
||||||
return std::nullopt;
|
throw std::runtime_error("file ended prematurely");
|
||||||
// We probably don't need this, but add it just to be sure.
|
// We probably don't need this, but add it just to be sure.
|
||||||
buf[size] = '\0';
|
buf[size] = '\0';
|
||||||
try {
|
try {
|
||||||
|
@ -921,12 +928,10 @@ std::optional<tiniergltf::GlTF> SelfType::tryParseGLTF(io::IReadFile* file)
|
||||||
return tiniergltf::readGlb(buf.get(), size);
|
return tiniergltf::readGlb(buf.get(), size);
|
||||||
else
|
else
|
||||||
return tiniergltf::readGlTF(buf.get(), size);
|
return tiniergltf::readGlTF(buf.get(), size);
|
||||||
} catch (const std::runtime_error &e) {
|
|
||||||
os::Printer::log("glTF loader", e.what(), ELL_ERROR);
|
|
||||||
return std::nullopt;
|
|
||||||
} catch (const std::out_of_range &e) {
|
} catch (const std::out_of_range &e) {
|
||||||
os::Printer::log("glTF loader", e.what(), ELL_ERROR);
|
throw std::runtime_error(e.what());
|
||||||
return std::nullopt;
|
} catch (const std::bad_optional_access &e) {
|
||||||
|
throw std::runtime_error(e.what());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -118,6 +118,9 @@ private:
|
||||||
std::size_t getPrimitiveCount(const std::size_t meshIdx) const;
|
std::size_t getPrimitiveCount(const std::size_t meshIdx) const;
|
||||||
|
|
||||||
void load();
|
void load();
|
||||||
|
const std::vector<std::string> &getWarnings() {
|
||||||
|
return warnings;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const tiniergltf::GlTF m_gltf_model;
|
const tiniergltf::GlTF m_gltf_model;
|
||||||
|
@ -126,6 +129,11 @@ private:
|
||||||
std::vector<std::function<void()>> m_mesh_loaders;
|
std::vector<std::function<void()>> m_mesh_loaders;
|
||||||
std::vector<CSkinnedMesh::SJoint *> m_loaded_nodes;
|
std::vector<CSkinnedMesh::SJoint *> m_loaded_nodes;
|
||||||
|
|
||||||
|
std::vector<std::string> warnings;
|
||||||
|
void warn(const std::string &warning) {
|
||||||
|
warnings.push_back(warning);
|
||||||
|
}
|
||||||
|
|
||||||
void copyPositions(const std::size_t accessorIdx,
|
void copyPositions(const std::size_t accessorIdx,
|
||||||
std::vector<video::S3DVertex>& vertices) const;
|
std::vector<video::S3DVertex>& vertices) const;
|
||||||
|
|
||||||
|
@ -152,7 +160,7 @@ private:
|
||||||
void loadAnimation(const std::size_t animIdx);
|
void loadAnimation(const std::size_t animIdx);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<tiniergltf::GlTF> tryParseGLTF(io::IReadFile *file);
|
tiniergltf::GlTF parseGLTF(io::IReadFile *file);
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace scene
|
} // namespace scene
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
// Minetest
|
// Minetest
|
||||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
|
#include "EDriverTypes.h"
|
||||||
#include "content/subgames.h"
|
#include "content/subgames.h"
|
||||||
#include "filesys.h"
|
#include "filesys.h"
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue