1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-01-16 17:29:55 +00:00
openmw/components/sceneutil/skeleton.cpp

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

178 lines
4.5 KiB
C++
Raw Normal View History

#include "skeleton.hpp"
#include <osg/MatrixTransform>
2018-08-14 15:42:41 +00:00
#include <components/debug/debuglog.hpp>
#include <components/misc/strings/lower.hpp>
#include <algorithm>
2015-04-21 18:30:48 +00:00
namespace SceneUtil
{
class InitBoneCacheVisitor : public osg::NodeVisitor
{
2022-09-22 18:26:05 +00:00
public:
typedef std::vector<osg::MatrixTransform*> TransformPath;
InitBoneCacheVisitor(std::unordered_map<std::string, TransformPath>& cache)
: osg::NodeVisitor(TRAVERSE_ALL_CHILDREN)
, mCache(cache)
2022-09-22 18:26:05 +00:00
{
}
2022-09-22 18:26:05 +00:00
void apply(osg::MatrixTransform& node) override
2022-09-22 18:26:05 +00:00
{
mPath.push_back(&node);
mCache.emplace(Misc::StringUtils::lowerCase(node.getName()), mPath);
traverse(node);
mPath.pop_back();
2022-09-22 18:26:05 +00:00
}
private:
TransformPath mPath;
std::unordered_map<std::string, TransformPath>& mCache;
2022-09-22 18:26:05 +00:00
};
Skeleton::Skeleton()
: mBoneCacheInit(false)
, mNeedToUpdateBoneMatrices(true)
, mActive(Active)
2015-05-23 20:44:00 +00:00
, mLastFrameNumber(0)
, mLastCullFrameNumber(0)
{
}
Skeleton::Skeleton(const Skeleton& copy, const osg::CopyOp& copyop)
2015-04-21 16:52:13 +00:00
: osg::Group(copy, copyop)
, mBoneCacheInit(false)
, mNeedToUpdateBoneMatrices(true)
, mActive(copy.mActive)
2015-05-23 20:44:00 +00:00
, mLastFrameNumber(0)
, mLastCullFrameNumber(0)
{
}
Bone* Skeleton::getBone(const std::string& name)
2022-09-22 18:26:05 +00:00
{
if (!mBoneCacheInit)
2022-09-22 18:26:05 +00:00
{
InitBoneCacheVisitor visitor(mBoneCache);
accept(visitor);
mBoneCacheInit = true;
2022-09-22 18:26:05 +00:00
}
BoneCache::iterator found = mBoneCache.find(Misc::StringUtils::lowerCase(name));
if (found == mBoneCache.end())
return nullptr;
// find or insert in the bone hierarchy
if (!mRootBone.get())
{
mRootBone = std::make_unique<Bone>();
}
Bone* bone = mRootBone.get();
for (osg::MatrixTransform* matrixTransform : found->second)
{
const auto it = std::find_if(bone->mChildren.begin(), bone->mChildren.end(),
[&](const auto& v) { return v->mNode == matrixTransform; });
2022-09-22 18:26:05 +00:00
if (it == bone->mChildren.end())
2022-09-22 18:26:05 +00:00
{
bone = bone->mChildren.emplace_back(std::make_unique<Bone>()).get();
mNeedToUpdateBoneMatrices = true;
2022-09-22 18:26:05 +00:00
}
else
bone = it->get();
2022-09-22 18:26:05 +00:00
bone->mNode = matrixTransform;
}
return bone;
}
void Skeleton::updateBoneMatrices(unsigned int traversalNumber)
{
if (traversalNumber != mLastFrameNumber)
2015-04-21 18:22:32 +00:00
mNeedToUpdateBoneMatrices = true;
mLastFrameNumber = traversalNumber;
2015-04-21 18:22:32 +00:00
if (mNeedToUpdateBoneMatrices)
{
if (mRootBone.get())
2022-09-22 18:26:05 +00:00
{
for (const auto& child : mRootBone->mChildren)
child->update(nullptr);
}
mNeedToUpdateBoneMatrices = false;
2022-09-22 18:26:05 +00:00
}
}
void Skeleton::setActive(ActiveType active)
{
mActive = active;
}
bool Skeleton::getActive() const
{
return mActive != Inactive;
}
void Skeleton::markDirty()
{
mLastFrameNumber = 0;
mBoneCache.clear();
mBoneCacheInit = false;
}
void Skeleton::traverse(osg::NodeVisitor& nv)
2022-09-22 18:26:05 +00:00
{
if (nv.getVisitorType() == osg::NodeVisitor::UPDATE_VISITOR)
2022-09-22 18:26:05 +00:00
{
if (mActive == Inactive && mLastFrameNumber != 0)
return;
if (mActive == SemiActive && mLastFrameNumber != 0 && mLastCullFrameNumber + 3 <= nv.getTraversalNumber())
2022-09-22 18:26:05 +00:00
return;
}
else if (nv.getVisitorType() == osg::NodeVisitor::CULL_VISITOR)
mLastCullFrameNumber = nv.getTraversalNumber();
osg::Group::traverse(nv);
}
void Skeleton::childInserted(unsigned int)
{
markDirty();
}
void Skeleton::childRemoved(unsigned int, unsigned int)
{
markDirty();
}
Bone::Bone()
: mNode(nullptr)
{
}
void Bone::update(const osg::Matrixf* parentMatrixInSkeletonSpace)
2022-09-22 18:26:05 +00:00
{
if (!mNode)
{
2018-08-14 15:42:41 +00:00
Log(Debug::Error) << "Error: Bone without node";
2022-09-22 18:26:05 +00:00
return;
}
if (parentMatrixInSkeletonSpace)
mMatrixInSkeletonSpace = mNode->getMatrix() * (*parentMatrixInSkeletonSpace);
2022-09-22 18:26:05 +00:00
else
mMatrixInSkeletonSpace = mNode->getMatrix();
2022-09-22 18:26:05 +00:00
for (const auto& child : mChildren)
child->update(&mMatrixInSkeletonSpace);
}
}