Added arbitrary recursive metadata to allow for glTF2's extensions to be properly represented.
Primary changes are to include/assimp/metadata.h, adding in the aiMetadata GetAiType function, adding the operator= to allow an aiMetadata type to be assigned, adding a check for the AI_AIMETADATA type flag as it can't be trivially memcpy'd. operator= is implemented with a by-value argument as then the copy is made by the copy constructor and we can just swap everything out and let the destructor handle the mess. Implemented parsing of the "extensions" flag on all glTF2 Nodes. Doesn't use the ReadValue helper function on numbers as it did not seem to fill out the Nullable structure properly.pull/3298/head
parent
8a57d5df40
commit
f6b4370f6a
|
@ -784,6 +784,48 @@ struct Mesh : public Object {
|
||||||
void Read(Value &pJSON_Object, Asset &pAsset_Root);
|
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;
|
||||||
|
|
||||||
|
// 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) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CustomExtension() = default;
|
||||||
|
|
||||||
|
CustomExtension(const CustomExtension& other)
|
||||||
|
: Object(other)
|
||||||
|
, mStringValue(other.mStringValue)
|
||||||
|
, mDoubleValue(other.mDoubleValue)
|
||||||
|
, mUint64Value(other.mUint64Value)
|
||||||
|
, mInt64Value(other.mInt64Value)
|
||||||
|
, mValues(other.mValues)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct Node : public Object {
|
struct Node : public Object {
|
||||||
std::vector<Ref<Node>> children;
|
std::vector<Ref<Node>> children;
|
||||||
std::vector<Ref<Mesh>> meshes;
|
std::vector<Ref<Mesh>> meshes;
|
||||||
|
@ -802,6 +844,8 @@ struct Node : public Object {
|
||||||
|
|
||||||
Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper.
|
Ref<Node> parent; //!< This is not part of the glTF specification. Used as a helper.
|
||||||
|
|
||||||
|
CustomExtension extensions;
|
||||||
|
|
||||||
Node() {}
|
Node() {}
|
||||||
void Read(Value &obj, Asset &r);
|
void Read(Value &obj, Asset &r);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1207,6 +1207,43 @@ 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;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
inline void Node::Read(Value &obj, Asset &r) {
|
inline void Node::Read(Value &obj, Asset &r) {
|
||||||
if (name.empty()) {
|
if (name.empty()) {
|
||||||
name = id;
|
name = id;
|
||||||
|
@ -1261,6 +1298,8 @@ inline void Node::Read(Value &obj, Asset &r) {
|
||||||
|
|
||||||
Value *curExtensions = FindObject(obj, "extensions");
|
Value *curExtensions = FindObject(obj, "extensions");
|
||||||
if (nullptr != curExtensions) {
|
if (nullptr != curExtensions) {
|
||||||
|
this->extensions = ReadExtensions("extensions", *curExtensions);
|
||||||
|
|
||||||
if (r.extensionsUsed.KHR_lights_punctual) {
|
if (r.extensionsUsed.KHR_lights_punctual) {
|
||||||
if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) {
|
if (Value *ext = FindObject(*curExtensions, "KHR_lights_punctual")) {
|
||||||
Value *curLight = FindUInt(*ext, "light");
|
Value *curLight = FindUInt(*ext, "light");
|
||||||
|
|
|
@ -847,6 +847,24 @@ static std::string GetNodeName(const Node &node) {
|
||||||
return node.name.empty() ? node.id : node.name;
|
return node.name.empty() ? node.id : node.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension, unsigned int depth = 0) {
|
||||||
|
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.mValues.isPresent) {
|
||||||
|
aiMetadata val;
|
||||||
|
for (size_t i = 0; i < extension.mValues.value.size(); ++i) {
|
||||||
|
ParseExtensions(&val, extension.mValues.value[i], depth + 2);
|
||||||
|
}
|
||||||
|
metadata->Add(extension.name.c_str(), val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) {
|
aiNode *ImportNode(aiScene *pScene, glTF2::Asset &r, std::vector<unsigned int> &meshOffsets, glTF2::Ref<glTF2::Node> &ptr) {
|
||||||
Node &node = *ptr;
|
Node &node = *ptr;
|
||||||
|
|
||||||
|
@ -863,6 +881,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);
|
GetNodeTransform(ainode->mTransformation, node);
|
||||||
|
|
||||||
if (!node.meshes.empty()) {
|
if (!node.meshes.empty()) {
|
||||||
|
@ -957,8 +980,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
|
//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
|
//it is added to meta data of parent node, because there is no other place to put it
|
||||||
if (node.light->range.isPresent) {
|
if (node.light->range.isPresent) {
|
||||||
ainode->mMetaData = aiMetadata::Alloc(1);
|
if (!ainode->mMetaData) {
|
||||||
ainode->mMetaData->Set(0, "PBR_LightRange", node.light->range.value);
|
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_DOUBLE = 4,
|
||||||
AI_AISTRING = 5,
|
AI_AISTRING = 5,
|
||||||
AI_AIVECTOR3D = 6,
|
AI_AIVECTOR3D = 6,
|
||||||
AI_META_MAX = 7,
|
AI_AIMETADATA = 7,
|
||||||
|
AI_META_MAX = 8,
|
||||||
|
|
||||||
#ifndef SWIG
|
#ifndef SWIG
|
||||||
FORCE_32BIT = INT_MAX
|
FORCE_32BIT = INT_MAX
|
||||||
|
@ -100,6 +101,8 @@ struct aiMetadataEntry {
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
struct aiMetadata;
|
||||||
|
|
||||||
// -------------------------------------------------------------------------------
|
// -------------------------------------------------------------------------------
|
||||||
/**
|
/**
|
||||||
* Helper functions to get the aiType enum entry for a type
|
* 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 &) {
|
inline aiMetadataType GetAiType(const aiVector3D &) {
|
||||||
return AI_AIVECTOR3D;
|
return AI_AIVECTOR3D;
|
||||||
}
|
}
|
||||||
|
inline aiMetadataType GetAiType(const aiMetadata &) {
|
||||||
|
return AI_AIMETADATA;
|
||||||
|
}
|
||||||
|
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
|
@ -204,6 +210,11 @@ struct aiMetadata {
|
||||||
rhs.Get<aiVector3D>(mKeys[i], v);
|
rhs.Get<aiVector3D>(mKeys[i], v);
|
||||||
mValues[i].mData = new aiVector3D(v);
|
mValues[i].mData = new aiVector3D(v);
|
||||||
} break;
|
} break;
|
||||||
|
case AI_AIMETADATA: {
|
||||||
|
aiMetadata v;
|
||||||
|
rhs.Get<aiMetadata>(mKeys[i], v);
|
||||||
|
mValues[i].mData = new aiMetadata(v);
|
||||||
|
} break;
|
||||||
#ifndef SWIG
|
#ifndef SWIG
|
||||||
case FORCE_32BIT:
|
case FORCE_32BIT:
|
||||||
#endif
|
#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.
|
* @brief The destructor.
|
||||||
*/
|
*/
|
||||||
~aiMetadata() {
|
~aiMetadata() {
|
||||||
|
@ -245,6 +264,9 @@ struct aiMetadata {
|
||||||
case AI_AIVECTOR3D:
|
case AI_AIVECTOR3D:
|
||||||
delete static_cast<aiVector3D *>(data);
|
delete static_cast<aiVector3D *>(data);
|
||||||
break;
|
break;
|
||||||
|
case AI_AIMETADATA:
|
||||||
|
delete static_cast<aiMetadata *>(data);
|
||||||
|
break;
|
||||||
#ifndef SWIG
|
#ifndef SWIG
|
||||||
case FORCE_32BIT:
|
case FORCE_32BIT:
|
||||||
#endif
|
#endif
|
||||||
|
@ -323,8 +345,10 @@ struct aiMetadata {
|
||||||
mValues[index].mType = GetAiType(value);
|
mValues[index].mType = GetAiType(value);
|
||||||
|
|
||||||
// Copy the given value to the dynamic storage
|
// 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));
|
::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 {
|
} else {
|
||||||
mValues[index].mData = new T(value);
|
mValues[index].mData = new T(value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue