8#include "spdlog/spdlog.h"
15 _instances.push_back(
this);
20 const auto it = std::find(_instances.begin(), _instances.end(),
this);
21 if (it != _instances.end()) {
34 _animations[name] = animation;
40 _animations[name] = animationTrack;
51 for (
auto& clip : _animEvaluator->clips()) {
62 return _skeleton->currentTime();
66 const auto& clips = _animEvaluator->clips();
67 if (!clips.empty() && clips.back()) {
68 return clips.back()->time();
77 if (_currAnim.empty()) {
78 spdlog::warn(
"No animation is playing to get a duration. Returning 0.");
82 if (
const auto animation = getCurrentAnimation()) {
83 return animation->duration();
86 if (
const auto track = getCurrentAnimTrack()) {
87 return track->duration();
98 _skeleton->setLooping(value);
101 if (_animEvaluator) {
102 for (
auto& clip : _animEvaluator->clips()) {
104 clip->setLoop(value);
112 if (model == _model) {
116 resetAnimationController();
119 if (!_currAnim.empty() && _animations.contains(_currAnim)) {
126 const auto it = _animations.
find(name);
127 if (it == _animations.end()) {
131 if (
const auto* animation = std::get_if<std::shared_ptr<Animation>>(&it->second)) {
140 const auto it = _animations.find(name);
141 if (it == _animations.end()) {
145 if (
const auto* animationTrack = std::get_if<std::shared_ptr<AnimTrack>>(&it->second)) {
146 return *animationTrack;
152 std::shared_ptr<Animation> AnimationComponent::getCurrentAnimation()
const
157 std::shared_ptr<AnimTrack> AnimationComponent::getCurrentAnimTrack()
const
168 if (!_animations.contains(name)) {
169 spdlog::error(
"Trying to play animation '{}' which doesn't exist", name);
173 _prevAnim = _currAnim;
177 if (!_skeleton && !_animEvaluator) {
178 createAnimationController();
181 _blending = blendTime > 0.0f && !_prevAnim.empty();
184 _blendSpeed = 1.0f / blendTime;
190 _fromSkel->setAnimation(prevAnim.get());
191 _fromSkel->addTime(_skeleton->currentTime());
194 _toSkel->setAnimation(currAnim.get());
196 }
else if (
const auto currAnim =
getAnimation(_currAnim)) {
197 _skeleton->setAnimation(currAnim.get());
201 if (_animEvaluator) {
202 auto& clips = _animEvaluator->clips();
204 while (clips.size() > 1) {
205 _animEvaluator->removeClip(0);
208 _animEvaluator->removeClips();
212 auto clip = std::make_shared<AnimClip>(track, 0.0f, 1.0f,
true, _loop);
213 clip->setName(_currAnim);
214 clip->setBlendWeight(_blending ? 0.0f : 1.0f);
216 _animEvaluator->addClip(clip);
233 if (!_animations.empty()) {
234 play(_animations.begin()->first);
239 void AnimationComponent::resetAnimationController()
245 _animEvaluator.reset();
248 void AnimationComponent::createAnimationController()
250 bool hasJson =
false;
253 for (
const auto& [_, animation] : _animations) {
254 if (std::holds_alternative<std::shared_ptr<AnimTrack>>(animation)) {
262 _fromSkel = std::make_unique<Skeleton>(_model);
263 _toSkel = std::make_unique<Skeleton>(_model);
264 _skeleton = std::make_unique<Skeleton>(_model);
265 _skeleton->setLooping(_loop);
266 _skeleton->setGraph(_model);
268 _animEvaluator = std::make_unique<AnimEvaluator>(std::make_unique<DefaultAnimBinder>(
_entity));
272 void AnimationComponent::stopCurrentAnimation()
278 _skeleton->setCurrentTime(0.0f);
279 _skeleton->setAnimation(
nullptr);
281 if (_animEvaluator) {
282 for (
auto& clip : _animEvaluator->clips()) {
287 _animEvaluator->update(0.0f);
288 _animEvaluator->removeClips();
296 if (_activate && _currAnim.empty() && !_animations.empty()) {
297 play(_animations.begin()->first);
307 _animEvaluator.reset();
312 float blendAlpha = _blend;
315 _blend += dt * _blendSpeed;
316 if (_blend >= 1.0f) {
321 if (_hasBlendCurve) {
323 blendAlpha = std::clamp(_blendCurve.value(_blend), 0.0f, 1.0f);
328 if (_skeleton && _model) {
330 _skeleton->blend(_fromSkel.get(), _toSkel.get(), blendAlpha);
332 const float delta = dt * _speed;
333 _skeleton->addTime(delta);
334 if (_speed > 0.0f && (_skeleton->currentTime() ==
duration()) && !_loop) {
336 }
else if (_speed < 0.0f && _skeleton->
currentTime() == 0.0f && !_loop) {
341 if (_blending && (_blend == 1.0f)) {
342 _skeleton->setAnimation(_toSkel->animation());
345 _skeleton->updateGraph();
349 if (_animEvaluator) {
350 for (
auto& clip : _animEvaluator->clips()) {
355 clip->setSpeed(_speed);
363 if (_blending && _animEvaluator->clips().size() > 1 && _animEvaluator->clips()[1]) {
364 _animEvaluator->clips()[1]->setBlendWeight(blendAlpha);
367 _animEvaluator->update(dt);
370 if (_blending && _blend == 1.0f) {
378 _hasBlendCurve =
true;
383 _hasBlendCurve =
false;
void setAnimations(const std::unordered_map< std::string, AnimationResource > &value)
std::shared_ptr< AnimTrack > getAnimTrack(const std::string &name) const
void play(const std::string &name, float blendTime=0.0f)
~AnimationComponent() override
float currentTime() const
void setBlendCurve(const Curve &curve)
void addAnimation(const std::string &name, const std::shared_ptr< Animation > &animation)
std::shared_ptr< Animation > getAnimation(const std::string &name) const
void setCurrentTime(float currentTime)
void setModel(GraphNode *model)
AnimationComponent(IComponentSystem *system, Entity *entity)
virtual bool enabled() const
Component(IComponentSystem *system, Entity *entity)
IComponentSystem * system() const
ECS entity — a GraphNode that hosts components defining its behavior.
Hierarchical scene graph node with local/world transforms and parent-child relationships.
std::vector< GraphNode * > find(const std::function< bool(GraphNode *)> &predicate)
Find all descendants (and self) matching a predicate.