From 417481d17f3864c8b7b47e000a857d1f4279946b Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 00:44:51 +0200 Subject: [PATCH 01/18] Rewrote gltf2 node extras import and added node extras export. No support for AI_AIVECTOR3D metadata type. No support for json arrays of metadata, just json objects. --- code/AssetLib/glTF2/glTF2Asset.h | 47 ++++++++++++++++++- code/AssetLib/glTF2/glTF2Asset.inl | 46 ++++++++++++++++++- code/AssetLib/glTF2/glTF2AssetWriter.inl | 41 ++++++++++++++++- code/AssetLib/glTF2/glTF2Exporter.cpp | 57 +++++++++++++++++++++++- code/AssetLib/glTF2/glTF2Importer.cpp | 34 +++++++++++--- code/Common/SceneCombiner.cpp | 3 ++ 6 files changed, 218 insertions(+), 10 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index c597fc951..bdc62dbc2 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -376,6 +376,51 @@ struct CustomExtension { } }; +struct ExtrasValue; + +//! Represents a union of metadata values +struct ExtrasValue { + std::string name; + + Nullable mBoolValue; + Nullable mInt32Value; + Nullable mUint64Value; + Nullable mFloatValue; + Nullable mDoubleValue; + Nullable mStringValue; + Nullable> mMetadataValue; + + ExtrasValue() = default; + ~ExtrasValue() = default; + + ExtrasValue(const ExtrasValue& other) : + name(other.name), + mStringValue(other.mStringValue), + mDoubleValue(other.mDoubleValue), + mUint64Value(other.mUint64Value), + mInt32Value(other.mInt32Value), + mBoolValue(other.mBoolValue), + mMetadataValue(other.mMetadataValue) { + } +}; + +//! Represents metadata in an glTF object +struct Extras { + std::vector mValues; + + inline bool HasExtras() const { + return mValues.size() != 0; + } + + Extras() = default; + ~Extras() = default; + + Extras(const Extras &other) : + mValues(other.mValues) { + // empty + } +}; + //! Base class for all glTF top-level objects struct Object { int index; //!< The index of this object within its property container @@ -384,7 +429,7 @@ struct Object { std::string name; //!< The user-defined name of this object CustomExtension customExtensions; - CustomExtension extras; + Extras extras; //! Objects marked as special are not exported (used to emulate the binary body buffer) virtual bool IsSpecial() const { return false; } diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index db47915d6..5dc51e7fa 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -139,6 +139,50 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) { return ret; } +inline ExtrasValue ReadExtrasValue(const char *name, Value &obj) { + ExtrasValue ret; + ret.name = name; + + if (obj.IsObject()) { + ret.mMetadataValue.value.reserve(obj.MemberCount()); + ret.mMetadataValue.isPresent = true; + for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { + auto &val = it->value; + ret.mMetadataValue.value.push_back(ReadExtrasValue(it->name.GetString(), val)); + } + } else if (obj.IsNumber()) { + if (obj.IsUint64()) { + ret.mUint64Value.value = obj.GetUint64(); + ret.mUint64Value.isPresent = true; + } else if (obj.IsInt()) { + ret.mInt32Value.value = obj.GetInt64(); + ret.mInt32Value.isPresent = true; + } else if (obj.IsDouble()) { + ret.mDoubleValue.value = obj.GetDouble(); + ret.mDoubleValue.isPresent = true; + } + } else if (obj.IsString()) { + ReadValue(obj, ret.mStringValue); + ret.mStringValue.isPresent = true; + } else if (obj.IsBool()) { + ret.mBoolValue.value = obj.GetBool(); + ret.mBoolValue.isPresent = true; + } + return ret; +} + +inline Extras ReadExtras(Value &obj) { + Extras ret; + + ret.mValues.reserve(obj.MemberCount()); + for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { + auto &val = it->value; + ret.mValues.push_back(ReadExtrasValue(it->name.GetString(), val)); + } + + return ret; +} + inline void CopyData(size_t count, const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride) { if (src_stride == dst_stride) { @@ -248,7 +292,7 @@ inline void Object::ReadExtensions(Value &val) { inline void Object::ReadExtras(Value &val) { if (Value *curExtras = FindObject(val, "extras")) { - this->extras = glTF2::ReadExtensions("extras", *curExtras); + this->extras = glTF2::ReadExtras(*curExtras); } } diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 0be139595..e1fcaefd4 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -620,6 +620,44 @@ namespace glTF2 { } } + inline void WriteExtrasValue(Value &parent, const ExtrasValue &value, AssetWriter &w) { + Value valueNode; + + if (value.mStringValue.isPresent) { + MakeValue(valueNode, value.mStringValue.value.c_str(), w.mAl); + } else if (value.mDoubleValue.isPresent) { + MakeValue(valueNode, value.mDoubleValue.value, w.mAl); + } else if (value.mUint64Value.isPresent) { + MakeValue(valueNode, value.mUint64Value.value, w.mAl); + } else if (value.mInt32Value.isPresent) { + MakeValue(valueNode, value.mInt32Value.value, w.mAl); + } else if (value.mBoolValue.isPresent) { + MakeValue(valueNode, value.mBoolValue.value, w.mAl); + } else if (value.mMetadataValue.isPresent) { + valueNode.SetObject(); + for (auto const &subvalue : value.mMetadataValue.value) { + WriteExtrasValue(valueNode, subvalue, w); + } + } + + parent.AddMember(StringRef(value.name), valueNode, w.mAl); + } + + inline void WriteExtras(Value &obj, const Extras &extras, AssetWriter &w) { + if (!extras.HasExtras()) { + return; + } + + Value extrasNode; + extrasNode.SetObject(); + + for (auto const &value : extras.mValues) { + WriteExtrasValue(extrasNode, value, w); + } + + obj.AddMember("extras", extrasNode, w.mAl); + } + inline void Write(Value& obj, Node& n, AssetWriter& w) { if (n.matrix.isPresent) { @@ -655,6 +693,8 @@ namespace glTF2 { if(n.skeletons.size()) { AddRefsVector(obj, "skeletons", n.skeletons, w.mAl); } + + WriteExtras(obj, n.extras, w); } inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/) @@ -728,7 +768,6 @@ namespace glTF2 { } } - inline AssetWriter::AssetWriter(Asset& a) : mDoc() , mAsset(a) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index da7591d52..f8b1995d9 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -445,6 +445,57 @@ inline Ref ExportData(Asset &a, std::string &meshName, Ref &bu return acc; } +inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, ExtrasValue &value) { + + value.name = name.C_Str(); + switch (metadataEntry.mType) { + case AI_BOOL: + value.mBoolValue.value = *static_cast(metadataEntry.mData); + value.mBoolValue.isPresent = true; + break; + case AI_INT32: + value.mInt32Value.value = *static_cast(metadataEntry.mData); + value.mInt32Value.isPresent = true; + break; + case AI_UINT64: + value.mUint64Value.value = *static_cast(metadataEntry.mData); + value.mUint64Value.isPresent = true; + break; + case AI_FLOAT: + value.mFloatValue.value = *static_cast(metadataEntry.mData); + value.mFloatValue.isPresent = true; + break; + case AI_DOUBLE: + value.mDoubleValue.value = *static_cast(metadataEntry.mData); + value.mDoubleValue.isPresent = true; + break; + case AI_AISTRING: + value.mStringValue.value = static_cast(metadataEntry.mData)->C_Str(); + value.mStringValue.isPresent = true; + break; + case AI_AIMETADATA: + const aiMetadata *subMetadata = static_cast(metadataEntry.mData); + value.mMetadataValue.value.resize(subMetadata->mNumProperties); + value.mMetadataValue.isPresent = true; + + for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) { + ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mMetadataValue.value.at(i)); + } + break; + } +} + +inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { + if (metadata == nullptr) { + return; + } + + extras.mValues.resize(metadata->mNumProperties); + for (unsigned int i = 0; i < metadata->mNumProperties; ++i) { + ExportNodeExtras(metadata->mValues[i], metadata->mKeys[i], extras.mValues.at(i)); + } +} + inline void SetSamplerWrap(SamplerWrap &wrap, aiTextureMapMode map) { switch (map) { case aiTextureMapMode_Clamp: @@ -1344,7 +1395,7 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) { return node.GetIndex(); } -/* + /* * Export node and recursively calls ExportNode for all children. * Since these nodes are not the root node, we also export the parent Ref */ @@ -1355,6 +1406,10 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { node->parent = parent; node->name = name; + if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) { + ExportNodeExtras(n->mMetaData, node->extras); + } + if (!n->mTransformation.IsIdentity()) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { aiQuaternion quaternion; diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 293d3dea7..a14e6ad6f 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1033,11 +1033,33 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { } } -void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) { - if (extension.mValues.isPresent) { - for (auto const &subExtension : extension.mValues.value) { - ParseExtensions(metadata, subExtension); +void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) { + + if (value.mBoolValue.isPresent) { + metadata->Add(value.name, value.mBoolValue.value); + } else if (value.mInt32Value.isPresent) { + metadata->Add(value.name, value.mInt32Value.value); + } else if (value.mUint64Value.isPresent) { + metadata->Add(value.name, value.mUint64Value.value); + } else if (value.mFloatValue.isPresent) { + metadata->Add(value.name, value.mFloatValue.value); + } else if (value.mDoubleValue.isPresent) { + metadata->Add(value.name, value.mDoubleValue.value); + } else if (value.mStringValue.isPresent) { + metadata->Add(value.name, aiString(value.mStringValue.value)); + } else if (value.mMetadataValue.isPresent) { + aiMetadata subMetadata; + for (auto const &subValue : value.mMetadataValue.value) { + ParseExtrasValue(&subMetadata, subValue); } + + metadata->Add(value.name, subMetadata); + } +} + +void ParseExtras(aiMetadata* metadata, const Extras& extras) { + for (auto const &value : extras.mValues) { + ParseExtrasValue(metadata, value); } } @@ -1059,12 +1081,12 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } } - if (node.customExtensions || node.extras) { + if (node.customExtensions || !node.extras.HasExtras()) { ainode->mMetaData = new aiMetadata; if (node.customExtensions) { ParseExtensions(ainode->mMetaData, node.customExtensions); } - if (node.extras) { + if (node.extras.HasExtras()) { ParseExtras(ainode->mMetaData, node.extras); } } diff --git a/code/Common/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp index 2c2539e54..1d32436c2 100644 --- a/code/Common/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -1349,6 +1349,9 @@ void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) { case AI_AIVECTOR3D: out.mData = new aiVector3D(*static_cast(in.mData)); break; + case AI_AIMETADATA: + out.mData = new aiMetadata(*static_cast(in.mData)); + break; default: ai_assert(false); break; From 5a2b811ba34cfd45d58349b3c3d1894e23f3e05e Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:04:05 +0200 Subject: [PATCH 02/18] Fixed extras presence check in gltf2 import. --- code/AssetLib/glTF2/glTF2Exporter.cpp | 6 ++---- code/AssetLib/glTF2/glTF2Importer.cpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index f8b1995d9..d3c88e479 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -486,7 +486,7 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name } inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { - if (metadata == nullptr) { + if (metadata == nullptr || metadata->mNumProperties == 0) { return; } @@ -1406,9 +1406,7 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { node->parent = parent; node->name = name; - if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) { - ExportNodeExtras(n->mMetaData, node->extras); - } + ExportNodeExtras(n->mMetaData, node->extras); if (!n->mTransformation.IsIdentity()) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index a14e6ad6f..e88cd0f08 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1081,7 +1081,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } } - if (node.customExtensions || !node.extras.HasExtras()) { + if (node.customExtensions || node.extras.HasExtras()) { ainode->mMetaData = new aiMetadata; if (node.customExtensions) { ParseExtensions(ainode->mMetaData, node.customExtensions); From 517fd3c76c81450e3967ffc1df5f7b90c1a7d94c Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:07:42 +0200 Subject: [PATCH 03/18] Added missing member copy in gltf2::ExtrasValue ctor. --- code/AssetLib/glTF2/glTF2Asset.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index bdc62dbc2..064634e40 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -376,9 +376,7 @@ struct CustomExtension { } }; -struct ExtrasValue; - -//! Represents a union of metadata values +//! Represents a union of metadata values. Only one nullable is supposed to be set. struct ExtrasValue { std::string name; @@ -396,6 +394,7 @@ struct ExtrasValue { ExtrasValue(const ExtrasValue& other) : name(other.name), mStringValue(other.mStringValue), + mFloatValue(other.mFloatValue), mDoubleValue(other.mDoubleValue), mUint64Value(other.mUint64Value), mInt32Value(other.mInt32Value), @@ -404,7 +403,7 @@ struct ExtrasValue { } }; -//! Represents metadata in an glTF object +//! Represents metadata in an glTF2 object struct Extras { std::vector mValues; From bdee65e577caa6f2eea8e6e22d2175407cde5de3 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:33:05 +0200 Subject: [PATCH 04/18] Got rid of gltf2::ExtrasValue and used gltf2::CustomExtension instead --- code/AssetLib/glTF2/glTF2Asset.h | 29 +------------------- code/AssetLib/glTF2/glTF2Asset.inl | 34 +----------------------- code/AssetLib/glTF2/glTF2AssetWriter.inl | 10 +++---- code/AssetLib/glTF2/glTF2Exporter.cpp | 16 +++++------ code/AssetLib/glTF2/glTF2Importer.cpp | 26 +----------------- 5 files changed, 14 insertions(+), 101 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 064634e40..9a117205d 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -376,36 +376,9 @@ struct CustomExtension { } }; -//! Represents a union of metadata values. Only one nullable is supposed to be set. -struct ExtrasValue { - std::string name; - - Nullable mBoolValue; - Nullable mInt32Value; - Nullable mUint64Value; - Nullable mFloatValue; - Nullable mDoubleValue; - Nullable mStringValue; - Nullable> mMetadataValue; - - ExtrasValue() = default; - ~ExtrasValue() = default; - - ExtrasValue(const ExtrasValue& other) : - name(other.name), - mStringValue(other.mStringValue), - mFloatValue(other.mFloatValue), - mDoubleValue(other.mDoubleValue), - mUint64Value(other.mUint64Value), - mInt32Value(other.mInt32Value), - mBoolValue(other.mBoolValue), - mMetadataValue(other.mMetadataValue) { - } -}; - //! Represents metadata in an glTF2 object struct Extras { - std::vector mValues; + std::vector mValues; inline bool HasExtras() const { return mValues.size() != 0; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 5dc51e7fa..3a7d127d3 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -139,45 +139,13 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) { return ret; } -inline ExtrasValue ReadExtrasValue(const char *name, Value &obj) { - ExtrasValue ret; - ret.name = name; - - if (obj.IsObject()) { - ret.mMetadataValue.value.reserve(obj.MemberCount()); - ret.mMetadataValue.isPresent = true; - for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { - auto &val = it->value; - ret.mMetadataValue.value.push_back(ReadExtrasValue(it->name.GetString(), val)); - } - } else if (obj.IsNumber()) { - if (obj.IsUint64()) { - ret.mUint64Value.value = obj.GetUint64(); - ret.mUint64Value.isPresent = true; - } else if (obj.IsInt()) { - ret.mInt32Value.value = obj.GetInt64(); - ret.mInt32Value.isPresent = true; - } else if (obj.IsDouble()) { - ret.mDoubleValue.value = obj.GetDouble(); - ret.mDoubleValue.isPresent = true; - } - } else if (obj.IsString()) { - ReadValue(obj, ret.mStringValue); - ret.mStringValue.isPresent = true; - } else if (obj.IsBool()) { - ret.mBoolValue.value = obj.GetBool(); - ret.mBoolValue.isPresent = true; - } - return ret; -} - inline Extras ReadExtras(Value &obj) { Extras ret; ret.mValues.reserve(obj.MemberCount()); for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { auto &val = it->value; - ret.mValues.push_back(ReadExtrasValue(it->name.GetString(), val)); + ret.mValues.push_back(ReadExtensions(it->name.GetString(), val)); } return ret; diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index e1fcaefd4..3acec58a5 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -620,7 +620,7 @@ namespace glTF2 { } } - inline void WriteExtrasValue(Value &parent, const ExtrasValue &value, AssetWriter &w) { + inline void WriteExtrasValue(Value &parent, const CustomExtension &value, AssetWriter &w) { Value valueNode; if (value.mStringValue.isPresent) { @@ -629,13 +629,13 @@ namespace glTF2 { MakeValue(valueNode, value.mDoubleValue.value, w.mAl); } else if (value.mUint64Value.isPresent) { MakeValue(valueNode, value.mUint64Value.value, w.mAl); - } else if (value.mInt32Value.isPresent) { - MakeValue(valueNode, value.mInt32Value.value, w.mAl); + } else if (value.mInt64Value.isPresent) { + MakeValue(valueNode, value.mInt64Value.value, w.mAl); } else if (value.mBoolValue.isPresent) { MakeValue(valueNode, value.mBoolValue.value, w.mAl); - } else if (value.mMetadataValue.isPresent) { + } else if (value.mValues.isPresent) { valueNode.SetObject(); - for (auto const &subvalue : value.mMetadataValue.value) { + for (auto const &subvalue : value.mValues.value) { WriteExtrasValue(valueNode, subvalue, w); } } diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index d3c88e479..028ab5c17 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -445,7 +445,7 @@ inline Ref ExportData(Asset &a, std::string &meshName, Ref &bu return acc; } -inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, ExtrasValue &value) { +inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, CustomExtension &value) { value.name = name.C_Str(); switch (metadataEntry.mType) { @@ -454,17 +454,13 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name value.mBoolValue.isPresent = true; break; case AI_INT32: - value.mInt32Value.value = *static_cast(metadataEntry.mData); - value.mInt32Value.isPresent = true; + value.mInt64Value.value = *static_cast(metadataEntry.mData); + value.mInt64Value.isPresent = true; break; case AI_UINT64: value.mUint64Value.value = *static_cast(metadataEntry.mData); value.mUint64Value.isPresent = true; break; - case AI_FLOAT: - value.mFloatValue.value = *static_cast(metadataEntry.mData); - value.mFloatValue.isPresent = true; - break; case AI_DOUBLE: value.mDoubleValue.value = *static_cast(metadataEntry.mData); value.mDoubleValue.isPresent = true; @@ -475,11 +471,11 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name break; case AI_AIMETADATA: const aiMetadata *subMetadata = static_cast(metadataEntry.mData); - value.mMetadataValue.value.resize(subMetadata->mNumProperties); - value.mMetadataValue.isPresent = true; + value.mValues.value.resize(subMetadata->mNumProperties); + value.mValues.isPresent = true; for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) { - ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mMetadataValue.value.at(i)); + ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mValues.value.at(i)); } break; } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index e88cd0f08..f34465444 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1033,33 +1033,9 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { } } -void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) { - - if (value.mBoolValue.isPresent) { - metadata->Add(value.name, value.mBoolValue.value); - } else if (value.mInt32Value.isPresent) { - metadata->Add(value.name, value.mInt32Value.value); - } else if (value.mUint64Value.isPresent) { - metadata->Add(value.name, value.mUint64Value.value); - } else if (value.mFloatValue.isPresent) { - metadata->Add(value.name, value.mFloatValue.value); - } else if (value.mDoubleValue.isPresent) { - metadata->Add(value.name, value.mDoubleValue.value); - } else if (value.mStringValue.isPresent) { - metadata->Add(value.name, aiString(value.mStringValue.value)); - } else if (value.mMetadataValue.isPresent) { - aiMetadata subMetadata; - for (auto const &subValue : value.mMetadataValue.value) { - ParseExtrasValue(&subMetadata, subValue); - } - - metadata->Add(value.name, subMetadata); - } -} - void ParseExtras(aiMetadata* metadata, const Extras& extras) { for (auto const &value : extras.mValues) { - ParseExtrasValue(metadata, value); + ParseExtensions(metadata, value); } } From 99c31045886039034bae70d44ba59320508d4e57 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 00:44:51 +0200 Subject: [PATCH 05/18] Rewrote gltf2 node extras import and added node extras export. No support for AI_AIVECTOR3D metadata type. No support for json arrays of metadata, just json objects. --- code/AssetLib/glTF2/glTF2Asset.h | 47 ++++++++++++++++++- code/AssetLib/glTF2/glTF2Asset.inl | 46 ++++++++++++++++++- code/AssetLib/glTF2/glTF2AssetWriter.inl | 41 ++++++++++++++++- code/AssetLib/glTF2/glTF2Exporter.cpp | 57 +++++++++++++++++++++++- code/AssetLib/glTF2/glTF2Importer.cpp | 34 +++++++++++--- code/Common/SceneCombiner.cpp | 3 ++ 6 files changed, 218 insertions(+), 10 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 44ab6c9c8..a4a615131 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -378,6 +378,51 @@ struct CustomExtension { CustomExtension& operator=(const CustomExtension&) = default; }; +struct ExtrasValue; + +//! Represents a union of metadata values +struct ExtrasValue { + std::string name; + + Nullable mBoolValue; + Nullable mInt32Value; + Nullable mUint64Value; + Nullable mFloatValue; + Nullable mDoubleValue; + Nullable mStringValue; + Nullable> mMetadataValue; + + ExtrasValue() = default; + ~ExtrasValue() = default; + + ExtrasValue(const ExtrasValue& other) : + name(other.name), + mStringValue(other.mStringValue), + mDoubleValue(other.mDoubleValue), + mUint64Value(other.mUint64Value), + mInt32Value(other.mInt32Value), + mBoolValue(other.mBoolValue), + mMetadataValue(other.mMetadataValue) { + } +}; + +//! Represents metadata in an glTF object +struct Extras { + std::vector mValues; + + inline bool HasExtras() const { + return mValues.size() != 0; + } + + Extras() = default; + ~Extras() = default; + + Extras(const Extras &other) : + mValues(other.mValues) { + // empty + } +}; + //! Base class for all glTF top-level objects struct Object { int index; //!< The index of this object within its property container @@ -386,7 +431,7 @@ struct Object { std::string name; //!< The user-defined name of this object CustomExtension customExtensions; - CustomExtension extras; + Extras extras; //! Objects marked as special are not exported (used to emulate the binary body buffer) virtual bool IsSpecial() const { return false; } diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index db47915d6..5dc51e7fa 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -139,6 +139,50 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) { return ret; } +inline ExtrasValue ReadExtrasValue(const char *name, Value &obj) { + ExtrasValue ret; + ret.name = name; + + if (obj.IsObject()) { + ret.mMetadataValue.value.reserve(obj.MemberCount()); + ret.mMetadataValue.isPresent = true; + for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { + auto &val = it->value; + ret.mMetadataValue.value.push_back(ReadExtrasValue(it->name.GetString(), val)); + } + } else if (obj.IsNumber()) { + if (obj.IsUint64()) { + ret.mUint64Value.value = obj.GetUint64(); + ret.mUint64Value.isPresent = true; + } else if (obj.IsInt()) { + ret.mInt32Value.value = obj.GetInt64(); + ret.mInt32Value.isPresent = true; + } else if (obj.IsDouble()) { + ret.mDoubleValue.value = obj.GetDouble(); + ret.mDoubleValue.isPresent = true; + } + } else if (obj.IsString()) { + ReadValue(obj, ret.mStringValue); + ret.mStringValue.isPresent = true; + } else if (obj.IsBool()) { + ret.mBoolValue.value = obj.GetBool(); + ret.mBoolValue.isPresent = true; + } + return ret; +} + +inline Extras ReadExtras(Value &obj) { + Extras ret; + + ret.mValues.reserve(obj.MemberCount()); + for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { + auto &val = it->value; + ret.mValues.push_back(ReadExtrasValue(it->name.GetString(), val)); + } + + return ret; +} + inline void CopyData(size_t count, const uint8_t *src, size_t src_stride, uint8_t *dst, size_t dst_stride) { if (src_stride == dst_stride) { @@ -248,7 +292,7 @@ inline void Object::ReadExtensions(Value &val) { inline void Object::ReadExtras(Value &val) { if (Value *curExtras = FindObject(val, "extras")) { - this->extras = glTF2::ReadExtensions("extras", *curExtras); + this->extras = glTF2::ReadExtras(*curExtras); } } diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index 0be139595..e1fcaefd4 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -620,6 +620,44 @@ namespace glTF2 { } } + inline void WriteExtrasValue(Value &parent, const ExtrasValue &value, AssetWriter &w) { + Value valueNode; + + if (value.mStringValue.isPresent) { + MakeValue(valueNode, value.mStringValue.value.c_str(), w.mAl); + } else if (value.mDoubleValue.isPresent) { + MakeValue(valueNode, value.mDoubleValue.value, w.mAl); + } else if (value.mUint64Value.isPresent) { + MakeValue(valueNode, value.mUint64Value.value, w.mAl); + } else if (value.mInt32Value.isPresent) { + MakeValue(valueNode, value.mInt32Value.value, w.mAl); + } else if (value.mBoolValue.isPresent) { + MakeValue(valueNode, value.mBoolValue.value, w.mAl); + } else if (value.mMetadataValue.isPresent) { + valueNode.SetObject(); + for (auto const &subvalue : value.mMetadataValue.value) { + WriteExtrasValue(valueNode, subvalue, w); + } + } + + parent.AddMember(StringRef(value.name), valueNode, w.mAl); + } + + inline void WriteExtras(Value &obj, const Extras &extras, AssetWriter &w) { + if (!extras.HasExtras()) { + return; + } + + Value extrasNode; + extrasNode.SetObject(); + + for (auto const &value : extras.mValues) { + WriteExtrasValue(extrasNode, value, w); + } + + obj.AddMember("extras", extrasNode, w.mAl); + } + inline void Write(Value& obj, Node& n, AssetWriter& w) { if (n.matrix.isPresent) { @@ -655,6 +693,8 @@ namespace glTF2 { if(n.skeletons.size()) { AddRefsVector(obj, "skeletons", n.skeletons, w.mAl); } + + WriteExtras(obj, n.extras, w); } inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/) @@ -728,7 +768,6 @@ namespace glTF2 { } } - inline AssetWriter::AssetWriter(Asset& a) : mDoc() , mAsset(a) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index da7591d52..f8b1995d9 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -445,6 +445,57 @@ inline Ref ExportData(Asset &a, std::string &meshName, Ref &bu return acc; } +inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, ExtrasValue &value) { + + value.name = name.C_Str(); + switch (metadataEntry.mType) { + case AI_BOOL: + value.mBoolValue.value = *static_cast(metadataEntry.mData); + value.mBoolValue.isPresent = true; + break; + case AI_INT32: + value.mInt32Value.value = *static_cast(metadataEntry.mData); + value.mInt32Value.isPresent = true; + break; + case AI_UINT64: + value.mUint64Value.value = *static_cast(metadataEntry.mData); + value.mUint64Value.isPresent = true; + break; + case AI_FLOAT: + value.mFloatValue.value = *static_cast(metadataEntry.mData); + value.mFloatValue.isPresent = true; + break; + case AI_DOUBLE: + value.mDoubleValue.value = *static_cast(metadataEntry.mData); + value.mDoubleValue.isPresent = true; + break; + case AI_AISTRING: + value.mStringValue.value = static_cast(metadataEntry.mData)->C_Str(); + value.mStringValue.isPresent = true; + break; + case AI_AIMETADATA: + const aiMetadata *subMetadata = static_cast(metadataEntry.mData); + value.mMetadataValue.value.resize(subMetadata->mNumProperties); + value.mMetadataValue.isPresent = true; + + for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) { + ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mMetadataValue.value.at(i)); + } + break; + } +} + +inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { + if (metadata == nullptr) { + return; + } + + extras.mValues.resize(metadata->mNumProperties); + for (unsigned int i = 0; i < metadata->mNumProperties; ++i) { + ExportNodeExtras(metadata->mValues[i], metadata->mKeys[i], extras.mValues.at(i)); + } +} + inline void SetSamplerWrap(SamplerWrap &wrap, aiTextureMapMode map) { switch (map) { case aiTextureMapMode_Clamp: @@ -1344,7 +1395,7 @@ unsigned int glTF2Exporter::ExportNodeHierarchy(const aiNode *n) { return node.GetIndex(); } -/* + /* * Export node and recursively calls ExportNode for all children. * Since these nodes are not the root node, we also export the parent Ref */ @@ -1355,6 +1406,10 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { node->parent = parent; node->name = name; + if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) { + ExportNodeExtras(n->mMetaData, node->extras); + } + if (!n->mTransformation.IsIdentity()) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { aiQuaternion quaternion; diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index 293d3dea7..a14e6ad6f 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1033,11 +1033,33 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { } } -void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) { - if (extension.mValues.isPresent) { - for (auto const &subExtension : extension.mValues.value) { - ParseExtensions(metadata, subExtension); +void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) { + + if (value.mBoolValue.isPresent) { + metadata->Add(value.name, value.mBoolValue.value); + } else if (value.mInt32Value.isPresent) { + metadata->Add(value.name, value.mInt32Value.value); + } else if (value.mUint64Value.isPresent) { + metadata->Add(value.name, value.mUint64Value.value); + } else if (value.mFloatValue.isPresent) { + metadata->Add(value.name, value.mFloatValue.value); + } else if (value.mDoubleValue.isPresent) { + metadata->Add(value.name, value.mDoubleValue.value); + } else if (value.mStringValue.isPresent) { + metadata->Add(value.name, aiString(value.mStringValue.value)); + } else if (value.mMetadataValue.isPresent) { + aiMetadata subMetadata; + for (auto const &subValue : value.mMetadataValue.value) { + ParseExtrasValue(&subMetadata, subValue); } + + metadata->Add(value.name, subMetadata); + } +} + +void ParseExtras(aiMetadata* metadata, const Extras& extras) { + for (auto const &value : extras.mValues) { + ParseExtrasValue(metadata, value); } } @@ -1059,12 +1081,12 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } } - if (node.customExtensions || node.extras) { + if (node.customExtensions || !node.extras.HasExtras()) { ainode->mMetaData = new aiMetadata; if (node.customExtensions) { ParseExtensions(ainode->mMetaData, node.customExtensions); } - if (node.extras) { + if (node.extras.HasExtras()) { ParseExtras(ainode->mMetaData, node.extras); } } diff --git a/code/Common/SceneCombiner.cpp b/code/Common/SceneCombiner.cpp index 2c2539e54..1d32436c2 100644 --- a/code/Common/SceneCombiner.cpp +++ b/code/Common/SceneCombiner.cpp @@ -1349,6 +1349,9 @@ void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) { case AI_AIVECTOR3D: out.mData = new aiVector3D(*static_cast(in.mData)); break; + case AI_AIMETADATA: + out.mData = new aiMetadata(*static_cast(in.mData)); + break; default: ai_assert(false); break; From 233198baefa8be47bbea4235d438e337c8eda0f2 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:04:05 +0200 Subject: [PATCH 06/18] Fixed extras presence check in gltf2 import. --- code/AssetLib/glTF2/glTF2Exporter.cpp | 6 ++---- code/AssetLib/glTF2/glTF2Importer.cpp | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index f8b1995d9..d3c88e479 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -486,7 +486,7 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name } inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { - if (metadata == nullptr) { + if (metadata == nullptr || metadata->mNumProperties == 0) { return; } @@ -1406,9 +1406,7 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref &parent) { node->parent = parent; node->name = name; - if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) { - ExportNodeExtras(n->mMetaData, node->extras); - } + ExportNodeExtras(n->mMetaData, node->extras); if (!n->mTransformation.IsIdentity()) { if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) { diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index a14e6ad6f..e88cd0f08 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1081,7 +1081,7 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector & } } - if (node.customExtensions || !node.extras.HasExtras()) { + if (node.customExtensions || node.extras.HasExtras()) { ainode->mMetaData = new aiMetadata; if (node.customExtensions) { ParseExtensions(ainode->mMetaData, node.customExtensions); From cb4d0ab7aa497f0ab4ac53e4ace079a7eb53d95f Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:07:42 +0200 Subject: [PATCH 07/18] Added missing member copy in gltf2::ExtrasValue ctor. --- code/AssetLib/glTF2/glTF2Asset.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index a4a615131..722e6d119 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -378,9 +378,7 @@ struct CustomExtension { CustomExtension& operator=(const CustomExtension&) = default; }; -struct ExtrasValue; - -//! Represents a union of metadata values +//! Represents a union of metadata values. Only one nullable is supposed to be set. struct ExtrasValue { std::string name; @@ -398,6 +396,7 @@ struct ExtrasValue { ExtrasValue(const ExtrasValue& other) : name(other.name), mStringValue(other.mStringValue), + mFloatValue(other.mFloatValue), mDoubleValue(other.mDoubleValue), mUint64Value(other.mUint64Value), mInt32Value(other.mInt32Value), @@ -406,7 +405,7 @@ struct ExtrasValue { } }; -//! Represents metadata in an glTF object +//! Represents metadata in an glTF2 object struct Extras { std::vector mValues; From da58fbe8fbe3252b5406cdfd2be6562d9d14ce69 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Fri, 22 Jul 2022 01:33:05 +0200 Subject: [PATCH 08/18] Got rid of gltf2::ExtrasValue and used gltf2::CustomExtension instead --- code/AssetLib/glTF2/glTF2Asset.h | 29 +------------------- code/AssetLib/glTF2/glTF2Asset.inl | 34 +----------------------- code/AssetLib/glTF2/glTF2AssetWriter.inl | 10 +++---- code/AssetLib/glTF2/glTF2Exporter.cpp | 16 +++++------ code/AssetLib/glTF2/glTF2Importer.cpp | 26 +----------------- 5 files changed, 14 insertions(+), 101 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 722e6d119..1aa37b569 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -378,36 +378,9 @@ struct CustomExtension { CustomExtension& operator=(const CustomExtension&) = default; }; -//! Represents a union of metadata values. Only one nullable is supposed to be set. -struct ExtrasValue { - std::string name; - - Nullable mBoolValue; - Nullable mInt32Value; - Nullable mUint64Value; - Nullable mFloatValue; - Nullable mDoubleValue; - Nullable mStringValue; - Nullable> mMetadataValue; - - ExtrasValue() = default; - ~ExtrasValue() = default; - - ExtrasValue(const ExtrasValue& other) : - name(other.name), - mStringValue(other.mStringValue), - mFloatValue(other.mFloatValue), - mDoubleValue(other.mDoubleValue), - mUint64Value(other.mUint64Value), - mInt32Value(other.mInt32Value), - mBoolValue(other.mBoolValue), - mMetadataValue(other.mMetadataValue) { - } -}; - //! Represents metadata in an glTF2 object struct Extras { - std::vector mValues; + std::vector mValues; inline bool HasExtras() const { return mValues.size() != 0; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 5dc51e7fa..3a7d127d3 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -139,45 +139,13 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) { return ret; } -inline ExtrasValue ReadExtrasValue(const char *name, Value &obj) { - ExtrasValue ret; - ret.name = name; - - if (obj.IsObject()) { - ret.mMetadataValue.value.reserve(obj.MemberCount()); - ret.mMetadataValue.isPresent = true; - for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { - auto &val = it->value; - ret.mMetadataValue.value.push_back(ReadExtrasValue(it->name.GetString(), val)); - } - } else if (obj.IsNumber()) { - if (obj.IsUint64()) { - ret.mUint64Value.value = obj.GetUint64(); - ret.mUint64Value.isPresent = true; - } else if (obj.IsInt()) { - ret.mInt32Value.value = obj.GetInt64(); - ret.mInt32Value.isPresent = true; - } else if (obj.IsDouble()) { - ret.mDoubleValue.value = obj.GetDouble(); - ret.mDoubleValue.isPresent = true; - } - } else if (obj.IsString()) { - ReadValue(obj, ret.mStringValue); - ret.mStringValue.isPresent = true; - } else if (obj.IsBool()) { - ret.mBoolValue.value = obj.GetBool(); - ret.mBoolValue.isPresent = true; - } - return ret; -} - inline Extras ReadExtras(Value &obj) { Extras ret; ret.mValues.reserve(obj.MemberCount()); for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { auto &val = it->value; - ret.mValues.push_back(ReadExtrasValue(it->name.GetString(), val)); + ret.mValues.push_back(ReadExtensions(it->name.GetString(), val)); } return ret; diff --git a/code/AssetLib/glTF2/glTF2AssetWriter.inl b/code/AssetLib/glTF2/glTF2AssetWriter.inl index e1fcaefd4..3acec58a5 100644 --- a/code/AssetLib/glTF2/glTF2AssetWriter.inl +++ b/code/AssetLib/glTF2/glTF2AssetWriter.inl @@ -620,7 +620,7 @@ namespace glTF2 { } } - inline void WriteExtrasValue(Value &parent, const ExtrasValue &value, AssetWriter &w) { + inline void WriteExtrasValue(Value &parent, const CustomExtension &value, AssetWriter &w) { Value valueNode; if (value.mStringValue.isPresent) { @@ -629,13 +629,13 @@ namespace glTF2 { MakeValue(valueNode, value.mDoubleValue.value, w.mAl); } else if (value.mUint64Value.isPresent) { MakeValue(valueNode, value.mUint64Value.value, w.mAl); - } else if (value.mInt32Value.isPresent) { - MakeValue(valueNode, value.mInt32Value.value, w.mAl); + } else if (value.mInt64Value.isPresent) { + MakeValue(valueNode, value.mInt64Value.value, w.mAl); } else if (value.mBoolValue.isPresent) { MakeValue(valueNode, value.mBoolValue.value, w.mAl); - } else if (value.mMetadataValue.isPresent) { + } else if (value.mValues.isPresent) { valueNode.SetObject(); - for (auto const &subvalue : value.mMetadataValue.value) { + for (auto const &subvalue : value.mValues.value) { WriteExtrasValue(valueNode, subvalue, w); } } diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index d3c88e479..028ab5c17 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -445,7 +445,7 @@ inline Ref ExportData(Asset &a, std::string &meshName, Ref &bu return acc; } -inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, ExtrasValue &value) { +inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name, CustomExtension &value) { value.name = name.C_Str(); switch (metadataEntry.mType) { @@ -454,17 +454,13 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name value.mBoolValue.isPresent = true; break; case AI_INT32: - value.mInt32Value.value = *static_cast(metadataEntry.mData); - value.mInt32Value.isPresent = true; + value.mInt64Value.value = *static_cast(metadataEntry.mData); + value.mInt64Value.isPresent = true; break; case AI_UINT64: value.mUint64Value.value = *static_cast(metadataEntry.mData); value.mUint64Value.isPresent = true; break; - case AI_FLOAT: - value.mFloatValue.value = *static_cast(metadataEntry.mData); - value.mFloatValue.isPresent = true; - break; case AI_DOUBLE: value.mDoubleValue.value = *static_cast(metadataEntry.mData); value.mDoubleValue.isPresent = true; @@ -475,11 +471,11 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name break; case AI_AIMETADATA: const aiMetadata *subMetadata = static_cast(metadataEntry.mData); - value.mMetadataValue.value.resize(subMetadata->mNumProperties); - value.mMetadataValue.isPresent = true; + value.mValues.value.resize(subMetadata->mNumProperties); + value.mValues.isPresent = true; for (unsigned i = 0; i < subMetadata->mNumProperties; ++i) { - ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mMetadataValue.value.at(i)); + ExportNodeExtras(subMetadata->mValues[i], subMetadata->mKeys[i], value.mValues.value.at(i)); } break; } diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index e88cd0f08..f34465444 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/code/AssetLib/glTF2/glTF2Importer.cpp @@ -1033,33 +1033,9 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) { } } -void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) { - - if (value.mBoolValue.isPresent) { - metadata->Add(value.name, value.mBoolValue.value); - } else if (value.mInt32Value.isPresent) { - metadata->Add(value.name, value.mInt32Value.value); - } else if (value.mUint64Value.isPresent) { - metadata->Add(value.name, value.mUint64Value.value); - } else if (value.mFloatValue.isPresent) { - metadata->Add(value.name, value.mFloatValue.value); - } else if (value.mDoubleValue.isPresent) { - metadata->Add(value.name, value.mDoubleValue.value); - } else if (value.mStringValue.isPresent) { - metadata->Add(value.name, aiString(value.mStringValue.value)); - } else if (value.mMetadataValue.isPresent) { - aiMetadata subMetadata; - for (auto const &subValue : value.mMetadataValue.value) { - ParseExtrasValue(&subMetadata, subValue); - } - - metadata->Add(value.name, subMetadata); - } -} - void ParseExtras(aiMetadata* metadata, const Extras& extras) { for (auto const &value : extras.mValues) { - ParseExtrasValue(metadata, value); + ParseExtensions(metadata, value); } } From abfe8ad413f031c144b4b4bdf00e7541092a9135 Mon Sep 17 00:00:00 2001 From: Bengt Rosenberger Date: Mon, 1 Aug 2022 14:39:10 +0200 Subject: [PATCH 09/18] Added suggested changes and fixed automated check errors --- code/AssetLib/glTF2/glTF2Asset.h | 27 +-------------------------- code/AssetLib/glTF2/glTF2Asset.inl | 2 +- code/AssetLib/glTF2/glTF2Exporter.cpp | 10 +++++++++- 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 1a44b8377..754d6b593 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/code/AssetLib/glTF2/glTF2Asset.h @@ -383,32 +383,7 @@ struct Extras { std::vector mValues; inline bool HasExtras() const { - return mValues.size() != 0; - } - - Extras() = default; - ~Extras() = default; - - Extras(const Extras &other) : - mValues(other.mValues) { - // empty - } -}; - -//! Represents metadata in an glTF2 object -struct Extras { - std::vector mValues; - - inline bool HasExtras() const { - return mValues.size() != 0; - } - - Extras() = default; - ~Extras() = default; - - Extras(const Extras &other) : - mValues(other.mValues) { - // empty + return !mValues.empty(); } }; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index 3a7d127d3..891fa27b5 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -145,7 +145,7 @@ inline Extras ReadExtras(Value &obj) { ret.mValues.reserve(obj.MemberCount()); for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) { auto &val = it->value; - ret.mValues.push_back(ReadExtensions(it->name.GetString(), val)); + ret.mValues.emplace_back(ReadExtensions(it->name.GetString(), val)); } return ret; diff --git a/code/AssetLib/glTF2/glTF2Exporter.cpp b/code/AssetLib/glTF2/glTF2Exporter.cpp index 028ab5c17..2996a8805 100644 --- a/code/AssetLib/glTF2/glTF2Exporter.cpp +++ b/code/AssetLib/glTF2/glTF2Exporter.cpp @@ -461,6 +461,10 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name value.mUint64Value.value = *static_cast(metadataEntry.mData); value.mUint64Value.isPresent = true; break; + case AI_FLOAT: + value.mDoubleValue.value = *static_cast(metadataEntry.mData); + value.mDoubleValue.isPresent = true; + break; case AI_DOUBLE: value.mDoubleValue.value = *static_cast(metadataEntry.mData); value.mDoubleValue.isPresent = true; @@ -469,7 +473,7 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name value.mStringValue.value = static_cast(metadataEntry.mData)->C_Str(); value.mStringValue.isPresent = true; break; - case AI_AIMETADATA: + case AI_AIMETADATA: { const aiMetadata *subMetadata = static_cast(metadataEntry.mData); value.mValues.value.resize(subMetadata->mNumProperties); value.mValues.isPresent = true; @@ -479,6 +483,10 @@ inline void ExportNodeExtras(const aiMetadataEntry &metadataEntry, aiString name } break; } + default: + // AI_AIVECTOR3D not handled + break; + } } inline void ExportNodeExtras(const aiMetadata *metadata, Extras &extras) { From e4621a31421f3ed89db9b3d491494993ae262db2 Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Wed, 24 May 2023 17:29:29 +0200 Subject: [PATCH 10/18] Update cpp-pm / hunter Fix a lot of CVE vulnerabilities Update abseil to LTFS 20220623.1 by @butteredmonkey in #656 Fix Hunter on Windows MSVC CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE 'ARM64EC' by @ccmvn in #659 openssl: update openssl to the latest 1.1.1t by @res0nance in #660 ceres-solver: per default disable CUDA support by @NeroBurner in #665 update range-v3 to version 0.12.0 by @alex-tdrn in #670 Update 'pybind11' to 2.10.4 by @hjmallon in #667 cli11: update cli11 to 2.3.2 by @res0nance in #669 openssl: update to v3 as 1.1.1 is almost eol by @res0nance in #668 Fix Hunter on Windows MSVC CMAKE_VS_PLATFORM_TOOLSET_HOST_ARCHITECTURE 'ARM64' by @ccmvn in #655 Boost: Fix building b2 (+ headers) on Apple tvOS with Xcode generator by @hjmallon in #647 assimp: add version 5.2.5 by @NovaSurfer in #640 SuiteSparse: update to v1.6.1 (SuiteSparse v5.4.0), with METIS and OpenBLAS by @NeroBurner in #642 OpenSSL: replace HUNTER_UWP_PLATFORM with CMAKE_SYSTEM_NAME check by @Dargun in #635 asio-grpc: Add version 2.3.0 by @Tradias in #636 Update OpenBLAS to v0.3.21 and add new BUILD_WITHOUT_LAPACK flag by @NeroBurner in #638 OpenBLAS: starting with 0.3.21 build with LAPACK support per default by @NeroBurner in #639 Update 'date' to v3.0.1 by @hjmallon in #615 Update 'SDL_net' package to v2.2.0-p0 by @drodin in #616 Update 'Jpeg' package to v9e-p0 by @drodin in #618 Update 'GTest' package to v1.12.1 by @drodin in #620 Update 'lcms' package to v2.13.1-p0 by @drodin in #621 Update 'giflib' package to v5.2.1-p0 by @drodin in #622 Update package 'WebP' to v1.2.4-p0 by @drodin in #623 Update 'Boost' to 1.80.0 by @tnixeu in #627 Update asio-grpc to 2.2.0 by @Tradias in #629 Update ZLIB to v1.2.13-p0 by @NeroBurner in #628 Add support for iOS simulator only builds by @hjmallon in #610 aws-sdk-cpp: Fix linking OpenSSL Crypto on Linux by @hjmallon in #630 and #631 OpenSSL: Fix build on universal windows platforms, add UWP job to global build matrix by @Dargun in #626 Update asio-grpc to v2.1.0 by @Tradias in #607 Update 'harfbuzz' package to v2.9.1-p0 by @drodin in #608 Update RocksDB to 7.5.3 by @twoentartian in #611 Fix CMAKE_IOS_INSTALL_COMBINED on Xcode 12+ by @hjmallon in #609 CI: Boost: update matrix.json to match general workflow by @NeroBurner in #612 Boost: update to v1.79.0 by @NeroBurner in #599 --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 20c735c4c..e0f034390 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) IF(ASSIMP_HUNTER_ENABLED) include("cmake-modules/HunterGate.cmake") HunterGate( - URL "https://github.com/cpp-pm/hunter/archive/v0.24.0.tar.gz" - SHA1 "a3d7f4372b1dcd52faa6ff4a3bd5358e1d0e5efd" + URL "https://github.com/cpp-pm/hunter/archive/v0.24.16.tar.gz" + SHA1 "aefcc56d2ad0021aa5bd5df72890151c" ) add_definitions(-DASSIMP_USE_HUNTER) From 1f5c7da82218819681f01a8a1c83cda65bee89bf Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Tue, 30 May 2023 16:23:57 +0200 Subject: [PATCH 11/18] Update CMakeLists.txt --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0f034390..5a6c0a433 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -49,8 +49,8 @@ option(ASSIMP_HUNTER_ENABLED "Enable Hunter package manager support" OFF) IF(ASSIMP_HUNTER_ENABLED) include("cmake-modules/HunterGate.cmake") HunterGate( - URL "https://github.com/cpp-pm/hunter/archive/v0.24.16.tar.gz" - SHA1 "aefcc56d2ad0021aa5bd5df72890151c" + URL "https://github.com/cpp-pm/hunter/archive/v0.24.17.tar.gz" + SHA1 "d9a9de341c9341b7d42d7374340f1871" ) add_definitions(-DASSIMP_USE_HUNTER) From 462755e5ba4e769b08cf8cf8f438543c2ce7ecda Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Tue, 30 May 2023 16:26:30 +0200 Subject: [PATCH 12/18] Update CMakeLists.txt fix sha1 --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 5a6c0a433..46c2a591c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,7 +50,7 @@ IF(ASSIMP_HUNTER_ENABLED) include("cmake-modules/HunterGate.cmake") HunterGate( URL "https://github.com/cpp-pm/hunter/archive/v0.24.17.tar.gz" - SHA1 "d9a9de341c9341b7d42d7374340f1871" + SHA1 "e6396699e414120e32557fe92db097b7655b760b" ) add_definitions(-DASSIMP_USE_HUNTER) From 54f5d01190d0952c5d4fcae1f34d7e3bba0a14e5 Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 31 May 2023 11:37:15 +0000 Subject: [PATCH 13/18] Fix Heap-buffer-overflow WRITE in Assimp::ObjFileImporter::createVertexArray --- code/AssetLib/Obj/ObjFileImporter.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/code/AssetLib/Obj/ObjFileImporter.cpp b/code/AssetLib/Obj/ObjFileImporter.cpp index cf4515794..173ef2074 100644 --- a/code/AssetLib/Obj/ObjFileImporter.cpp +++ b/code/AssetLib/Obj/ObjFileImporter.cpp @@ -323,7 +323,7 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF return nullptr; } - aiMesh *pMesh = new aiMesh; + std::unique_ptr pMesh(new aiMesh); if (!pObjMesh->m_name.empty()) { pMesh->mName.Set(pObjMesh->m_name); } @@ -385,9 +385,9 @@ aiMesh *ObjFileImporter::createTopology(const ObjFile::Model *pModel, const ObjF } // Create mesh vertices - createVertexArray(pModel, pData, meshIndex, pMesh, uiIdxCount); + createVertexArray(pModel, pData, meshIndex, pMesh.get(), uiIdxCount); - return pMesh; + return pMesh.release(); } // ------------------------------------------------------------------------------------------------ @@ -498,6 +498,10 @@ void ObjFileImporter::createVertexArray(const ObjFile::Model *pModel, if (vertexIndex) { if (!last) { + if (pMesh->mNumVertices <= newIndex + 1) { + throw DeadlyImportError("OBJ: bad vertex index"); + } + pMesh->mVertices[newIndex + 1] = pMesh->mVertices[newIndex]; if (!sourceFace->m_normals.empty() && !pModel->mNormals.empty()) { pMesh->mNormals[newIndex + 1] = pMesh->mNormals[newIndex]; From 1538669f70e3c49449630e9f8e58d2d5f1e12291 Mon Sep 17 00:00:00 2001 From: Kim Kulling Date: Wed, 31 May 2023 20:45:51 +0200 Subject: [PATCH 14/18] Update_ Use latest ubuntu image and switch to ninja --- Dockerfile | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Dockerfile b/Dockerfile index b65d131a4..5da5458f8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,14 +1,9 @@ -FROM ubuntu:14.04 +FROM ubuntu:22.04 -RUN apt-get update && apt-get install -y \ +RUN apt-get update && apt-get install -y ninja-build \ git cmake build-essential software-properties-common -RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update && apt-get install -y gcc-4.9 g++-4.9 && \ - cd /usr/bin && \ - rm gcc g++ cpp && \ - ln -s gcc-4.9 gcc && \ - ln -s g++-4.9 g++ && \ - ln -s cpp-4.9 cpp +RUN add-apt-repository ppa:ubuntu-toolchain-r/test && apt-get update WORKDIR /opt @@ -19,7 +14,8 @@ WORKDIR /opt/assimp RUN git checkout master \ && mkdir build && cd build && \ - cmake \ + cmake -G 'Ninja' \ -DCMAKE_BUILD_TYPE=Release \ + -DASSIMP_BUILD_ASSIMP_TOOLS=ON \ .. && \ - make && make install + ninja -j4 && ninja install From 62cefd5b275628ff97a77d0cd9220e1c35794a3f Mon Sep 17 00:00:00 2001 From: mosfet80 Date: Sat, 3 Jun 2023 11:16:39 +0200 Subject: [PATCH 15/18] Update pugiXML library Release highlights: xml_attribute::set_value, xml_node::set_value and xml_text::set now have overloads that accept pointer to non-null-terminated string and size Fix error handling in xml_document::save_file that could result in the function succeeding while running out of disk space Fix memory leak during error handling of some out-of-memory conditions during xml_document::load --- contrib/pugixml/src/pugiconfig.hpp | 2 +- contrib/pugixml/src/pugixml.cpp | 303 ++++++++++++++++++++--------- contrib/pugixml/src/pugixml.hpp | 9 +- 3 files changed, 224 insertions(+), 90 deletions(-) diff --git a/contrib/pugixml/src/pugiconfig.hpp b/contrib/pugixml/src/pugiconfig.hpp index e07060c4d..9bf2efd39 100644 --- a/contrib/pugixml/src/pugiconfig.hpp +++ b/contrib/pugixml/src/pugiconfig.hpp @@ -1,5 +1,5 @@ /** - * pugixml parser - version 1.12 + * pugixml parser - version 1.13 * -------------------------------------------------------- * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ diff --git a/contrib/pugixml/src/pugixml.cpp b/contrib/pugixml/src/pugixml.cpp index 60b55da3a..c63645b67 100644 --- a/contrib/pugixml/src/pugixml.cpp +++ b/contrib/pugixml/src/pugixml.cpp @@ -1,5 +1,5 @@ /** - * pugixml parser - version 1.12 + * pugixml parser - version 1.13 * -------------------------------------------------------- * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ @@ -1276,12 +1276,14 @@ PUGI__NS_BEGIN child->parent = parent; - if (node->next_sibling) - node->next_sibling->prev_sibling_c = child; + xml_node_struct* next = node->next_sibling; + + if (next) + next->prev_sibling_c = child; else parent->first_child->prev_sibling_c = child; - child->next_sibling = node->next_sibling; + child->next_sibling = next; child->prev_sibling_c = node; node->next_sibling = child; @@ -1293,12 +1295,14 @@ PUGI__NS_BEGIN child->parent = parent; - if (node->prev_sibling_c->next_sibling) - node->prev_sibling_c->next_sibling = child; + xml_node_struct* prev = node->prev_sibling_c; + + if (prev->next_sibling) + prev->next_sibling = child; else parent->first_child = child; - child->prev_sibling_c = node->prev_sibling_c; + child->prev_sibling_c = prev; child->next_sibling = node; node->prev_sibling_c = child; @@ -1308,15 +1312,18 @@ PUGI__NS_BEGIN { xml_node_struct* parent = node->parent; - if (node->next_sibling) - node->next_sibling->prev_sibling_c = node->prev_sibling_c; - else - parent->first_child->prev_sibling_c = node->prev_sibling_c; + xml_node_struct* next = node->next_sibling; + xml_node_struct* prev = node->prev_sibling_c; - if (node->prev_sibling_c->next_sibling) - node->prev_sibling_c->next_sibling = node->next_sibling; + if (next) + next->prev_sibling_c = prev; else - parent->first_child = node->next_sibling; + parent->first_child->prev_sibling_c = prev; + + if (prev->next_sibling) + prev->next_sibling = next; + else + parent->first_child = next; node->parent = 0; node->prev_sibling_c = 0; @@ -1360,39 +1367,46 @@ PUGI__NS_BEGIN inline void insert_attribute_after(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) { - if (place->next_attribute) - place->next_attribute->prev_attribute_c = attr; + xml_attribute_struct* next = place->next_attribute; + + if (next) + next->prev_attribute_c = attr; else node->first_attribute->prev_attribute_c = attr; - attr->next_attribute = place->next_attribute; + attr->next_attribute = next; attr->prev_attribute_c = place; place->next_attribute = attr; } inline void insert_attribute_before(xml_attribute_struct* attr, xml_attribute_struct* place, xml_node_struct* node) { - if (place->prev_attribute_c->next_attribute) - place->prev_attribute_c->next_attribute = attr; + xml_attribute_struct* prev = place->prev_attribute_c; + + if (prev->next_attribute) + prev->next_attribute = attr; else node->first_attribute = attr; - attr->prev_attribute_c = place->prev_attribute_c; + attr->prev_attribute_c = prev; attr->next_attribute = place; place->prev_attribute_c = attr; } inline void remove_attribute(xml_attribute_struct* attr, xml_node_struct* node) { - if (attr->next_attribute) - attr->next_attribute->prev_attribute_c = attr->prev_attribute_c; - else - node->first_attribute->prev_attribute_c = attr->prev_attribute_c; + xml_attribute_struct* next = attr->next_attribute; + xml_attribute_struct* prev = attr->prev_attribute_c; - if (attr->prev_attribute_c->next_attribute) - attr->prev_attribute_c->next_attribute = attr->next_attribute; + if (next) + next->prev_attribute_c = prev; else - node->first_attribute = attr->next_attribute; + node->first_attribute->prev_attribute_c = prev; + + if (prev->next_attribute) + prev->next_attribute = next; + else + node->first_attribute = next; attr->prev_attribute_c = 0; attr->next_attribute = 0; @@ -4707,6 +4721,9 @@ PUGI__NS_BEGIN // get actual encoding xml_encoding buffer_encoding = impl::get_buffer_encoding(encoding, contents, size); + // if convert_buffer below throws bad_alloc, we still need to deallocate contents if we own it + auto_deleter contents_guard(own ? contents : 0, xml_memory::deallocate); + // get private buffer char_t* buffer = 0; size_t length = 0; @@ -4714,6 +4731,9 @@ PUGI__NS_BEGIN // coverity[var_deref_model] if (!impl::convert_buffer(buffer, length, buffer_encoding, contents, size, is_mutable)) return impl::make_parse_result(status_out_of_memory); + // after this we either deallocate contents (below) or hold on to it via doc->buffer, so we don't need to guard it + contents_guard.release(); + // delete original buffer if we performed a conversion if (own && buffer != contents && contents) impl::xml_memory::deallocate(contents); @@ -5050,7 +5070,7 @@ PUGI__NS_BEGIN xml_writer_file writer(file); doc.save(writer, indent, flags, encoding); - return ferror(file) == 0; + return fflush(file) == 0 && ferror(file) == 0; } struct name_null_sentry @@ -5185,53 +5205,72 @@ namespace pugi PUGI__FN xml_attribute xml_attribute::next_attribute() const { - return _attr ? xml_attribute(_attr->next_attribute) : xml_attribute(); + if (!_attr) return xml_attribute(); + return xml_attribute(_attr->next_attribute); } PUGI__FN xml_attribute xml_attribute::previous_attribute() const { - return _attr && _attr->prev_attribute_c->next_attribute ? xml_attribute(_attr->prev_attribute_c) : xml_attribute(); + if (!_attr) return xml_attribute(); + xml_attribute_struct* prev = _attr->prev_attribute_c; + return prev->next_attribute ? xml_attribute(prev) : xml_attribute(); } PUGI__FN const char_t* xml_attribute::as_string(const char_t* def) const { - return (_attr && _attr->value) ? _attr->value + 0 : def; + if (!_attr) return def; + const char_t* value = _attr->value; + return value ? value : def; } PUGI__FN int xml_attribute::as_int(int def) const { - return (_attr && _attr->value) ? impl::get_value_int(_attr->value) : def; + if (!_attr) return def; + const char_t* value = _attr->value; + return value ? impl::get_value_int(value) : def; } PUGI__FN unsigned int xml_attribute::as_uint(unsigned int def) const { - return (_attr && _attr->value) ? impl::get_value_uint(_attr->value) : def; + if (!_attr) return def; + const char_t* value = _attr->value; + return value ? impl::get_value_uint(value) : def; } PUGI__FN double xml_attribute::as_double(double def) const { - return (_attr && _attr->value) ? impl::get_value_double(_attr->value) : def; + if (!_attr) return def; + const char_t* value = _attr->value; + return value ? impl::get_value_double(value) : def; } PUGI__FN float xml_attribute::as_float(float def) const { - return (_attr && _attr->value) ? impl::get_value_float(_attr->value) : def; + if (!_attr) return def; + const char_t* value = _attr->value; + return value ? impl::get_value_float(value) : def; } PUGI__FN bool xml_attribute::as_bool(bool def) const { - return (_attr && _attr->value) ? impl::get_value_bool(_attr->value) : def; + if (!_attr) return def; + const char_t* value = _attr->value; + return value ? impl::get_value_bool(value) : def; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long xml_attribute::as_llong(long long def) const { - return (_attr && _attr->value) ? impl::get_value_llong(_attr->value) : def; + if (!_attr) return def; + const char_t* value = _attr->value; + return value ? impl::get_value_llong(value) : def; } PUGI__FN unsigned long long xml_attribute::as_ullong(unsigned long long def) const { - return (_attr && _attr->value) ? impl::get_value_ullong(_attr->value) : def; + if (!_attr) return def; + const char_t* value = _attr->value; + return value ? impl::get_value_ullong(value) : def; } #endif @@ -5242,12 +5281,16 @@ namespace pugi PUGI__FN const char_t* xml_attribute::name() const { - return (_attr && _attr->name) ? _attr->name + 0 : PUGIXML_TEXT(""); + if (!_attr) return PUGIXML_TEXT(""); + const char_t* name = _attr->name; + return name ? name : PUGIXML_TEXT(""); } PUGI__FN const char_t* xml_attribute::value() const { - return (_attr && _attr->value) ? _attr->value + 0 : PUGIXML_TEXT(""); + if (!_attr) return PUGIXML_TEXT(""); + const char_t* value = _attr->value; + return value ? value : PUGIXML_TEXT(""); } PUGI__FN size_t xml_attribute::hash_value() const @@ -5329,6 +5372,13 @@ namespace pugi return impl::strcpy_insitu(_attr->name, _attr->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } + PUGI__FN bool xml_attribute::set_value(const char_t* rhs, size_t sz) + { + if (!_attr) return false; + + return impl::strcpy_insitu(_attr->value, _attr->header, impl::xml_memory_page_value_allocated_mask, rhs, sz); + } + PUGI__FN bool xml_attribute::set_value(const char_t* rhs) { if (!_attr) return false; @@ -5521,7 +5571,9 @@ namespace pugi PUGI__FN const char_t* xml_node::name() const { - return (_root && _root->name) ? _root->name + 0 : PUGIXML_TEXT(""); + if (!_root) return PUGIXML_TEXT(""); + const char_t* name = _root->name; + return name ? name : PUGIXML_TEXT(""); } PUGI__FN xml_node_type xml_node::type() const @@ -5531,7 +5583,9 @@ namespace pugi PUGI__FN const char_t* xml_node::value() const { - return (_root && _root->value) ? _root->value + 0 : PUGIXML_TEXT(""); + if (!_root) return PUGIXML_TEXT(""); + const char_t* value = _root->value; + return value ? value : PUGIXML_TEXT(""); } PUGI__FN xml_node xml_node::child(const char_t* name_) const @@ -5539,7 +5593,11 @@ namespace pugi if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + { + const char_t* iname = i->name; + if (iname && impl::strequal(name_, iname)) + return xml_node(i); + } return xml_node(); } @@ -5549,8 +5607,11 @@ namespace pugi if (!_root) return xml_attribute(); for (xml_attribute_struct* i = _root->first_attribute; i; i = i->next_attribute) - if (i->name && impl::strequal(name_, i->name)) + { + const char_t* iname = i->name; + if (iname && impl::strequal(name_, iname)) return xml_attribute(i); + } return xml_attribute(); } @@ -5560,7 +5621,11 @@ namespace pugi if (!_root) return xml_node(); for (xml_node_struct* i = _root->next_sibling; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + { + const char_t* iname = i->name; + if (iname && impl::strequal(name_, iname)) + return xml_node(i); + } return xml_node(); } @@ -5575,7 +5640,11 @@ namespace pugi if (!_root) return xml_node(); for (xml_node_struct* i = _root->prev_sibling_c; i->next_sibling; i = i->prev_sibling_c) - if (i->name && impl::strequal(name_, i->name)) return xml_node(i); + { + const char_t* iname = i->name; + if (iname && impl::strequal(name_, iname)) + return xml_node(i); + } return xml_node(); } @@ -5591,24 +5660,30 @@ namespace pugi // optimistically search from hint up until the end for (xml_attribute_struct* i = hint; i; i = i->next_attribute) - if (i->name && impl::strequal(name_, i->name)) + { + const char_t* iname = i->name; + if (iname && impl::strequal(name_, iname)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = i->next_attribute; return xml_attribute(i); } + } // wrap around and search from the first attribute until the hint // 'j' null pointer check is technically redundant, but it prevents a crash in case the assertion above fails for (xml_attribute_struct* j = _root->first_attribute; j && j != hint; j = j->next_attribute) - if (j->name && impl::strequal(name_, j->name)) + { + const char_t* jname = j->name; + if (jname && impl::strequal(name_, jname)) { // update hint to maximize efficiency of searching for consecutive attributes hint_._attr = j->next_attribute; return xml_attribute(j); } + } return xml_attribute(); } @@ -5616,9 +5691,8 @@ namespace pugi PUGI__FN xml_node xml_node::previous_sibling() const { if (!_root) return xml_node(); - - if (_root->prev_sibling_c->next_sibling) return xml_node(_root->prev_sibling_c); - else return xml_node(); + xml_node_struct* prev = _root->prev_sibling_c; + return prev->next_sibling ? xml_node(prev) : xml_node(); } PUGI__FN xml_node xml_node::parent() const @@ -5645,8 +5719,11 @@ namespace pugi return _root->value; for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (impl::is_text_node(i) && i->value) - return i->value; + { + const char_t* ivalue = i->value; + if (impl::is_text_node(i) && ivalue) + return ivalue; + } return PUGIXML_TEXT(""); } @@ -5658,22 +5735,28 @@ namespace pugi PUGI__FN xml_attribute xml_node::first_attribute() const { - return _root ? xml_attribute(_root->first_attribute) : xml_attribute(); + if (!_root) return xml_attribute(); + return xml_attribute(_root->first_attribute); } PUGI__FN xml_attribute xml_node::last_attribute() const { - return _root && _root->first_attribute ? xml_attribute(_root->first_attribute->prev_attribute_c) : xml_attribute(); + if (!_root) return xml_attribute(); + xml_attribute_struct* first = _root->first_attribute; + return first ? xml_attribute(first->prev_attribute_c) : xml_attribute(); } PUGI__FN xml_node xml_node::first_child() const { - return _root ? xml_node(_root->first_child) : xml_node(); + if (!_root) return xml_node(); + return xml_node(_root->first_child); } PUGI__FN xml_node xml_node::last_child() const { - return _root && _root->first_child ? xml_node(_root->first_child->prev_sibling_c) : xml_node(); + if (!_root) return xml_node(); + xml_node_struct* first = _root->first_child; + return first ? xml_node(first->prev_sibling_c) : xml_node(); } PUGI__FN bool xml_node::set_name(const char_t* rhs) @@ -5686,6 +5769,16 @@ namespace pugi return impl::strcpy_insitu(_root->name, _root->header, impl::xml_memory_page_name_allocated_mask, rhs, impl::strlength(rhs)); } + PUGI__FN bool xml_node::set_value(const char_t* rhs, size_t sz) + { + xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; + + if (type_ != node_pcdata && type_ != node_cdata && type_ != node_comment && type_ != node_pi && type_ != node_doctype) + return false; + + return impl::strcpy_insitu(_root->value, _root->header, impl::xml_memory_page_value_allocated_mask, rhs, sz); + } + PUGI__FN bool xml_node::set_value(const char_t* rhs) { xml_node_type type_ = _root ? PUGI__NODETYPE(_root) : node_null; @@ -6199,12 +6292,22 @@ namespace pugi if (!_root) return xml_node(); for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) - if (i->name && impl::strequal(name_, i->name)) + { + const char_t* iname = i->name; + if (iname && impl::strequal(name_, iname)) { for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) - return xml_node(i); + { + const char_t* aname = a->name; + if (aname && impl::strequal(attr_name, aname)) + { + const char_t* avalue = a->value; + if (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT(""))) + return xml_node(i); + } + } } + } return xml_node(); } @@ -6215,8 +6318,15 @@ namespace pugi for (xml_node_struct* i = _root->first_child; i; i = i->next_sibling) for (xml_attribute_struct* a = i->first_attribute; a; a = a->next_attribute) - if (a->name && impl::strequal(attr_name, a->name) && impl::strequal(attr_value, a->value ? a->value + 0 : PUGIXML_TEXT(""))) - return xml_node(i); + { + const char_t* aname = a->name; + if (aname && impl::strequal(attr_name, aname)) + { + const char_t* avalue = a->value; + if (impl::strequal(attr_value, avalue ? avalue : PUGIXML_TEXT(""))) + return xml_node(i); + } + } return xml_node(); } @@ -6230,8 +6340,9 @@ namespace pugi for (xml_node_struct* i = _root; i; i = i->parent) { + const char_t* iname = i->name; offset += (i != _root); - offset += i->name ? impl::strlength(i->name) : 0; + offset += iname ? impl::strlength(iname) : 0; } string_t result; @@ -6242,12 +6353,13 @@ namespace pugi if (j != _root) result[--offset] = delimiter; - if (j->name) + const char_t* jname = j->name; + if (jname) { - size_t length = impl::strlength(j->name); + size_t length = impl::strlength(jname); offset -= length; - memcpy(&result[offset], j->name, length * sizeof(char_t)); + memcpy(&result[offset], jname, length * sizeof(char_t)); } } @@ -6285,7 +6397,8 @@ namespace pugi { for (xml_node_struct* j = context._root->first_child; j; j = j->next_sibling) { - if (j->name && impl::strequalrange(j->name, path_segment, static_cast(path_segment_end - path_segment))) + const char_t* jname = j->name; + if (jname && impl::strequalrange(jname, path_segment, static_cast(path_segment_end - path_segment))) { xml_node subsearch = xml_node(j).first_element_by_path(next_segment, delimiter); @@ -6477,68 +6590,84 @@ namespace pugi PUGI__FN const char_t* xml_text::get() const { xml_node_struct* d = _data(); - - return (d && d->value) ? d->value + 0 : PUGIXML_TEXT(""); + if (!d) return PUGIXML_TEXT(""); + const char_t* value = d->value; + return value ? value : PUGIXML_TEXT(""); } PUGI__FN const char_t* xml_text::as_string(const char_t* def) const { xml_node_struct* d = _data(); - - return (d && d->value) ? d->value + 0 : def; + if (!d) return def; + const char_t* value = d->value; + return value ? value : def; } PUGI__FN int xml_text::as_int(int def) const { xml_node_struct* d = _data(); - - return (d && d->value) ? impl::get_value_int(d->value) : def; + if (!d) return def; + const char_t* value = d->value; + return value ? impl::get_value_int(value) : def; } PUGI__FN unsigned int xml_text::as_uint(unsigned int def) const { xml_node_struct* d = _data(); - - return (d && d->value) ? impl::get_value_uint(d->value) : def; + if (!d) return def; + const char_t* value = d->value; + return value ? impl::get_value_uint(value) : def; } PUGI__FN double xml_text::as_double(double def) const { xml_node_struct* d = _data(); - - return (d && d->value) ? impl::get_value_double(d->value) : def; + if (!d) return def; + const char_t* value = d->value; + return value ? impl::get_value_double(value) : def; } PUGI__FN float xml_text::as_float(float def) const { xml_node_struct* d = _data(); - - return (d && d->value) ? impl::get_value_float(d->value) : def; + if (!d) return def; + const char_t* value = d->value; + return value ? impl::get_value_float(value) : def; } PUGI__FN bool xml_text::as_bool(bool def) const { xml_node_struct* d = _data(); - - return (d && d->value) ? impl::get_value_bool(d->value) : def; + if (!d) return def; + const char_t* value = d->value; + return value ? impl::get_value_bool(value) : def; } #ifdef PUGIXML_HAS_LONG_LONG PUGI__FN long long xml_text::as_llong(long long def) const { xml_node_struct* d = _data(); - - return (d && d->value) ? impl::get_value_llong(d->value) : def; + if (!d) return def; + const char_t* value = d->value; + return value ? impl::get_value_llong(value) : def; } PUGI__FN unsigned long long xml_text::as_ullong(unsigned long long def) const { xml_node_struct* d = _data(); - - return (d && d->value) ? impl::get_value_ullong(d->value) : def; + if (!d) return def; + const char_t* value = d->value; + return value ? impl::get_value_ullong(value) : def; } #endif + PUGI__FN bool xml_text::set(const char_t* rhs, size_t sz) + { + xml_node_struct* dn = _data_new(); + + return dn ? impl::strcpy_insitu(dn->value, dn->header, impl::xml_memory_page_value_allocated_mask, rhs, sz) : false; + } + PUGI__FN bool xml_text::set(const char_t* rhs) { xml_node_struct* dn = _data_new(); @@ -7294,7 +7423,7 @@ namespace pugi using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file(path_, (flags & format_save_file_text) ? "w" : "wb"), impl::close_file); - return impl::save_file_impl(*this, file.data, indent, flags, encoding); + return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0; } PUGI__FN bool xml_document::save_file(const wchar_t* path_, const char_t* indent, unsigned int flags, xml_encoding encoding) const @@ -7302,7 +7431,7 @@ namespace pugi using impl::auto_deleter; // MSVC7 workaround auto_deleter file(impl::open_file_wide(path_, (flags & format_save_file_text) ? L"w" : L"wb"), impl::close_file); - return impl::save_file_impl(*this, file.data, indent, flags, encoding); + return impl::save_file_impl(*this, file.data, indent, flags, encoding) && fclose(file.release()) == 0; } PUGI__FN xml_node xml_document::document_element() const diff --git a/contrib/pugixml/src/pugixml.hpp b/contrib/pugixml/src/pugixml.hpp index 579f14399..050df154c 100644 --- a/contrib/pugixml/src/pugixml.hpp +++ b/contrib/pugixml/src/pugixml.hpp @@ -1,5 +1,5 @@ /** - * pugixml parser - version 1.12 + * pugixml parser - version 1.13 * -------------------------------------------------------- * Copyright (C) 2006-2022, by Arseny Kapoulkine (arseny.kapoulkine@gmail.com) * Report bugs and download new versions at https://pugixml.org/ @@ -14,7 +14,7 @@ // Define version macro; evaluates to major * 1000 + minor * 10 + patch so that it's safe to use in less-than comparisons // Note: pugixml used major * 100 + minor * 10 + patch format up until 1.9 (which had version identifier 190); starting from pugixml 1.10, the minor version number is two digits #ifndef PUGIXML_VERSION -# define PUGIXML_VERSION 1120 // 1.12 +# define PUGIXML_VERSION 1130 // 1.13 #endif // Include user configuration file (this can define various configuration macros) @@ -115,6 +115,8 @@ #ifndef PUGIXML_NULL # if __cplusplus >= 201103 # define PUGIXML_NULL nullptr +# elif defined(_MSC_VER) && _MSC_VER >= 1600 +# define PUGIXML_NULL nullptr # else # define PUGIXML_NULL 0 # endif @@ -416,6 +418,7 @@ namespace pugi // Set attribute name/value (returns false if attribute is empty or there is not enough memory) bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs, size_t sz); bool set_value(const char_t* rhs); // Set attribute value with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") @@ -550,6 +553,7 @@ namespace pugi // Set node name/value (returns false if node is empty, there is not enough memory, or node can not have name/value) bool set_name(const char_t* rhs); + bool set_value(const char_t* rhs, size_t sz); bool set_value(const char_t* rhs); // Add attribute with specified name. Returns added attribute, or empty attribute on errors. @@ -775,6 +779,7 @@ namespace pugi bool as_bool(bool def = false) const; // Set text (returns false if object is empty or there is not enough memory) + bool set(const char_t* rhs, size_t sz); bool set(const char_t* rhs); // Set text with type conversion (numbers are converted to strings, boolean is converted to "true"/"false") From 5cc4a61d66cf234cfa59d7a1914ab4462bcb583a Mon Sep 17 00:00:00 2001 From: Alex Date: Wed, 31 May 2023 06:28:03 +0000 Subject: [PATCH 16/18] Fix Heap-buffer-overflow READ in Assimp::MD5::MD5MeshParser::MD5MeshParser --- code/AssetLib/MD5/MD5Parser.cpp | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/code/AssetLib/MD5/MD5Parser.cpp b/code/AssetLib/MD5/MD5Parser.cpp index dce4c5732..97dedab71 100644 --- a/code/AssetLib/MD5/MD5Parser.cpp +++ b/code/AssetLib/MD5/MD5Parser.cpp @@ -228,15 +228,20 @@ bool MD5Parser::ParseSection(Section &out) { out.data[out.length] = '\0'; // parse a string, enclosed in quotation marks -#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \ - while ('\"' != *sz) \ - ++sz; \ - const char *szStart = ++sz; \ - while ('\"' != *sz) \ - ++sz; \ - const char *szEnd = (sz++); \ - out.length = (ai_uint32)(szEnd - szStart); \ - ::memcpy(out.data, szStart, out.length); \ +#define AI_MD5_PARSE_STRING_IN_QUOTATION(out) \ + out.length = 0; \ + while ('\"' != *sz && '\0' != *sz) \ + ++sz; \ + if ('\0' != *sz) { \ + const char *szStart = ++sz; \ + while ('\"' != *sz && '\0' != *sz) \ + ++sz; \ + if ('\0' != *sz) { \ + const char *szEnd = (sz++); \ + out.length = (ai_uint32)(szEnd - szStart); \ + ::memcpy(out.data, szStart, out.length); \ + } \ + } \ out.data[out.length] = '\0'; // ------------------------------------------------------------------------------------------------ // .MD5MESH parsing function From 23f9990b220a262f14d4c192e737a91294fcebf8 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 4 Jun 2023 07:50:00 +0000 Subject: [PATCH 17/18] Fix UNKNOWN READ in aiTexture::~aiTexture --- code/AssetLib/MDL/MDLLoader.cpp | 2 +- code/AssetLib/MDL/MDLMaterialLoader.cpp | 9 ++++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/code/AssetLib/MDL/MDLLoader.cpp b/code/AssetLib/MDL/MDLLoader.cpp index 76b61cda5..098b53e76 100644 --- a/code/AssetLib/MDL/MDLLoader.cpp +++ b/code/AssetLib/MDL/MDLLoader.cpp @@ -274,7 +274,7 @@ void MDLImporter::InternReadFile(const std::string &pFile, // ------------------------------------------------------------------------------------------------ // Check whether we're still inside the valid file range void MDLImporter::SizeCheck(const void *szPos) { - if (!szPos || (const unsigned char *)szPos > this->mBuffer + this->iFileSize) { + if (!szPos || (const unsigned char *)szPos > this->mBuffer + this->iFileSize || szPos < this->mBuffer) { throw DeadlyImportError("Invalid MDL file. The file is too small " "or contains invalid data."); } diff --git a/code/AssetLib/MDL/MDLMaterialLoader.cpp b/code/AssetLib/MDL/MDLMaterialLoader.cpp index 799368264..fbda40151 100644 --- a/code/AssetLib/MDL/MDLMaterialLoader.cpp +++ b/code/AssetLib/MDL/MDLMaterialLoader.cpp @@ -703,7 +703,14 @@ void MDLImporter::SkipSkinLump_3DGS_MDL7( tex.pcData = bad_texel; tex.mHeight = iHeight; tex.mWidth = iWidth; - ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex); + + try { + ParseTextureColorData(szCurrent, iMasked, &iSkip, &tex); + } catch (...) { + // FIX: Important, otherwise the destructor will crash + tex.pcData = nullptr; + throw; + } // FIX: Important, otherwise the destructor will crash tex.pcData = nullptr; From cb8602915399545f0a7cb7dd4fddc1fef2ad954c Mon Sep 17 00:00:00 2001 From: Kristjan Skutta Date: Tue, 6 Jun 2023 06:16:26 +0200 Subject: [PATCH 18/18] Fixed missing config property lookup for removal of empty bones. --- code/PostProcessing/LimitBoneWeightsProcess.cpp | 7 ++++--- code/PostProcessing/LimitBoneWeightsProcess.h | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/code/PostProcessing/LimitBoneWeightsProcess.cpp b/code/PostProcessing/LimitBoneWeightsProcess.cpp index 7047ec0f1..16b32143e 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.cpp +++ b/code/PostProcessing/LimitBoneWeightsProcess.cpp @@ -81,6 +81,7 @@ void LimitBoneWeightsProcess::Execute( aiScene* pScene) { // Executes the post processing step on the given imported data. void LimitBoneWeightsProcess::SetupProperties(const Importer* pImp) { this->mMaxWeights = pImp->GetPropertyInteger(AI_CONFIG_PP_LBW_MAX_WEIGHTS,AI_LMW_MAX_WEIGHTS); + this->mRemoveEmptyBones = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES, 1) != 0; } // ------------------------------------------------------------------------------------------------ @@ -172,9 +173,9 @@ void LimitBoneWeightsProcess::ProcessMesh(aiMesh* pMesh) { } // remove empty bones -#ifdef AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES - pMesh->mNumBones = removeEmptyBones(pMesh); -#endif // AI_CONFIG_IMPORT_REMOVE_EMPTY_BONES + if (mRemoveEmptyBones) { + pMesh->mNumBones = removeEmptyBones(pMesh); + } if (!DefaultLogger::isNullLogger()) { ASSIMP_LOG_INFO("Removed ", removed, " weights. Input bones: ", old_bones, ". Output bones: ", pMesh->mNumBones); diff --git a/code/PostProcessing/LimitBoneWeightsProcess.h b/code/PostProcessing/LimitBoneWeightsProcess.h index b19d536cf..8e5ebd80d 100644 --- a/code/PostProcessing/LimitBoneWeightsProcess.h +++ b/code/PostProcessing/LimitBoneWeightsProcess.h @@ -133,6 +133,7 @@ public: /** Maximum number of bones influencing any single vertex. */ unsigned int mMaxWeights; + bool mRemoveEmptyBones; }; } // end of namespace Assimp