Fixed crash with entity destruction
This commit is contained in:
@@ -61,7 +61,8 @@ Ogre::Entity *AnimationTreeSystem::findAnimatedEntity(flecs::entity e)
|
||||
t.node->getAttachedObject(i);
|
||||
if (obj->getMovableType() == "Entity") {
|
||||
Ogre::Entity *ent =
|
||||
static_cast<Ogre::Entity *>(obj);
|
||||
static_cast<Ogre::Entity *>(
|
||||
obj);
|
||||
if (ent->hasSkeleton())
|
||||
return ent;
|
||||
}
|
||||
@@ -87,13 +88,14 @@ bool AnimationTreeSystem::setupEntity(flecs::entity e,
|
||||
|
||||
EntityAnimTreeState &state = m_states[e.id()];
|
||||
state.ogreEntity = ent;
|
||||
state.ogreEntityName = ent->getName();
|
||||
state.rootBone = nullptr;
|
||||
state.animations.clear();
|
||||
|
||||
Ogre::SkeletonInstance *skel = ent->getSkeleton();
|
||||
|
||||
/* Find and freeze root bone */
|
||||
const char *rootNames[] = {"Root", "mixamorig:Hips", "Spineroot"};
|
||||
const char *rootNames[] = { "Root", "mixamorig:Hips", "Spineroot" };
|
||||
for (const char *name : rootNames) {
|
||||
try {
|
||||
state.rootBone = skel->getBone(name);
|
||||
@@ -102,7 +104,8 @@ bool AnimationTreeSystem::setupEntity(flecs::entity e,
|
||||
}
|
||||
}
|
||||
if (state.rootBone) {
|
||||
state.rootBindingPosition = state.rootBone->getInitialPosition();
|
||||
state.rootBindingPosition =
|
||||
state.rootBone->getInitialPosition();
|
||||
state.rootBindingOrientation =
|
||||
state.rootBone->getInitialOrientation();
|
||||
state.rootBindingScale = state.rootBone->getInitialScale();
|
||||
@@ -124,11 +127,9 @@ bool AnimationTreeSystem::setupEntity(flecs::entity e,
|
||||
* Animation::apply() in OGRE 14) */
|
||||
if (state.rootBone) {
|
||||
as->destroyBlendMask();
|
||||
as->createBlendMask(skel->getNumBones(),
|
||||
1.0f);
|
||||
as->createBlendMask(skel->getNumBones(), 1.0f);
|
||||
as->setBlendMaskEntry(
|
||||
state.rootBone->getHandle(),
|
||||
0.0f);
|
||||
state.rootBone->getHandle(), 0.0f);
|
||||
}
|
||||
|
||||
AnimationRuntimeInfo info;
|
||||
@@ -142,18 +143,20 @@ bool AnimationTreeSystem::setupEntity(flecs::entity e,
|
||||
state.rootBone->getHandle();
|
||||
if (anim->hasNodeTrack(handle)) {
|
||||
info.rootTrack =
|
||||
anim->getNodeTrack(handle);
|
||||
if (info.rootTrack->getNumKeyFrames() >=
|
||||
anim->getNodeTrack(
|
||||
handle);
|
||||
if (info.rootTrack
|
||||
->getNumKeyFrames() >=
|
||||
2) {
|
||||
Ogre::TransformKeyFrame *tkfBeg =
|
||||
info.rootTrack
|
||||
->getNodeKeyFrame(0);
|
||||
Ogre::TransformKeyFrame *tkfEnd =
|
||||
info.rootTrack
|
||||
->getNodeKeyFrame(
|
||||
info.rootTrack
|
||||
->getNumKeyFrames() -
|
||||
1);
|
||||
0);
|
||||
Ogre::TransformKeyFrame *tkfEnd =
|
||||
info.rootTrack->getNodeKeyFrame(
|
||||
info.rootTrack
|
||||
->getNumKeyFrames() -
|
||||
1);
|
||||
info.loopTranslation =
|
||||
tkfEnd->getTranslate() -
|
||||
tkfBeg->getTranslate();
|
||||
@@ -169,9 +172,11 @@ bool AnimationTreeSystem::setupEntity(flecs::entity e,
|
||||
|
||||
/* Initialize default state machine states */
|
||||
initializeTreeStates(at.root, at);
|
||||
std::cout << " setupEntity done: animations=" << state.animations.size()
|
||||
<< " rootBone=" << (state.rootBone ? state.rootBone->getName() : "null")
|
||||
<< std::endl;
|
||||
std::cout
|
||||
<< " setupEntity done: animations=" << state.animations.size()
|
||||
<< " rootBone="
|
||||
<< (state.rootBone ? state.rootBone->getName() : "null")
|
||||
<< std::endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -183,16 +188,40 @@ void AnimationTreeSystem::teardownEntity(flecs::entity e)
|
||||
|
||||
EntityAnimTreeState &state = it->second;
|
||||
|
||||
for (auto &pair : state.animations) {
|
||||
if (pair.second.ogreAnimState)
|
||||
pair.second.ogreAnimState->destroyBlendMask();
|
||||
/*
|
||||
* The Ogre::Entity may have already been destroyed by
|
||||
* EditorUISystem::deleteEntity before the Flecs OnRemove
|
||||
* observer fires. In that case the AnimationState pointers
|
||||
* are dangling and we must not touch them.
|
||||
*
|
||||
* We detect this by checking whether the cached Ogre::Entity
|
||||
* name is still known to the scene manager. We use the
|
||||
* cached name string (ogreEntityName) rather than
|
||||
* ogreEntity->getName() because the pointer may already be
|
||||
* dangling.
|
||||
*/
|
||||
bool ogreEntityAlive = false;
|
||||
if (!state.ogreEntityName.empty()) {
|
||||
try {
|
||||
ogreEntityAlive =
|
||||
m_sceneMgr->hasEntity(state.ogreEntityName);
|
||||
} catch (...) {
|
||||
ogreEntityAlive = false;
|
||||
}
|
||||
}
|
||||
|
||||
disableAllAnimations(state);
|
||||
if (ogreEntityAlive) {
|
||||
for (auto &pair : state.animations) {
|
||||
if (pair.second.ogreAnimState)
|
||||
pair.second.ogreAnimState->destroyBlendMask();
|
||||
}
|
||||
|
||||
if (state.rootBone) {
|
||||
state.rootBone->setManuallyControlled(false);
|
||||
state.rootBone = nullptr;
|
||||
disableAllAnimations(state);
|
||||
|
||||
if (state.rootBone) {
|
||||
state.rootBone->setManuallyControlled(false);
|
||||
state.rootBone = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
state.animations.clear();
|
||||
@@ -210,15 +239,16 @@ void AnimationTreeSystem::disableAllAnimations(EntityAnimTreeState &state)
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationTreeSystem::initializeTreeStates(
|
||||
const AnimationTreeNode &node, AnimationTreeComponent &at)
|
||||
void AnimationTreeSystem::initializeTreeStates(const AnimationTreeNode &node,
|
||||
AnimationTreeComponent &at)
|
||||
{
|
||||
if (node.type == "stateMachine") {
|
||||
if (at.currentStates.find(node.name) ==
|
||||
at.currentStates.end()) {
|
||||
for (const auto &child : node.children) {
|
||||
if (child.type == "state") {
|
||||
at.currentStates[node.name] = child.name;
|
||||
at.currentStates[node.name] =
|
||||
child.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -236,9 +266,9 @@ void AnimationTreeSystem::resolveTemplate(AnimationTreeComponent &at)
|
||||
AnimationTreeTemplate *templ = nullptr;
|
||||
AnimationTreeComponent *templAt = nullptr;
|
||||
|
||||
m_world.query<AnimationTreeTemplate, AnimationTreeComponent>()
|
||||
.each([&](flecs::entity, AnimationTreeTemplate &t,
|
||||
AnimationTreeComponent &ta) {
|
||||
m_world.query<AnimationTreeTemplate, AnimationTreeComponent>().each(
|
||||
[&](flecs::entity, AnimationTreeTemplate &t,
|
||||
AnimationTreeComponent &ta) {
|
||||
if (t.name == at.templateName) {
|
||||
templ = &t;
|
||||
templAt = &ta;
|
||||
@@ -246,8 +276,8 @@ void AnimationTreeSystem::resolveTemplate(AnimationTreeComponent &at)
|
||||
});
|
||||
|
||||
if (!templ) {
|
||||
m_world.query<AnimationTreeTemplate>()
|
||||
.each([&](flecs::entity, AnimationTreeTemplate &t) {
|
||||
m_world.query<AnimationTreeTemplate>().each(
|
||||
[&](flecs::entity, AnimationTreeTemplate &t) {
|
||||
if (t.name == at.templateName)
|
||||
templ = &t;
|
||||
});
|
||||
@@ -266,159 +296,155 @@ void AnimationTreeSystem::update(float deltaTime)
|
||||
if (!m_initialized)
|
||||
return;
|
||||
|
||||
m_world.query<AnimationTreeComponent>().each(
|
||||
[this, deltaTime](flecs::entity e,
|
||||
AnimationTreeComponent &at) {
|
||||
resolveTemplate(at);
|
||||
m_world.query<AnimationTreeComponent>().each([this, deltaTime](
|
||||
flecs::entity e,
|
||||
AnimationTreeComponent
|
||||
&at) {
|
||||
resolveTemplate(at);
|
||||
|
||||
if (at.dirty) {
|
||||
if (setupEntity(e, at))
|
||||
at.dirty = false;
|
||||
}
|
||||
if (at.dirty) {
|
||||
if (setupEntity(e, at))
|
||||
at.dirty = false;
|
||||
}
|
||||
|
||||
auto it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
auto it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
|
||||
/* Validate cached entity pointer -
|
||||
/* Validate cached entity pointer -
|
||||
* CharacterSlotSystem rebuilds can destroy and
|
||||
* recreate the Ogre::Entity */
|
||||
Ogre::Entity *currentEnt = findAnimatedEntity(e);
|
||||
if (currentEnt != it->second.ogreEntity) {
|
||||
if (!setupEntity(e, at)) {
|
||||
return;
|
||||
}
|
||||
it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
}
|
||||
|
||||
EntityAnimTreeState &state = it->second;
|
||||
if (!state.ogreEntity)
|
||||
return;
|
||||
|
||||
if (!at.enabled) {
|
||||
disableAllAnimations(state);
|
||||
Ogre::Entity *currentEnt = findAnimatedEntity(e);
|
||||
if (currentEnt != it->second.ogreEntity) {
|
||||
if (!setupEntity(e, at)) {
|
||||
return;
|
||||
}
|
||||
it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
return;
|
||||
}
|
||||
|
||||
/* Sync external state changes (editor) */
|
||||
syncStateChanges(at, state);
|
||||
EntityAnimTreeState &state = it->second;
|
||||
if (!state.ogreEntity)
|
||||
return;
|
||||
|
||||
/* Evaluate tree */
|
||||
EvalContext ctx;
|
||||
ctx.deltaTime = deltaTime;
|
||||
evaluateNode(at.root, 1.0f, 1.0f, at, state, ctx);
|
||||
if (!at.enabled) {
|
||||
disableAllAnimations(state);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Apply animation weights and advance */
|
||||
Ogre::Vector3 totalRootMotion =
|
||||
Ogre::Vector3::ZERO;
|
||||
Ogre::SceneNode *sceneNode =
|
||||
state.ogreEntity->getParentSceneNode();
|
||||
/* Sync external state changes (editor) */
|
||||
syncStateChanges(at, state);
|
||||
|
||||
for (auto &pair : ctx.animData) {
|
||||
const Ogre::String &animName = pair.first;
|
||||
AnimEvalData &data = pair.second;
|
||||
/* Evaluate tree */
|
||||
EvalContext ctx;
|
||||
ctx.deltaTime = deltaTime;
|
||||
evaluateNode(at.root, 1.0f, 1.0f, at, state, ctx);
|
||||
|
||||
auto itAnim =
|
||||
state.animations.find(animName);
|
||||
if (itAnim == state.animations.end())
|
||||
continue;
|
||||
AnimationRuntimeInfo &info =
|
||||
itAnim->second;
|
||||
/* Apply animation weights and advance */
|
||||
Ogre::Vector3 totalRootMotion = Ogre::Vector3::ZERO;
|
||||
Ogre::SceneNode *sceneNode =
|
||||
state.ogreEntity->getParentSceneNode();
|
||||
|
||||
if (!info.ogreAnimState)
|
||||
continue;
|
||||
for (auto &pair : ctx.animData) {
|
||||
const Ogre::String &animName = pair.first;
|
||||
AnimEvalData &data = pair.second;
|
||||
|
||||
bool active = data.weight > 0.001f;
|
||||
info.ogreAnimState->setEnabled(active);
|
||||
info.ogreAnimState->setWeight(
|
||||
Ogre::Math::Clamp(data.weight, 0.0f,
|
||||
1.0f));
|
||||
auto itAnim = state.animations.find(animName);
|
||||
if (itAnim == state.animations.end())
|
||||
continue;
|
||||
AnimationRuntimeInfo &info = itAnim->second;
|
||||
|
||||
if (active && data.timeDelta != 0.0f) {
|
||||
float lastTime = info.ogreAnimState
|
||||
->getTimePosition();
|
||||
info.ogreAnimState->addTime(
|
||||
data.timeDelta);
|
||||
float thisTime =
|
||||
info.ogreAnimState
|
||||
->getTimePosition();
|
||||
float length =
|
||||
info.ogreAnimState
|
||||
->getLength();
|
||||
bool loop =
|
||||
info.ogreAnimState
|
||||
->getLoop();
|
||||
if (!info.ogreAnimState)
|
||||
continue;
|
||||
|
||||
int loops = 0;
|
||||
if (loop && length > 0.0f) {
|
||||
loops = (int)std::round(
|
||||
(lastTime + data.timeDelta -
|
||||
thisTime) /
|
||||
length);
|
||||
}
|
||||
bool active = data.weight > 0.001f;
|
||||
info.ogreAnimState->setEnabled(active);
|
||||
info.ogreAnimState->setWeight(
|
||||
Ogre::Math::Clamp(data.weight, 0.0f, 1.0f));
|
||||
|
||||
if (at.useRootMotion &&
|
||||
info.rootTrack) {
|
||||
Ogre::TransformKeyFrame tkf(
|
||||
nullptr, 0.0f);
|
||||
info.rootTrack
|
||||
->getInterpolatedKeyFrame(
|
||||
lastTime, &tkf);
|
||||
Ogre::Vector3 lastPos =
|
||||
tkf.getTranslate();
|
||||
info.rootTrack
|
||||
->getInterpolatedKeyFrame(
|
||||
thisTime, &tkf);
|
||||
Ogre::Vector3 thisPos =
|
||||
tkf.getTranslate();
|
||||
Ogre::Vector3 delta =
|
||||
thisPos - lastPos +
|
||||
loops *
|
||||
info.loopTranslation;
|
||||
totalRootMotion +=
|
||||
delta * data.weight;
|
||||
}
|
||||
if (active && data.timeDelta != 0.0f) {
|
||||
float lastTime =
|
||||
info.ogreAnimState->getTimePosition();
|
||||
info.ogreAnimState->addTime(data.timeDelta);
|
||||
float thisTime =
|
||||
info.ogreAnimState->getTimePosition();
|
||||
float length = info.ogreAnimState->getLength();
|
||||
bool loop = info.ogreAnimState->getLoop();
|
||||
|
||||
int loops = 0;
|
||||
if (loop && length > 0.0f) {
|
||||
loops = (int)std::round(
|
||||
(lastTime + data.timeDelta -
|
||||
thisTime) /
|
||||
length);
|
||||
}
|
||||
|
||||
if (at.useRootMotion && info.rootTrack) {
|
||||
Ogre::TransformKeyFrame tkf(nullptr,
|
||||
0.0f);
|
||||
info.rootTrack->getInterpolatedKeyFrame(
|
||||
lastTime, &tkf);
|
||||
Ogre::Vector3 lastPos =
|
||||
tkf.getTranslate();
|
||||
info.rootTrack->getInterpolatedKeyFrame(
|
||||
thisTime, &tkf);
|
||||
Ogre::Vector3 thisPos =
|
||||
tkf.getTranslate();
|
||||
Ogre::Vector3 delta =
|
||||
thisPos - lastPos +
|
||||
loops * info.loopTranslation;
|
||||
totalRootMotion += delta * data.weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (at.useRootMotion && sceneNode) {
|
||||
if (e.has<CharacterComponent>()) {
|
||||
auto &cc = e.get_mut<CharacterComponent>();
|
||||
if (deltaTime > 0.0000001f) {
|
||||
float safeDelta = Ogre::Math::Clamp(deltaTime, 0.005f, 0.99f);
|
||||
Ogre::Quaternion worldRot = sceneNode->_getDerivedOrientation();
|
||||
cc.linearVelocity = worldRot * totalRootMotion / safeDelta;
|
||||
cc.linearVelocity.x = Ogre::Math::Clamp(cc.linearVelocity.x, -16.0f, 16.0f);
|
||||
cc.linearVelocity.z = Ogre::Math::Clamp(cc.linearVelocity.z, -16.0f, 16.0f);
|
||||
cc.linearVelocity.y = Ogre::Math::Clamp(cc.linearVelocity.y, -10.5f, 10.0f);
|
||||
}
|
||||
} else {
|
||||
sceneNode->translate(totalRootMotion,
|
||||
if (at.useRootMotion && sceneNode) {
|
||||
if (e.has<CharacterComponent>()) {
|
||||
auto &cc = e.get_mut<CharacterComponent>();
|
||||
if (deltaTime > 0.0000001f) {
|
||||
float safeDelta = Ogre::Math::Clamp(
|
||||
deltaTime, 0.005f, 0.99f);
|
||||
Ogre::Quaternion worldRot =
|
||||
sceneNode
|
||||
->_getDerivedOrientation();
|
||||
cc.linearVelocity = worldRot *
|
||||
totalRootMotion /
|
||||
safeDelta;
|
||||
cc.linearVelocity.x = Ogre::Math::Clamp(
|
||||
cc.linearVelocity.x, -16.0f,
|
||||
16.0f);
|
||||
cc.linearVelocity.z = Ogre::Math::Clamp(
|
||||
cc.linearVelocity.z, -16.0f,
|
||||
16.0f);
|
||||
cc.linearVelocity.y = Ogre::Math::Clamp(
|
||||
cc.linearVelocity.y, -10.5f,
|
||||
10.0f);
|
||||
}
|
||||
} else {
|
||||
sceneNode->translate(totalRootMotion,
|
||||
Ogre::Node::TS_LOCAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Reset root bone to binding pose */
|
||||
if (state.rootBone) {
|
||||
state.rootBone->setPosition(
|
||||
state.rootBindingPosition);
|
||||
state.rootBone->setOrientation(
|
||||
state.rootBindingOrientation);
|
||||
state.rootBone->setScale(
|
||||
state.rootBindingScale);
|
||||
}
|
||||
/* Reset root bone to binding pose */
|
||||
if (state.rootBone) {
|
||||
state.rootBone->setPosition(state.rootBindingPosition);
|
||||
state.rootBone->setOrientation(
|
||||
state.rootBindingOrientation);
|
||||
state.rootBone->setScale(state.rootBindingScale);
|
||||
}
|
||||
|
||||
/* Handle end-of-animation transitions */
|
||||
checkEndTransitions(e, at, state, ctx);
|
||||
});
|
||||
/* Handle end-of-animation transitions */
|
||||
checkEndTransitions(e, at, state, ctx);
|
||||
});
|
||||
}
|
||||
|
||||
void AnimationTreeSystem::evaluateNode(
|
||||
const AnimationTreeNode &node, float parentWeight, float timeMul,
|
||||
const AnimationTreeComponent &at, EntityAnimTreeState &state,
|
||||
EvalContext &ctx)
|
||||
void AnimationTreeSystem::evaluateNode(const AnimationTreeNode &node,
|
||||
float parentWeight, float timeMul,
|
||||
const AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state,
|
||||
EvalContext &ctx)
|
||||
{
|
||||
if (parentWeight < 0.001f)
|
||||
return;
|
||||
@@ -453,8 +479,7 @@ void AnimationTreeSystem::evaluateNode(
|
||||
/* Update fades */
|
||||
std::vector<Ogre::String> doneIn;
|
||||
for (const auto &inName : fade.fadeIn) {
|
||||
fade.weights[inName] +=
|
||||
ctx.deltaTime * node.fadeSpeed;
|
||||
fade.weights[inName] += ctx.deltaTime * node.fadeSpeed;
|
||||
if (fade.weights[inName] >= 1.0f) {
|
||||
fade.weights[inName] = 1.0f;
|
||||
doneIn.push_back(inName);
|
||||
@@ -465,8 +490,7 @@ void AnimationTreeSystem::evaluateNode(
|
||||
|
||||
std::vector<Ogre::String> doneOut;
|
||||
for (const auto &outName : fade.fadeOut) {
|
||||
fade.weights[outName] -=
|
||||
ctx.deltaTime * node.fadeSpeed;
|
||||
fade.weights[outName] -= ctx.deltaTime * node.fadeSpeed;
|
||||
if (fade.weights[outName] <= 0.0f) {
|
||||
fade.weights[outName] = 0.0f;
|
||||
doneOut.push_back(outName);
|
||||
@@ -481,19 +505,18 @@ void AnimationTreeSystem::evaluateNode(
|
||||
continue;
|
||||
float w = fade.weights[child.name];
|
||||
if (w > 0.001f)
|
||||
evaluateNode(child, parentWeight * w,
|
||||
timeMul, at, state, ctx);
|
||||
evaluateNode(child, parentWeight * w, timeMul,
|
||||
at, state, ctx);
|
||||
}
|
||||
|
||||
/* Queue end-transition check */
|
||||
if (node.endTransitions.find(currentName) !=
|
||||
node.endTransitions.end())
|
||||
ctx.endChecks.push_back(
|
||||
{node.name, currentName});
|
||||
ctx.endChecks.push_back({ node.name, currentName });
|
||||
} else if (node.type == "state") {
|
||||
if (!node.children.empty())
|
||||
evaluateNode(node.children[0], parentWeight,
|
||||
timeMul, at, state, ctx);
|
||||
evaluateNode(node.children[0], parentWeight, timeMul,
|
||||
at, state, ctx);
|
||||
} else if (node.type == "animation") {
|
||||
auto &data = ctx.animData[node.animationName];
|
||||
data.weight += parentWeight;
|
||||
@@ -501,8 +524,8 @@ void AnimationTreeSystem::evaluateNode(
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationTreeSystem::syncStateChanges(
|
||||
AnimationTreeComponent &at, EntityAnimTreeState &state)
|
||||
void AnimationTreeSystem::syncStateChanges(AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state)
|
||||
{
|
||||
for (auto &pair : at.currentStates) {
|
||||
auto itPrev = state.prevStates.find(pair.first);
|
||||
@@ -519,15 +542,15 @@ void AnimationTreeSystem::syncStateChanges(
|
||||
}
|
||||
/* Also track newly added state machines */
|
||||
for (auto &pair : at.currentStates) {
|
||||
if (state.prevStates.find(pair.first) ==
|
||||
state.prevStates.end())
|
||||
if (state.prevStates.find(pair.first) == state.prevStates.end())
|
||||
state.prevStates[pair.first] = pair.second;
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationTreeSystem::checkEndTransitions(
|
||||
flecs::entity e, AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state, EvalContext &ctx)
|
||||
void AnimationTreeSystem::checkEndTransitions(flecs::entity e,
|
||||
AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state,
|
||||
EvalContext &ctx)
|
||||
{
|
||||
for (auto &pair : ctx.endChecks) {
|
||||
const Ogre::String &smName = pair.first;
|
||||
@@ -546,32 +569,28 @@ void AnimationTreeSystem::checkEndTransitions(
|
||||
findStateNode(*smNode, stateName);
|
||||
if (!stNode)
|
||||
continue;
|
||||
const AnimationTreeNode *animNode =
|
||||
findAnimationNode(*stNode);
|
||||
const AnimationTreeNode *animNode = findAnimationNode(*stNode);
|
||||
if (!animNode)
|
||||
continue;
|
||||
|
||||
auto itAnim = state.animations.find(
|
||||
animNode->animationName);
|
||||
auto itAnim = state.animations.find(animNode->animationName);
|
||||
if (itAnim == state.animations.end())
|
||||
continue;
|
||||
Ogre::AnimationState *as =
|
||||
itAnim->second.ogreAnimState;
|
||||
Ogre::AnimationState *as = itAnim->second.ogreAnimState;
|
||||
if (!as)
|
||||
continue;
|
||||
|
||||
float t = as->getTimePosition();
|
||||
float len = as->getLength();
|
||||
if (len > 0.0f && t >= len * 0.99f)
|
||||
setStateInternal(e, at, state, smName,
|
||||
itTrans->second, true);
|
||||
setStateInternal(e, at, state, smName, itTrans->second,
|
||||
true);
|
||||
}
|
||||
}
|
||||
|
||||
void AnimationTreeSystem::setState(flecs::entity e,
|
||||
const Ogre::String &stateMachineName,
|
||||
const Ogre::String &stateName,
|
||||
bool reset)
|
||||
const Ogre::String &stateName, bool reset)
|
||||
{
|
||||
auto it = m_states.find(e.id());
|
||||
if (it == m_states.end())
|
||||
@@ -579,15 +598,15 @@ void AnimationTreeSystem::setState(flecs::entity e,
|
||||
if (!e.has<AnimationTreeComponent>())
|
||||
return;
|
||||
auto &at = e.get_mut<AnimationTreeComponent>();
|
||||
setStateInternal(e, at, it->second, stateMachineName,
|
||||
stateName, reset);
|
||||
setStateInternal(e, at, it->second, stateMachineName, stateName, reset);
|
||||
}
|
||||
|
||||
void AnimationTreeSystem::setStateInternal(
|
||||
flecs::entity e, AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state,
|
||||
const Ogre::String &stateMachineName,
|
||||
const Ogre::String &stateName, bool reset)
|
||||
void AnimationTreeSystem::setStateInternal(flecs::entity e,
|
||||
AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state,
|
||||
const Ogre::String &stateMachineName,
|
||||
const Ogre::String &stateName,
|
||||
bool reset)
|
||||
{
|
||||
(void)e;
|
||||
auto itCurrent = at.currentStates.find(stateMachineName);
|
||||
@@ -627,8 +646,9 @@ void AnimationTreeSystem::setStateInternal(
|
||||
}
|
||||
}
|
||||
|
||||
Ogre::String AnimationTreeSystem::getCurrentState(
|
||||
flecs::entity e, const Ogre::String &stateMachineName)
|
||||
Ogre::String
|
||||
AnimationTreeSystem::getCurrentState(flecs::entity e,
|
||||
const Ogre::String &stateMachineName)
|
||||
{
|
||||
if (!e.has<AnimationTreeComponent>())
|
||||
return "";
|
||||
@@ -639,8 +659,9 @@ Ogre::String AnimationTreeSystem::getCurrentState(
|
||||
return "";
|
||||
}
|
||||
|
||||
const AnimationTreeNode *AnimationTreeSystem::findStateMachineNode(
|
||||
const AnimationTreeNode &root, const Ogre::String &name) const
|
||||
const AnimationTreeNode *
|
||||
AnimationTreeSystem::findStateMachineNode(const AnimationTreeNode &root,
|
||||
const Ogre::String &name) const
|
||||
{
|
||||
if (root.type == "stateMachine" && root.name == name)
|
||||
return &root;
|
||||
@@ -653,9 +674,9 @@ const AnimationTreeNode *AnimationTreeSystem::findStateMachineNode(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const AnimationTreeNode *AnimationTreeSystem::findStateNode(
|
||||
const AnimationTreeNode &smNode,
|
||||
const Ogre::String &stateName) const
|
||||
const AnimationTreeNode *
|
||||
AnimationTreeSystem::findStateNode(const AnimationTreeNode &smNode,
|
||||
const Ogre::String &stateName) const
|
||||
{
|
||||
for (const auto &child : smNode.children) {
|
||||
if (child.type == "state" && child.name == stateName)
|
||||
@@ -664,14 +685,13 @@ const AnimationTreeNode *AnimationTreeSystem::findStateNode(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const AnimationTreeNode *AnimationTreeSystem::findAnimationNode(
|
||||
const AnimationTreeNode &stateNode) const
|
||||
const AnimationTreeNode *
|
||||
AnimationTreeSystem::findAnimationNode(const AnimationTreeNode &stateNode) const
|
||||
{
|
||||
if (stateNode.type == "animation")
|
||||
return &stateNode;
|
||||
for (const auto &child : stateNode.children) {
|
||||
const AnimationTreeNode *found =
|
||||
findAnimationNode(child);
|
||||
const AnimationTreeNode *found = findAnimationNode(child);
|
||||
if (found)
|
||||
return found;
|
||||
}
|
||||
|
||||
@@ -61,12 +61,14 @@ private:
|
||||
|
||||
struct EntityAnimTreeState {
|
||||
Ogre::Entity *ogreEntity = nullptr;
|
||||
Ogre::String ogreEntityName; /* cached for safe teardown */
|
||||
Ogre::Bone *rootBone = nullptr;
|
||||
Ogre::Vector3 rootBindingPosition;
|
||||
Ogre::Quaternion rootBindingOrientation;
|
||||
Ogre::Vector3 rootBindingScale;
|
||||
|
||||
std::unordered_map<Ogre::String, AnimationRuntimeInfo> animations;
|
||||
std::unordered_map<Ogre::String, AnimationRuntimeInfo>
|
||||
animations;
|
||||
std::unordered_map<Ogre::String, FadeInfo> fadeStates;
|
||||
/* Track previous currentStates to detect external changes */
|
||||
std::unordered_map<Ogre::String, Ogre::String> prevStates;
|
||||
@@ -80,7 +82,7 @@ private:
|
||||
struct EvalContext {
|
||||
float deltaTime = 0.0f;
|
||||
std::unordered_map<Ogre::String, AnimEvalData> animData;
|
||||
std::vector<std::pair<Ogre::String, Ogre::String>> endChecks;
|
||||
std::vector<std::pair<Ogre::String, Ogre::String> > endChecks;
|
||||
};
|
||||
|
||||
bool setupEntity(flecs::entity e, AnimationTreeComponent &at);
|
||||
@@ -92,8 +94,7 @@ private:
|
||||
float timeMul, const AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state, EvalContext &ctx);
|
||||
void checkEndTransitions(flecs::entity e, AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state,
|
||||
EvalContext &ctx);
|
||||
EntityAnimTreeState &state, EvalContext &ctx);
|
||||
void syncStateChanges(AnimationTreeComponent &at,
|
||||
EntityAnimTreeState &state);
|
||||
void setStateInternal(flecs::entity e, AnimationTreeComponent &at,
|
||||
@@ -104,14 +105,14 @@ private:
|
||||
/* Resolve template reference and copy tree if template changed */
|
||||
void resolveTemplate(AnimationTreeComponent &at);
|
||||
|
||||
const AnimationTreeNode *findStateMachineNode(
|
||||
const AnimationTreeNode &root,
|
||||
const Ogre::String &name) const;
|
||||
const AnimationTreeNode *findStateNode(
|
||||
const AnimationTreeNode &smNode,
|
||||
const Ogre::String &stateName) const;
|
||||
const AnimationTreeNode *findAnimationNode(
|
||||
const AnimationTreeNode &stateNode) const;
|
||||
const AnimationTreeNode *
|
||||
findStateMachineNode(const AnimationTreeNode &root,
|
||||
const Ogre::String &name) const;
|
||||
const AnimationTreeNode *
|
||||
findStateNode(const AnimationTreeNode &smNode,
|
||||
const Ogre::String &stateName) const;
|
||||
const AnimationTreeNode *
|
||||
findAnimationNode(const AnimationTreeNode &stateNode) const;
|
||||
|
||||
flecs::world &m_world;
|
||||
Ogre::SceneManager *m_sceneMgr;
|
||||
|
||||
Reference in New Issue
Block a user