diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index 3c5a6423fd..835bd53d1d 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -27,7 +27,7 @@ add_openmw_dir (mwrender bulletdebugdraw globalmap characterpreview camera localmap water terrainstorage ripplesimulation renderbin actoranimation landmanager navmesh actorspaths recastmesh fogmanager objectpaging groundcover postprocessor pingpongcull luminancecalculator pingpongcanvas transparentpass precipitationocclusion ripples - actorutil distortion animationpriority bonegroup blendmask + actorutil distortion animationpriority bonegroup blendmask animblendcontroller ) add_openmw_dir (mwinput diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 2f8e8c2c73..3dbe5b40af 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -60,7 +60,6 @@ #include "../mwmechanics/weapontype.hpp" #include "actorutil.hpp" -#include "animblendcontroller.cpp" #include "rotatecontroller.hpp" #include "util.hpp" #include "vismask.hpp" @@ -402,8 +401,7 @@ namespace return lightModel; } - void assignBoneBlendCallbackRecursive(MWRender::BoneAnimBlendController* controller, - MWRender::ActiveControllersVector& activeControllers, osg::Node* parent, bool isRoot) + void assignBoneBlendCallbackRecursive(MWRender::BoneAnimBlendController* controller, osg::Node* parent, bool isRoot) { // Attempt to cast node to an osgAnimation::Bone if (!isRoot && dynamic_cast(parent)) @@ -454,7 +452,7 @@ namespace osg::Group* group = parent->asGroup(); if (group) for (unsigned int i = 0; i < group->getNumChildren(); ++i) - assignBoneBlendCallbackRecursive(controller, activeControllers, group->getChild(i), false); + assignBoneBlendCallbackRecursive(controller, group->getChild(i), false); } } @@ -1085,31 +1083,31 @@ namespace MWRender return mNodeMap; } - template - inline osg::Callback* Animation::handleBlendTransform(osg::ref_ptr node, + template + inline osg::Callback* Animation::handleBlendTransform(const osg::ref_ptr& node, osg::ref_ptr keyframeController, - std::map, osg::ref_ptr>>& blendControllers, + std::map, osg::ref_ptr>& blendControllers, const AnimBlendStateData& stateData, const osg::ref_ptr& blendRules, const AnimState& active) { osg::ref_ptr animController; - if (blendControllers.contains(node)) { - animController = blendControllers[node]; + animController = blendControllers.at(node); animController->setKeyframeTrack(keyframeController, stateData, blendRules); } else { animController = new ControllerType(keyframeController, stateData, blendRules); - blendControllers[node] = animController; + blendControllers.emplace(node, animController); if constexpr (std::is_same_v) - assignBoneBlendCallbackRecursive(animController, mActiveControllers, node, true); + assignBoneBlendCallbackRecursive(animController, node, true); } keyframeController->mTime = active.mTime; + osg::Callback* asCallback = animController->getAsCallback(); if constexpr (std::is_same_v) { // IMPORTANT: we must gather all transforms at point of change before next update @@ -1118,13 +1116,13 @@ namespace MWRender animController->gatherRecursiveBoneTransforms(static_cast(node.get())); // Register blend callback after the initial animation callback - node->addUpdateCallback(animController->getAsCallback()); - mActiveControllers.emplace_back(node, animController->getAsCallback()); + node->addUpdateCallback(asCallback); + mActiveControllers.emplace_back(node, asCallback); return keyframeController->getAsCallback(); } - return animController->getAsCallback(); + return asCallback; } void Animation::resetActiveGroups() @@ -1181,14 +1179,13 @@ namespace MWRender { if (dynamic_cast(node.get())) { - callback = handleBlendTransform(node, - it->second, mAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second); + callback = handleBlendTransform(node, it->second, + mAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second); } else if (dynamic_cast(node.get())) { - callback - = handleBlendTransform(node, it->second, - mBoneAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second); + callback = handleBlendTransform(node, it->second, + mBoneAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second); } } diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index b11639b21f..36a84ba2ab 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -306,10 +306,10 @@ namespace MWRender void removeFromSceneImpl(); - template - inline osg::Callback* handleBlendTransform(osg::ref_ptr node, + template + inline osg::Callback* handleBlendTransform(const osg::ref_ptr& node, osg::ref_ptr keyframeController, - std::map, osg::ref_ptr>>& blendControllers, + std::map, osg::ref_ptr>& blendControllers, const AnimBlendStateData& stateData, const osg::ref_ptr& blendRules, const AnimState& active); diff --git a/apps/openmw/mwrender/animblendcontroller.cpp b/apps/openmw/mwrender/animblendcontroller.cpp index ed3d3e955b..59149e45e4 100644 --- a/apps/openmw/mwrender/animblendcontroller.cpp +++ b/apps/openmw/mwrender/animblendcontroller.cpp @@ -4,6 +4,7 @@ #include +#include #include #include @@ -90,18 +91,26 @@ namespace MWRender } } - template - AnimBlendController::AnimBlendController(osg::ref_ptr keyframeTrack, - const AnimBlendStateData& newState, osg::ref_ptr blendRules) - : mTimeFactor(0.0f) - , mInterpFactor(0.0f) + AnimBlendController::AnimBlendController(const osg::ref_ptr& keyframeTrack, + const AnimBlendStateData& newState, const osg::ref_ptr& blendRules) { setKeyframeTrack(keyframeTrack, newState, blendRules); } - template - void AnimBlendController::setKeyframeTrack(osg::ref_ptr kft, - const AnimBlendStateData& newState, osg::ref_ptr blendRules) + NifAnimBlendController::NifAnimBlendController(const osg::ref_ptr& keyframeTrack, + const AnimBlendStateData& newState, const osg::ref_ptr& blendRules) + : AnimBlendController(keyframeTrack, newState, blendRules) + { + } + + BoneAnimBlendController::BoneAnimBlendController(const osg::ref_ptr& keyframeTrack, + const AnimBlendStateData& newState, const osg::ref_ptr& blendRules) + : AnimBlendController(keyframeTrack, newState, blendRules) + { + } + + void AnimBlendController::setKeyframeTrack(const osg::ref_ptr& kft, + const AnimBlendStateData& newState, const osg::ref_ptr& blendRules) { // If animation has changed then start blending if (newState.mGroupname != mAnimState.mGroupname || newState.mStartKey != mAnimState.mStartKey @@ -139,8 +148,22 @@ namespace MWRender } } - template - void AnimBlendController::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot) + void AnimBlendController::calculateInterpFactor(float time) + { + if (mBlendDuration != 0) + mTimeFactor = std::min((time - mBlendStartTime) / mBlendDuration, 1.0f); + else + mTimeFactor = 1; + + mInterpActive = mTimeFactor < 1.0; + + if (mInterpActive) + mInterpFactor = mEasingFn(mTimeFactor); + else + mInterpFactor = 1.0f; + } + + void BoneAnimBlendController::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot) { // Incase group traversal encountered something that isnt a bone if (!bone) @@ -156,8 +179,7 @@ namespace MWRender } } - template - void AnimBlendController::applyBoneBlend(osgAnimation::Bone* bone) + void BoneAnimBlendController::applyBoneBlend(osgAnimation::Bone* bone) { // If we are done with interpolation then we can safely skip this as the bones are correct if (!mInterpActive) @@ -200,24 +222,7 @@ namespace MWRender bone->setMatrixInSkeletonSpace(lerpedMatrix); } - template - void AnimBlendController::calculateInterpFactor(float time) - { - if (mBlendDuration != 0) - mTimeFactor = std::min((time - mBlendStartTime) / mBlendDuration, 1.0f); - else - mTimeFactor = 1; - - mInterpActive = mTimeFactor < 1.0; - - if (mInterpActive) - mInterpFactor = mEasingFn(mTimeFactor); - else - mInterpFactor = 1.0f; - } - - template - void AnimBlendController::operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv) + void BoneAnimBlendController::operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv) { // HOW THIS WORKS: This callback method is called only for bones with attached keyframe controllers // such as bip01, bip01 spine1 etc. The child bones of these controllers have their own callback wrapper @@ -237,11 +242,10 @@ namespace MWRender if (mInterpActive) applyBoneBlend(node); - SceneUtil::NodeCallback, osgAnimation::Bone*>::traverse(node, nv); + SceneUtil::NodeCallback::traverse(node, nv); } - template - void AnimBlendController::operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv) + void NifAnimBlendController::operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv) { // HOW THIS WORKS: The actual retrieval of the bone transformation based on animation is done by the // KeyframeController (mKeyframeTrack). The KeyframeController retreives time data (playback position) every @@ -303,6 +307,6 @@ namespace MWRender // instantly hide/show objects in which case the scale interpolation is undesirable. node->setScale(*scale); - SceneUtil::NodeCallback, NifOsg::MatrixTransform*>::traverse(node, nv); + SceneUtil::NodeCallback::traverse(node, nv); } } diff --git a/apps/openmw/mwrender/animblendcontroller.hpp b/apps/openmw/mwrender/animblendcontroller.hpp index d08db5d643..38d83af7cd 100644 --- a/apps/openmw/mwrender/animblendcontroller.hpp +++ b/apps/openmw/mwrender/animblendcontroller.hpp @@ -27,49 +27,28 @@ namespace MWRender std::string mStartKey; }; - template - class AnimBlendController : public SceneUtil::NodeCallback, NodeClass*>, - public SceneUtil::Controller + class AnimBlendController : public SceneUtil::Controller { public: - AnimBlendController(osg::ref_ptr keyframeTrack, - const AnimBlendStateData& animState, osg::ref_ptr blendRules); + AnimBlendController(const osg::ref_ptr& keyframeTrack, + const AnimBlendStateData& animState, const osg::ref_ptr& blendRules); AnimBlendController() {} - AnimBlendController(const AnimBlendController& other, const osg::CopyOp&) - : AnimBlendController(other.mKeyframeTrack, other.mAnimState, other.mAnimBlendRules) - { - } - - META_Object(MWRender, AnimBlendController) - - void operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv); - void operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv); - - void setKeyframeTrack(osg::ref_ptr kft, const AnimBlendStateData& animState, - osg::ref_ptr blendRules); - - osg::Callback* getAsCallback() { return this; } + void setKeyframeTrack(const osg::ref_ptr& kft, + const AnimBlendStateData& animState, const osg::ref_ptr& blendRules); bool getBlendTrigger() const { return mBlendTrigger; } - void gatherRecursiveBoneTransforms(osgAnimation::Bone* parent, bool isRoot = true); - void applyBoneBlend(osgAnimation::Bone* parent); - - private: + protected: Easings::EasingFn mEasingFn; - float mBlendDuration; + float mBlendDuration = 0.0f; + float mBlendStartTime = 0.0f; + float mTimeFactor = 0.0f; + float mInterpFactor = 0.0f; bool mBlendTrigger = false; - float mBlendStartTime; - osg::Quat mBlendStartRot; - osg::Vec3f mBlendStartTrans; - float mBlendStartScale; - - float mTimeFactor; - float mInterpFactor; - bool mInterpActive; + bool mInterpActive = false; AnimBlendStateData mAnimState; osg::ref_ptr mAnimBlendRules; @@ -80,8 +59,55 @@ namespace MWRender inline void calculateInterpFactor(float time); }; - using NifAnimBlendController = AnimBlendController; - using BoneAnimBlendController = AnimBlendController; + 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 diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 4909fe4f89..480d1abf2f 100644 --- a/components/sceneutil/serialize.cpp +++ b/components/sceneutil/serialize.cpp @@ -187,20 +187,20 @@ namespace SceneUtil mgr->addWrapper(new GeometrySerializer); // ignore the below for now to avoid warning spam - const char* ignore[] = { "Debug::DebugDrawer", "MWRender::AnimBlendController", - "MWRender::AnimBlendController", "MWRender::BoneAnimBlendControllerWrapper", - "MWRender::PtrHolder", "Resource::TemplateRef", "Resource::TemplateMultiRef", - "SceneUtil::CompositeStateSetUpdater", "SceneUtil::UBOManager", "SceneUtil::LightListCallback", - "SceneUtil::LightManagerUpdateCallback", "SceneUtil::FFPLightStateAttribute", - "SceneUtil::UpdateRigBounds", "SceneUtil::UpdateRigGeometry", "SceneUtil::LightSource", - "SceneUtil::DisableLight", "SceneUtil::MWShadowTechnique", "SceneUtil::TextKeyMapHolder", - "Shader::AddedState", "Shader::RemovedAlphaFunc", "NifOsg::FlipController", - "NifOsg::KeyframeController", "NifOsg::Emitter", "NifOsg::ParticleColorAffector", - "NifOsg::ParticleSystem", "NifOsg::GravityAffector", "NifOsg::ParticleBomb", "NifOsg::GrowFadeAffector", - "NifOsg::InverseWorldMatrix", "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController", - "NifOsg::UpdateMorphGeometry", "NifOsg::UVController", "NifOsg::VisController", "osgMyGUI::Drawable", - "osg::DrawCallback", "osg::UniformBufferObject", "osgOQ::ClearQueriesCallback", - "osgOQ::RetrieveQueriesCallback", "osg::DummyObject" }; + const char* ignore[] = { "Debug::DebugDrawer", "MWRender::NifAnimBlendController", + "MWRender::BoneAnimBlendController", "MWRender::BoneAnimBlendControllerWrapper", "MWRender::PtrHolder", + "Resource::TemplateRef", "Resource::TemplateMultiRef", "SceneUtil::CompositeStateSetUpdater", + "SceneUtil::UBOManager", "SceneUtil::LightListCallback", "SceneUtil::LightManagerUpdateCallback", + "SceneUtil::FFPLightStateAttribute", "SceneUtil::UpdateRigBounds", "SceneUtil::UpdateRigGeometry", + "SceneUtil::LightSource", "SceneUtil::DisableLight", "SceneUtil::MWShadowTechnique", + "SceneUtil::TextKeyMapHolder", "Shader::AddedState", "Shader::RemovedAlphaFunc", + "NifOsg::FlipController", "NifOsg::KeyframeController", "NifOsg::Emitter", + "NifOsg::ParticleColorAffector", "NifOsg::ParticleSystem", "NifOsg::GravityAffector", + "NifOsg::ParticleBomb", "NifOsg::GrowFadeAffector", "NifOsg::InverseWorldMatrix", + "NifOsg::StaticBoundingBoxCallback", "NifOsg::GeomMorpherController", "NifOsg::UpdateMorphGeometry", + "NifOsg::UVController", "NifOsg::VisController", "osgMyGUI::Drawable", "osg::DrawCallback", + "osg::UniformBufferObject", "osgOQ::ClearQueriesCallback", "osgOQ::RetrieveQueriesCallback", + "osg::DummyObject" }; for (size_t i = 0; i < sizeof(ignore) / sizeof(ignore[0]); ++i) { mgr->addWrapper(makeDummySerializer(ignore[i]));