From 19555043d70f972feedb89786fc24a2b83b4f7e9 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Thu, 3 May 2018 00:49:15 +0300 Subject: [PATCH] Implement an event system for animations It can be used to sync other actions to certain points of the animation. --- source/animation.cpp | 65 +++++++++++++++++++++++++++++++++ source/animation.h | 20 +++++++++- source/animationeventobserver.h | 25 +++++++++++++ source/animationplayer.cpp | 43 +++++++++++++++++++++- source/animationplayer.h | 15 ++++++++ 5 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 source/animationeventobserver.h diff --git a/source/animation.cpp b/source/animation.cpp index 2f78d1ea..744262d8 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -3,6 +3,7 @@ #include #include #include "animation.h" +#include "animationeventobserver.h" #include "armature.h" #include "error.h" #include "pose.h" @@ -71,6 +72,15 @@ void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtrkeyframes.begin()), + event_iter(animation->events.begin()), end(false) { } @@ -263,6 +274,24 @@ Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t) return *this; } +void Animation::Iterator::dispatch_events(AnimationEventObserver &observer) +{ + vector::const_iterator events_end = animation->events.end(); + if(end) + { + for(; event_iter!=events_end; ++event_iter) + observer.animation_event(0, event_iter->name, event_iter->value); + } + else if(event_iter!=events_end) + { + Time::TimeDelta t = time_since_keyframe; + if(iter->prev) + t += iter->prev->time; + for(; (event_iter!=events_end && event_iter->time<=t); ++event_iter) + observer.animation_event(0, event_iter->name, event_iter->value); + } +} + Matrix Animation::Iterator::get_matrix() const { if(!iter->prev) @@ -329,12 +358,48 @@ Animation::Loader::Loader(Animation &a, Collection &c): void Animation::Loader::init() { add("armature", &Animation::armature); + add("event", &Loader::event); + add("event", &Loader::event1i); + add("event", &Loader::event1f); + add("event", &Loader::event2f); + add("event", &Loader::event3f); + add("event", &Loader::event4f); add("interval", &Loader::interval); add("keyframe", &Loader::keyframe); add("keyframe", &Loader::keyframe_inline); add("looping", &Animation::looping); } +void Animation::Loader::event(const string &n) +{ + obj.add_event(current_time, n); +} + +void Animation::Loader::event1i(const string &n, int v) +{ + obj.add_event(current_time, n, v); +} + +void Animation::Loader::event1f(const string &n, float v) +{ + obj.add_event(current_time, n, v); +} + +void Animation::Loader::event2f(const string &n, float v0, float v1) +{ + obj.add_event(current_time, n, LinAl::Vector(v0, v1)); +} + +void Animation::Loader::event3f(const string &n, float v0, float v1, float v2) +{ + obj.add_event(current_time, n, Vector3(v0, v1, v2)); +} + +void Animation::Loader::event4f(const string &n, float v0, float v1, float v2, float v3) +{ + obj.add_event(current_time, n, Vector4(v0, v1, v2, v3)); +} + void Animation::Loader::keyframe(const string &n) { obj.add_keyframe(current_time, get_collection().get(n)); diff --git a/source/animation.h b/source/animation.h index dd3cc688..c190bdbf 100644 --- a/source/animation.h +++ b/source/animation.h @@ -9,6 +9,7 @@ namespace Msp { namespace GL { +class AnimationEventObserver; class Armature; class Matrix; class Pose; @@ -31,6 +32,12 @@ public: private: void init(); + void event(const std::string &); + void event1i(const std::string &, int); + void event1f(const std::string &, float); + void event2f(const std::string &, float, float); + void event3f(const std::string &, float, float, float); + void event4f(const std::string &, float, float, float, float); void keyframe(const std::string &); void keyframe_inline(); void interval(float); @@ -72,6 +79,13 @@ private: void prepare(const Animation &); }; + struct Event + { + Time::TimeDelta time; + std::string name; + Variant value; + }; + struct UniformInfo { std::string name; @@ -86,6 +100,7 @@ public: private: const Animation *animation; std::vector::const_iterator iter; + std::vector::const_iterator event_iter; Time::TimeDelta time_since_keyframe; bool end; @@ -93,6 +108,7 @@ public: Iterator(const Animation &); Iterator &operator+=(const Time::TimeDelta &); + void dispatch_events(AnimationEventObserver &); bool is_end() const { return end; } Matrix get_matrix() const; @@ -103,6 +119,7 @@ public: private: const Armature *armature; std::vector keyframes; + std::vector events; bool looping; std::vector uniforms; @@ -121,8 +138,9 @@ public: private: void add_keyframe(const Time::TimeDelta &, const RefPtr &); void prepare_keyframe(TimedKeyFrame &); - public: + void add_event(const Time::TimeDelta &, const std::string &, const Variant & = Variant()); + void set_looping(bool); }; diff --git a/source/animationeventobserver.h b/source/animationeventobserver.h new file mode 100644 index 00000000..167b966c --- /dev/null +++ b/source/animationeventobserver.h @@ -0,0 +1,25 @@ +#ifndef MSP_GL_ANIMATIONEVENTOBSERVER_H_ +#define MSP_GL_ANIMATIONEVENTOBSERVER_H_ + +#include +#include + +namespace Msp { +namespace GL { + +class AnimatedObject; + +class AnimationEventObserver +{ +protected: + AnimationEventObserver() { } +public: + virtual ~AnimationEventObserver() { } + + virtual void animation_event(AnimatedObject *, const std::string &, const Variant &) { } +}; + +} // namespace GL +} // namespace Msp + +#endif diff --git a/source/animationplayer.cpp b/source/animationplayer.cpp index cd716798..6b5a481f 100644 --- a/source/animationplayer.cpp +++ b/source/animationplayer.cpp @@ -1,3 +1,4 @@ +#include #include "animatedobject.h" #include "animationplayer.h" #include "armature.h" @@ -44,6 +45,34 @@ unsigned AnimationPlayer::get_n_active_animations(const AnimatedObject &obj) con return (i!=objects.end() ? i->second.animations.size() : 0); } +void AnimationPlayer::observe_events(AnimatedObject &obj, AnimationEventObserver &observer) +{ + Target &target = get_slot(obj); + if(find(target.event_observers, &observer)==target.event_observers.end()) + target.event_observers.push_back(&observer); +} + +void AnimationPlayer::unobserve_events(AnimatedObject &obj, AnimationEventObserver &observer) +{ + ObjectMap::iterator i = objects.find(&obj); + if(i==objects.end()) + return; + + vector::iterator j = find(i->second.event_observers, &observer); + if(j!=i->second.event_observers.end()) + i->second.event_observers.erase(j); +} + +void AnimationPlayer::unobserve_events(AnimationEventObserver &observer) +{ + for(ObjectMap::iterator i=objects.begin(); i!=objects.end(); ++i) + { + vector::iterator j = find(i->second.event_observers, &observer); + if(j!=i->second.event_observers.end()) + i->second.event_observers.erase(j); + } +} + void AnimationPlayer::stop(AnimatedObject &obj) { objects.erase(&obj); @@ -72,10 +101,10 @@ void AnimationPlayer::tick(const Time::TimeDelta &dt) { if(i->second.stacked) tick_stacked(i->second, dt); - else + else if(!i->second.animations.empty()) tick_single(i->second, dt); - if(i->second.animations.empty()) + if(i->second.animations.empty() && i->second.event_observers.empty()) objects.erase(i++); else ++i; @@ -99,6 +128,8 @@ void AnimationPlayer::tick_single(Target &target, const Time::TimeDelta &dt) target.object.set_pose_matrix(i, anim.iterator.get_pose_matrix(i)); } + anim.iterator.dispatch_events(target); + if(!anim.iterator.is_end()) target.animations.clear(); } @@ -134,6 +165,8 @@ void AnimationPlayer::tick_stacked(Target &target, const Time::TimeDelta &dt) for(vector::iterator i=target.animations.begin(); i!=target.animations.end(); ) { + i->iterator.dispatch_events(target); + if(i->iterator.is_end()) i = target.animations.erase(i); else @@ -165,6 +198,12 @@ AnimationPlayer::Target::Target(AnimatedObject &o): stacked(false) { } +void AnimationPlayer::Target::animation_event(AnimatedObject *, const string &name, const Variant &value) +{ + for(vector::const_iterator i=event_observers.begin(); i!=event_observers.end(); ++i) + (*i)->animation_event(&object, name, value); +} + AnimationPlayer::PlayingAnimation::PlayingAnimation(const Animation &a): animation(&a), diff --git a/source/animationplayer.h b/source/animationplayer.h index 5d5f4cb8..4c6e9cec 100644 --- a/source/animationplayer.h +++ b/source/animationplayer.h @@ -3,6 +3,7 @@ #include #include "animation.h" +#include "animationeventobserver.h" #include "matrix.h" namespace Msp { @@ -32,8 +33,11 @@ private: const Armature *armature; std::vector animations; bool stacked; + std::vector event_observers; Target(AnimatedObject &); + + virtual void animation_event(AnimatedObject *, const std::string &, const Variant &); }; typedef std::map ObjectMap; @@ -54,6 +58,17 @@ public: /// Returns the number of animations currently affecting an object. unsigned get_n_active_animations(const AnimatedObject &) const; + /** Request delivery of animation events for the given object. Events will + be delivered from all current and future animations until the observer is + removed. */ + void observe_events(AnimatedObject &, AnimationEventObserver &); + + /// Remove an event observer from one object. + void unobserve_events(AnimatedObject &, AnimationEventObserver &); + + /// Remove an event observer from all objects. + void unobserve_events(AnimationEventObserver &); + /// Stops all animations affecting an object. void stop(AnimatedObject &); -- 2.43.0