Cleanup, refactor, rename AnimBlendControllerBase -> AnimBlendController

pull/3236/head
Sam Hellawell 8 months ago
parent 42406ed0af
commit 00a7d0281f

@ -14,6 +14,7 @@
#include <osgParticle/ParticleSystem>
#include <osgAnimation/Bone>
#include <osgAnimation/UpdateBone>
#include <components/debug/debuglog.hpp>
@ -400,28 +401,25 @@ namespace
return lightModel;
}
}
namespace MWRender
{
void assignBoneBlendCallbackRecursive(
BoneAnimBlendController* controller, ActiveControllersVector& activeControllers, osg::Node* parent, bool isRoot)
void assignBoneBlendCallbackRecursive(MWRender::BoneAnimBlendController* controller,
MWRender::ActiveControllersVector& activeControllers, osg::Node* parent, bool isRoot)
{
// Attempt to cast node to an osgAnimation::Bone
osgAnimation::Bone* bone = dynamic_cast<osgAnimation::Bone*>(parent);
if (!isRoot && bone)
if (!isRoot && dynamic_cast<osgAnimation::Bone*>(parent))
{
// Wrapping in a custom callback object allows for nested callback chaining, otherwise it has link to self
// issues we need to share the base BoneAnimBlendController as that contains blending information and is
// guaranteed to update before
osg::ref_ptr<osg::Callback> cb = new BoneAnimBlendControllerWrapper(controller, bone);
osgAnimation::Bone* bone = static_cast<osgAnimation::Bone*>(parent);
osg::ref_ptr<osg::Callback> cb = new MWRender::BoneAnimBlendControllerWrapper(controller, bone);
// Ensure there is no other AnimBlendController - this can happen when using
// multiple animations with different roots, such as NPC animation
osg::Callback* updateCb = bone->getUpdateCallback();
while (updateCb)
{
if (updateCb->className() == std::string_view(controller->className()))
if (dynamic_cast<MWRender::BoneAnimBlendController*>(updateCb))
{
osg::ref_ptr<osg::Callback> nextCb = updateCb->getNestedCallback();
bone->removeUpdateCallback(updateCb);
@ -438,7 +436,7 @@ namespace MWRender
updateCb = bone->getUpdateCallback();
while (updateCb)
{
if (updateCb->className() == std::string_view("UpdateBone"))
if (dynamic_cast<osgAnimation::UpdateBone*>(updateCb))
{
// Override the immediate callback after the UpdateBone
osg::ref_ptr<osg::Callback> lastCb = updateCb->getNestedCallback();
@ -458,7 +456,10 @@ namespace MWRender
for (unsigned int i = 0; i < group->getNumChildren(); ++i)
assignBoneBlendCallbackRecursive(controller, activeControllers, group->getChild(i), false);
}
}
namespace MWRender
{
class TransparencyUpdater : public SceneUtil::StateSetUpdater
{
public:
@ -777,7 +778,7 @@ namespace MWRender
blendRules
= mResourceSystem->getAnimBlendRulesManager()->getRules(globalBlendConfigPath, blendConfigPath);
if (blendRules == nullptr)
Log(Debug::Warning) << "Animation blending files were not found '" << blendConfigPath.value()
Log(Debug::Warning) << "Unable to find animation blending rules: '" << blendConfigPath.value()
<< "' or '" << globalBlendConfigPath.value() << "'";
}
else
@ -1087,7 +1088,7 @@ namespace MWRender
template <typename ControllerType, typename NodeType>
inline osg::Callback* Animation::handleBlendTransform(osg::ref_ptr<osg::Node> node,
osg::ref_ptr<SceneUtil::KeyframeController> keyframeController,
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<AnimBlendControllerBase<NodeType>>>& blendControllers,
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<AnimBlendController<NodeType>>>& blendControllers,
const AnimBlendStateData& stateData, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules,
const AnimState& active)
{
@ -1164,7 +1165,8 @@ namespace MWRender
if (active != mStates.end())
{
std::shared_ptr<AnimSource> animsrc = active->second.mSource;
AnimBlendStateData stateData = active->second.asAnimBlendStateData();
const AnimBlendStateData stateData
= { .mGroupname = active->second.mGroupname, .mStartKey = active->second.mStartKey };
for (AnimSource::ControllerMap::iterator it = animsrc->mControllerMap[blendMask].begin();
it != animsrc->mControllerMap[blendMask].end(); ++it)
@ -1173,18 +1175,16 @@ namespace MWRender
it->first); // this should not throw, we already checked for the node existing in addAnimSource
const bool useSmoothAnims = Settings::game().mSmoothAnimTransitions;
const bool isNifTransform = dynamic_cast<NifOsg::MatrixTransform*>(node.get()) != nullptr;
const bool isBoneTransform = dynamic_cast<osgAnimation::Bone*>(node.get()) != nullptr;
osg::Callback* callback = it->second->getAsCallback();
if (useSmoothAnims)
{
if (isNifTransform)
if (dynamic_cast<NifOsg::MatrixTransform*>(node.get()))
{
callback = handleBlendTransform<AnimBlendController, NifOsg::MatrixTransform>(node,
callback = handleBlendTransform<NifAnimBlendController, NifOsg::MatrixTransform>(node,
it->second, mAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second);
}
else if (isBoneTransform)
else if (dynamic_cast<osgAnimation::Bone*>(node.get()))
{
callback
= handleBlendTransform<BoneAnimBlendController, osgAnimation::Bone>(node, it->second,
@ -1956,7 +1956,7 @@ namespace MWRender
osg::Callback* cb = node->getUpdateCallback();
while (cb)
{
if (dynamic_cast<AnimBlendController*>(cb) || dynamic_cast<BoneAnimBlendController*>(cb)
if (dynamic_cast<NifAnimBlendController*>(cb) || dynamic_cast<BoneAnimBlendController*>(cb)
|| dynamic_cast<SceneUtil::KeyframeController*>(cb))
{
foundKeyframeCtrl = true;

@ -2,13 +2,13 @@
#define GAME_RENDER_ANIMATION_H
#include "animationpriority.hpp"
#include "animblendcontroller.hpp"
#include "blendmask.hpp"
#include "bonegroup.hpp"
#include "../mwworld/movementdirection.hpp"
#include "../mwworld/ptr.hpp"
#include "animblendcontroller.hpp"
#include <components/misc/strings/algorithm.hpp>
#include <components/sceneutil/animblendrules.hpp>
#include <components/sceneutil/controller.hpp>
@ -170,12 +170,6 @@ namespace MWRender
float getTime() const { return *mTime; }
void setTime(float time) { *mTime = time; }
bool blendMaskContains(size_t blendMask) const { return (mBlendMask & (1 << blendMask)); }
AnimBlendStateData asAnimBlendStateData() const
{
AnimBlendStateData stateData = { .mGroupname = mGroupname, .mStartKey = mStartKey };
return stateData;
}
bool shouldLoop() const { return getTime() >= mLoopStopTime && mLoopingEnabled && mLoopCount > 0; }
};
@ -207,7 +201,7 @@ namespace MWRender
ActiveControllersVector mActiveControllers;
// Keep track of the animation controllers for easy access
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<AnimBlendController>> mAnimBlendControllers;
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<NifAnimBlendController>> mAnimBlendControllers;
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<BoneAnimBlendController>> mBoneAnimBlendControllers;
std::shared_ptr<AnimationTime> mAnimationTimePtr[sNumBlendMasks];
@ -315,7 +309,7 @@ namespace MWRender
template <typename ControllerType, typename NodeType>
inline osg::Callback* handleBlendTransform(osg::ref_ptr<osg::Node> node,
osg::ref_ptr<SceneUtil::KeyframeController> keyframeController,
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<AnimBlendControllerBase<NodeType>>>& blendControllers,
std::map<osg::ref_ptr<osg::Node>, osg::ref_ptr<AnimBlendController<NodeType>>>& blendControllers,
const AnimBlendStateData& stateData, const osg::ref_ptr<const SceneUtil::AnimBlendRules>& blendRules,
const AnimState& active);

@ -1,5 +1,7 @@
#include "animblendcontroller.hpp"
#include <components/debug/debuglog.hpp>
#include <osgAnimation/Bone>
#include <string>
@ -89,9 +91,8 @@ namespace MWRender
}
template <typename NodeClass>
AnimBlendControllerBase<NodeClass>::AnimBlendControllerBase(
osg::ref_ptr<SceneUtil::KeyframeController> keyframeTrack, AnimBlendStateData newState,
osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules)
AnimBlendController<NodeClass>::AnimBlendController(osg::ref_ptr<SceneUtil::KeyframeController> keyframeTrack,
const AnimBlendStateData& newState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules)
: mTimeFactor(0.0f)
, mInterpFactor(0.0f)
{
@ -99,8 +100,8 @@ namespace MWRender
}
template <typename NodeClass>
void AnimBlendControllerBase<NodeClass>::setKeyframeTrack(osg::ref_ptr<SceneUtil::KeyframeController> kft,
AnimBlendStateData newState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules)
void AnimBlendController<NodeClass>::setKeyframeTrack(osg::ref_ptr<SceneUtil::KeyframeController> kft,
const AnimBlendStateData& newState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules)
{
// If animation has changed then start blending
if (newState.mGroupname != mAnimState.mGroupname || newState.mStartKey != mAnimState.mStartKey
@ -139,7 +140,7 @@ namespace MWRender
}
template <typename NodeClass>
void AnimBlendControllerBase<NodeClass>::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot)
void AnimBlendController<NodeClass>::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot)
{
// Incase group traversal encountered something that isnt a bone
if (!bone)
@ -156,7 +157,7 @@ namespace MWRender
}
template <typename NodeClass>
void AnimBlendControllerBase<NodeClass>::applyBoneBlend(osgAnimation::Bone* bone)
void AnimBlendController<NodeClass>::applyBoneBlend(osgAnimation::Bone* bone)
{
// If we are done with interpolation then we can safely skip this as the bones are correct
if (!mInterpActive)
@ -200,7 +201,7 @@ namespace MWRender
}
template <typename NodeClass>
void AnimBlendControllerBase<NodeClass>::calculateInterpFactor(float time)
void AnimBlendController<NodeClass>::calculateInterpFactor(float time)
{
if (mBlendDuration != 0)
mTimeFactor = std::min((time - mBlendStartTime) / mBlendDuration, 1.0f);
@ -216,7 +217,7 @@ namespace MWRender
}
template <typename NodeClass>
void AnimBlendControllerBase<NodeClass>::operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv)
void AnimBlendController<NodeClass>::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
@ -236,11 +237,11 @@ namespace MWRender
if (mInterpActive)
applyBoneBlend(node);
SceneUtil::NodeCallback<AnimBlendControllerBase<NodeClass>, osgAnimation::Bone*>::traverse(node, nv);
SceneUtil::NodeCallback<AnimBlendController<NodeClass>, osgAnimation::Bone*>::traverse(node, nv);
}
template <typename NodeClass>
void AnimBlendControllerBase<NodeClass>::operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv)
void AnimBlendController<NodeClass>::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
@ -302,6 +303,6 @@ namespace MWRender
// instantly hide/show objects in which case the scale interpolation is undesirable.
node->setScale(*scale);
SceneUtil::NodeCallback<AnimBlendControllerBase<NodeClass>, NifOsg::MatrixTransform*>::traverse(node, nv);
SceneUtil::NodeCallback<AnimBlendController<NodeClass>, NifOsg::MatrixTransform*>::traverse(node, nv);
}
}

@ -8,7 +8,6 @@
#include <osgAnimation/Bone>
#include <components/debug/debuglog.hpp>
#include <components/nifosg/matrixtransform.hpp>
#include <components/sceneutil/animblendrules.hpp>
#include <components/sceneutil/controller.hpp>
@ -29,28 +28,26 @@ namespace MWRender
};
template <typename NodeClass>
class AnimBlendControllerBase : public SceneUtil::NodeCallback<AnimBlendControllerBase<NodeClass>, NodeClass*>,
public SceneUtil::Controller
class AnimBlendController : public SceneUtil::NodeCallback<AnimBlendController<NodeClass>, NodeClass*>,
public SceneUtil::Controller
{
public:
AnimBlendControllerBase(osg::ref_ptr<SceneUtil::KeyframeController> keyframeTrack, AnimBlendStateData animState,
osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules);
AnimBlendController(osg::ref_ptr<SceneUtil::KeyframeController> keyframeTrack,
const AnimBlendStateData& animState, osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules);
AnimBlendControllerBase() {}
AnimBlendController() {}
AnimBlendControllerBase(const AnimBlendControllerBase<NodeClass>& copy, const osg::CopyOp&)
: mTimeFactor(0.0f)
, mInterpFactor(0.0f)
AnimBlendController(const AnimBlendController& other, const osg::CopyOp&)
: AnimBlendController(other.mKeyframeTrack, other.mAnimState, other.mAnimBlendRules)
{
setKeyframeTrack(copy.getKeyframeTrack(), copy.getAnimState(), copy.getBlendRules());
}
META_Object(MWRender, AnimBlendControllerBase<NodeClass>)
META_Object(MWRender, AnimBlendController<NodeClass>)
void operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv);
void operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv);
void setKeyframeTrack(osg::ref_ptr<SceneUtil::KeyframeController> kft, AnimBlendStateData animState,
void setKeyframeTrack(osg::ref_ptr<SceneUtil::KeyframeController> kft, const AnimBlendStateData& animState,
osg::ref_ptr<const SceneUtil::AnimBlendRules> blendRules);
osg::Callback* getAsCallback() { return this; }
@ -60,10 +57,6 @@ namespace MWRender
void gatherRecursiveBoneTransforms(osgAnimation::Bone* parent, bool isRoot = true);
void applyBoneBlend(osgAnimation::Bone* parent);
osg::ref_ptr<SceneUtil::KeyframeController> getKeyframeTrack() const { return mKeyframeTrack; }
osg::ref_ptr<const SceneUtil::AnimBlendRules> getBlendRules() const { return mAnimBlendRules; }
AnimBlendStateData getAnimState() const { return mAnimState; }
private:
Easings::EasingFn mEasingFn;
float mBlendDuration;
@ -87,19 +80,29 @@ namespace MWRender
inline void calculateInterpFactor(float time);
};
using AnimBlendController = AnimBlendControllerBase<NifOsg::MatrixTransform>;
using BoneAnimBlendController = AnimBlendControllerBase<osgAnimation::Bone>;
using NifAnimBlendController = AnimBlendController<NifOsg::MatrixTransform>;
using BoneAnimBlendController = AnimBlendController<osgAnimation::Bone>;
// Assigned to child bones with an instance of AnimBlendControllerBase
// Assigned to child bones with an instance of AnimBlendController
class BoneAnimBlendControllerWrapper : public osg::Callback
{
public:
BoneAnimBlendControllerWrapper(osg::ref_ptr<BoneAnimBlendController> rootCallback, osg::Node* node)
BoneAnimBlendControllerWrapper(osg::ref_ptr<BoneAnimBlendController> rootCallback, osgAnimation::Bone* node)
: mRootCallback(rootCallback)
, mNode(node)
{
}
BoneAnimBlendControllerWrapper() {}
BoneAnimBlendControllerWrapper(const BoneAnimBlendControllerWrapper& copy, const osg::CopyOp&)
: mRootCallback(copy.mRootCallback)
, mNode(copy.mNode)
{
mRootCallback = rootCallback;
mNode = dynamic_cast<osgAnimation::Bone*>(node);
}
META_Object(MWRender, BoneAnimBlendControllerWrapper)
bool run(osg::Object* object, osg::Object* data) override
{
mRootCallback->applyBoneBlend(mNode);
@ -107,9 +110,6 @@ namespace MWRender
return true;
}
const char* libraryName() const override { return "openmw"; }
const char* className() const override { return "AnimBlendController"; }
private:
osg::ref_ptr<BoneAnimBlendController> mRootCallback;
osgAnimation::Bone* mNode;

@ -26,7 +26,6 @@ namespace Resource
AnimBlendRulesManager::AnimBlendRulesManager(const VFS::Manager* vfs, double expiryDelay)
: ResourceManager(vfs, expiryDelay)
, mVfs(vfs)
{
}
@ -58,27 +57,15 @@ namespace Resource
osg::ref_ptr<const AnimBlendRules> AnimBlendRulesManager::loadRules(VFS::Path::NormalizedView path)
{
const std::string normalized = VFS::Path::normalizeFilename(path.value());
std::optional<osg::ref_ptr<osg::Object>> obj = mCache->getRefFromObjectCacheOrNone(normalized);
std::optional<osg::ref_ptr<osg::Object>> obj = mCache->getRefFromObjectCacheOrNone(path);
if (obj.has_value())
{
return osg::ref_ptr<AnimBlendRules>(static_cast<AnimBlendRules*>(obj->get()));
}
else
{
osg::ref_ptr<AnimBlendRules> blendRules = AnimBlendRules::fromFile(mVfs, path);
if (blendRules)
{
// Blend rules were found in VFS, cache them.
mCache->addEntryToObjectCache(normalized, blendRules);
return blendRules;
}
}
// No blend rules were found in VFS, cache a nullptr.
osg::ref_ptr<AnimBlendRules> nullRules = nullptr;
mCache->addEntryToObjectCache(normalized, nullRules);
return nullRules;
osg::ref_ptr<AnimBlendRules> blendRules = AnimBlendRules::fromFile(mVFS, path);
mCache->addEntryToObjectCache(path.value(), blendRules);
return blendRules;
}
void AnimBlendRulesManager::reportStats(unsigned int frameNumber, osg::Stats* stats) const

@ -27,8 +27,6 @@ namespace Resource
private:
osg::ref_ptr<const SceneUtil::AnimBlendRules> loadRules(VFS::Path::NormalizedView path);
const VFS::Manager* mVfs;
};
}

@ -127,7 +127,7 @@ namespace SceneUtil
mRules.insert(mRules.end(), rules.begin(), rules.end());
}
inline bool AnimBlendRules::fitsRuleString(const std::string& str, const std::string& ruleStr) const
inline bool AnimBlendRules::fitsRuleString(const std::string_view& str, const std::string_view& ruleStr) const
{
// A wildcard only supported in the beginning or the end of the rule string in hopes that this will be more
// performant. And most likely this kind of support is enough.

@ -42,7 +42,7 @@ namespace SceneUtil
private:
std::vector<BlendRule> mRules;
inline bool fitsRuleString(const std::string& str, const std::string& ruleStr) const;
inline bool fitsRuleString(const std::string_view& str, const std::string_view& ruleStr) const;
};
}

@ -187,20 +187,20 @@ namespace SceneUtil
mgr->addWrapper(new GeometrySerializer);
// ignore the below for now to avoid warning spam
const char* ignore[] = { "Debug::DebugDrawer", "AnimBlendControllerBase<NifOsg::MatrixTransform>",
"AnimBlendControllerBase<osgAnimation::Bone>", "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::AnimBlendController<NifOsg::MatrixTransform>",
"MWRender::AnimBlendController<osgAnimation::Bone>", "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]));

Loading…
Cancel
Save