|
@@ -185,6 +185,17 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
|
|
|
return unique_name;
|
|
|
}
|
|
|
|
|
|
+/// This struct manages nodes which may or may not end up in the node hierarchy.
|
|
|
+/// When a node becomes a child of another node, that node becomes its owner and mOwnership should be released.
|
|
|
+struct FBXConverter::PotentialNode
|
|
|
+{
|
|
|
+ PotentialNode() : mOwnership(new aiNode), mNode(mOwnership.get()) {}
|
|
|
+ PotentialNode(const std::string& name) : mOwnership(new aiNode(name)), mNode(mOwnership.get()) {}
|
|
|
+ aiNode* operator->() { return mNode; }
|
|
|
+ std::unique_ptr<aiNode> mOwnership;
|
|
|
+ aiNode* mNode;
|
|
|
+};
|
|
|
+
|
|
|
/// todo: pre-build node hierarchy
|
|
|
/// todo: get bone from stack
|
|
|
/// todo: make map of aiBone* to aiNode*
|
|
@@ -192,137 +203,129 @@ std::string FBXConverter::MakeUniqueNodeName(const Model *const model, const aiN
|
|
|
void FBXConverter::ConvertNodes(uint64_t id, aiNode *parent, aiNode *root_node) {
|
|
|
const std::vector<const Connection *> &conns = doc.GetConnectionsByDestinationSequenced(id, "Model");
|
|
|
|
|
|
- std::vector<aiNode *> nodes;
|
|
|
+ std::vector<PotentialNode> nodes;
|
|
|
nodes.reserve(conns.size());
|
|
|
|
|
|
- std::vector<aiNode *> nodes_chain;
|
|
|
- std::vector<aiNode *> post_nodes_chain;
|
|
|
-
|
|
|
- try {
|
|
|
- for (const Connection *con : conns) {
|
|
|
- // ignore object-property links
|
|
|
- if (con->PropertyName().length()) {
|
|
|
- // really important we document why this is ignored.
|
|
|
- FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
|
|
|
- continue; //?
|
|
|
- }
|
|
|
-
|
|
|
- // convert connection source object into Object base class
|
|
|
- const Object *const object = con->SourceObject();
|
|
|
- if (nullptr == object) {
|
|
|
- FBXImporter::LogError("failed to convert source object for Model link");
|
|
|
- continue;
|
|
|
- }
|
|
|
+ std::vector<PotentialNode> nodes_chain;
|
|
|
+ std::vector<PotentialNode> post_nodes_chain;
|
|
|
|
|
|
- // FBX Model::Cube, Model::Bone001, etc elements
|
|
|
- // This detects if we can cast the object into this model structure.
|
|
|
- const Model *const model = dynamic_cast<const Model *>(object);
|
|
|
+ for (const Connection *con : conns) {
|
|
|
+ // ignore object-property links
|
|
|
+ if (con->PropertyName().length()) {
|
|
|
+ // really important we document why this is ignored.
|
|
|
+ FBXImporter::LogInfo("ignoring property link - no docs on why this is ignored");
|
|
|
+ continue; //?
|
|
|
+ }
|
|
|
|
|
|
- if (nullptr != model) {
|
|
|
- nodes_chain.clear();
|
|
|
- post_nodes_chain.clear();
|
|
|
+ // convert connection source object into Object base class
|
|
|
+ const Object *const object = con->SourceObject();
|
|
|
+ if (nullptr == object) {
|
|
|
+ FBXImporter::LogError("failed to convert source object for Model link");
|
|
|
+ continue;
|
|
|
+ }
|
|
|
|
|
|
- aiMatrix4x4 new_abs_transform = parent->mTransformation;
|
|
|
- std::string node_name = FixNodeName(model->Name());
|
|
|
- // even though there is only a single input node, the design of
|
|
|
- // assimp (or rather: the complicated transformation chain that
|
|
|
- // is employed by fbx) means that we may need multiple aiNode's
|
|
|
- // to represent a fbx node's transformation.
|
|
|
+ // FBX Model::Cube, Model::Bone001, etc elements
|
|
|
+ // This detects if we can cast the object into this model structure.
|
|
|
+ const Model *const model = dynamic_cast<const Model *>(object);
|
|
|
|
|
|
- // generate node transforms - this includes pivot data
|
|
|
- // if need_additional_node is true then you t
|
|
|
- const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
|
|
|
+ if (nullptr != model) {
|
|
|
+ nodes_chain.clear();
|
|
|
+ post_nodes_chain.clear();
|
|
|
|
|
|
- // assert that for the current node we must have at least a single transform
|
|
|
- ai_assert(nodes_chain.size());
|
|
|
+ aiMatrix4x4 new_abs_transform = parent->mTransformation;
|
|
|
+ std::string node_name = FixNodeName(model->Name());
|
|
|
+ // even though there is only a single input node, the design of
|
|
|
+ // assimp (or rather: the complicated transformation chain that
|
|
|
+ // is employed by fbx) means that we may need multiple aiNode's
|
|
|
+ // to represent a fbx node's transformation.
|
|
|
|
|
|
- if (need_additional_node) {
|
|
|
- nodes_chain.push_back(new aiNode(node_name));
|
|
|
- }
|
|
|
+ // generate node transforms - this includes pivot data
|
|
|
+ // if need_additional_node is true then you t
|
|
|
+ const bool need_additional_node = GenerateTransformationNodeChain(*model, node_name, nodes_chain, post_nodes_chain);
|
|
|
|
|
|
- //setup metadata on newest node
|
|
|
- SetupNodeMetadata(*model, *nodes_chain.back());
|
|
|
+ // assert that for the current node we must have at least a single transform
|
|
|
+ ai_assert(nodes_chain.size());
|
|
|
|
|
|
- // link all nodes in a row
|
|
|
- aiNode *last_parent = parent;
|
|
|
- for (aiNode *child : nodes_chain) {
|
|
|
- ai_assert(child);
|
|
|
+ if (need_additional_node) {
|
|
|
+ nodes_chain.emplace_back(PotentialNode(node_name));
|
|
|
+ }
|
|
|
|
|
|
- if (last_parent != parent) {
|
|
|
- last_parent->mNumChildren = 1;
|
|
|
- last_parent->mChildren = new aiNode *[1];
|
|
|
- last_parent->mChildren[0] = child;
|
|
|
- }
|
|
|
+ //setup metadata on newest node
|
|
|
+ SetupNodeMetadata(*model, *nodes_chain.back().mNode);
|
|
|
|
|
|
- child->mParent = last_parent;
|
|
|
- last_parent = child;
|
|
|
+ // link all nodes in a row
|
|
|
+ aiNode *last_parent = parent;
|
|
|
+ for (PotentialNode& child : nodes_chain) {
|
|
|
+ ai_assert(child.mNode);
|
|
|
|
|
|
- new_abs_transform *= child->mTransformation;
|
|
|
+ if (last_parent != parent) {
|
|
|
+ last_parent->mNumChildren = 1;
|
|
|
+ last_parent->mChildren = new aiNode *[1];
|
|
|
+ last_parent->mChildren[0] = child.mOwnership.release();
|
|
|
}
|
|
|
|
|
|
- // attach geometry
|
|
|
- ConvertModel(*model, nodes_chain.back(), root_node, new_abs_transform);
|
|
|
+ child->mParent = last_parent;
|
|
|
+ last_parent = child.mNode;
|
|
|
|
|
|
- // check if there will be any child nodes
|
|
|
- const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
|
|
|
+ new_abs_transform *= child->mTransformation;
|
|
|
+ }
|
|
|
|
|
|
- // if so, link the geometric transform inverse nodes
|
|
|
- // before we attach any child nodes
|
|
|
- if (child_conns.size()) {
|
|
|
- for (aiNode *postnode : post_nodes_chain) {
|
|
|
- ai_assert(postnode);
|
|
|
+ // attach geometry
|
|
|
+ ConvertModel(*model, nodes_chain.back().mNode, root_node, new_abs_transform);
|
|
|
|
|
|
- if (last_parent != parent) {
|
|
|
- last_parent->mNumChildren = 1;
|
|
|
- last_parent->mChildren = new aiNode *[1];
|
|
|
- last_parent->mChildren[0] = postnode;
|
|
|
- }
|
|
|
+ // check if there will be any child nodes
|
|
|
+ const std::vector<const Connection *> &child_conns = doc.GetConnectionsByDestinationSequenced(model->ID(), "Model");
|
|
|
|
|
|
- postnode->mParent = last_parent;
|
|
|
- last_parent = postnode;
|
|
|
+ // if so, link the geometric transform inverse nodes
|
|
|
+ // before we attach any child nodes
|
|
|
+ if (child_conns.size()) {
|
|
|
+ for (PotentialNode& postnode : post_nodes_chain) {
|
|
|
+ ai_assert(postnode.mNode);
|
|
|
|
|
|
- new_abs_transform *= postnode->mTransformation;
|
|
|
+ if (last_parent != parent) {
|
|
|
+ last_parent->mNumChildren = 1;
|
|
|
+ last_parent->mChildren = new aiNode *[1];
|
|
|
+ last_parent->mChildren[0] = postnode.mOwnership.release();
|
|
|
}
|
|
|
- } else {
|
|
|
- // free the nodes we allocated as we don't need them
|
|
|
- Util::delete_fun<aiNode> deleter;
|
|
|
- std::for_each(
|
|
|
- post_nodes_chain.begin(),
|
|
|
- post_nodes_chain.end(),
|
|
|
- deleter);
|
|
|
- }
|
|
|
|
|
|
- // recursion call - child nodes
|
|
|
- ConvertNodes(model->ID(), last_parent, root_node);
|
|
|
+ postnode->mParent = last_parent;
|
|
|
+ last_parent = postnode.mNode;
|
|
|
|
|
|
- if (doc.Settings().readLights) {
|
|
|
- ConvertLights(*model, node_name);
|
|
|
+ new_abs_transform *= postnode->mTransformation;
|
|
|
}
|
|
|
+ } else {
|
|
|
+ // free the nodes we allocated as we don't need them
|
|
|
+ post_nodes_chain.clear();
|
|
|
+ }
|
|
|
|
|
|
- if (doc.Settings().readCameras) {
|
|
|
- ConvertCameras(*model, node_name);
|
|
|
- }
|
|
|
+ // recursion call - child nodes
|
|
|
+ ConvertNodes(model->ID(), last_parent, root_node);
|
|
|
|
|
|
- nodes.push_back(nodes_chain.front());
|
|
|
- nodes_chain.clear();
|
|
|
+ if (doc.Settings().readLights) {
|
|
|
+ ConvertLights(*model, node_name);
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- if (nodes.size()) {
|
|
|
- parent->mChildren = new aiNode *[nodes.size()]();
|
|
|
- parent->mNumChildren = static_cast<unsigned int>(nodes.size());
|
|
|
+ if (doc.Settings().readCameras) {
|
|
|
+ ConvertCameras(*model, node_name);
|
|
|
+ }
|
|
|
|
|
|
- std::swap_ranges(nodes.begin(), nodes.end(), parent->mChildren);
|
|
|
- } else {
|
|
|
- parent->mNumChildren = 0;
|
|
|
- parent->mChildren = nullptr;
|
|
|
+ nodes.push_back(std::move(nodes_chain.front()));
|
|
|
+ nodes_chain.clear();
|
|
|
}
|
|
|
+ }
|
|
|
|
|
|
- } catch (std::exception &) {
|
|
|
- Util::delete_fun<aiNode> deleter;
|
|
|
- std::for_each(nodes.begin(), nodes.end(), deleter);
|
|
|
- std::for_each(nodes_chain.begin(), nodes_chain.end(), deleter);
|
|
|
- std::for_each(post_nodes_chain.begin(), post_nodes_chain.end(), deleter);
|
|
|
+ if (nodes.size()) {
|
|
|
+ parent->mChildren = new aiNode *[nodes.size()]();
|
|
|
+ parent->mNumChildren = static_cast<unsigned int>(nodes.size());
|
|
|
+
|
|
|
+ for (unsigned int i = 0; i < nodes.size(); ++i)
|
|
|
+ {
|
|
|
+ parent->mChildren[i] = nodes[i].mOwnership.release();
|
|
|
+ }
|
|
|
+ nodes.clear();
|
|
|
+ } else {
|
|
|
+ parent->mNumChildren = 0;
|
|
|
+ parent->mChildren = nullptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -681,8 +684,8 @@ std::string FBXConverter::NameTransformationChainNode(const std::string &name, T
|
|
|
return name + std::string(MAGIC_NODE_TAG) + "_" + NameTransformationComp(comp);
|
|
|
}
|
|
|
|
|
|
-bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<aiNode *> &output_nodes,
|
|
|
- std::vector<aiNode *> &post_output_nodes) {
|
|
|
+bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std::string &name, std::vector<PotentialNode> &output_nodes,
|
|
|
+ std::vector<PotentialNode> &post_output_nodes) {
|
|
|
const PropertyTable &props = model.Props();
|
|
|
const Model::RotOrder rot = model.RotationOrder();
|
|
|
|
|
@@ -828,7 +831,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
|
|
|
chain[i] = chain[i].Inverse();
|
|
|
}
|
|
|
|
|
|
- aiNode *nd = new aiNode();
|
|
|
+ PotentialNode nd;
|
|
|
nd->mName.Set(NameTransformationChainNode(name, comp));
|
|
|
nd->mTransformation = chain[i];
|
|
|
|
|
@@ -836,9 +839,9 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
|
|
|
if (comp == TransformationComp_GeometricScalingInverse ||
|
|
|
comp == TransformationComp_GeometricRotationInverse ||
|
|
|
comp == TransformationComp_GeometricTranslationInverse) {
|
|
|
- post_output_nodes.push_back(nd);
|
|
|
+ post_output_nodes.emplace_back(std::move(nd));
|
|
|
} else {
|
|
|
- output_nodes.push_back(nd);
|
|
|
+ output_nodes.emplace_back(std::move(nd));
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -847,8 +850,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
|
|
|
}
|
|
|
|
|
|
// else, we can just multiply the matrices together
|
|
|
- aiNode *nd = new aiNode();
|
|
|
- output_nodes.push_back(nd);
|
|
|
+ PotentialNode nd;
|
|
|
|
|
|
// name passed to the method is already unique
|
|
|
nd->mName.Set(name);
|
|
@@ -857,6 +859,7 @@ bool FBXConverter::GenerateTransformationNodeChain(const Model &model, const std
|
|
|
for (unsigned int i = TransformationComp_Translation; i < TransformationComp_MAXIMUM; i++) {
|
|
|
nd->mTransformation = nd->mTransformation * chain[i];
|
|
|
}
|
|
|
+ output_nodes.push_back(std::move(nd));
|
|
|
return false;
|
|
|
}
|
|
|
|