mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 15:56:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			179 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			179 lines
		
	
	
	
		
			6.1 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
#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/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& copy, const osg::CopyOp& copyop)
 | 
						|
        : 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);
 | 
						|
    }
 | 
						|
}
 |