diff --git a/code/AssetLib/glTF2/glTF2Asset.h b/code/AssetLib/glTF2/glTF2Asset.h index 6aa0f92ed..605cda332 100644 --- a/code/AssetLib/glTF2/glTF2Asset.h +++ b/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 mStringValue; + Nullable mDoubleValue; + Nullable mUint64Value; + Nullable mInt64Value; + Nullable mBoolValue; + + // std::vector handles both Object and Array + Nullable> 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 mStringValue; - Nullable mDoubleValue; - Nullable mUint64Value; - Nullable mInt64Value; - Nullable mBoolValue; - - // std::vector handles both Object and Array - Nullable> 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> children; std::vector> meshes; @@ -896,8 +903,6 @@ struct Node : public Object { Ref parent; //!< This is not part of the glTF specification. Used as a helper. - CustomExtension extensions; - Node() {} void Read(Value &obj, Asset &r); }; diff --git a/code/AssetLib/glTF2/glTF2Asset.inl b/code/AssetLib/glTF2/glTF2Asset.inl index b51ac20c2..4bcfea5f7 100644 --- a/code/AssetLib/glTF2/glTF2Asset.inl +++ b/code/AssetLib/glTF2/glTF2Asset.inl @@ -4,7 +4,6 @@ Open Asset Import Library (assimp) Copyright (c) 2006-2021, assimp team - All rights reserved. Redistribution and use of this software in source and binary forms, @@ -304,6 +303,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 +366,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 @@ -569,6 +611,7 @@ Ref LazyDict::Retrieve(unsigned int i) { inst->oIndex = i; ReadMember(obj, "name", inst->name); inst->Read(obj, mAsset); + inst->ReadExtensions(obj); Ref result = Add(inst.release()); mRecursiveReferenceCheck.erase(i); @@ -733,12 +776,13 @@ inline void Buffer::EncodedRegion_Mark(const size_t pOffset, const size_t pEncod } inline void Buffer::EncodedRegion_SetCurrent(const std::string &pID) { - if ((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) return; + if ((EncodedRegion_Current != nullptr) && (EncodedRegion_Current->ID == pID)) { + return; + } for (SEncodedRegion *reg : EncodedRegion_List) { if (reg->ID == pID) { EncodedRegion_Current = reg; - return; } } @@ -788,10 +832,13 @@ inline bool Buffer::ReplaceData_joint(const size_t pBufferData_Offset, const siz } inline size_t Buffer::AppendData(uint8_t *data, size_t length) { - size_t offset = this->byteLength; + const size_t offset = this->byteLength; + // Force alignment to 4 bits - Grow((length + 3) & ~3); + const size_t paddedLength = (length + 3) & ~3; + Grow(paddedLength); memcpy(mData.get() + offset, data, length); + memset(mData.get() + offset + length, 0, paddedLength - length); return offset; } @@ -820,9 +867,7 @@ inline void Buffer::Grow(size_t amount) { // // struct BufferView // - inline void BufferView::Read(Value &obj, Asset &r) { - if (Value *bufferVal = FindUInt(obj, "buffer")) { buffer = r.buffers.Retrieve(bufferVal->GetUint()); } @@ -842,16 +887,21 @@ inline void BufferView::Read(Value &obj, Asset &r) { } inline uint8_t *BufferView::GetPointer(size_t accOffset) { - if (!buffer) return nullptr; + if (!buffer) { + return nullptr; + } uint8_t *basePtr = buffer->GetPointer(); - if (!basePtr) return nullptr; + if (!basePtr) { + return nullptr; + } size_t offset = accOffset + byteOffset; if (buffer->EncodedRegion_Current != nullptr) { const size_t begin = buffer->EncodedRegion_Current->Offset; const size_t end = begin + buffer->EncodedRegion_Current->DecodedData_Length; - if ((offset >= begin) && (offset < end)) + if ((offset >= begin) && (offset < end)) { return &buffer->EncodedRegion_Current->DecodedData[offset - begin]; + } } return basePtr + offset; @@ -877,18 +927,18 @@ inline void Accessor::Sparse::PatchData(unsigned int elementSize) { while (pIndices != indicesEnd) { size_t offset; switch (indicesType) { - case ComponentType_UNSIGNED_BYTE: - offset = *pIndices; - break; - case ComponentType_UNSIGNED_SHORT: - offset = *reinterpret_cast(pIndices); - break; - case ComponentType_UNSIGNED_INT: - offset = *reinterpret_cast(pIndices); - break; - default: - // have fun with float and negative values from signed types as indices. - throw DeadlyImportError("Unsupported component type in index."); + case ComponentType_UNSIGNED_BYTE: + offset = *pIndices; + break; + case ComponentType_UNSIGNED_SHORT: + offset = *reinterpret_cast(pIndices); + break; + case ComponentType_UNSIGNED_INT: + offset = *reinterpret_cast(pIndices); + break; + default: + // have fun with float and negative values from signed types as indices. + throw DeadlyImportError("Unsupported component type in index."); } offset *= elementSize; @@ -900,7 +950,6 @@ inline void Accessor::Sparse::PatchData(unsigned int elementSize) { } inline void Accessor::Read(Value &obj, Asset &r) { - if (Value *bufferViewVal = FindUInt(obj, "bufferView")) { bufferView = r.bufferViews.Retrieve(bufferViewVal->GetUint()); } @@ -1683,42 +1732,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 +1788,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"); diff --git a/code/AssetLib/glTF2/glTF2Importer.cpp b/code/AssetLib/glTF2/glTF2Importer.cpp index aadc9fb16..d2fb1e9b8 100644 --- a/code/AssetLib/glTF2/glTF2Importer.cpp +++ b/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 & } } - 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); + } } } diff --git a/include/assimp/material.h b/include/assimp/material.h index 2024be07f..f0207c6de 100644 --- a/include/assimp/material.h +++ b/include/assimp/material.h @@ -1499,8 +1499,6 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialFloatArray( ai_real *pOut, unsigned int *pMax); -#ifdef __cplusplus - // --------------------------------------------------------------------------- /** @brief Retrieve a single float property with a specific key from the material. * @@ -1520,7 +1518,7 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialFloatArray( * @return Specifies whether the key has been found. If not, the output * float remains unmodified.*/ // --------------------------------------------------------------------------- -inline aiReturn aiGetMaterialFloat(const aiMaterial *pMat, +inline aiReturn aiGetMaterialFloat(const C_STRUCT aiMaterial *pMat, const char *pKey, unsigned int type, unsigned int index, @@ -1528,14 +1526,6 @@ inline aiReturn aiGetMaterialFloat(const aiMaterial *pMat, return aiGetMaterialFloatArray(pMat, pKey, type, index, pOut, (unsigned int *)0x0); } -#else - -// Use our friend, the C preprocessor -#define aiGetMaterialFloat (pMat, type, index, pKey, pOut) \ - aiGetMaterialFloatArray(pMat, type, index, pKey, pOut, NULL) - -#endif //!__cplusplus - // --------------------------------------------------------------------------- /** @brief Retrieve an array of integer values with a specific key * from a material @@ -1548,8 +1538,6 @@ ASSIMP_API C_ENUM aiReturn aiGetMaterialIntegerArray(const C_STRUCT aiMaterial * int *pOut, unsigned int *pMax); -#ifdef __cplusplus - // --------------------------------------------------------------------------- /** @brief Retrieve an integer property with a specific key from a material * @@ -1563,14 +1551,6 @@ inline aiReturn aiGetMaterialInteger(const C_STRUCT aiMaterial *pMat, return aiGetMaterialIntegerArray(pMat, pKey, type, index, pOut, (unsigned int *)0x0); } -#else - -// use our friend, the C preprocessor -#define aiGetMaterialInteger (pMat, type, index, pKey, pOut) \ - aiGetMaterialIntegerArray(pMat, type, index, pKey, pOut, NULL) - -#endif //!__cplusplus - // --------------------------------------------------------------------------- /** @brief Retrieve a color value from the material property table * diff --git a/include/assimp/metadata.h b/include/assimp/metadata.h index 551a9aba4..57fedfbfc 100644 --- a/include/assimp/metadata.h +++ b/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; }