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.pull/4658/head
parent
749fe898b1
commit
417481d17f
|
@ -376,6 +376,51 @@ struct CustomExtension {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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
|
//! Base class for all glTF top-level objects
|
||||||
struct Object {
|
struct Object {
|
||||||
int index; //!< The index of this object within its property container
|
int index; //!< The index of this object within its property container
|
||||||
|
@ -384,7 +429,7 @@ struct Object {
|
||||||
std::string name; //!< The user-defined name of this object
|
std::string name; //!< The user-defined name of this object
|
||||||
|
|
||||||
CustomExtension customExtensions;
|
CustomExtension customExtensions;
|
||||||
CustomExtension extras;
|
Extras extras;
|
||||||
|
|
||||||
//! Objects marked as special are not exported (used to emulate the binary body buffer)
|
//! Objects marked as special are not exported (used to emulate the binary body buffer)
|
||||||
virtual bool IsSpecial() const { return false; }
|
virtual bool IsSpecial() const { return false; }
|
||||||
|
|
|
@ -139,6 +139,50 @@ inline CustomExtension ReadExtensions(const char *name, Value &obj) {
|
||||||
return ret;
|
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,
|
inline void CopyData(size_t count, const uint8_t *src, size_t src_stride,
|
||||||
uint8_t *dst, size_t dst_stride) {
|
uint8_t *dst, size_t dst_stride) {
|
||||||
if (src_stride == dst_stride) {
|
if (src_stride == dst_stride) {
|
||||||
|
@ -248,7 +292,7 @@ inline void Object::ReadExtensions(Value &val) {
|
||||||
|
|
||||||
inline void Object::ReadExtras(Value &val) {
|
inline void Object::ReadExtras(Value &val) {
|
||||||
if (Value *curExtras = FindObject(val, "extras")) {
|
if (Value *curExtras = FindObject(val, "extras")) {
|
||||||
this->extras = glTF2::ReadExtensions("extras", *curExtras);
|
this->extras = glTF2::ReadExtras(*curExtras);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
inline void Write(Value& obj, Node& n, AssetWriter& w)
|
||||||
{
|
{
|
||||||
if (n.matrix.isPresent) {
|
if (n.matrix.isPresent) {
|
||||||
|
@ -655,6 +693,8 @@ namespace glTF2 {
|
||||||
if(n.skeletons.size()) {
|
if(n.skeletons.size()) {
|
||||||
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
|
AddRefsVector(obj, "skeletons", n.skeletons, w.mAl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WriteExtras(obj, n.extras, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/)
|
inline void Write(Value& /*obj*/, Program& /*b*/, AssetWriter& /*w*/)
|
||||||
|
@ -728,7 +768,6 @@ namespace glTF2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline AssetWriter::AssetWriter(Asset& a)
|
inline AssetWriter::AssetWriter(Asset& a)
|
||||||
: mDoc()
|
: mDoc()
|
||||||
, mAsset(a)
|
, mAsset(a)
|
||||||
|
|
|
@ -445,6 +445,57 @@ inline Ref<Accessor> ExportData(Asset &a, std::string &meshName, Ref<Buffer> &bu
|
||||||
return acc;
|
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) {
|
inline void SetSamplerWrap(SamplerWrap &wrap, aiTextureMapMode map) {
|
||||||
switch (map) {
|
switch (map) {
|
||||||
case aiTextureMapMode_Clamp:
|
case aiTextureMapMode_Clamp:
|
||||||
|
@ -1355,6 +1406,10 @@ unsigned int glTF2Exporter::ExportNode(const aiNode *n, Ref<Node> &parent) {
|
||||||
node->parent = parent;
|
node->parent = parent;
|
||||||
node->name = name;
|
node->name = name;
|
||||||
|
|
||||||
|
if (n->mMetaData != nullptr && n->mMetaData->mNumProperties > 0) {
|
||||||
|
ExportNodeExtras(n->mMetaData, node->extras);
|
||||||
|
}
|
||||||
|
|
||||||
if (!n->mTransformation.IsIdentity()) {
|
if (!n->mTransformation.IsIdentity()) {
|
||||||
if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) {
|
if (mScene->mNumAnimations > 0 || (mProperties && mProperties->HasPropertyBool("GLTF2_NODE_IN_TRS"))) {
|
||||||
aiQuaternion quaternion;
|
aiQuaternion quaternion;
|
||||||
|
|
|
@ -1033,11 +1033,33 @@ void ParseExtensions(aiMetadata *metadata, const CustomExtension &extension) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ParseExtras(aiMetadata *metadata, const CustomExtension &extension) {
|
void ParseExtrasValue(aiMetadata *metadata, const ExtrasValue &value) {
|
||||||
if (extension.mValues.isPresent) {
|
|
||||||
for (auto const &subExtension : extension.mValues.value) {
|
if (value.mBoolValue.isPresent) {
|
||||||
ParseExtensions(metadata, subExtension);
|
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;
|
ainode->mMetaData = new aiMetadata;
|
||||||
if (node.customExtensions) {
|
if (node.customExtensions) {
|
||||||
ParseExtensions(ainode->mMetaData, node.customExtensions);
|
ParseExtensions(ainode->mMetaData, node.customExtensions);
|
||||||
}
|
}
|
||||||
if (node.extras) {
|
if (node.extras.HasExtras()) {
|
||||||
ParseExtras(ainode->mMetaData, node.extras);
|
ParseExtras(ainode->mMetaData, node.extras);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1349,6 +1349,9 @@ void SceneCombiner::Copy(aiMetadata **_dest, const aiMetadata *src) {
|
||||||
case AI_AIVECTOR3D:
|
case AI_AIVECTOR3D:
|
||||||
out.mData = new aiVector3D(*static_cast<aiVector3D *>(in.mData));
|
out.mData = new aiVector3D(*static_cast<aiVector3D *>(in.mData));
|
||||||
break;
|
break;
|
||||||
|
case AI_AIMETADATA:
|
||||||
|
out.mData = new aiMetadata(*static_cast<aiMetadata *>(in.mData));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
ai_assert(false);
|
ai_assert(false);
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue