diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 73c0a414dc..04d524c70f 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -14,6 +14,7 @@ #include #include +#include #include @@ -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(parent); - if (!isRoot && bone) + if (!isRoot && dynamic_cast(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 cb = new BoneAnimBlendControllerWrapper(controller, bone); + osgAnimation::Bone* bone = static_cast(parent); + osg::ref_ptr 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(updateCb)) { osg::ref_ptr 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(updateCb)) { // Override the immediate callback after the UpdateBone osg::ref_ptr 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 inline osg::Callback* Animation::handleBlendTransform(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) { @@ -1164,7 +1165,8 @@ namespace MWRender if (active != mStates.end()) { std::shared_ptr 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(node.get()) != nullptr; - const bool isBoneTransform = dynamic_cast(node.get()) != nullptr; osg::Callback* callback = it->second->getAsCallback(); if (useSmoothAnims) { - if (isNifTransform) + if (dynamic_cast(node.get())) { - callback = handleBlendTransform(node, + callback = handleBlendTransform(node, it->second, mAnimBlendControllers, stateData, animsrc->mAnimBlendRules, active->second); } - else if (isBoneTransform) + else if (dynamic_cast(node.get())) { callback = handleBlendTransform(node, it->second, @@ -1956,7 +1956,7 @@ namespace MWRender osg::Callback* cb = node->getUpdateCallback(); while (cb) { - if (dynamic_cast(cb) || dynamic_cast(cb) + if (dynamic_cast(cb) || dynamic_cast(cb) || dynamic_cast(cb)) { foundKeyframeCtrl = true; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 82d7d98eba..b11639b21f 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -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 #include #include @@ -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> mAnimBlendControllers; + std::map, osg::ref_ptr> mAnimBlendControllers; std::map, osg::ref_ptr> mBoneAnimBlendControllers; std::shared_ptr mAnimationTimePtr[sNumBlendMasks]; @@ -315,7 +309,7 @@ namespace MWRender template inline osg::Callback* handleBlendTransform(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 e22e2ccfa3..ed3d3e955b 100644 --- a/apps/openmw/mwrender/animblendcontroller.cpp +++ b/apps/openmw/mwrender/animblendcontroller.cpp @@ -1,5 +1,7 @@ #include "animblendcontroller.hpp" +#include + #include #include @@ -89,9 +91,8 @@ namespace MWRender } template - AnimBlendControllerBase::AnimBlendControllerBase( - osg::ref_ptr keyframeTrack, AnimBlendStateData newState, - osg::ref_ptr blendRules) + AnimBlendController::AnimBlendController(osg::ref_ptr keyframeTrack, + const AnimBlendStateData& newState, osg::ref_ptr blendRules) : mTimeFactor(0.0f) , mInterpFactor(0.0f) { @@ -99,8 +100,8 @@ namespace MWRender } template - void AnimBlendControllerBase::setKeyframeTrack(osg::ref_ptr kft, - AnimBlendStateData newState, osg::ref_ptr blendRules) + void AnimBlendController::setKeyframeTrack(osg::ref_ptr kft, + const AnimBlendStateData& newState, osg::ref_ptr blendRules) { // If animation has changed then start blending if (newState.mGroupname != mAnimState.mGroupname || newState.mStartKey != mAnimState.mStartKey @@ -139,7 +140,7 @@ namespace MWRender } template - void AnimBlendControllerBase::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot) + void AnimBlendController::gatherRecursiveBoneTransforms(osgAnimation::Bone* bone, bool isRoot) { // Incase group traversal encountered something that isnt a bone if (!bone) @@ -156,7 +157,7 @@ namespace MWRender } template - void AnimBlendControllerBase::applyBoneBlend(osgAnimation::Bone* bone) + void AnimBlendController::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 - void AnimBlendControllerBase::calculateInterpFactor(float time) + void AnimBlendController::calculateInterpFactor(float time) { if (mBlendDuration != 0) mTimeFactor = std::min((time - mBlendStartTime) / mBlendDuration, 1.0f); @@ -216,7 +217,7 @@ namespace MWRender } template - void AnimBlendControllerBase::operator()(osgAnimation::Bone* node, osg::NodeVisitor* nv) + void AnimBlendController::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, osgAnimation::Bone*>::traverse(node, nv); + SceneUtil::NodeCallback, osgAnimation::Bone*>::traverse(node, nv); } template - void AnimBlendControllerBase::operator()(NifOsg::MatrixTransform* node, osg::NodeVisitor* nv) + void AnimBlendController::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, NifOsg::MatrixTransform*>::traverse(node, nv); + SceneUtil::NodeCallback, NifOsg::MatrixTransform*>::traverse(node, nv); } } diff --git a/apps/openmw/mwrender/animblendcontroller.hpp b/apps/openmw/mwrender/animblendcontroller.hpp index 59ab2cbcd5..d08db5d643 100644 --- a/apps/openmw/mwrender/animblendcontroller.hpp +++ b/apps/openmw/mwrender/animblendcontroller.hpp @@ -8,7 +8,6 @@ #include -#include #include #include #include @@ -29,28 +28,26 @@ namespace MWRender }; template - class AnimBlendControllerBase : public SceneUtil::NodeCallback, NodeClass*>, - public SceneUtil::Controller + class AnimBlendController : public SceneUtil::NodeCallback, NodeClass*>, + public SceneUtil::Controller { public: - AnimBlendControllerBase(osg::ref_ptr keyframeTrack, AnimBlendStateData animState, - osg::ref_ptr blendRules); + AnimBlendController(osg::ref_ptr keyframeTrack, + const AnimBlendStateData& animState, osg::ref_ptr blendRules); - AnimBlendControllerBase() {} + AnimBlendController() {} - AnimBlendControllerBase(const AnimBlendControllerBase& 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) + 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, AnimBlendStateData animState, + void setKeyframeTrack(osg::ref_ptr kft, const AnimBlendStateData& animState, osg::ref_ptr 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 getKeyframeTrack() const { return mKeyframeTrack; } - osg::ref_ptr 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; - using BoneAnimBlendController = AnimBlendControllerBase; + using NifAnimBlendController = AnimBlendController; + using BoneAnimBlendController = AnimBlendController; - // 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 rootCallback, osg::Node* node) + BoneAnimBlendControllerWrapper(osg::ref_ptr 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(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 mRootCallback; osgAnimation::Bone* mNode; diff --git a/components/resource/animblendrulesmanager.cpp b/components/resource/animblendrulesmanager.cpp index 68560c3ed1..550315cace 100644 --- a/components/resource/animblendrulesmanager.cpp +++ b/components/resource/animblendrulesmanager.cpp @@ -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 AnimBlendRulesManager::loadRules(VFS::Path::NormalizedView path) { - const std::string normalized = VFS::Path::normalizeFilename(path.value()); - std::optional> obj = mCache->getRefFromObjectCacheOrNone(normalized); + std::optional> obj = mCache->getRefFromObjectCacheOrNone(path); if (obj.has_value()) { return osg::ref_ptr(static_cast(obj->get())); } - else - { - osg::ref_ptr 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 nullRules = nullptr; - mCache->addEntryToObjectCache(normalized, nullRules); - return nullRules; + osg::ref_ptr blendRules = AnimBlendRules::fromFile(mVFS, path); + mCache->addEntryToObjectCache(path.value(), blendRules); + return blendRules; } void AnimBlendRulesManager::reportStats(unsigned int frameNumber, osg::Stats* stats) const diff --git a/components/resource/animblendrulesmanager.hpp b/components/resource/animblendrulesmanager.hpp index cab8f01985..79fd869954 100644 --- a/components/resource/animblendrulesmanager.hpp +++ b/components/resource/animblendrulesmanager.hpp @@ -27,8 +27,6 @@ namespace Resource private: osg::ref_ptr loadRules(VFS::Path::NormalizedView path); - - const VFS::Manager* mVfs; }; } diff --git a/components/sceneutil/animblendrules.cpp b/components/sceneutil/animblendrules.cpp index 716eb62374..2f760f41f3 100644 --- a/components/sceneutil/animblendrules.cpp +++ b/components/sceneutil/animblendrules.cpp @@ -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. diff --git a/components/sceneutil/animblendrules.hpp b/components/sceneutil/animblendrules.hpp index db03c0fd0a..913d3531c0 100644 --- a/components/sceneutil/animblendrules.hpp +++ b/components/sceneutil/animblendrules.hpp @@ -42,7 +42,7 @@ namespace SceneUtil private: std::vector 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; }; } diff --git a/components/sceneutil/serialize.cpp b/components/sceneutil/serialize.cpp index 73be49929c..4909fe4f89 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", "AnimBlendControllerBase", - "AnimBlendControllerBase", "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", + "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" }; for (size_t i = 0; i < sizeof(ignore) / sizeof(ignore[0]); ++i) { mgr->addWrapper(makeDummySerializer(ignore[i]));