Skip to content

Commit

Permalink
Merge pull request #3298 from Evangel63/recursive_metadata
Browse files Browse the repository at this point in the history
Added arbitrary recursive metadata to allow for glTF2's extensions to…
  • Loading branch information
kimkulling committed Jun 27, 2020
2 parents 8a57d5d + 6d85280 commit 45531df
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 6 deletions.
46 changes: 46 additions & 0 deletions code/AssetLib/glTF2/glTF2Asset.h
Expand Up @@ -784,6 +784,50 @@ 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();
}

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;
Expand All @@ -802,6 +846,8 @@ 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);
};
Expand Down
43 changes: 43 additions & 0 deletions code/AssetLib/glTF2/glTF2Asset.inl
Expand Up @@ -1207,6 +1207,47 @@ 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;
Expand Down Expand Up @@ -1261,6 +1302,8 @@ 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");
Expand Down
34 changes: 32 additions & 2 deletions code/AssetLib/glTF2/glTF2Importer.cpp
Expand Up @@ -847,6 +847,26 @@ static std::string GetNodeName(const Node &node) {
return node.name.empty() ? node.id : node.name;
}

void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) {
if (extension.mStringValue.isPresent) {
metadata->Add(extension.name.c_str(), aiString(extension.mStringValue.value));
} else if (extension.mDoubleValue.isPresent) {
metadata->Add(extension.name.c_str(), extension.mDoubleValue.value);
} else if (extension.mUint64Value.isPresent) {
metadata->Add(extension.name.c_str(), extension.mUint64Value.value);
} else if (extension.mInt64Value.isPresent) {
metadata->Add(extension.name.c_str(), static_cast<int32_t>(extension.mInt64Value.value));
} else if (extension.mBoolValue.isPresent) {
metadata->Add(extension.name.c_str(), extension.mBoolValue.value);
} else if (extension.mValues.isPresent) {
aiMetadata val;
for (size_t i = 0; i < extension.mValues.value.size(); ++i) {
ParseExtensions(&val, extension.mValues.value[i]);
}
metadata->Add(extension.name.c_str(), val);
}
}

aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) {
Node &node = *ptr;

Expand All @@ -863,6 +883,11 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
}
}

if (node.extensions) {
ainode->mMetaData = new aiMetadata;
ParseExtensions(ainode->mMetaData, node.extensions);
}

GetNodeTransform(ainode->mTransformation, node);

if (!node.meshes.empty()) {
Expand Down Expand Up @@ -957,8 +982,13 @@ aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &
//range is optional - see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_lights_punctual
//it is added to meta data of parent node, because there is no other place to put it
if (node.light->range.isPresent) {
ainode->mMetaData = aiMetadata::Alloc(1);
ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
if (!ainode->mMetaData) {
ainode->mMetaData = aiMetadata::Alloc(1);
ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
}
else {
ainode->mMetaData->Add("PBR_LightRange", node.light->range.value);
}
}
}

Expand Down
113 changes: 110 additions & 3 deletions include/assimp/metadata.h
Expand Up @@ -69,7 +69,8 @@ typedef enum aiMetadataType {
AI_DOUBLE = 4,
AI_AISTRING = 5,
AI_AIVECTOR3D = 6,
AI_META_MAX = 7,
AI_AIMETADATA = 7,
AI_META_MAX = 8,

#ifndef SWIG
FORCE_32BIT = INT_MAX
Expand Down Expand Up @@ -100,6 +101,8 @@ struct aiMetadataEntry {

#include <string>

struct aiMetadata;

// -------------------------------------------------------------------------------
/**
* Helper functions to get the aiType enum entry for a type
Expand Down Expand Up @@ -127,6 +130,9 @@ inline aiMetadataType GetAiType(const aiString &) {
inline aiMetadataType GetAiType(const aiVector3D &) {
return AI_AIVECTOR3D;
}
inline aiMetadataType GetAiType(const aiMetadata &) {
return AI_AIMETADATA;
}

#endif // __cplusplus

Expand Down Expand Up @@ -204,6 +210,11 @@ struct aiMetadata {
rhs.Get<aiVector3D>(mKeys[i], v);
mValues[i].mData = new aiVector3D(v);
} break;
case AI_AIMETADATA: {
aiMetadata v;
rhs.Get<aiMetadata>(mKeys[i], v);
mValues[i].mData = new aiMetadata(v);
} break;
#ifndef SWIG
case FORCE_32BIT:
#endif
Expand All @@ -213,7 +224,15 @@ struct aiMetadata {
}
}

/**
aiMetadata &operator=(aiMetadata rhs) {
using std::swap;
swap(mNumProperties, rhs.mNumProperties);
swap(mKeys, rhs.mKeys);
swap(mValues, rhs.mValues);
return *this;
}

/**
* @brief The destructor.
*/
~aiMetadata() {
Expand Down Expand Up @@ -245,6 +264,9 @@ struct aiMetadata {
case AI_AIVECTOR3D:
delete static_cast<aiVector3D *>(data);
break;
case AI_AIMETADATA:
delete static_cast<aiMetadata *>(data);
break;
#ifndef SWIG
case FORCE_32BIT:
#endif
Expand Down Expand Up @@ -323,8 +345,10 @@ struct aiMetadata {
mValues[index].mType = GetAiType(value);

// Copy the given value to the dynamic storage
if (nullptr != mValues[index].mData) {
if (nullptr != mValues[index].mData && AI_AIMETADATA != mValues[index].mType) {
::memcpy(mValues[index].mData, &value, sizeof(T));
} else if (nullptr != mValues[index].mData && AI_AIMETADATA == mValues[index].mType) {
*static_cast<T *>(mValues[index].mData) = value;
} else {
mValues[index].mData = new T(value);
}
Expand Down Expand Up @@ -418,6 +442,89 @@ struct aiMetadata {
return false;
}

friend bool CompareKeys(const aiMetadata &lhs, const aiMetadata &rhs) {
if (lhs.mNumProperties != rhs.mNumProperties) {
return false;
}

for (unsigned int i = 0; i < lhs.mNumProperties; ++i) {
if (lhs.mKeys[i] != rhs.mKeys[i]) {
return false;
}
}
return true;
}

friend bool CompareValues(const aiMetadata &lhs, const aiMetadata &rhs) {
if (lhs.mNumProperties != rhs.mNumProperties) {
return false;
}

for (unsigned int i = 0; i < lhs.mNumProperties; ++i) {
if (lhs.mValues[i].mType != rhs.mValues[i].mType) {
return false;
}

switch (lhs.mValues[i].mType) {
case AI_BOOL: {
if (*static_cast<bool *>(lhs.mValues[i].mData) != *static_cast<bool *>(rhs.mValues[i].mData)) {
return false;
}
} break;
case AI_INT32: {
if (*static_cast<int32_t *>(lhs.mValues[i].mData) != *static_cast<int32_t *>(rhs.mValues[i].mData)) {
return false;
}
} break;
case AI_UINT64: {
if (*static_cast<uint64_t *>(lhs.mValues[i].mData) != *static_cast<uint64_t *>(rhs.mValues[i].mData)) {
return false;
}
} break;
case AI_FLOAT: {
if (*static_cast<float *>(lhs.mValues[i].mData) != *static_cast<float *>(rhs.mValues[i].mData)) {
return false;
}
} break;
case AI_DOUBLE: {
if (*static_cast<double *>(lhs.mValues[i].mData) != *static_cast<double *>(rhs.mValues[i].mData)) {
return false;
}
} break;
case AI_AISTRING: {
if (*static_cast<aiString *>(lhs.mValues[i].mData) != *static_cast<aiString *>(rhs.mValues[i].mData)) {
return false;
}
} break;
case AI_AIVECTOR3D: {
if (*static_cast<aiVector3D *>(lhs.mValues[i].mData) != *static_cast<aiVector3D *>(rhs.mValues[i].mData)) {
return false;
}
} break;
case AI_AIMETADATA: {
if (*static_cast<aiMetadata *>(lhs.mValues[i].mData) != *static_cast<aiMetadata *>(rhs.mValues[i].mData)) {
return false;
}
} break;
#ifndef SWIG
case FORCE_32BIT:
#endif
default:
break;
}
}

return true;
}

friend bool operator==(const aiMetadata &lhs, const aiMetadata &rhs) {
return CompareKeys(lhs, rhs) && CompareValues(lhs, rhs);
}

friend bool operator!=(const aiMetadata &lhs, const aiMetadata &rhs) {
return !(lhs == rhs);
}

#endif // __cplusplus
};

Expand Down
11 changes: 10 additions & 1 deletion test/unit/utMetadata.cpp
Expand Up @@ -197,9 +197,11 @@ TEST_F( utMetadata, copy_test ) {
m_data->Set( 5, "aiString", strVal );
aiVector3D vecVal( 1, 2, 3 );
m_data->Set( 6, "aiVector3D", vecVal );
aiMetadata metaVal;
m_data->Set( 7, "aiMetadata", metaVal );

aiMetadata copy( *m_data );
EXPECT_EQ( 7u, copy.mNumProperties );
EXPECT_EQ( 8u, copy.mNumProperties );

// bool test
{
Expand Down Expand Up @@ -251,4 +253,11 @@ TEST_F( utMetadata, copy_test ) {
EXPECT_TRUE( copy.Get( "aiVector3D", v ) );
EXPECT_EQ( vecVal, v );
}

// metadata test
{
aiMetadata v;
EXPECT_TRUE( copy.Get( "aiMetadata", v ) );
EXPECT_EQ( metaVal, v );
}
}

0 comments on commit 45531df

Please sign in to comment.