From cdb7caffbd9f3ccccedc17a864cb95ec99c74440 Mon Sep 17 00:00:00 2001 From: Alexander Gessler Date: Sat, 25 Aug 2012 22:24:08 +0200 Subject: [PATCH] - fbx: add special output node name tag to mark fbx null nodes. --- code/FBXConverter.cpp | 76 ++++++++++++++++++++++++++++++++++++++++--- code/FBXDocument.h | 6 ++++ code/FBXModel.cpp | 16 +++++++++ 3 files changed, 93 insertions(+), 5 deletions(-) diff --git a/code/FBXConverter.cpp b/code/FBXConverter.cpp index bd1d5b861..0c17f11d4 100644 --- a/code/FBXConverter.cpp +++ b/code/FBXConverter.cpp @@ -61,6 +61,8 @@ namespace FBX { #define MAGIC_NODE_TAG "_$AssimpFbx$" +#define MAGIC_NULL_TAG "_$AssimpFbxNull$" + #define CONVERT_FBX_TIME(time) static_cast(time) / 46186158000L // XXX vc9's debugger won't step into anonymous namespaces @@ -204,16 +206,17 @@ private: // is supposed to have. If there is none, add another node to // preserve the name - people might have scripts etc. that rely // on specific node names. - bool has_name = false; + aiNode* name_carrier = NULL; BOOST_FOREACH(aiNode* prenode, nodes_chain) { if ( !strcmp(prenode->mName.C_Str(), original_name.c_str()) ) { - has_name = true; + name_carrier = prenode; break; } } - if(!has_name) { + if(!name_carrier) { nodes_chain.push_back(new aiNode(original_name)); + name_carrier = nodes_chain.back(); } // link all nodes in a row @@ -247,6 +250,14 @@ private: ConvertCameras(*model); } + // preserve the info that a node was marked as Null node + // in the original file. + if(model->IsNull()) { + const std::string& new_name = original_name + MAGIC_NULL_TAG; + RenameNode(original_name, new_name); + name_carrier->mName.Set( new_name.c_str() ); + } + nodes.push_back(nodes_chain.front()); nodes_chain.clear(); } @@ -1620,6 +1631,54 @@ private: // ------------------------------------------------------------------------------------------------ + // rename a node already partially converted. fixed_name is a string previously returned by + // FixNodeName, new_name specifies the string FixNodeName should return on all further invocations + // which would previously have returned the old value. + // + // this also updates names in node animations, cameras and light sources and is thus slow. + // + // NOTE: the caller is responsible for ensuring that the new name is unique and does + // not collide with any other identifiers. The best way to ensure this is to only + // append to the old name, which is guaranteed to match these requirements. + void RenameNode(const std::string& fixed_name, const std::string& new_name) + { + ai_assert(node_names.find(fixed_name) != node_names.end()); + ai_assert(node_names.find(new_name) == node_names.end()); + + renamed_nodes[fixed_name] = new_name; + + const aiString fn(fixed_name); + + BOOST_FOREACH(aiCamera* cam, cameras) { + if (cam->mName == fn) { + cam->mName.Set(new_name); + break; + } + } + + BOOST_FOREACH(aiLight* light, lights) { + if (light->mName == fn) { + light->mName.Set(new_name); + break; + } + } + + BOOST_FOREACH(aiAnimation* anim, animations) { + for (unsigned int i = 0; i < anim->mNumChannels; ++i) { + aiNodeAnim* const na = anim->mChannels[i]; + if (na->mNodeName == fn) { + na->mNodeName.Set(new_name); + break; + } + } + } + } + + + // ------------------------------------------------------------------------------------------------ + // takes a fbx node name and returns the identifier to be used in the assimp output scene. + // the function is guaranteed to provide consistent results over multiple invocations + // UNLESS RenameNode() is called for a particular node name. std::string FixNodeName(const std::string& name) { // strip Model:: prefix, avoiding ambiguities (i.e. don't strip if @@ -1636,7 +1695,9 @@ private: } } node_names[temp] = true; - return temp; + + const NameNameMap::const_iterator rit = renamed_nodes.find(temp); + return rit == renamed_nodes.end() ? temp : (*rit).second; } const NodeNameMap::const_iterator it = node_names.find(name); @@ -1646,7 +1707,9 @@ private: } } node_names[name] = false; - return name; + + const NameNameMap::const_iterator rit = renamed_nodes.find(name); + return rit == renamed_nodes.end() ? name : (*rit).second; } @@ -2631,6 +2694,9 @@ private: typedef std::map NodeNameMap; NodeNameMap node_names; + typedef std::map NameNameMap; + NameNameMap renamed_nodes; + double anim_fps; aiScene* const out; diff --git a/code/FBXDocument.h b/code/FBXDocument.h index a21425cb4..2a0e59673 100644 --- a/code/FBXDocument.h +++ b/code/FBXDocument.h @@ -485,6 +485,12 @@ public: return attributes; } +public: + + /** convenience method to check if the node has a Null node marker */ + bool IsNull() const; + + private: void ResolveLinks(const Element& element, const Document& doc); diff --git a/code/FBXModel.cpp b/code/FBXModel.cpp index 9e2d1eb77..d6d329801 100644 --- a/code/FBXModel.cpp +++ b/code/FBXModel.cpp @@ -134,6 +134,22 @@ void Model::ResolveLinks(const Element& element, const Document& doc) } +// ------------------------------------------------------------------------------------------------ +bool Model::IsNull() const +{ + const std::vector& attrs = GetAttributes(); + BOOST_FOREACH(const NodeAttribute* att, attrs) { + + const Null* null_tag = dynamic_cast(att); + if(null_tag) { + return true; + } + } + + return false; +} + + } //!FBX } //!Assimp