Support proper actuator animation

This commit is contained in:
2025-09-27 01:23:16 +03:00
parent 7e06da700a
commit 25280a9cbe
16 changed files with 528 additions and 103 deletions

View File

@@ -2,8 +2,64 @@
#define CHARACTER_ANIMATION_MODULE_H_
#include <Ogre.h>
#include <flecs.h>
#include "GameData.h"
#include "LuaData.h"
namespace ECS
{
struct AnimationTrigger;
struct AnimationTriggerSubscriber {
virtual void operator()(const AnimationTrigger *trigger) = 0;
};
struct AnimationTrigger {
Ogre::String name;
float time;
float weight;
std::vector<AnimationTriggerSubscriber *> subscriber_list;
float getTriggerTime() const
{
return time;
}
float getMinWeight() const
{
return weight;
}
const Ogre::String &getName() const
{
return name;
}
void notify(float weight)
{
int i;
if (weight < this->weight)
return;
for (i = 0; i < subscriber_list.size(); i++)
(*subscriber_list[i])(this);
}
void addSubscriber(AnimationTriggerSubscriber *sub)
{
if (std::find(subscriber_list.begin(), subscriber_list.end(),
sub) != subscriber_list.end())
return;
subscriber_list.push_back(sub);
}
void removeSubscriber(AnimationTriggerSubscriber *sub)
{
auto it = std::find(subscriber_list.begin(),
subscriber_list.end(), sub);
if (it != subscriber_list.end())
subscriber_list.erase(it);
}
void clearSubscribers()
{
subscriber_list.clear();
}
AnimationTrigger(const Ogre::String name, float time, float weight)
: name(name)
, time(time)
, weight(weight)
{
}
};
struct Animation {
Ogre::AnimationState *mAnimationState;
Ogre::Animation *mSkelAnimation;
@@ -11,6 +67,7 @@ struct Animation {
Ogre::NodeAnimationTrack *mRootTrack;
float m_weight;
float m_accWeight;
std::multimap<float, AnimationTrigger *> trigger_list;
Animation(Ogre::AnimationState *animState,
Ogre::Animation *skelAnimation)
: mAnimationState(animState)
@@ -30,19 +87,25 @@ struct Animation {
// mRootTracks[i]->removeAllKeyFrames();
}
}
#if 0
OgreAssert(mHipsTrack, "no hips track");
OgreAssert(mRootTrack, "no Root track");
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
Ogre::Vector3 motion = Ogre::Vector3::ZERO;
for (j = 0; j < mRootTrack->getNumKeyFrames(); j++) {
Ogre::Vector3 trans =
mRootTrack->getNodeKeyFrame(j)->getTranslate();
if (j == 0)
delta = trans;
else
delta = trans - motion;
mRootTrack->getNodeKeyFrame(j)->setTranslate(delta);
motion = trans;
#endif
if (mRootTrack) {
Ogre::Vector3 delta = Ogre::Vector3::ZERO;
Ogre::Vector3 motion = Ogre::Vector3::ZERO;
for (j = 0; j < mRootTrack->getNumKeyFrames(); j++) {
Ogre::Vector3 trans =
mRootTrack->getNodeKeyFrame(j)
->getTranslate();
if (j == 0)
delta = trans;
else
delta = trans - motion;
mRootTrack->getNodeKeyFrame(j)->setTranslate(
delta);
motion = trans;
}
}
}
Ogre::String getName()
@@ -78,7 +141,9 @@ struct Animation {
}
void addTime(float time)
{
preUpdateTriggers();
mAnimationState->addTime(time);
postUpdateTriggers(time);
}
void reset()
{
@@ -96,6 +161,67 @@ struct Animation {
{
return m_accWeight;
}
void addTrigger(AnimationTrigger *trigger)
{
trigger_list.insert(std::pair<float, AnimationTrigger *>(
trigger->getTriggerTime(), trigger));
}
void clearTriggers()
{
auto it = trigger_list.begin();
while (it != trigger_list.end()) {
delete it->second;
it++;
}
trigger_list.clear();
}
float mpreUpdateTime;
void preUpdateTriggers()
{
mpreUpdateTime = mAnimationState->getTimePosition() /
mAnimationState->getLength();
}
void postUpdateTriggers(float delta)
{
float postUpdateTime = mAnimationState->getTimePosition() /
mAnimationState->getLength();
bool positive = delta >= 0.0f;
if (positive)
updateTriggers(mpreUpdateTime, postUpdateTime);
else
updateTriggers(postUpdateTime, mpreUpdateTime);
}
void updateTriggers(float currentTime, float nextTime)
{
int i;
float weight = getWeight();
if (currentTime <= nextTime) {
auto it = trigger_list.lower_bound(currentTime);
while (it != trigger_list.end()) {
if (nextTime <=
it->second->getTriggerTime()) // in future, sorrted by time
return;
it->second->notify(weight);
}
} else {
updateTriggers(currentTime, 1);
updateTriggers(0, nextTime);
}
}
float getLength() const
{
if (getEnabled())
return mAnimationState->getLength();
else
return 0.0f;
}
float getTimePosition() const
{
if (getEnabled())
return mAnimationState->getTimePosition();
else
return 0.0f;
}
};
struct AnimationNode {
@@ -109,6 +235,8 @@ struct AnimationNode {
virtual void addTime(float time) = 0;
virtual void setWeight(float weight) = 0;
virtual void reset() = 0;
virtual float getLength() const = 0;
virtual float getTimePosition() const = 0;
float getWeight()
{
return m_weight;
@@ -121,6 +249,13 @@ struct AnimationNode {
{
m_name = name;
}
virtual float getTime() const
{
float l = getLength();
if (l > 0.0f)
return getTimePosition() / l;
return 0.0f;
}
};
struct AnimationNodeAnimation : AnimationNode {
@@ -144,6 +279,20 @@ struct AnimationNodeAnimation : AnimationNode {
{
mAnimation->reset();
}
float getLength() const
{
if (enabled)
return mAnimation->getLength();
else
return 0.0f;
}
float getTimePosition() const
{
if (enabled)
return mAnimation->getTimePosition();
else
return 0.0f;
}
};
struct AnimationNodeStateMachineState : AnimationNode {
AnimationNodeStateMachineState()
@@ -164,6 +313,14 @@ struct AnimationNodeStateMachineState : AnimationNode {
{
children[0]->reset();
}
float getLength() const
{
return children[0]->getLength();
}
float getTimePosition() const
{
return children[0]->getLength();
}
};
struct AnimationNodeSpeed : AnimationNode {
float m_speed;
@@ -187,6 +344,25 @@ struct AnimationNodeSpeed : AnimationNode {
{
children[0]->reset();
}
float getLength() const
{
if (m_speed > 0.0f || m_speed < 0.0f)
return children[0]->getLength() / m_speed;
return 0.0f;
}
float getTimePosition() const
{
if (m_speed > 0.0f || m_speed < 0.0f)
return children[0]->getTimePosition() / m_speed;
return 0.0f;
}
float getTime() const override
{
float l = children[0]->getLength();
if (l > 0.0f)
return children[0]->getTimePosition() / l;
return 0.0f;
}
};
struct AnimationNodeStateMachine : AnimationNode {
std::map<Ogre::String, AnimationNode *> stateMap;
@@ -215,8 +391,10 @@ struct AnimationNodeStateMachine : AnimationNode {
configured = true;
}
if (debug) {
std::cout<< "state machine addTime" << std::endl;
std::cout << "state machine children: " << children.size() << std::endl;
std::cout << "state machine addTime" << std::endl;
std::cout
<< "state machine children: " << children.size()
<< std::endl;
}
for (i = 0; i < children.size(); i++) {
if (debug)
@@ -230,8 +408,10 @@ struct AnimationNodeStateMachine : AnimationNode {
child->setWeight(Ogre::Math::Clamp<Ogre::Real>(
newWeight * m_weight, 0, m_weight));
if (debug) {
std::cout << "fade in: " << newWeight << std::endl;
std::cout << "m_weight: " << m_weight << std::endl;
std::cout << "fade in: " << newWeight
<< std::endl;
std::cout << "m_weight: " << m_weight
<< std::endl;
}
if (newWeight >= 1)
fade_in.erase(child);
@@ -254,7 +434,8 @@ struct AnimationNodeStateMachine : AnimationNode {
int i;
if (weight > m_weight && currentAnim)
fade_in.insert(currentAnim);
if (weight < m_weight && currentAnim && currentAnim->getWeight() > weight)
if (weight < m_weight && currentAnim &&
currentAnim->getWeight() > weight)
currentAnim->setWeight(weight);
m_weight = weight;
bool enabled = weight > 0.001f;
@@ -273,7 +454,8 @@ struct AnimationNodeStateMachine : AnimationNode {
{
int i;
if (debug)
std::cout << "children: " << children.size() << std::endl;
std::cout << "children: " << children.size()
<< std::endl;
for (i = 0; i < children.size(); i++)
addState(children[i]);
if (debug)
@@ -312,6 +494,20 @@ struct AnimationNodeStateMachine : AnimationNode {
{
return mCurrentStateName;
}
float getLength() const
{
if (currentAnim)
return currentAnim->getLength();
else
return 0.0f;
}
float getTimePosition() const
{
if (currentAnim)
return currentAnim->getTimePosition();
else
return 0.0f;
}
};
#define ANIM_FADE_SPEED \
@@ -340,6 +536,14 @@ struct AnimationNodeOutput : AnimationNode {
{
children[0]->reset();
}
float getLength() const
{
return children[0]->getLength();
}
float getTimePosition() const
{
return children[0]->getTimePosition();
}
};
struct AnimationSystem : AnimationNode {
@@ -353,6 +557,7 @@ struct AnimationSystem : AnimationNode {
std::vector<Animation *> vanimation_list;
void add_animation(const Ogre::String &name, Animation *animation)
{
OgreAssert(animation, "No animation " + name);
animation_list[name] = animation;
vanimation_list.push_back(animation);
}
@@ -388,13 +593,49 @@ struct AnimationSystem : AnimationNode {
OgreAssert(parent, "bad parent");
Animation *animation =
mAnimationSystem->animation_list[animation_name];
OgreAssert(animation,
"bad animation " + animation_name);
AnimationNodeAnimation *onode =
new AnimationNodeAnimation(animation);
OgreAssert(onode, "bad animation");
OgreAssert(onode->mAnimation, "bad animation");
animation_nodes.push_back(onode);
parent->children.push_back(onode);
animationNodeList.push_back(onode);
return this;
}
AnimationSystemBuilder *trigger(flecs::entity e,
const Ogre::String &name,
float time,
const Ogre::String &event)
{
struct EventSubscriber : AnimationTriggerSubscriber {
flecs::entity ent;
Ogre::String event;
void operator()(const AnimationTrigger *trigger)
{
ECS::get_mut<LuaData>().call_handler(
event, ent, ent);
}
EventSubscriber(flecs::entity e,
const Ogre::String &event)
: ent(e)
, event(event)
{
}
};
OgreAssert(parent, "bad parent");
Animation *animation =
static_cast<AnimationNodeAnimation *>(parent)
->mAnimation;
OgreAssert(animation, "bad animation");
AnimationTrigger *trigger =
new AnimationTrigger(name, time, 0.1f);
EventSubscriber *sub = new EventSubscriber(e, event);
trigger->addSubscriber(sub);
animation->addTrigger(trigger);
return this;
}
AnimationSystemBuilder *speed(float speed,
const Ogre::String &anchor = "")
{
@@ -451,6 +692,7 @@ struct AnimationSystem : AnimationNode {
for (i = 0; i < m_builder.animationNodeList.size(); i++) {
AnimationNodeAnimation *anim =
m_builder.animationNodeList[i];
OgreAssert(anim->mAnimation, "No animation");
float weight = anim->getWeight();
anim->mAnimation->increaseAccWeight(weight);
#ifdef VDEBUG
@@ -490,6 +732,14 @@ struct AnimationSystem : AnimationNode {
{
return static_cast<T *>(m_builder.nodeMap[name]);
}
float getLength() const
{
return m_builder.animation_nodes[0]->getLength();
}
float getTimePosition() const
{
return m_builder.animation_nodes[0]->getTimePosition();
}
};
struct AnimationControl {