diff --git a/apps/openmw/mwmechanics/character.cpp b/apps/openmw/mwmechanics/character.cpp index 92eec1af64..ac8d417f35 100644 --- a/apps/openmw/mwmechanics/character.cpp +++ b/apps/openmw/mwmechanics/character.cpp @@ -942,7 +942,7 @@ void split(const std::string &s, char delim, std::vector &elems) { } } -void CharacterController::handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, const std::multimap &map) +void CharacterController::handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map) { const std::string &evt = key->second; diff --git a/apps/openmw/mwmechanics/character.hpp b/apps/openmw/mwmechanics/character.hpp index 614beca1c0..aa3c035ba1 100644 --- a/apps/openmw/mwmechanics/character.hpp +++ b/apps/openmw/mwmechanics/character.hpp @@ -238,8 +238,7 @@ public: CharacterController(const MWWorld::Ptr &ptr, MWRender::Animation *anim); virtual ~CharacterController(); - virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map); + virtual void handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map); // 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 8f36417954..77157377b4 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -151,20 +151,8 @@ namespace } }; - NifOsg::TextKeyMap::const_iterator findGroupStart(const NifOsg::TextKeyMap &keys, const std::string &groupname) - { - NifOsg::TextKeyMap::const_iterator iter(keys.begin()); - for(;iter != keys.end();++iter) - { - if(iter->second.compare(0, groupname.size(), groupname) == 0 && - iter->second.compare(groupname.size(), 2, ": ") == 0) - break; - } - return iter; - } - - float calcAnimVelocity(const std::multimap& keys, - NifOsg::KeyframeController *nonaccumctrl, const osg::Vec3f& accum, const std::string &groupname) + float calcAnimVelocity(const NifOsg::TextKeyMap& keys, NifOsg::KeyframeController *nonaccumctrl, + const osg::Vec3f& accum, const std::string &groupname) { const std::string start = groupname+": start"; const std::string loopstart = groupname+": loop start"; @@ -179,7 +167,7 @@ namespace // but the animation velocity calculation uses the second one. // As result the animation velocity calculation is not correct, and this incorrect velocity must be replicated, // because otherwise the Creature's Speed (dagoth uthol) would not be sufficient to move fast enough. - NifOsg::TextKeyMap::const_reverse_iterator keyiter(keys.rbegin()); + auto keyiter = keys.rbegin(); while(keyiter != keys.rend()) { if(keyiter->second == start || keyiter->second == loopstart) @@ -553,7 +541,7 @@ namespace MWRender ControllerMap mControllerMap[Animation::sNumBlendMasks]; - const std::multimap& getTextKeys() const; + const NifOsg::TextKeyMap& getTextKeys() const; }; void UpdateVfxCallback::operator()(osg::Node* node, osg::NodeVisitor* nv) @@ -702,7 +690,7 @@ namespace MWRender return 0; } - const std::multimap &Animation::AnimSource::getTextKeys() const + const NifOsg::TextKeyMap &Animation::AnimSource::getTextKeys() const { return mKeyframes->mTextKeys; } @@ -825,7 +813,7 @@ namespace MWRender for(;iter != mAnimSources.end();++iter) { const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); - if(findGroupStart(keys, anim) != keys.end()) + if (keys.hasGroupStart(anim)) return true; } @@ -838,7 +826,7 @@ namespace MWRender { const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); - NifOsg::TextKeyMap::const_iterator found = findGroupStart(keys, groupname); + const auto found = keys.findGroupStart(groupname); if(found != keys.end()) return found->first; } @@ -851,7 +839,7 @@ namespace MWRender { const NifOsg::TextKeyMap &keys = (*iter)->getTextKeys(); - for(NifOsg::TextKeyMap::const_iterator iterKey(keys.begin()); iterKey != keys.end(); ++iterKey) + for(auto iterKey = keys.begin(); iterKey != keys.end(); ++iterKey) { if(iterKey->second.compare(0, textKey.size(), textKey) == 0) return iterKey->first; @@ -861,8 +849,8 @@ namespace MWRender return -1.f; } - void Animation::handleTextKey(AnimState &state, const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map) + void Animation::handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, + const NifOsg::TextKeyMap& map) { const std::string &evt = key->second; @@ -939,7 +927,7 @@ namespace MWRender if (state.mPlaying) { - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); + auto textkey = textkeys.lowerBound(state.getTime()); while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); @@ -955,7 +943,7 @@ namespace MWRender if(state.getTime() >= state.mLoopStopTime) break; - NifOsg::TextKeyMap::const_iterator textkey(textkeys.lower_bound(state.getTime())); + auto textkey = textkeys.lowerBound(state.getTime()); while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, groupname, textkey, textkeys); @@ -974,7 +962,7 @@ namespace MWRender { // 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. - NifOsg::TextKeyMap::const_reverse_iterator groupend(keys.rbegin()); + auto groupend = keys.rbegin(); for(;groupend != keys.rend();++groupend) { if(groupend->second.compare(0, groupname.size(), groupname) == 0 && @@ -983,7 +971,7 @@ namespace MWRender } std::string starttag = groupname+": "+start; - NifOsg::TextKeyMap::const_reverse_iterator startkey(groupend); + auto startkey = groupend; while(startkey != keys.rend() && startkey->second != starttag) ++startkey; if(startkey == keys.rend() && start == "loop start") @@ -997,7 +985,7 @@ namespace MWRender return false; const std::string stoptag = groupname+": "+stop; - NifOsg::TextKeyMap::const_reverse_iterator stopkey(groupend); + auto stopkey = groupend; while(stopkey != keys.rend() // We have to ignore extra garbage at the end. // The Scrib's idle3 animation has "Idle3: Stop." instead of "Idle3: Stop". @@ -1030,7 +1018,7 @@ namespace MWRender const std::string loopstarttag = groupname+": loop start"; const std::string loopstoptag = groupname+": loop stop"; - NifOsg::TextKeyMap::const_reverse_iterator key(groupend); + auto key = groupend; for (; key != startkey && key != keys.rend(); ++key) { if (key->first > state.getTime()) @@ -1201,7 +1189,7 @@ namespace MWRender for(;animsrc != mAnimSources.rend();++animsrc) { const NifOsg::TextKeyMap &keys = (*animsrc)->getTextKeys(); - if(findGroupStart(keys, groupname) != keys.end()) + if (keys.hasGroupStart(groupname)) break; } if(animsrc == mAnimSources.rend()) @@ -1280,7 +1268,7 @@ namespace MWRender } const NifOsg::TextKeyMap &textkeys = state.mSource->getTextKeys(); - NifOsg::TextKeyMap::const_iterator textkey(textkeys.upper_bound(state.getTime())); + auto textkey = textkeys.upperBound(state.getTime()); float timepassed = duration * state.mSpeedMult; while(state.mPlaying) @@ -1316,7 +1304,7 @@ namespace MWRender state.setTime(state.mLoopStartTime); state.mPlaying = true; - textkey = textkeys.lower_bound(state.getTime()); + textkey = textkeys.lowerBound(state.getTime()); while(textkey != textkeys.end() && textkey->first <= state.getTime()) { handleTextKey(state, stateiter->first, textkey, textkeys); diff --git a/apps/openmw/mwrender/animation.hpp b/apps/openmw/mwrender/animation.hpp index 7b1e1d3e9f..dddde7d9a5 100644 --- a/apps/openmw/mwrender/animation.hpp +++ b/apps/openmw/mwrender/animation.hpp @@ -5,6 +5,7 @@ #include #include +#include namespace ESM { @@ -147,8 +148,8 @@ public: class TextKeyListener { public: - virtual void handleTextKey(const std::string &groupname, const std::multimap::const_iterator &key, - const std::multimap& map) = 0; + virtual void handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, + const NifOsg::TextKeyMap& map) = 0; virtual ~TextKeyListener() = default; }; @@ -296,12 +297,12 @@ protected: * the marker is not found, or if the markers are the same, it returns * false. */ - bool reset(AnimState &state, const std::multimap &keys, + bool reset(AnimState &state, const NifOsg::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, const std::multimap::const_iterator &key, - const std::multimap& map); + void handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, + const NifOsg::TextKeyMap& map); /** Sets the root model of the object. * diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index 5217642740..e3c6d823f7 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -157,7 +157,8 @@ namespace nextpos = std::distance(str.begin(), ++last); } std::string result = str.substr(pos, nextpos-pos); - textkeys.insert(std::make_pair(tk->list[i].time, Misc::StringUtils::lowerCase(result))); + Misc::StringUtils::lowerCaseInPlace(result); + textkeys.emplace(tk->list[i].time, std::move(result)); pos = nextpos; } diff --git a/components/nifosg/nifloader.hpp b/components/nifosg/nifloader.hpp index 4de9027b89..49a78ad5f6 100644 --- a/components/nifosg/nifloader.hpp +++ b/components/nifosg/nifloader.hpp @@ -7,6 +7,7 @@ #include #include "controller.hpp" +#include "textkeymap.hpp" namespace osg { @@ -20,8 +21,6 @@ namespace Resource namespace NifOsg { - typedef std::multimap TextKeyMap; - struct TextKeyMapHolder : public osg::Object { public: diff --git a/components/nifosg/textkeymap.hpp b/components/nifosg/textkeymap.hpp new file mode 100644 index 0000000000..49e1e461e4 --- /dev/null +++ b/components/nifosg/textkeymap.hpp @@ -0,0 +1,87 @@ +#ifndef OPENMW_COMPONENTS_NIFOSG_TEXTKEYMAP +#define OPENMW_COMPONENTS_NIFOSG_TEXTKEYMAP + +#include +#include +#include +#include + +namespace NifOsg +{ + class TextKeyMap + { + public: + using ConstIterator = std::multimap::const_iterator; + + auto begin() const noexcept + { + return mTextKeyByTime.begin(); + } + + auto end() const noexcept + { + return mTextKeyByTime.end(); + } + + auto rbegin() const noexcept + { + return mTextKeyByTime.rbegin(); + } + + auto rend() const noexcept + { + return mTextKeyByTime.rend(); + } + + auto lowerBound(float time) const + { + return mTextKeyByTime.lower_bound(time); + } + + auto upperBound(float time) const + { + return mTextKeyByTime.upper_bound(time); + } + + void emplace(float time, std::string&& textKey) + { + const auto separator = textKey.find(": "); + if (separator != std::string::npos) + mGroups.emplace(textKey.substr(0, separator)); + + mTextKeyByTime.emplace(time, std::move(textKey)); + } + + bool empty() const noexcept + { + return mTextKeyByTime.empty(); + } + + auto findGroupStart(const std::string &groupName) const + { + return std::find_if(mTextKeyByTime.begin(), mTextKeyByTime.end(), IsGroupStart{groupName}); + } + + bool hasGroupStart(const std::string &groupName) const + { + return mGroups.count(groupName) > 0; + } + + private: + struct IsGroupStart + { + const std::string &mGroupName; + + bool operator ()(const std::multimap::value_type& value) const + { + return value.second.compare(0, mGroupName.size(), mGroupName) == 0 && + value.second.compare(mGroupName.size(), 2, ": ") == 0; + } + }; + + std::set mGroups; + std::multimap mTextKeyByTime; + }; +} + +#endif