Collada: Importer generates animations from <library_animation_clips>, if the node is present.

pull/791/head
Trond Abusdal 2016-02-07 23:36:49 +01:00
parent 2466ae6c2e
commit c34717639e
3 changed files with 170 additions and 1 deletions

View File

@ -597,6 +597,18 @@ struct Animation
for( std::vector<Animation*>::iterator it = mSubAnims.begin(); it != mSubAnims.end(); ++it)
delete *it;
}
void CollectChannelsRecursively(std::vector<AnimationChannel> &channels)
{
channels.insert(channels.end(), mChannels.begin(), mChannels.end());
for (std::vector<Animation*>::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 */

View File

@ -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<std::string, std::vector<std::string>> 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 <animation_clip> 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 <library_animation_clips> 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<std::string>::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 <library_animation_clips>
// 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;
}
}
}
}

View File

@ -83,6 +83,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);
@ -313,6 +319,14 @@ namespace Assimp
typedef std::map<std::string, Collada::Controller> ControllerLibrary;
ControllerLibrary mControllerLibrary;
/** Animation library: animation references by ID */
typedef std::map<std::string, Collada::Animation*> AnimationLibrary;
AnimationLibrary mAnimationLibrary;
/** Animation clip library: clip animation references by ID */
typedef std::vector<std::pair<std::string, std::vector<std::string>>> AnimationClipLibrary;
AnimationClipLibrary mAnimationClipLibrary;
/** Pointer to the root node. Don't delete, it just points to one of
the nodes in the node library. */
Collada::Node* mRootNode;