#ifndef OPENMW_MWRENDER_ANIMBLENDCONTROLLER_H #define OPENMW_MWRENDER_ANIMBLENDCONTROLLER_H #include #include #include #include #include #include #include #include #include #include namespace MWRender { typedef float (*EasingFn)(float); struct AnimBlendStateData { std::string mGroupname; std::string mStartKey; }; class AnimBlendController : public SceneUtil::Controller { public: AnimBlendController(const osg::ref_ptr& keyframeTrack, const AnimBlendStateData& animState, const osg::ref_ptr& blendRules); AnimBlendController(); void setKeyframeTrack(const osg::ref_ptr& kft, const AnimBlendStateData& animState, const osg::ref_ptr& blendRules); bool getBlendTrigger() const { return mBlendTrigger; } protected: EasingFn mEasingFn; float mBlendDuration = 0.0f; float mBlendStartTime = 0.0f; float mTimeFactor = 0.0f; float mInterpFactor = 0.0f; bool mBlendTrigger = false; bool mInterpActive = false; AnimBlendStateData mAnimState; osg::ref_ptr mAnimBlendRules; osg::ref_ptr mKeyframeTrack; std::unordered_map mBlendBoneTransforms; inline void calculateInterpFactor(float time); }; class NifAnimBlendController : public SceneUtil::NodeCallback, public AnimBlendController { public: NifAnimBlendController(const osg::ref_ptr& keyframeTrack, const AnimBlendStateData& animState, const osg::ref_ptr& blendRules); NifAnimBlendController() {} NifAnimBlendController(const NifAnimBlendController& other, const osg::CopyOp&) : NifAnimBlendController(other.mKeyframeTrack, other.mAnimState, other.mAnimBlendRules) { } META_Object(MWRender, NifAnimBlendController) void operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv); osg::Callback* getAsCallback() { return this; } private: osg::Quat mBlendStartRot; osg::Vec3f mBlendStartTrans; float mBlendStartScale = 0.0f; }; class BoneAnimBlendController : public SceneUtil::NodeCallback, public AnimBlendController { public: BoneAnimBlendController(const osg::ref_ptr& keyframeTrack, const AnimBlendStateData& animState, const osg::ref_ptr& blendRules); BoneAnimBlendController() {} BoneAnimBlendController(const BoneAnimBlendController& other, const osg::CopyOp&) : BoneAnimBlendController(other.mKeyframeTrack, other.mAnimState, other.mAnimBlendRules) { } void gatherRecursiveBoneTransforms(osgAnimation::Bone* parent, bool isRoot = true); void applyBoneBlend(osgAnimation::Bone* parent); META_Object(MWRender, BoneAnimBlendController) void operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv); osg::Callback* getAsCallback() { return this; } }; // Assigned to child bones with an instance of AnimBlendController class BoneAnimBlendControllerWrapper : public osg::Callback { public: BoneAnimBlendControllerWrapper(osg::ref_ptr rootCallback, osgAnimation::Bone* node) : mRootCallback(std::move(rootCallback)) , mNode(node) { } BoneAnimBlendControllerWrapper() {} BoneAnimBlendControllerWrapper(const BoneAnimBlendControllerWrapper& copy, const osg::CopyOp&) : mRootCallback(copy.mRootCallback) , mNode(copy.mNode) { } META_Object(MWRender, BoneAnimBlendControllerWrapper) bool run(osg::Object* object, osg::Object* data) override { mRootCallback->applyBoneBlend(mNode); traverse(object, data); return true; } private: osg::ref_ptr mRootCallback; osgAnimation::Bone* mNode{ nullptr }; }; } #endif