From f78a5d795c0395c48d441989ddaeaffb6eae02d4 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Wed, 18 Nov 2020 22:48:47 +0200 Subject: [PATCH 1/6] Separate keyframes logic to provide basis for osgAnimation integration. --- apps/openmw/mwmechanics/character.cpp | 2 +- apps/openmw/mwmechanics/character.hpp | 2 +- apps/openmw/mwrender/animation.cpp | 43 ++++++------ apps/openmw/mwrender/animation.hpp | 20 +++--- apps/openmw/mwrender/npcanimation.cpp | 5 +- components/nifosg/controller.cpp | 3 +- components/nifosg/controller.hpp | 6 +- components/nifosg/nifloader.cpp | 18 ++--- components/nifosg/nifloader.hpp | 38 +---------- components/resource/keyframemanager.cpp | 53 +++++++++++++-- components/resource/keyframemanager.hpp | 10 ++- components/resource/resourcesystem.cpp | 2 +- components/sceneutil/keyframe.hpp | 68 +++++++++++++++++++ .../{nifosg => sceneutil}/textkeymap.hpp | 6 +- 14 files changed, 174 insertions(+), 102 deletions(-) create mode 100644 components/sceneutil/keyframe.hpp rename components/{nifosg => sceneutil}/textkeymap.hpp (94%) diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 657f2e2eca..9b3c8576ea 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -936,7 +936,7 @@ void split(const std::string &s, char delim, std::vector &elems) { } } -void CharacterController::handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map) +void CharacterController::handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) { const std::string &evt = key->second; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 949affcfde..2308ba971d 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -241,7 +241,7 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); - void handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map) override; + void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, const SceneUtil::TextKeyMap& map) override; // Be careful when to call this, see comment in Actors void updateContinuousVfx(); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 10a6b2be42..f8ff3780d3 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -20,8 +20,7 @@ #include #include -#include // KeyframeHolder -#include +#include #include @@ -148,7 +147,7 @@ namespace } }; - float calcAnimVelocity(const NifOsg::TextKeyMap& keys, NifOsg::KeyframeController *nonaccumctrl, + float calcAnimVelocity(const SceneUtil::TextKeyMap& keys, SceneUtil::KeyframeController *nonaccumctrl, const osg::Vec3f& accum, const std::string &groupname) { const std::string start = groupname+": start"; @@ -530,13 +529,13 @@ namespace MWRender struct Animation::AnimSource { - osg::ref_ptr mKeyframes; + osg::ref_ptr mKeyframes; - typedef std::map > ControllerMap; + typedef std::map > ControllerMap; ControllerMap mControllerMap[Animation::sNumBlendMasks]; - const NifOsg::TextKeyMap& getTextKeys() const; + const SceneUtil::TextKeyMap& getTextKeys() const; }; void UpdateVfxCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) @@ -688,7 +687,7 @@ namespace MWRender return 0; } - const NifOsg::TextKeyMap &Animation::AnimSource::getTextKeys() const + const SceneUtil::TextKeyMap &Animation::AnimSource::getTextKeys() const { return mKeyframes->mTextKeys; } @@ -729,8 +728,6 @@ namespace MWRender if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) kfname.replace(kfname.size()-4, 4, ".kf"); - else - return; addSingleAnimSource(kfname, baseModel); @@ -753,7 +750,7 @@ namespace MWRender const NodeMap& nodeMap = getNodeMap(); - for (NifOsg::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin(); + for (SceneUtil::KeyframeHolder::KeyframeControllerMap::const_iterator it = animsrc->mKeyframes->mKeyframeControllers.begin(); it != animsrc->mKeyframes->mKeyframeControllers.end(); ++it) { std::string bonename = Misc::StringUtils::lowerCase(it->first); @@ -769,7 +766,7 @@ namespace MWRender size_t blendMask = detectBlendMask(node); // clone the controller, because each Animation needs its own ControllerSource - osg::ref_ptr cloned = new NifOsg::KeyframeController(*it->second, osg::CopyOp::SHALLOW_COPY); + osg::ref_ptr cloned = osg::clone(it->second.get(), osg::CopyOp::SHALLOW_COPY); cloned->setSource(mAnimationTimePtr[blendMask]); animsrc->mControllerMap[blendMask].insert(std::make_pair(bonename, cloned)); @@ -810,7 +807,7 @@ namespace MWRender AnimSourceList::const_iterator iter(mAnimSources.begin()); for(;iter != mAnimSources.end();++iter) { - const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + const SceneUtil::TextKeyMap &keys = (*iter)->getTextKeys(); if (keys.hasGroupStart(anim)) return true; } @@ -822,7 +819,7 @@ namespace MWRender { for(AnimSourceList::const_reverse_iterator iter(mAnimSources.rbegin()); iter != mAnimSources.rend(); ++iter) { - const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + const SceneUtil::TextKeyMap &keys = (*iter)->getTextKeys(); const auto found = keys.findGroupStart(groupname); if(found != keys.end()) @@ -835,7 +832,7 @@ namespace MWRender { for(AnimSourceList::const_reverse_iterator iter(mAnimSources.rbegin()); iter != mAnimSources.rend(); ++iter) { - const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); + const SceneUtil::TextKeyMap &keys = (*iter)->getTextKeys(); for(auto iterKey = keys.begin(); iterKey != keys.end(); ++iterKey) { @@ -847,8 +844,8 @@ namespace MWRender return -1.f; } - void Animation::handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, - const NifOsg::TextKeyMap& map) + void Animation::handleTextKey(AnimState &state, const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, + const SceneUtil::TextKeyMap& map) { const std::string &evt = key->second; @@ -911,7 +908,7 @@ namespace MWRender AnimSourceList::reverse_iterator iter(mAnimSources.rbegin()); for(;iter != mAnimSources.rend();++iter) { - const NifOsg::TextKeyMap &textkeys = (*iter)->getTextKeys(); + const SceneUtil::TextKeyMap &textkeys = (*iter)->getTextKeys(); if(reset(state, textkeys, groupname, start, stop, startpoint, loopfallback)) { state.mSource = *iter; @@ -956,7 +953,7 @@ namespace MWRender resetActiveGroups(); } - bool Animation::reset(AnimState &state, const NifOsg::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) + bool Animation::reset(AnimState &state, const SceneUtil::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback) { // Look for text keys in reverse. This normally wouldn't matter, but for some reason undeadwolf_2.nif has two // separate walkforward keys, and the last one is supposed to be used. @@ -1186,7 +1183,7 @@ namespace MWRender AnimSourceList::const_reverse_iterator animsrc(mAnimSources.rbegin()); for(;animsrc != mAnimSources.rend();++animsrc) { - const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys(); + const SceneUtil::TextKeyMap &keys = (*animsrc)->getTextKeys(); if (keys.hasGroupStart(groupname)) break; } @@ -1194,7 +1191,7 @@ namespace MWRender return 0.0f; float velocity = 0.0f; - const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys(); + const SceneUtil::TextKeyMap &keys = (*animsrc)->getTextKeys(); const AnimSource::ControllerMap& ctrls = (*animsrc)->mControllerMap[0]; for (AnimSource::ControllerMap::const_iterator it = ctrls.begin(); it != ctrls.end(); ++it) @@ -1215,7 +1212,7 @@ namespace MWRender while(!(velocity > 1.0f) && ++animiter != mAnimSources.rend()) { - const NifOsg::TextKeyMap &keys2 = (*animiter)->getTextKeys(); + const SceneUtil::TextKeyMap &keys2 = (*animiter)->getTextKeys(); const AnimSource::ControllerMap& ctrls2 = (*animiter)->mControllerMap[0]; for (AnimSource::ControllerMap::const_iterator it = ctrls2.begin(); it != ctrls2.end(); ++it) @@ -1265,7 +1262,7 @@ namespace MWRender continue; } - const NifOsg::TextKeyMap &textkeys = state.mSource->getTextKeys(); + const SceneUtil::TextKeyMap &textkeys = state.mSource->getTextKeys(); auto textkey = textkeys.upperBound(state.getTime()); float timepassed = duration * state.mSpeedMult; @@ -1839,7 +1836,7 @@ namespace MWRender osg::Callback* cb = node->getUpdateCallback(); while (cb) { - if (dynamic_cast(cb)) + if (dynamic_cast(cb)) { foundKeyframeCtrl = true; break; diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 9d03831be5..ebfe8a2e59 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -4,8 +4,8 @@ #include "../mwworld/ptr.hpp" #include +#include #include -#include #include @@ -20,14 +20,10 @@ namespace Resource class ResourceSystem; } -namespace NifOsg +namespace SceneUtil { class KeyframeHolder; class KeyframeController; -} - -namespace SceneUtil -{ class LightSource; class LightListCallback; class Skeleton; @@ -150,8 +146,8 @@ public: class TextKeyListener { public: - virtual void handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, - const NifOsg::TextKeyMap& map) = 0; + virtual void handleTextKey(const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, + const SceneUtil::TextKeyMap& map) = 0; virtual ~TextKeyListener() = default; }; @@ -242,7 +238,7 @@ protected: osg::ref_ptr mAccumRoot; // The controller animating that node. - osg::ref_ptr mAccumCtrl; + osg::ref_ptr mAccumCtrl; // Used to reset the position of the accumulation root every frame - the movement should be applied to the physics system osg::ref_ptr mResetAccumRootCallback; @@ -306,12 +302,12 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(AnimState &state, const NifOsg::TextKeyMap &keys, + bool reset(AnimState &state, const SceneUtil::TextKeyMap &keys, const std::string &groupname, const std::string &start, const std::string &stop, float startpoint, bool loopfallback); - void handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, - const NifOsg::TextKeyMap& map); + void handleTextKey(AnimState &state, const std::string &groupname, SceneUtil::TextKeyMap::ConstIterator key, + const SceneUtil::TextKeyMap& map); /** Sets the root model of the object. * diff --git a/apps/openmw/mwrender/npcanimation.cpp b/apps/openmw/mwrender/npcanimation.cpp index 36213fc96d..d97e57115a 100644 --- a/apps/openmw/mwrender/npcanimation.cpp +++ b/apps/openmw/mwrender/npcanimation.cpp @@ -19,11 +19,10 @@ #include #include #include +#include #include -#include // TextKeyMapHolder - #include #include "../mwworld/esmstore.hpp" @@ -864,7 +863,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g for (unsigned int i=0; igetUserDataContainer()->getNumUserObjects(); ++i) { osg::Object* obj = node->getUserDataContainer()->getUserObject(i); - if (NifOsg::TextKeyMapHolder* keys = dynamic_cast(obj)) + if (SceneUtil::TextKeyMapHolder* keys = dynamic_cast(obj)) { for (const auto &key : keys->mTextKeys) { diff --git a/components/nifosg/controller.cpp b/components/nifosg/controller.cpp index 64e9f7de6c..31fd92b43e 100644 --- a/components/nifosg/controller.cpp +++ b/components/nifosg/controller.cpp @@ -71,8 +71,7 @@ KeyframeController::KeyframeController() } KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) - : osg::NodeCallback(copy, copyop) - , Controller(copy) + : SceneUtil::KeyframeController(copy, copyop) , mRotations(copy.mRotations) , mXRotations(copy.mXRotations) , mYRotations(copy.mYRotations) diff --git a/components/nifosg/controller.hpp b/components/nifosg/controller.hpp index 996e4ef979..0063b2ec0f 100644 --- a/components/nifosg/controller.hpp +++ b/components/nifosg/controller.hpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include @@ -226,7 +226,7 @@ namespace NifOsg std::vector mKeyFrames; }; - class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller + class KeyframeController : public SceneUtil::KeyframeController { public: // This is used if there's no interpolator but there is data (Morrowind meshes). @@ -242,7 +242,7 @@ namespace NifOsg META_Object(NifOsg, KeyframeController) - virtual osg::Vec3f getTranslation(float time) const; + osg::Vec3f getTranslation(float time) const override; void operator() (osg::Node*, osg::NodeVisitor*) override; diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index a5a61b3176..751bdb51fe 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -139,7 +139,7 @@ namespace } }; - void extractTextKeys(const Nif::NiTextKeyExtraData *tk, NifOsg::TextKeyMap &textkeys) + void extractTextKeys(const Nif::NiTextKeyExtraData *tk, SceneUtil::TextKeyMap &textkeys) { for(size_t i = 0;i < tk->list.size();i++) { @@ -234,7 +234,7 @@ namespace NifOsg // This is used to queue emitters that weren't attached to their node yet. std::vector>> mEmitterQueue; - static void loadKf(Nif::NIFFilePtr nif, KeyframeHolder& target) + static void loadKf(Nif::NIFFilePtr nif, SceneUtil::KeyframeHolder& target) { const Nif::NiSequenceStreamHelper *seq = nullptr; const size_t numRoots = nif->numRoots(); @@ -284,7 +284,7 @@ namespace NifOsg if (key->data.empty() && key->interpolator.empty()) continue; - osg::ref_ptr callback(handleKeyframeController(key)); + osg::ref_ptr callback(handleKeyframeController(key)); callback->setFunction(std::shared_ptr(new NifOsg::ControllerFunction(key))); if (!target.mKeyframeControllers.emplace(strdata->string, callback).second) @@ -305,7 +305,7 @@ namespace NifOsg if (!nifNode) nif->fail("Found no root nodes"); - osg::ref_ptr textkeys (new TextKeyMapHolder); + osg::ref_ptr textkeys (new SceneUtil::TextKeyMapHolder); osg::ref_ptr created = handleNode(nifNode, nullptr, imageManager, std::vector(), 0, false, false, false, &textkeys->mTextKeys); @@ -353,10 +353,10 @@ namespace NifOsg else if (props[i].getPtr()->recType == Nif::RC_NiTexturingProperty) { if (props[i].getPtr()->recIndex == mFirstRootTextureIndex) - applyTo->setUserValue("overrideFx", 1); + applyTo->setUserValue("overrideFx", 1); } handleProperty(props[i].getPtr(), applyTo, composite, imageManager, boundTextures, animflags); - } + } } } @@ -514,7 +514,7 @@ namespace NifOsg } osg::ref_ptr handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager, - std::vector boundTextures, int animflags, bool skipMeshes, bool hasMarkers, bool hasAnimatedParents, TextKeyMap* textKeys, osg::Node* rootNode=nullptr) + std::vector boundTextures, int animflags, bool skipMeshes, bool hasMarkers, bool hasAnimatedParents, SceneUtil::TextKeyMap* textKeys, osg::Node* rootNode=nullptr) { if (rootNode != nullptr && Misc::StringUtils::ciEqual(nifNode->name, "Bounding Box")) return nullptr; @@ -1197,7 +1197,7 @@ namespace NifOsg for (const auto& strip : data->strips) { if (strip.size() >= 3) - geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), + geometry->addPrimitiveSet(new osg::DrawElementsUShort(osg::PrimitiveSet::TRIANGLE_STRIP, strip.size(), (unsigned short*)strip.data())); } } @@ -1929,7 +1929,7 @@ namespace NifOsg return impl.load(file, imageManager); } - void Loader::loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target) + void Loader::loadKf(Nif::NIFFilePtr kf, SceneUtil::KeyframeHolder& target) { LoaderImpl impl(kf->getFilename(), kf->getVersion(), kf->getUserVersion(), kf->getBethVersion()); impl.loadKf(kf, target); diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 49a78ad5f6..8ee6b41674 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -2,12 +2,13 @@ #define OPENMW_COMPONENTS_NIFOSG_LOADER #include +#include +#include #include #include #include "controller.hpp" -#include "textkeymap.hpp" namespace osg { @@ -21,39 +22,6 @@ namespace Resource namespace NifOsg { - struct TextKeyMapHolder : public osg::Object - { - public: - TextKeyMapHolder() {} - TextKeyMapHolder(const TextKeyMapHolder& copy, const osg::CopyOp& copyop) - : osg::Object(copy, copyop) - , mTextKeys(copy.mTextKeys) - {} - - TextKeyMap mTextKeys; - - META_Object(NifOsg, TextKeyMapHolder) - - }; - - class KeyframeHolder : public osg::Object - { - public: - KeyframeHolder() {} - KeyframeHolder(const KeyframeHolder& copy, const osg::CopyOp& copyop) - : mTextKeys(copy.mTextKeys) - , mKeyframeControllers(copy.mKeyframeControllers) - { - } - - TextKeyMap mTextKeys; - - META_Object(OpenMW, KeyframeHolder) - - typedef std::map > KeyframeControllerMap; - KeyframeControllerMap mKeyframeControllers; - }; - /// The main class responsible for loading NIF files into an OSG-Scenegraph. /// @par This scene graph is self-contained and can be cloned using osg::clone if desired. Particle emitters /// and programs hold a pointer to their ParticleSystem, which would need to be manually updated when cloning. @@ -64,7 +32,7 @@ namespace NifOsg static osg::ref_ptr load(Nif::NIFFilePtr file, Resource::ImageManager* imageManager); /// Load keyframe controllers from the given kf file. - static void loadKf(Nif::NIFFilePtr kf, KeyframeHolder& target); + static void loadKf(Nif::NIFFilePtr kf, SceneUtil::KeyframeHolder& target); /// Set whether or not nodes marked as "MRK" should be shown. /// These should be hidden ingame, but visible in the editor. diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 8c5c50adca..ef6339adb5 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -2,13 +2,45 @@ #include +#include + #include "objectcache.hpp" +#include "scenemanager.hpp" + +namespace +{ + class RetrieveAnimationsVisitor : public osg::NodeVisitor + { + public: + RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target) {} + + + virtual void apply(osg::Node& node) + { + if (node.libraryName() == std::string("osgAnimation")) + std::cout << "found an " << node.className() << std::endl; + traverse(node); + } + + private: + SceneUtil::KeyframeHolder& mTarget; + }; + + std::string getFileExtension(const std::string& file) + { + size_t extPos = file.find_last_of('.'); + if (extPos != std::string::npos && extPos+1 < file.size()) + return file.substr(extPos+1); + return std::string(); + } +} namespace Resource { - KeyframeManager::KeyframeManager(const VFS::Manager* vfs) + KeyframeManager::KeyframeManager(const VFS::Manager* vfs, SceneManager* sceneManager) : ResourceManager(vfs) + , mSceneManager(sceneManager) { } @@ -16,19 +48,28 @@ namespace Resource { } - osg::ref_ptr KeyframeManager::get(const std::string &name) + osg::ref_ptr KeyframeManager::get(const std::string &name) { std::string normalized = name; mVFS->normalizeFilename(normalized); osg::ref_ptr obj = mCache->getRefFromObjectCache(normalized); if (obj) - return osg::ref_ptr(static_cast(obj.get())); + return osg::ref_ptr(static_cast(obj.get())); else { - osg::ref_ptr loaded (new NifOsg::KeyframeHolder); - NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); - + osg::ref_ptr loaded (new SceneUtil::KeyframeHolder); + std::string ext = getFileExtension(normalized); + if (ext == "kf") + { + NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); + } + else + { + osg::ref_ptr scene = mSceneManager->getTemplate(normalized); + RetrieveAnimationsVisitor rav(*loaded.get()); + const_cast(scene.get())->accept(rav); // const_cast required because there is no const version of osg::NodeVisitor + } mCache->addEntryToObjectCache(normalized, loaded); return loaded; } diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index fe1c4014e0..e186e2783b 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -4,26 +4,30 @@ #include #include -#include +#include #include "resourcemanager.hpp" namespace Resource { + class SceneManager; + /// @brief Managing of keyframe resources /// @note May be used from any thread. class KeyframeManager : public ResourceManager { public: - KeyframeManager(const VFS::Manager* vfs); + KeyframeManager(const VFS::Manager* vfs, SceneManager* sceneManager); ~KeyframeManager(); /// Retrieve a read-only keyframe resource by name (case-insensitive). /// @note Throws an exception if the resource is not found. - osg::ref_ptr get(const std::string& name); + osg::ref_ptr get(const std::string& name); void reportStats(unsigned int frameNumber, osg::Stats* stats) const override; + private: + SceneManager* mSceneManager; }; } diff --git a/components/resource/resourcesystem.cpp b/components/resource/resourcesystem.cpp index 2015ba874d..ab9d0aba2c 100644 --- a/components/resource/resourcesystem.cpp +++ b/components/resource/resourcesystem.cpp @@ -14,9 +14,9 @@ namespace Resource : mVFS(vfs) { mNifFileManager.reset(new NifFileManager(vfs)); - mKeyframeManager.reset(new KeyframeManager(vfs)); mImageManager.reset(new ImageManager(vfs)); mSceneManager.reset(new SceneManager(vfs, mImageManager.get(), mNifFileManager.get())); + mKeyframeManager.reset(new KeyframeManager(vfs, mSceneManager.get())); addResourceManager(mNifFileManager.get()); addResourceManager(mKeyframeManager.get()); diff --git a/components/sceneutil/keyframe.hpp b/components/sceneutil/keyframe.hpp new file mode 100644 index 0000000000..c993c7b7c7 --- /dev/null +++ b/components/sceneutil/keyframe.hpp @@ -0,0 +1,68 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_KEYFRAME_HPP +#define OPENMW_COMPONENTS_SCENEUTIL_KEYFRAME_HPP + +#include + +#include + +#include +#include + +namespace SceneUtil +{ + + class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller + { + public: + KeyframeController() {} + + KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop) + : osg::NodeCallback(copy, copyop) + , SceneUtil::Controller(copy) + {} + META_Object(SceneUtil, KeyframeController) + + virtual osg::Vec3f getTranslation(float time) const { return osg::Vec3f(); } + + virtual void operator() (osg::Node* node, osg::NodeVisitor* nodeVisitor) { traverse(node, nodeVisitor); } + }; + + /// Wrapper object containing an animation track as a ref-countable osg::Object. + struct TextKeyMapHolder : public osg::Object + { + public: + TextKeyMapHolder() {} + TextKeyMapHolder(const TextKeyMapHolder& copy, const osg::CopyOp& copyop) + : osg::Object(copy, copyop) + , mTextKeys(copy.mTextKeys) + {} + + TextKeyMap mTextKeys; + + META_Object(SceneUtil, TextKeyMapHolder) + + }; + + /// Wrapper object containing the animation track and its KeyframeControllers. + class KeyframeHolder : public osg::Object + { + public: + KeyframeHolder() {} + KeyframeHolder(const KeyframeHolder& copy, const osg::CopyOp& copyop) + : mTextKeys(copy.mTextKeys) + , mKeyframeControllers(copy.mKeyframeControllers) + { + } + + TextKeyMap mTextKeys; + + META_Object(SceneUtil, KeyframeHolder) + + /// Controllers mapped to node name. + typedef std::map > KeyframeControllerMap; + KeyframeControllerMap mKeyframeControllers; + }; + +} + +#endif diff --git a/components/nifosg/textkeymap.hpp b/components/sceneutil/textkeymap.hpp similarity index 94% rename from components/nifosg/textkeymap.hpp rename to components/sceneutil/textkeymap.hpp index 49e1e461e4..ee58bc72a7 100644 --- a/components/nifosg/textkeymap.hpp +++ b/components/sceneutil/textkeymap.hpp @@ -1,12 +1,12 @@ -#ifndef OPENMW_COMPONENTS_NIFOSG_TEXTKEYMAP -#define OPENMW_COMPONENTS_NIFOSG_TEXTKEYMAP +#ifndef OPENMW_COMPONENTS_SCENEUTIL_TEXTKEYMAP +#define OPENMW_COMPONENTS_SCENEUTIL_TEXTKEYMAP #include #include #include #include -namespace NifOsg +namespace SceneUtil { class TextKeyMap { From 6e77ad1f6a77cd31bd7fbf8ed7007015899013e9 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Thu, 19 Nov 2020 01:11:56 +0200 Subject: [PATCH 2/6] OSG-Collada animation support --- CMakeLists.txt | 2 +- apps/openmw/mwrender/animation.cpp | 2 + components/CMakeLists.txt | 5 +- components/resource/animation.cpp | 40 +++++ components/resource/animation.hpp | 39 +++++ components/resource/keyframemanager.cpp | 94 +++++++++--- components/resource/keyframemanager.hpp | 20 +++ components/resource/scenemanager.cpp | 2 +- components/sceneutil/clone.cpp | 12 +- components/sceneutil/keyframe.hpp | 13 ++ components/sceneutil/osgacontroller.cpp | 195 ++++++++++++++++++++++++ components/sceneutil/osgacontroller.hpp | 70 +++++++++ 12 files changed, 471 insertions(+), 23 deletions(-) create mode 100644 components/resource/animation.cpp create mode 100644 components/resource/animation.hpp create mode 100644 components/sceneutil/osgacontroller.cpp create mode 100644 components/sceneutil/osgacontroller.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 37696f44c4..76764fbd93 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -259,7 +259,7 @@ if(NOT HAVE_STDINT_H) endif() -find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX osgShadow) +find_package(OpenSceneGraph 3.3.4 REQUIRED osgDB osgViewer osgText osgGA osgParticle osgUtil osgFX osgShadow osgAnimation) include_directories(SYSTEM ${OPENSCENEGRAPH_INCLUDE_DIRS}) set(USED_OSG_PLUGINS diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index f8ff3780d3..8c9f5f4939 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -782,6 +782,8 @@ namespace MWRender NodeMap::const_iterator found = nodeMap.find("bip01"); if (found == nodeMap.end()) found = nodeMap.find("root bone"); + if (found == nodeMap.end()) + found = nodeMap.find("root"); if (found != nodeMap.end()) mAccumRoot = found->second; diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 08f183f5e8..3c18990375 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -41,7 +41,8 @@ add_component_dir (vfs ) add_component_dir (resource - scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem resourcemanager stats + scenemanager keyframemanager imagemanager bulletshapemanager bulletshape niffilemanager objectcache multiobjectcache resourcesystem + resourcemanager stats animation ) add_component_dir (shader @@ -51,7 +52,7 @@ add_component_dir (shader add_component_dir (sceneutil clone attach visitor util statesetupdater controller skeleton riggeometry morphgeometry lightcontroller lightmanager lightutil positionattitudetransform workqueue unrefqueue pathgridutil waterutil writescene serialize optimizer - actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin + actorutil detourdebugdraw navmesh agentpath shadow mwshadowtechnique recastmesh shadowsbin osgacontroller ) add_component_dir (nif diff --git a/components/resource/animation.cpp b/components/resource/animation.cpp new file mode 100644 index 0000000000..34ae162ee7 --- /dev/null +++ b/components/resource/animation.cpp @@ -0,0 +1,40 @@ +#include + +#include +#include + +namespace Resource +{ + Animation::Animation(const Animation& anim, const osg::CopyOp& copyop): osg::Object(anim, copyop), + mDuration(0.0f), + mStartTime(0.0f) + { + const osgAnimation::ChannelList& channels = anim.getChannels(); + for (const osg::ref_ptr channel: channels) + addChannel(channel.get()->clone()); + } + + void Animation::addChannel(osg::ref_ptr pChannel) + { + mChannels.push_back(pChannel); + } + + std::vector>& Animation::getChannels() + { + return mChannels; + } + + const std::vector>& Animation::getChannels() const + { + return mChannels; + } + + bool Animation::update (double time) + { + for (const osg::ref_ptr channel: mChannels) + { + channel->update(time, 1.0f, 0); + } + return true; + } +} diff --git a/components/resource/animation.hpp b/components/resource/animation.hpp new file mode 100644 index 0000000000..885394747e --- /dev/null +++ b/components/resource/animation.hpp @@ -0,0 +1,39 @@ +#ifndef OPENMW_COMPONENTS_RESOURCE_ANIMATION_HPP +#define OPENMW_COMPONENTS_RESOURCE_ANIMATION_HPP + +#include + +#include +#include +#include + +namespace Resource +{ + /// Stripped down class of osgAnimation::Animation, only needed for OSG's plugin formats like dae + class Animation : public osg::Object + { + public: + META_Object(Resource, Animation) + + Animation() : + mDuration(0.0), mStartTime(0) {} + + Animation(const Animation&, const osg::CopyOp&); + ~Animation() {} + + void addChannel (osg::ref_ptr pChannel); + + std::vector>& getChannels(); + + const std::vector>& getChannels() const; + + bool update (double time); + + protected: + double mDuration; + double mStartTime; + std::vector> mChannels; + }; +} + +#endif diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index ef6339adb5..6cda9728cd 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -2,29 +2,86 @@ #include -#include +#include +#include +#include +#include +#include +#include + +#include "animation.hpp" #include "objectcache.hpp" #include "scenemanager.hpp" -namespace +namespace OsgAOpenMW { - class RetrieveAnimationsVisitor : public osg::NodeVisitor + + RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr animationManager) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager) {} + + void RetrieveAnimationsVisitor::apply(osg::Node& node) { - public: - RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target) {} + if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && node.getName() == std::string("root")) + { + if (!mAnimationManager) + { + traverse(node); + return; + } + osg::ref_ptr callback = new OsgaController::KeyframeController(); - virtual void apply(osg::Node& node) - { - if (node.libraryName() == std::string("osgAnimation")) - std::cout << "found an " << node.className() << std::endl; - traverse(node); - } + std::vector emulatedAnimations; - private: - SceneUtil::KeyframeHolder& mTarget; - }; + for (auto animation : mAnimationManager->getAnimationList()) + { + if (animation) + { + if (animation->getName() == "Default") //"Default" is osg dae plugin's default naming scheme for unnamed animations + { + animation->setName(std::string("idle")); // animation naming scheme "idle: start" and "idle: stop" is the default idle animation that OpenMW seems to want to play + } + + osg::ref_ptr mergedAnimationTrack = new Resource::Animation; + std::string animationName = animation->getName(); + std::string start = animationName + std::string(": start"); + std::string stop = animationName + std::string(": stop"); + std::string loopstart = animationName + std::string(": loop start"); + std::string loopstop = animationName + std::string(": loop stop"); + + const osgAnimation::ChannelList& channels = animation->getChannels(); + for (const osg::ref_ptr channel: channels) + { + mergedAnimationTrack->addChannel(channel.get()->clone()); // is ->clone needed? + } + mergedAnimationTrack->setName(animation->getName()); + callback->addMergedAnimationTrack(mergedAnimationTrack); + + float startTime = animation->getStartTime(); + float stopTime = startTime + animation->getDuration(); + + // mTextKeys is a nif-thing, used by OpenMW's animation system + // Format is likely "AnimationName: [Keyword_optional] [Start OR Stop]" + // AnimationNames are keywords like idle2, idle3... AiPackages and various mechanics control which animations are played + // Keywords can be stuff like Loop, Equip, Unequip, Block, InventoryHandtoHand, InventoryWeaponOneHand, PickProbe, Slash, Thrust, Chop... even "Slash Small Follow" + mTarget.mTextKeys.emplace(startTime, std::move(start)); + mTarget.mTextKeys.emplace(stopTime, std::move(stop)); + mTarget.mTextKeys.emplace(startTime, std::move(loopstart)); + mTarget.mTextKeys.emplace(stopTime, std::move(loopstop)); + + SceneUtil::EmulatedAnimation emulatedAnimation; + emulatedAnimation.mStartTime = startTime; + emulatedAnimation.mStopTime = stopTime; + emulatedAnimation.mName = animationName; + emulatedAnimations.emplace_back(emulatedAnimation); + } + } + callback->setEmulatedAnimations(emulatedAnimations); + mTarget.mKeyframeControllers.emplace(node.getName(), callback); + } + + traverse(node); + } std::string getFileExtension(const std::string& file) { @@ -59,16 +116,17 @@ namespace Resource else { osg::ref_ptr loaded (new SceneUtil::KeyframeHolder); - std::string ext = getFileExtension(normalized); + std::string ext = OsgAOpenMW::getFileExtension(normalized); if (ext == "kf") { NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); } else { - osg::ref_ptr scene = mSceneManager->getTemplate(normalized); - RetrieveAnimationsVisitor rav(*loaded.get()); - const_cast(scene.get())->accept(rav); // const_cast required because there is no const version of osg::NodeVisitor + osg::ref_ptr scene = const_cast ( mSceneManager->getTemplate(normalized).get() ); + osg::ref_ptr bam = dynamic_cast (scene->getUpdateCallback()); + OsgAOpenMW::RetrieveAnimationsVisitor rav(*loaded.get(), bam); + scene->accept(rav); } mCache->addEntryToObjectCache(normalized, loaded); return loaded; diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index e186e2783b..4f83196f34 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -2,12 +2,32 @@ #define OPENMW_COMPONENTS_KEYFRAMEMANAGER_H #include +#include #include #include #include "resourcemanager.hpp" +namespace OsgAOpenMW +{ + /// @brief extract animations to OpenMW's animation system + class RetrieveAnimationsVisitor : public osg::NodeVisitor + { + public: + RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr animationManager); + + virtual void apply(osg::Node& node); + + private: + SceneUtil::KeyframeHolder& mTarget; + osg::ref_ptr mAnimationManager; + + }; + + std::string getFileExtension(const std::string& file); +} + namespace Resource { diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index 44ba7e6878..e99003b749 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -492,7 +492,7 @@ namespace Resource } catch (std::exception& e) { - static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2" }; + static const char * const sMeshTypes[] = { "nif", "osg", "osgt", "osgb", "osgx", "osg2", "dae" }; for (unsigned int i=0; i +#include +#include +#include +#include + #include #include #include @@ -30,6 +35,11 @@ namespace SceneUtil mUpdaterToOldPs[cloned] = updater->getParticleSystem(0); return cloned; } + + if (dynamic_cast(node) || dynamic_cast(node)) + { + return osg::clone(node, *this); + } return osg::CopyOp::operator()(node); } @@ -38,7 +48,7 @@ namespace SceneUtil if (const osgParticle::ParticleSystem* partsys = dynamic_cast(drawable)) return operator()(partsys); - if (dynamic_cast(drawable) || dynamic_cast(drawable)) + if (dynamic_cast(drawable) || dynamic_cast(drawable) || dynamic_cast(drawable) || dynamic_cast(drawable)) { return static_cast(drawable->clone(*this)); } diff --git a/components/sceneutil/keyframe.hpp b/components/sceneutil/keyframe.hpp index c993c7b7c7..5a0435469c 100644 --- a/components/sceneutil/keyframe.hpp +++ b/components/sceneutil/keyframe.hpp @@ -7,9 +7,16 @@ #include #include +#include namespace SceneUtil { + struct EmulatedAnimation + { + float mStartTime; + float mStopTime; + std::string mName; + }; class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller { @@ -19,12 +26,18 @@ namespace SceneUtil KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop) : osg::NodeCallback(copy, copyop) , SceneUtil::Controller(copy) + , mMergedAnimationTracks(copy.mMergedAnimationTracks) + , mEmulatedAnimations(copy.mEmulatedAnimations) {} META_Object(SceneUtil, KeyframeController) virtual osg::Vec3f getTranslation(float time) const { return osg::Vec3f(); } virtual void operator() (osg::Node* node, osg::NodeVisitor* nodeVisitor) { traverse(node, nodeVisitor); } + + protected: + std::vector> mMergedAnimationTracks; // Used only by osgAnimation-based formats (e.g. dae) + std::vector mEmulatedAnimations; }; /// Wrapper object containing an animation track as a ref-countable osg::Object. diff --git a/components/sceneutil/osgacontroller.cpp b/components/sceneutil/osgacontroller.cpp new file mode 100644 index 0000000000..6b635d4ea1 --- /dev/null +++ b/components/sceneutil/osgacontroller.cpp @@ -0,0 +1,195 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace OsgaController +{ + LinkVisitor::LinkVisitor() : osg::NodeVisitor( TRAVERSE_ALL_CHILDREN ) + { + mAnimation = nullptr; + } + + void LinkVisitor::link(osgAnimation::UpdateMatrixTransform* umt) + { + const osgAnimation::ChannelList& channels = mAnimation->getChannels(); + for (const osg::ref_ptr 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 (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::handle_stateset(osg::StateSet* stateset) + { + if (!stateset) + return; + const osg::StateSet::AttributeList& attributeList = stateset->getAttributeList(); + for (auto attribute : attributeList) + { + osg::StateAttribute* sattr = attribute.second.first.get(); + osgAnimation::UpdateMatrixTransform* umt = dynamic_cast(sattr->getUpdateCallback()); //Can this even be in sa? + if (umt) link(umt); + } + } + + void LinkVisitor::setAnimation(Resource::Animation* animation) + { + mAnimation = animation; + } + + void LinkVisitor::apply(osg::Node& node) + { + osg::StateSet* st = node.getStateSet(); + if (st) + handle_stateset(st); + + osg::Callback* cb = node.getUpdateCallback(); + while (cb) + { + osgAnimation::UpdateMatrixTransform* umt = dynamic_cast(cb); + if (umt) + if (node.getName() != "root") link(umt); + cb = cb->getNestedCallback(); + } + + traverse( node ); + } + + void LinkVisitor::apply(osg::Geode& node) + { + for (unsigned int i = 0; i < node.getNumDrawables(); i++) + { + osg::Drawable* drawable = node.getDrawable(i); + if (drawable && drawable->getStateSet()) + handle_stateset(drawable->getStateSet()); + } + apply(static_cast(node)); + } + + KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop) + { + mLinker = nullptr; + } + + osg::Vec3f KeyframeController::getTranslation(float time) const + { + osg::Vec3f translationValue; + std::string animationName; + float newTime = time; + + //Find the correct animation based on time + for (auto emulatedAnimation : mEmulatedAnimations) + { + if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime) + { + newTime = time - emulatedAnimation.mStartTime; + animationName = emulatedAnimation.mName; + } + } + + //Find the root transform track in animation + for (auto mergedAnimationTrack : mMergedAnimationTracks) + { + if (mergedAnimationTrack->getName() != animationName) continue; + + const osgAnimation::ChannelList& channels = mergedAnimationTrack->getChannels(); + + for (const osg::ref_ptr channel: channels) + { + if (channel->getTargetName() != "root" || channel->getName() != "transform") continue; + + if ( osgAnimation::MatrixLinearSampler* templateSampler = dynamic_cast (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 KeyframeController::update(float time, std::string animationName) + { + for (auto mergedAnimationTrack : mMergedAnimationTracks) + { + if (mergedAnimationTrack->getName() == animationName) mergedAnimationTrack->update(time); + } + } + + void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) + { + if (hasInput()) + { + if (mNeedToLink) + { + for (auto mergedAnimationTrack : mMergedAnimationTracks) + { + if (!mLinker.valid()) mLinker = new LinkVisitor(); + mLinker->setAnimation(mergedAnimationTrack); + node->accept(*mLinker); + } + mNeedToLink = false; + } + + float time = getInputValue(nv); + + for (auto emulatedAnimation : mEmulatedAnimations) + { + if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime) + { + update(time - emulatedAnimation.mStartTime, emulatedAnimation.mName); + } + } + } + + traverse(node, nv); + } + + void KeyframeController::setEmulatedAnimations(std::vector emulatedAnimations) + { + mEmulatedAnimations = emulatedAnimations; + } + + void KeyframeController::addMergedAnimationTrack(osg::ref_ptr animationTrack) + { + mMergedAnimationTracks.emplace_back(animationTrack); + } +} diff --git a/components/sceneutil/osgacontroller.hpp b/components/sceneutil/osgacontroller.hpp new file mode 100644 index 0000000000..4ae1221992 --- /dev/null +++ b/components/sceneutil/osgacontroller.hpp @@ -0,0 +1,70 @@ +#ifndef OPENMW_COMPONENTS_SCENEUTIL_OSGACONTROLLER_HPP +#define OPENMW_COMPONENTS_SCENEUTIL_OSGACONTROLLER_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace OsgaController +{ + class LinkVisitor : public osg::NodeVisitor + { + public: + LinkVisitor(); + + virtual void link(osgAnimation::UpdateMatrixTransform* umt); + + virtual void handle_stateset(osg::StateSet* stateset); + + virtual void setAnimation(Resource::Animation* animation); + + virtual void apply(osg::Node& node); + + virtual void apply(osg::Geode& node); + + protected: + Resource::Animation* mAnimation; + }; + + class KeyframeController : public SceneUtil::KeyframeController + { + public: + /// @brief Handles the animation for osgAnimation formats + KeyframeController() {}; + + KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); + + META_Object(OsgaController, KeyframeController) + + /// @brief Handles the location of the instance + osg::Vec3f getTranslation(float time) const override; + + /// @brief Calls animation track update() + void update(float time, std::string animationName); + + /// @brief Called every frame for osgAnimation + void operator() (osg::Node*, osg::NodeVisitor*) override; + + /// @brief Sets details of the animations + void setEmulatedAnimations(std::vector emulatedAnimations); + + /// @brief Adds an animation track to a model + void addMergedAnimationTrack(osg::ref_ptr animationTrack); + private: + bool mNeedToLink = true; + osg::ref_ptr mLinker; + }; +} + +#endif From 32d4344803702efb99d435b0732a4c883c4c360a Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Fri, 20 Nov 2020 19:38:29 +0200 Subject: [PATCH 3/6] Don't copy osga-data in base class keyframecontroller, fix warnings. --- components/resource/keyframemanager.cpp | 4 ++-- components/resource/keyframemanager.hpp | 2 +- components/sceneutil/keyframe.hpp | 15 +-------------- components/sceneutil/osgacontroller.cpp | 4 +++- components/sceneutil/osgacontroller.hpp | 16 +++++++++++++--- 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 6cda9728cd..d084d6a08e 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -31,7 +31,7 @@ namespace OsgAOpenMW osg::ref_ptr callback = new OsgaController::KeyframeController(); - std::vector emulatedAnimations; + std::vector emulatedAnimations; for (auto animation : mAnimationManager->getAnimationList()) { @@ -69,7 +69,7 @@ namespace OsgAOpenMW mTarget.mTextKeys.emplace(startTime, std::move(loopstart)); mTarget.mTextKeys.emplace(stopTime, std::move(loopstop)); - SceneUtil::EmulatedAnimation emulatedAnimation; + OsgaController::EmulatedAnimation emulatedAnimation; emulatedAnimation.mStartTime = startTime; emulatedAnimation.mStopTime = stopTime; emulatedAnimation.mName = animationName; diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index 4f83196f34..778b4bc9a9 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -17,7 +17,7 @@ namespace OsgAOpenMW public: RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr animationManager); - virtual void apply(osg::Node& node); + virtual void apply(osg::Node& node) override; private: SceneUtil::KeyframeHolder& mTarget; diff --git a/components/sceneutil/keyframe.hpp b/components/sceneutil/keyframe.hpp index 5a0435469c..e09541cb9a 100644 --- a/components/sceneutil/keyframe.hpp +++ b/components/sceneutil/keyframe.hpp @@ -11,13 +11,6 @@ namespace SceneUtil { - struct EmulatedAnimation - { - float mStartTime; - float mStopTime; - std::string mName; - }; - class KeyframeController : public osg::NodeCallback, public SceneUtil::Controller { public: @@ -26,18 +19,12 @@ namespace SceneUtil KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop) : osg::NodeCallback(copy, copyop) , SceneUtil::Controller(copy) - , mMergedAnimationTracks(copy.mMergedAnimationTracks) - , mEmulatedAnimations(copy.mEmulatedAnimations) {} META_Object(SceneUtil, KeyframeController) virtual osg::Vec3f getTranslation(float time) const { return osg::Vec3f(); } - virtual void operator() (osg::Node* node, osg::NodeVisitor* nodeVisitor) { traverse(node, nodeVisitor); } - - protected: - std::vector> mMergedAnimationTracks; // Used only by osgAnimation-based formats (e.g. dae) - std::vector mEmulatedAnimations; + virtual void operator() (osg::Node* node, osg::NodeVisitor* nodeVisitor) override { traverse(node, nodeVisitor); } }; /// Wrapper object containing an animation track as a ref-countable osg::Object. diff --git a/components/sceneutil/osgacontroller.cpp b/components/sceneutil/osgacontroller.cpp index 6b635d4ea1..e20ecb5b89 100644 --- a/components/sceneutil/osgacontroller.cpp +++ b/components/sceneutil/osgacontroller.cpp @@ -102,6 +102,8 @@ namespace OsgaController } KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop) + , mMergedAnimationTracks(copy.mMergedAnimationTracks) + , mEmulatedAnimations(copy.mEmulatedAnimations) { mLinker = nullptr; } @@ -183,7 +185,7 @@ namespace OsgaController traverse(node, nv); } - void KeyframeController::setEmulatedAnimations(std::vector emulatedAnimations) + void KeyframeController::setEmulatedAnimations(std::vector emulatedAnimations) { mEmulatedAnimations = emulatedAnimations; } diff --git a/components/sceneutil/osgacontroller.hpp b/components/sceneutil/osgacontroller.hpp index 4ae1221992..a3072088aa 100644 --- a/components/sceneutil/osgacontroller.hpp +++ b/components/sceneutil/osgacontroller.hpp @@ -18,6 +18,13 @@ namespace OsgaController { + struct EmulatedAnimation + { + float mStartTime; + float mStopTime; + std::string mName; + }; + class LinkVisitor : public osg::NodeVisitor { public: @@ -29,9 +36,9 @@ namespace OsgaController virtual void setAnimation(Resource::Animation* animation); - virtual void apply(osg::Node& node); + virtual void apply(osg::Node& node) override; - virtual void apply(osg::Geode& node); + virtual void apply(osg::Geode& node) override; protected: Resource::Animation* mAnimation; @@ -57,13 +64,16 @@ namespace OsgaController void operator() (osg::Node*, osg::NodeVisitor*) override; /// @brief Sets details of the animations - void setEmulatedAnimations(std::vector emulatedAnimations); + void setEmulatedAnimations(std::vector emulatedAnimations); /// @brief Adds an animation track to a model void addMergedAnimationTrack(osg::ref_ptr animationTrack); + private: bool mNeedToLink = true; osg::ref_ptr mLinker; + std::vector> mMergedAnimationTracks; // Used only by osgAnimation-based formats (e.g. dae) + std::vector mEmulatedAnimations; }; } From 3232faa703bfe5963895c35a69534def1c283e21 Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Fri, 20 Nov 2020 19:41:01 +0200 Subject: [PATCH 4/6] Use const ref instead of value --- components/sceneutil/osgacontroller.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/sceneutil/osgacontroller.cpp b/components/sceneutil/osgacontroller.cpp index e20ecb5b89..503d9cf022 100644 --- a/components/sceneutil/osgacontroller.cpp +++ b/components/sceneutil/osgacontroller.cpp @@ -115,7 +115,7 @@ namespace OsgaController float newTime = time; //Find the correct animation based on time - for (auto emulatedAnimation : mEmulatedAnimations) + for (const EmulatedAnimation& emulatedAnimation : mEmulatedAnimations) { if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime) { @@ -125,7 +125,7 @@ namespace OsgaController } //Find the root transform track in animation - for (auto mergedAnimationTrack : mMergedAnimationTracks) + for (const osg::ref_ptr mergedAnimationTrack : mMergedAnimationTracks) { if (mergedAnimationTrack->getName() != animationName) continue; @@ -150,7 +150,7 @@ namespace OsgaController void KeyframeController::update(float time, std::string animationName) { - for (auto mergedAnimationTrack : mMergedAnimationTracks) + for (const osg::ref_ptr mergedAnimationTrack : mMergedAnimationTracks) { if (mergedAnimationTrack->getName() == animationName) mergedAnimationTrack->update(time); } @@ -162,7 +162,7 @@ namespace OsgaController { if (mNeedToLink) { - for (auto mergedAnimationTrack : mMergedAnimationTracks) + for (const osg::ref_ptr mergedAnimationTrack : mMergedAnimationTracks) { if (!mLinker.valid()) mLinker = new LinkVisitor(); mLinker->setAnimation(mergedAnimationTrack); @@ -173,7 +173,7 @@ namespace OsgaController float time = getInputValue(nv); - for (auto emulatedAnimation : mEmulatedAnimations) + for (const EmulatedAnimation& emulatedAnimation : mEmulatedAnimations) { if (time > emulatedAnimation.mStartTime && time < emulatedAnimation.mStopTime) { From 08dcbe30b37cb266bebf3c8171e9130e5bea9d5d Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Fri, 20 Nov 2020 19:46:08 +0200 Subject: [PATCH 5/6] Earlier nullptr check --- components/resource/keyframemanager.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index d084d6a08e..421b0ddf7b 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -23,12 +23,6 @@ namespace OsgAOpenMW { if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && node.getName() == std::string("root")) { - if (!mAnimationManager) - { - traverse(node); - return; - } - osg::ref_ptr callback = new OsgaController::KeyframeController(); std::vector emulatedAnimations; @@ -125,8 +119,11 @@ namespace Resource { osg::ref_ptr scene = const_cast ( mSceneManager->getTemplate(normalized).get() ); osg::ref_ptr bam = dynamic_cast (scene->getUpdateCallback()); - OsgAOpenMW::RetrieveAnimationsVisitor rav(*loaded.get(), bam); - scene->accept(rav); + if (bam) + { + OsgAOpenMW::RetrieveAnimationsVisitor rav(*loaded.get(), bam); + scene->accept(rav); + } } mCache->addEntryToObjectCache(normalized, loaded); return loaded; From 55dcc6582a7b5024994368fbdf07a998b1394cbd Mon Sep 17 00:00:00 2001 From: Nelsson Huotari Date: Sat, 28 Nov 2020 15:03:10 +0200 Subject: [PATCH 6/6] Don't duplicate getFileExtension, use OpenMW's namespaces --- components/resource/keyframemanager.cpp | 20 ++++++-------------- components/resource/keyframemanager.hpp | 4 +--- components/resource/scenemanager.cpp | 17 ++++++++--------- components/resource/scenemanager.hpp | 1 + components/sceneutil/osgacontroller.cpp | 14 +++++++------- components/sceneutil/osgacontroller.hpp | 10 +++++----- 6 files changed, 28 insertions(+), 38 deletions(-) diff --git a/components/resource/keyframemanager.cpp b/components/resource/keyframemanager.cpp index 421b0ddf7b..af0f365ee5 100644 --- a/components/resource/keyframemanager.cpp +++ b/components/resource/keyframemanager.cpp @@ -14,7 +14,7 @@ #include "objectcache.hpp" #include "scenemanager.hpp" -namespace OsgAOpenMW +namespace Resource { RetrieveAnimationsVisitor::RetrieveAnimationsVisitor(SceneUtil::KeyframeHolder& target, osg::ref_ptr animationManager) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mTarget(target), mAnimationManager(animationManager) {} @@ -23,9 +23,9 @@ namespace OsgAOpenMW { if (node.libraryName() == std::string("osgAnimation") && node.className() == std::string("Bone") && node.getName() == std::string("root")) { - osg::ref_ptr callback = new OsgaController::KeyframeController(); + osg::ref_ptr callback = new SceneUtil::OsgAnimationController(); - std::vector emulatedAnimations; + std::vector emulatedAnimations; for (auto animation : mAnimationManager->getAnimationList()) { @@ -63,7 +63,7 @@ namespace OsgAOpenMW mTarget.mTextKeys.emplace(startTime, std::move(loopstart)); mTarget.mTextKeys.emplace(stopTime, std::move(loopstop)); - OsgaController::EmulatedAnimation emulatedAnimation; + SceneUtil::EmulatedAnimation emulatedAnimation; emulatedAnimation.mStartTime = startTime; emulatedAnimation.mStopTime = stopTime; emulatedAnimation.mName = animationName; @@ -76,14 +76,6 @@ namespace OsgAOpenMW traverse(node); } - - std::string getFileExtension(const std::string& file) - { - size_t extPos = file.find_last_of('.'); - if (extPos != std::string::npos && extPos+1 < file.size()) - return file.substr(extPos+1); - return std::string(); - } } namespace Resource @@ -110,7 +102,7 @@ namespace Resource else { osg::ref_ptr loaded (new SceneUtil::KeyframeHolder); - std::string ext = OsgAOpenMW::getFileExtension(normalized); + std::string ext = Resource::getFileExtension(normalized); if (ext == "kf") { NifOsg::Loader::loadKf(Nif::NIFFilePtr(new Nif::NIFFile(mVFS->getNormalized(normalized), normalized)), *loaded.get()); @@ -121,7 +113,7 @@ namespace Resource osg::ref_ptr bam = dynamic_cast (scene->getUpdateCallback()); if (bam) { - OsgAOpenMW::RetrieveAnimationsVisitor rav(*loaded.get(), bam); + Resource::RetrieveAnimationsVisitor rav(*loaded.get(), bam); scene->accept(rav); } } diff --git a/components/resource/keyframemanager.hpp b/components/resource/keyframemanager.hpp index 778b4bc9a9..3e992ac5e9 100644 --- a/components/resource/keyframemanager.hpp +++ b/components/resource/keyframemanager.hpp @@ -9,7 +9,7 @@ #include "resourcemanager.hpp" -namespace OsgAOpenMW +namespace Resource { /// @brief extract animations to OpenMW's animation system class RetrieveAnimationsVisitor : public osg::NodeVisitor @@ -24,8 +24,6 @@ namespace OsgAOpenMW osg::ref_ptr mAnimationManager; }; - - std::string getFileExtension(const std::string& file); } namespace Resource diff --git a/components/resource/scenemanager.cpp b/components/resource/scenemanager.cpp index e99003b749..2630cd4536 100644 --- a/components/resource/scenemanager.cpp +++ b/components/resource/scenemanager.cpp @@ -338,17 +338,9 @@ namespace Resource Resource::ImageManager* mImageManager; }; - std::string getFileExtension(const std::string& file) - { - size_t extPos = file.find_last_of('.'); - if (extPos != std::string::npos && extPos+1 < file.size()) - return file.substr(extPos+1); - return std::string(); - } - osg::ref_ptr load (Files::IStreamPtr file, const std::string& normalizedFilename, Resource::ImageManager* imageManager, Resource::NifFileManager* nifFileManager) { - std::string ext = getFileExtension(normalizedFilename); + std::string ext = Resource::getFileExtension(normalizedFilename); if (ext == "nif") return NifOsg::Loader::load(nifFileManager->get(normalizedFilename), imageManager); else @@ -780,4 +772,11 @@ namespace Resource return shaderVisitor; } + std::string getFileExtension(const std::string& file) + { + size_t extPos = file.find_last_of('.'); + if (extPos != std::string::npos && extPos+1 < file.size()) + return file.substr(extPos+1); + return std::string(); + } } diff --git a/components/resource/scenemanager.hpp b/components/resource/scenemanager.hpp index 8df556158e..fd75070a18 100644 --- a/components/resource/scenemanager.hpp +++ b/components/resource/scenemanager.hpp @@ -181,6 +181,7 @@ namespace Resource void operator = (const SceneManager&); }; + std::string getFileExtension(const std::string& file); } #endif diff --git a/components/sceneutil/osgacontroller.cpp b/components/sceneutil/osgacontroller.cpp index 503d9cf022..87e6f02fee 100644 --- a/components/sceneutil/osgacontroller.cpp +++ b/components/sceneutil/osgacontroller.cpp @@ -21,7 +21,7 @@ #include #include -namespace OsgaController +namespace SceneUtil { LinkVisitor::LinkVisitor() : osg::NodeVisitor( TRAVERSE_ALL_CHILDREN ) { @@ -101,14 +101,14 @@ namespace OsgaController apply(static_cast(node)); } - KeyframeController::KeyframeController(const KeyframeController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop) + OsgAnimationController::OsgAnimationController(const OsgAnimationController ©, const osg::CopyOp ©op) : SceneUtil::KeyframeController(copy, copyop) , mMergedAnimationTracks(copy.mMergedAnimationTracks) , mEmulatedAnimations(copy.mEmulatedAnimations) { mLinker = nullptr; } - osg::Vec3f KeyframeController::getTranslation(float time) const + osg::Vec3f OsgAnimationController::getTranslation(float time) const { osg::Vec3f translationValue; std::string animationName; @@ -148,7 +148,7 @@ namespace OsgaController return osg::Vec3f(); } - void KeyframeController::update(float time, std::string animationName) + void OsgAnimationController::update(float time, std::string animationName) { for (const osg::ref_ptr mergedAnimationTrack : mMergedAnimationTracks) { @@ -156,7 +156,7 @@ namespace OsgaController } } - void KeyframeController::operator() (osg::Node* node, osg::NodeVisitor* nv) + void OsgAnimationController::operator() (osg::Node* node, osg::NodeVisitor* nv) { if (hasInput()) { @@ -185,12 +185,12 @@ namespace OsgaController traverse(node, nv); } - void KeyframeController::setEmulatedAnimations(std::vector emulatedAnimations) + void OsgAnimationController::setEmulatedAnimations(std::vector emulatedAnimations) { mEmulatedAnimations = emulatedAnimations; } - void KeyframeController::addMergedAnimationTrack(osg::ref_ptr animationTrack) + void OsgAnimationController::addMergedAnimationTrack(osg::ref_ptr animationTrack) { mMergedAnimationTracks.emplace_back(animationTrack); } diff --git a/components/sceneutil/osgacontroller.hpp b/components/sceneutil/osgacontroller.hpp index a3072088aa..f1c1584c2a 100644 --- a/components/sceneutil/osgacontroller.hpp +++ b/components/sceneutil/osgacontroller.hpp @@ -16,7 +16,7 @@ #include #include -namespace OsgaController +namespace SceneUtil { struct EmulatedAnimation { @@ -44,15 +44,15 @@ namespace OsgaController Resource::Animation* mAnimation; }; - class KeyframeController : public SceneUtil::KeyframeController + class OsgAnimationController : public SceneUtil::KeyframeController { public: /// @brief Handles the animation for osgAnimation formats - KeyframeController() {}; + OsgAnimationController() {}; - KeyframeController(const KeyframeController& copy, const osg::CopyOp& copyop); + OsgAnimationController(const OsgAnimationController& copy, const osg::CopyOp& copyop); - META_Object(OsgaController, KeyframeController) + META_Object(SceneUtil, OsgAnimationController) /// @brief Handles the location of the instance osg::Vec3f getTranslation(float time) const override;