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