Verified Commit a59e25e0 authored by elsid's avatar elsid

Optimize MWRender::Animation::hasAnimation

Use a set to check for group start existence.
Reduce time taken from 2.6% to 0.08% and
MWMechanics::MechanicsManager::update from 7% to 5%
in relative CPU time usage for a scene with ~100 actors.
parent 61fbc1cd
......@@ -942,7 +942,7 @@ void split(const std::string &s, char delim, std::vector<std::string> &elems) {
}
}
void CharacterController::handleTextKey(const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key, const std::multimap<float, std::string> &map)
void CharacterController::handleTextKey(const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key, const NifOsg::TextKeyMap& map)
{
const std::string &evt = key->second;
......
......@@ -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<float, std::string>::const_iterator &key,
const std::multimap<float, std::string>& 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();
......
......@@ -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<float, std::string>& 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<float, std::string>& 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<float, std::string> &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<float, std::string>::const_iterator &key,
const std::multimap<float, std::string>& 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);
......
......@@ -5,6 +5,7 @@
#include <components/sceneutil/controller.hpp>
#include <components/sceneutil/util.hpp>
#include <components/nifosg/textkeymap.hpp>
namespace ESM
{
......@@ -147,8 +148,8 @@ public:
class TextKeyListener
{
public:
virtual void handleTextKey(const std::string &groupname, const std::multimap<float, std::string>::const_iterator &key,
const std::multimap<float, std::string>& 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<float, std::string> &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<float, std::string>::const_iterator &key,
const std::multimap<float, std::string>& map);
void handleTextKey(AnimState &state, const std::string &groupname, NifOsg::TextKeyMap::ConstIterator key,
const NifOsg::TextKeyMap& map);
/** Sets the root model of the object.
*
......
......@@ -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;
}
......
......@@ -7,6 +7,7 @@
#include <osg/Referenced>
#include "controller.hpp"
#include "textkeymap.hpp"
namespace osg
{
......@@ -20,8 +21,6 @@ namespace Resource
namespace NifOsg
{
typedef std::multimap<float,std::string> TextKeyMap;
struct TextKeyMapHolder : public osg::Object
{
public:
......
#ifndef OPENMW_COMPONENTS_NIFOSG_TEXTKEYMAP
#define OPENMW_COMPONENTS_NIFOSG_TEXTKEYMAP
#include <algorithm>
#include <map>
#include <set>
#include <string>
namespace NifOsg
{
class TextKeyMap
{
public:
using ConstIterator = std::multimap<float, std::string>::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<float, std::string>::value_type& value) const
{
return value.second.compare(0, mGroupName.size(), mGroupName) == 0 &&
value.second.compare(mGroupName.size(), 2, ": ") == 0;
}
};
std::set<std::string> mGroups;
std::multimap<float, std::string> mTextKeyByTime;
};
}
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment