ソースを参照

Merge pull request #3955 from Evangel63/master

Add scene metadata for glTF2 files as allowed by the glTF2 specification
Kim Kulling 4 年 前
コミット
bd9b28bc45

+ 51 - 46
code/AssetLib/glTF2/glTF2Asset.h

@@ -356,6 +356,53 @@ struct Nullable {
             isPresent(true) {}
 };
 
+struct CustomExtension {
+    //
+    // A struct containing custom extension data added to a glTF2 file
+    // Has to contain Object, Array, String, Double, Uint64, and Int64 at a minimum
+    // String, Double, Uint64, and Int64 are stored in the Nullables
+    // Object and Array are stored in the std::vector
+    //
+    std::string name;
+
+    Nullable<std::string> mStringValue;
+    Nullable<double> mDoubleValue;
+    Nullable<uint64_t> mUint64Value;
+    Nullable<int64_t> mInt64Value;
+    Nullable<bool> mBoolValue;
+
+    // std::vector<CustomExtension> handles both Object and Array
+    Nullable<std::vector<CustomExtension>> mValues;
+
+    operator bool() const {
+        return Size() != 0;
+    }
+
+    size_t Size() const {
+        if (mValues.isPresent) {
+            return mValues.value.size();
+        } else if (mStringValue.isPresent || mDoubleValue.isPresent || mUint64Value.isPresent || mInt64Value.isPresent || mBoolValue.isPresent) {
+            return 1;
+        }
+        return 0;
+    }
+
+    CustomExtension() = default;
+    
+    ~CustomExtension() = default;
+    
+    CustomExtension(const CustomExtension &other) :
+            name(other.name),
+            mStringValue(other.mStringValue),
+            mDoubleValue(other.mDoubleValue),
+            mUint64Value(other.mUint64Value),
+            mInt64Value(other.mInt64Value),
+            mBoolValue(other.mBoolValue),
+            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
@@ -363,6 +410,8 @@ struct Object {
     std::string id; //!< The globally unique ID used to reference this object
     std::string name; //!< The user-defined name of this object
 
+    CustomExtension customExtensions;
+
     //! Objects marked as special are not exported (used to emulate the binary body buffer)
     virtual bool IsSpecial() const { return false; }
 
@@ -377,6 +426,8 @@ struct Object {
     inline Value *FindArray(Value &val, const char *id);
     inline Value *FindObject(Value &val, const char *id);
     inline Value *FindExtension(Value &val, const char *extensionId);
+
+    inline void ReadExtensions(Value &val);
 };
 
 //
@@ -834,50 +885,6 @@ struct Mesh : public Object {
     void Read(Value &pJSON_Object, Asset &pAsset_Root);
 };
 
-struct CustomExtension : public Object {
-    //
-    // A struct containing custom extension data added to a glTF2 file
-    // Has to contain Object, Array, String, Double, Uint64, and Int64 at a minimum
-    // String, Double, Uint64, and Int64 are stored in the Nullables
-    // Object and Array are stored in the std::vector
-    //
-
-    Nullable<std::string> mStringValue;
-    Nullable<double> mDoubleValue;
-    Nullable<uint64_t> mUint64Value;
-    Nullable<int64_t> mInt64Value;
-    Nullable<bool> mBoolValue;
-
-    // std::vector<CustomExtension> handles both Object and Array
-    Nullable<std::vector<CustomExtension>> mValues;
-
-    operator bool() const {
-        return Size() != 0;
-    }
-
-    size_t Size() const {
-        if (mValues.isPresent) {
-            return mValues.value.size();
-        } else if (mStringValue.isPresent || mDoubleValue.isPresent || mUint64Value.isPresent || mInt64Value.isPresent || mBoolValue.isPresent) {
-            return 1;
-        }
-        return 0;
-    }
-
-    CustomExtension() = default;
-
-    CustomExtension(const CustomExtension &other)
-        : Object(other)
-        , mStringValue(other.mStringValue)
-        , mDoubleValue(other.mDoubleValue)
-        , mUint64Value(other.mUint64Value)
-        , mInt64Value(other.mInt64Value)
-        , mBoolValue(other.mBoolValue)
-        , mValues(other.mValues)
-    {
-    }
-};
-
 struct Node : public Object {
     std::vector<Ref<Node>> children;
     std::vector<Ref<Mesh>> meshes;
@@ -896,8 +903,6 @@ struct Node : public Object {
 
     Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper.
 
-    CustomExtension extensions;
-
     Node() {}
     void Read(Value &obj, Asset &r);
 };

+ 44 - 38
code/AssetLib/glTF2/glTF2Asset.inl

@@ -304,6 +304,43 @@ inline Value *FindObject(Document &doc, const char *memberId) {
 inline Value *FindExtension(Value &val, const char *extensionId) {
     return FindExtensionInContext(val, extensionId, "the document");
 }
+
+inline CustomExtension ReadExtensions(const char *name, Value &obj) {
+    CustomExtension ret;
+    ret.name = name;
+    if (obj.IsObject()) {
+        ret.mValues.isPresent = true;
+        for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
+            auto &val = it->value;
+            ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
+        }
+    } else if (obj.IsArray()) {
+        ret.mValues.value.reserve(obj.Size());
+        ret.mValues.isPresent = true;
+        for (unsigned int i = 0; i < obj.Size(); ++i) {
+            ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
+        }
+    } else if (obj.IsNumber()) {
+        if (obj.IsUint64()) {
+            ret.mUint64Value.value = obj.GetUint64();
+            ret.mUint64Value.isPresent = true;
+        } else if (obj.IsInt64()) {
+            ret.mInt64Value.value = obj.GetInt64();
+            ret.mInt64Value.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;
+}
+
 } // namespace
 
 inline Value *Object::FindString(Value &val, const char *memberId) {
@@ -330,6 +367,12 @@ inline Value *Object::FindExtension(Value &val, const char *extensionId) {
     return FindExtensionInContext(val, extensionId, id.c_str(), name.c_str());
 }
 
+inline void Object::ReadExtensions(Value &val) {
+    if (Value *curExtensions = FindObject(val, "extensions")) {
+        this->customExtensions = glTF2::ReadExtensions("extensions", *curExtensions);
+    }
+}
+
 #ifdef ASSIMP_ENABLE_DRACO
 
 template <typename T>
@@ -569,6 +612,7 @@ Ref<T> LazyDict<T>::Retrieve(unsigned int i) {
     inst->oIndex = i;
     ReadMember(obj, "name", inst->name);
     inst->Read(obj, mAsset);
+    inst->ReadExtensions(obj);
 
     Ref<T> result = Add(inst.release());
     mRecursiveReferenceCheck.erase(i);
@@ -1683,42 +1727,6 @@ inline void Light::Read(Value &obj, Asset & /*r*/) {
     }
 }
 
-inline CustomExtension ReadExtensions(const char *name, Value &obj) {
-    CustomExtension ret;
-    ret.name = name;
-    if (obj.IsObject()) {
-        ret.mValues.isPresent = true;
-        for (auto it = obj.MemberBegin(); it != obj.MemberEnd(); ++it) {
-            auto &val = it->value;
-            ret.mValues.value.push_back(ReadExtensions(it->name.GetString(), val));
-        }
-    } else if (obj.IsArray()) {
-        ret.mValues.value.reserve(obj.Size());
-        ret.mValues.isPresent = true;
-        for (unsigned int i = 0; i < obj.Size(); ++i) {
-            ret.mValues.value.push_back(ReadExtensions(name, obj[i]));
-        }
-    } else if (obj.IsNumber()) {
-        if (obj.IsUint64()) {
-            ret.mUint64Value.value = obj.GetUint64();
-            ret.mUint64Value.isPresent = true;
-        } else if (obj.IsInt64()) {
-            ret.mInt64Value.value = obj.GetInt64();
-            ret.mInt64Value.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 void Node::Read(Value &obj, Asset &r) {
     if (name.empty()) {
         name = id;
@@ -1775,8 +1783,6 @@ inline void Node::Read(Value &obj, Asset &r) {
 
     Value *curExtensions = FindObject(obj, "extensions");
     if (nullptr != curExtensions) {
-        this->extensions = ReadExtensions("extensions", *curExtensions);
-
         if (r.extensionsUsed.KHR_lights_punctual) {
             if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) {
                 Value *curLight = FindUInt(*ext, "light");

+ 8 - 4
code/AssetLib/glTF2/glTF2Importer.cpp

@@ -503,7 +503,7 @@ void glTF2Importer::ImportMeshes(glTF2::Asset &r) {
                                                "\" does not match the vertex count");
                     continue;
                 }
-                
+
                 auto componentType = attr.color[c]->componentType;
                 if (componentType == glTF2::ComponentType_FLOAT) {
                     attr.color[c]->ExtractData(aim->mColors[c]);
@@ -1016,9 +1016,9 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
             }
         }
 
-        if (node.extensions) {
+        if (node.customExtensions) {
             ainode->mMetaData = new aiMetadata;
-            ParseExtensions(ainode->mMetaData, node.extensions);
+            ParseExtensions(ainode->mMetaData, node.customExtensions);
         }
 
         GetNodeTransform(ainode->mTransformation, node);
@@ -1512,7 +1512,8 @@ void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) {
     const bool hasVersion = !a.asset.version.empty();
     const bool hasGenerator = !a.asset.generator.empty();
     const bool hasCopyright = !a.asset.copyright.empty();
-    if (hasVersion || hasGenerator || hasCopyright) {
+    const bool hasSceneMetadata = a.scene->customExtensions;
+    if (hasVersion || hasGenerator || hasCopyright || hasSceneMetadata) {
         mScene->mMetaData = new aiMetadata;
         if (hasVersion) {
             mScene->mMetaData->Add(AI_METADATA_SOURCE_FORMAT_VERSION, aiString(a.asset.version));
@@ -1523,6 +1524,9 @@ void glTF2Importer::ImportCommonMetadata(glTF2::Asset& a) {
         if (hasCopyright) {
             mScene->mMetaData->Add(AI_METADATA_SOURCE_COPYRIGHT, aiString(a.asset.copyright));
         }
+        if (hasSceneMetadata) {
+            ParseExtensions(mScene->mMetaData, a.scene->customExtensions);
+        }
     }
 }
 

+ 1 - 1
include/assimp/metadata.h

@@ -432,7 +432,7 @@ struct aiMetadata {
 
     /// Check whether there is a metadata entry for the given key.
     /// \param [in] Key - the key value value to check for.
-    inline bool HasKey(const char *key) {
+    inline bool HasKey(const char *key) const {
         if (nullptr == key) {
             return false;
         }