|
|
|
#include <components/sceneutil/osgacontroller.hpp>
|
|
|
|
|
|
|
|
#include <osg/Node>
|
|
|
|
#include <osg/NodeVisitor>
|
|
|
|
#include <osg/ref_ptr>
|
|
|
|
|
|
|
|
#include <osgAnimation/Animation>
|
|
|
|
#include <osgAnimation/Channel>
|
|
|
|
#include <osgAnimation/Sampler>
|
|
|
|
#include <osgAnimation/UpdateMatrixTransform>
|
|
|
|
|
|
|
|
#include <components/debug/debuglog.hpp>
|
|
|
|
#include <components/misc/strings/lower.hpp>
|
|
|
|
#include <components/resource/animation.hpp>
|
|
|
|
#include <components/sceneutil/controller.hpp>
|
|
|
|
#include <components/sceneutil/keyframe.hpp>
|
|
|
|
|
|
|
|
namespace SceneUtil
|
|
|
|
{
|
|
|
|
LinkVisitor::LinkVisitor() : osg::NodeVisitor( TRAVERSE_ALL_CHILDREN )
|
|
|
|
{
|
|
|
|
mAnimation = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LinkVisitor::link(osgAnimation::UpdateMatrixTransform* umt)
|
|
|
|
{
|
|
|
|
const osgAnimation::ChannelList& channels = mAnimation->getChannels();
|
|
|
|
for (const auto& channel: channels)
|
|
|
|
{
|
|
|
|
const std::string& channelName = channel->getName();
|
|
|
|
const std::string& channelTargetName = channel->getTargetName();
|
|
|
|
|
|
|
|
if (channelTargetName != umt->getName()) continue;
|
|
|
|
|
|
|
|
// check if we can link a StackedTransformElement to the current Channel
|
|
|
|
for (const auto & stackedTransform : umt->getStackedTransforms())
|
|
|
|
{
|
|
|
|
osgAnimation::StackedTransformElement* element = stackedTransform.get();
|
|
|
|
if (element && !element->getName().empty() && channelName == element->getName())
|
|
|
|
{
|
|
|
|
osgAnimation::Target* target = element->getOrCreateTarget();
|
|
|
|
if (target)
|
|
|
|
{
|
|
|
|
channel->setTarget(target);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LinkVisitor::setAnimation(Resource::Animation* animation)
|
|
|
|
{
|
|
|
|
mAnimation = animation;
|
|
|
|
}
|
|
|
|
|
|
|
|
void LinkVisitor::apply(osg::Node& node)
|
|
|
|
{
|
|
|
|
osg::Callback* cb = node.getUpdateCallback();
|
|
|
|
while (cb)
|
|
|
|
{
|
|
|
|
osgAnimation::UpdateMatrixTransform* umt = dynamic_cast<osgAnimation::UpdateMatrixTransform*>(cb);
|
|
|
|
if (umt)
|
|
|
|
if (Misc::StringUtils::lowerCase(node.getName()) != "bip01") link(umt);
|
|
|
|
cb = cb->getNestedCallback();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (node.getNumChildrenRequiringUpdateTraversal())
|
|
|
|
traverse( node );
|
|
|
|
}
|
|
|
|
|
|
|
|
OsgAnimationController::OsgAnimationController(const OsgAnimationController ©, const osg::CopyOp ©op)
|
|
|
|
: osg::Object(copy, copyop)
|
|
|
|
, SceneUtil::KeyframeController(copy)
|
|
|
|
, SceneUtil::NodeCallback<OsgAnimationController>(copy, copyop)
|
|
|
|
, mEmulatedAnimations(copy.mEmulatedAnimations)
|
|
|
|
{
|
|
|
|
mLinker = nullptr;
|
|
|
|
for (const auto& mergedAnimationTrack : copy.mMergedAnimationTracks)
|
|
|
|
{
|
|
|
|
Resource::Animation* copiedAnimationTrack = static_cast<Resource::Animation*>(mergedAnimationTrack.get()->clone(copyop));
|
|
|
|
mMergedAnimationTracks.emplace_back(copiedAnimationTrack);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::Vec3f OsgAnimationController::getTranslation(float time) const
|
|
|
|
{
|
|
|
|
osg::Vec3f translationValue;
|
|
|
|
std::string animationName;
|
|
|
|
float newTime = time;
|
|
|
|
|
|
|
|
//Find the correct animation based on time
|
|
|
|
for (const EmulatedAnimation& emulatedAnimation : mEmulatedAnimations)
|
|
|
|
{
|
|
|
|
if (time >= emulatedAnimation.mStartTime && time <= emulatedAnimation.mStopTime)
|
|
|
|
{
|
|
|
|
newTime = time - emulatedAnimation.mStartTime;
|
|
|
|
animationName = emulatedAnimation.mName;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Find the root transform track in animation
|
|
|
|
for (const auto& mergedAnimationTrack : mMergedAnimationTracks)
|
|
|
|
{
|
|
|
|
if (mergedAnimationTrack->getName() != animationName) continue;
|
|
|
|
|
|
|
|
const osgAnimation::ChannelList& channels = mergedAnimationTrack->getChannels();
|
|
|
|
|
|
|
|
for (const auto& channel: channels)
|
|
|
|
{
|
|
|
|
if (channel->getTargetName() != "bip01" || channel->getName() != "transform") continue;
|
|
|
|
|
|
|
|
if ( osgAnimation::MatrixLinearSampler* templateSampler = dynamic_cast<osgAnimation::MatrixLinearSampler*> (channel->getSampler()) )
|
|
|
|
{
|
|
|
|
osg::Matrixf matrix;
|
|
|
|
templateSampler->getValueAt(newTime, matrix);
|
|
|
|
translationValue = matrix.getTrans();
|
|
|
|
return osg::Vec3f(translationValue[0], translationValue[1], translationValue[2]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return osg::Vec3f();
|
|
|
|
}
|
|
|
|
|
|
|
|
void OsgAnimationController::update(float time, const std::string& animationName)
|
|
|
|
{
|
|
|
|
for (const auto& mergedAnimationTrack : mMergedAnimationTracks)
|
|
|
|
{
|
|
|
|
if (mergedAnimationTrack->getName() == animationName) mergedAnimationTrack->update(time);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void OsgAnimationController::operator() (osg::Node* node, osg::NodeVisitor* nv)
|
|
|
|
{
|
|
|
|
if (hasInput())
|
|
|
|
{
|
|
|
|
if (mNeedToLink)
|
|
|
|
{
|
|
|
|
for (const auto& mergedAnimationTrack : mMergedAnimationTracks)
|
|
|
|
{
|
|
|
|
if (!mLinker.valid()) mLinker = new LinkVisitor();
|
|
|
|
mLinker->setAnimation(mergedAnimationTrack);
|
|
|
|
node->accept(*mLinker);
|
|
|
|
}
|
|
|
|
mNeedToLink = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
float time = getInputValue(nv);
|
|
|
|
|
|
|
|
for (const EmulatedAnimation& emulatedAnimation : mEmulatedAnimations)
|
|
|
|
{
|
|
|
|
if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime)
|
|
|
|
{
|
|
|
|
update(time - emulatedAnimation.mStartTime, emulatedAnimation.mName);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
traverse(node, nv);
|
|
|
|
}
|
|
|
|
|
|
|
|
void OsgAnimationController::setEmulatedAnimations(const std::vector<EmulatedAnimation>& emulatedAnimations)
|
|
|
|
{
|
|
|
|
mEmulatedAnimations = emulatedAnimations;
|
|
|
|
}
|
|
|
|
|
|
|
|
void OsgAnimationController::addMergedAnimationTrack(osg::ref_ptr<Resource::Animation> animationTrack)
|
|
|
|
{
|
|
|
|
mMergedAnimationTracks.emplace_back(animationTrack);
|
|
|
|
}
|
|
|
|
}
|