Merge pull request #3298 from Evangel63/recursive_metadata
Added arbitrary recursive metadata to allow for glTF2's extensions to…pull/3299/head
commit
45531df9aa
|
@ -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;
|
||||
|
@ -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);
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
@ -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");
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -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()) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -100,6 +101,8 @@ struct aiMetadataEntry {
|
|||
|
||||
#include <string>
|
||||
|
||||
struct aiMetadata;
|
||||
|
||||
// -------------------------------------------------------------------------------
|
||||
/**
|
||||
* Helper functions to get the aiType enum entry for a type
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue