Преглед изворни кода

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.
Bengt Rosenberger пре 3 година
родитељ
комит
99c3104588

+ 46 - 1
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<bool> mBoolValue;
+    Nullable<int32_t> mInt32Value;
+    Nullable<uint64_t> mUint64Value;
+    Nullable<float> mFloatValue;
+    Nullable<double> mDoubleValue;
+    Nullable<std::string> mStringValue;
+    Nullable<std::vector<ExtrasValue>> 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<ExtrasValue> 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; }

+ 45 - 1
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);
     }
 }
 

+ 40 - 1
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)

+ 56 - 1
code/AssetLib/glTF2/glTF2Exporter.cpp

@@ -445,6 +445,57 @@ inline Ref<Accessor> ExportData(Asset &a, std::string &meshName, Ref<Buffer> &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<bool *>(metadataEntry.mData);
+        value.mBoolValue.isPresent = true;
+        break;
+    case AI_INT32:
+        value.mInt32Value.value = *static_cast<int32_t *>(metadataEntry.mData);
+        value.mInt32Value.isPresent = true;
+        break;
+    case AI_UINT64:
+        value.mUint64Value.value = *static_cast<uint64_t *>(metadataEntry.mData);
+        value.mUint64Value.isPresent = true;
+        break;
+    case AI_FLOAT:
+        value.mFloatValue.value = *static_cast<double *>(metadataEntry.mData);
+        value.mFloatValue.isPresent = true;
+        break;
+    case AI_DOUBLE:
+        value.mDoubleValue.value = *static_cast<double *>(metadataEntry.mData);
+        value.mDoubleValue.isPresent = true;
+        break;
+    case AI_AISTRING:
+        value.mStringValue.value = static_cast<aiString *>(metadataEntry.mData)->C_Str();
+        value.mStringValue.isPresent = true;
+        break;
+    case AI_AIMETADATA:
+        const aiMetadata *subMetadata = static_cast<aiMetadata *>(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<Node>
  */
@@ -1355,6 +1406,10 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref<Node> &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;

+ 28 - 6
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<unsigned int> &
             }
         }
 
-        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);
             }
         }

+ 3 - 0
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<aiVector3D *>(in.mData));
             break;
+        case AI_AIMETADATA:
+            out.mData = new aiMetadata(*static_cast<aiMetadata *>(in.mData));
+            break;
         default:
             ai_assert(false);
             break;