From c34717639ecb7c99e136bce9952e32b7be330c2a Mon Sep 17 00:00:00 2001 From: Trond Abusdal Date: Sun, 7 Feb 2016 23:36:49 +0100 Subject: [PATCH] Collada: Importer generates animations from , if the node is present. --- code/ColladaHelper.h | 12 ++++ code/ColladaParser.cpp | 145 ++++++++++++++++++++++++++++++++++++++++- code/ColladaParser.h | 14 ++++ 3 files changed, 170 insertions(+), 1 deletion(-) diff --git a/code/ColladaHelper.h b/code/ColladaHelper.h index ae9b45bb0..a741ef705 100644 --- a/code/ColladaHelper.h +++ b/code/ColladaHelper.h @@ -597,6 +597,18 @@ struct Animation for( std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) delete *it; } + + void CollectChannelsRecursively(std::vector &channels) + { + channels.insert(channels.end(), mChannels.begin(), mChannels.end()); + + for (std::vector::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it) + { + Animation *pAnim = (*it); + + pAnim->CollectChannelsRecursively(channels); + } + } }; /** Description of a collada animation channel which has been determined to affect the current node */ diff --git a/code/ColladaParser.cpp b/code/ColladaParser.cpp index 7778103bd..915947504 100644 --- a/code/ColladaParser.cpp +++ b/code/ColladaParser.cpp @@ -187,6 +187,8 @@ void ColladaParser::ReadStructure() ReadAssetInfo(); else if( IsElement( "library_animations")) ReadAnimationLibrary(); + else if (IsElement("library_animation_clips")) + ReadAnimationClipLibrary(); else if( IsElement( "library_controllers")) ReadControllerLibrary(); else if( IsElement( "library_images")) @@ -271,6 +273,131 @@ void ColladaParser::ReadAssetInfo() } } +// ------------------------------------------------------------------------------------------------ +// Reads the animation clips +void ColladaParser::ReadAnimationClipLibrary() +{ + if (mReader->isEmptyElement()) + return; + + while (mReader->read()) + { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + if (IsElement("animation_clip")) + { + // optional name given as an attribute + std::string animName; + int indexName = TestAttribute("name"); + int indexID = TestAttribute("id"); + if (indexName >= 0) + animName = mReader->getAttributeValue(indexName); + else if (indexID >= 0) + animName = mReader->getAttributeValue(indexID); + else + animName = "animation_" + mAnimationClipLibrary.size(); + + std::pair> clip; + + clip.first = animName; + + while (mReader->read()) + { + if (mReader->getNodeType() == irr::io::EXN_ELEMENT) + { + if (IsElement("instance_animation")) + { + int indexUrl = TestAttribute("url"); + if (indexUrl >= 0) + { + const char* url = mReader->getAttributeValue(indexUrl); + if (url[0] != '#') + ThrowException("Unknown reference format"); + + url++; + + clip.second.push_back(url); + } + } + else + { + // ignore the rest + SkipElement(); + } + } + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if (strcmp(mReader->getNodeName(), "animation_clip") != 0) + ThrowException("Expected end of element."); + + break; + } + } + + if (clip.second.size() > 0) + { + mAnimationClipLibrary.push_back(clip); + } + } + else + { + // ignore the rest + SkipElement(); + } + } + else if (mReader->getNodeType() == irr::io::EXN_ELEMENT_END) + { + if (strcmp(mReader->getNodeName(), "library_animation_clips") != 0) + ThrowException("Expected end of element."); + + break; + } + } +} + +// ------------------------------------------------------------------------------------------------ +// Re-build animations from animation clip library, if present. +void ColladaParser::RebuildRootAnimationsFromClips() +{ + if (mAnimationClipLibrary.size() > 0) + { + Animation temp; + + for (AnimationClipLibrary::iterator it = mAnimationClipLibrary.begin(); it != mAnimationClipLibrary.end(); ++it) + { + std::string clipName = it->first; + + printf("Clip: %s\n", clipName.c_str()); + + Animation *clip = new Animation(); + clip->mName = clipName; + + temp.mSubAnims.push_back(clip); + + for (std::vector::iterator a = it->second.begin(); a != it->second.end(); ++a) + { + std::string animationID = *a; + + printf(" Animation instance: %s\n", animationID.c_str()); + + AnimationLibrary::iterator animation = mAnimationLibrary.find(animationID); + + if (animation != mAnimationLibrary.end()) + { + Animation *pSourceAnimation = animation->second; + + pSourceAnimation->CollectChannelsRecursively(clip->mChannels); + } + } + } + + mAnims = temp; + + // Ensure no double deletes. + temp.mSubAnims.clear(); + } +} + // ------------------------------------------------------------------------------------------------ // Reads the animation library void ColladaParser::ReadAnimationLibrary() @@ -318,12 +445,17 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) // optional name given as an attribute std::string animName; + std::string animID; int indexName = TestAttribute( "name"); int indexID = TestAttribute( "id"); + + if (indexID >= 0) + animID = mReader->getAttributeValue(indexID); + if( indexName >= 0) animName = mReader->getAttributeValue( indexName); else if( indexID >= 0) - animName = mReader->getAttributeValue( indexID); + animName = animID; else animName = "animation"; @@ -395,11 +527,17 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) // it turned out to have channels - add them if( !channels.empty()) { + // FIXME: Is this essentially doing the same as "single-anim-node" codepath in + // ColladaLoader::StoreAnimations? If not, defer this to where animation + // clip instances are set up. Due to handling of + // this cannot be done here, as the channel owner is lost. +/* // special filtering for stupid exporters packing each channel into a separate animation if( channels.size() == 1) { pParent->mChannels.push_back( channels.begin()->second); } else +*/ { // else create the animation, if not done yet, and store the channels if( !anim) @@ -410,6 +548,11 @@ void ColladaParser::ReadAnimation( Collada::Animation* pParent) } for( ChannelMap::const_iterator it = channels.begin(); it != channels.end(); ++it) anim->mChannels.push_back( it->second); + + if (indexID >= 0) + { + mAnimationLibrary[animID] = anim; + } } } } diff --git a/code/ColladaParser.h b/code/ColladaParser.h index 6b8fe182e..1ea4a13d7 100644 --- a/code/ColladaParser.h +++ b/code/ColladaParser.h @@ -82,6 +82,12 @@ namespace Assimp /** Reads the animation library */ void ReadAnimationLibrary(); + + /** Reads the animation clip library */ + void ReadAnimationClipLibrary(); + + /** Re-build animations from animation clip library, if present */ + void RebuildRootAnimationsFromClips(); /** Reads an animation into the given parent structure */ void ReadAnimation( Collada::Animation* pParent); @@ -312,6 +318,14 @@ namespace Assimp /** Controller library: joint controllers by ID */ typedef std::map ControllerLibrary; ControllerLibrary mControllerLibrary; + + /** Animation library: animation references by ID */ + typedef std::map AnimationLibrary; + AnimationLibrary mAnimationLibrary; + + /** Animation clip library: clip animation references by ID */ + typedef std::vector>> AnimationClipLibrary; + AnimationClipLibrary mAnimationClipLibrary; /** Pointer to the root node. Don't delete, it just points to one of the nodes in the node library. */