It can be used to sync other actions to certain points of the animation.
#include <msp/datafile/collection.h>
#include <msp/time/units.h>
#include "animation.h"
+#include "animationeventobserver.h"
#include "armature.h"
#include "error.h"
#include "pose.h"
prepare_keyframe(tkf);
}
+void Animation::add_event(const Time::TimeDelta &t, const string &n, const Variant &v)
+{
+ Event event;
+ event.time = t;
+ event.name = n;
+ event.value = v;
+ events.push_back(event);
+}
+
void Animation::set_looping(bool l)
{
looping = l;
Animation::Iterator::Iterator(const Animation &a):
animation(&a),
iter(animation->keyframes.begin()),
+ event_iter(animation->events.begin()),
end(false)
{ }
return *this;
}
+void Animation::Iterator::dispatch_events(AnimationEventObserver &observer)
+{
+ vector<Event>::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)
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<float, 2>(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<KeyFrame>(n));
namespace Msp {
namespace GL {
+class AnimationEventObserver;
class Armature;
class Matrix;
class Pose;
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);
void prepare(const Animation &);
};
+ struct Event
+ {
+ Time::TimeDelta time;
+ std::string name;
+ Variant value;
+ };
+
struct UniformInfo
{
std::string name;
private:
const Animation *animation;
std::vector<TimedKeyFrame>::const_iterator iter;
+ std::vector<Event>::const_iterator event_iter;
Time::TimeDelta time_since_keyframe;
bool end;
Iterator(const Animation &);
Iterator &operator+=(const Time::TimeDelta &);
+ void dispatch_events(AnimationEventObserver &);
bool is_end() const { return end; }
Matrix get_matrix() const;
private:
const Armature *armature;
std::vector<TimedKeyFrame> keyframes;
+ std::vector<Event> events;
bool looping;
std::vector<UniformInfo> uniforms;
private:
void add_keyframe(const Time::TimeDelta &, const RefPtr<const KeyFrame> &);
void prepare_keyframe(TimedKeyFrame &);
-
public:
+ void add_event(const Time::TimeDelta &, const std::string &, const Variant & = Variant());
+
void set_looping(bool);
};
--- /dev/null
+#ifndef MSP_GL_ANIMATIONEVENTOBSERVER_H_
+#define MSP_GL_ANIMATIONEVENTOBSERVER_H_
+
+#include <string>
+#include <msp/core/variant.h>
+
+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
+#include <msp/core/algorithm.h>
#include "animatedobject.h"
#include "animationplayer.h"
#include "armature.h"
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<AnimationEventObserver *>::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<AnimationEventObserver *>::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);
{
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;
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();
}
for(vector<PlayingAnimation>::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
stacked(false)
{ }
+void AnimationPlayer::Target::animation_event(AnimatedObject *, const string &name, const Variant &value)
+{
+ for(vector<AnimationEventObserver *>::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),
#include <msp/time/timedelta.h>
#include "animation.h"
+#include "animationeventobserver.h"
#include "matrix.h"
namespace Msp {
const Armature *armature;
std::vector<PlayingAnimation> animations;
bool stacked;
+ std::vector<AnimationEventObserver *> event_observers;
Target(AnimatedObject &);
+
+ virtual void animation_event(AnimatedObject *, const std::string &, const Variant &);
};
typedef std::map<const AnimatedObject *, Target> ObjectMap;
/// 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 &);