#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"
}
void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
+{
+ RefPtr<const KeyFrame> kfr(&kf);
+ kfr.keep();
+ add_keyframe(t, kfr);
+}
+
+void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf)
{
if(!keyframes.empty() && t<keyframes.back().time)
throw invalid_argument("Animation::add_keyframe");
- TimedKeyFrame tkf(*this);
+ bool realloc = (keyframes.size()>=keyframes.capacity());
+
+ keyframes.push_back(TimedKeyFrame());
+ TimedKeyFrame &tkf = keyframes.back();
tkf.time = t;
- tkf.keyframe = &kf;
- tkf.keyframe.keep();
- prepare_keyframe(tkf);
- keyframes.push_back(tkf);
-}
+ tkf.keyframe = kf;
-void Animation::set_looping(bool l)
-{
- looping = l;
+ if(realloc)
+ {
+ for(unsigned i=1; i<keyframes.size(); ++i)
+ keyframes[i].prev = &keyframes[i-1];
+ }
+ else if(keyframes.size()>1)
+ tkf.prev = &tkf-1;
+
+ prepare_keyframe(tkf);
}
void Animation::prepare_keyframe(TimedKeyFrame &tkf)
{
- tkf.prev = (keyframes.empty() ? 0 : &keyframes.back());
-
const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
{
uniforms.push_back(UniformInfo(i->first, i->second.size));
}
- tkf.prepare();
+ tkf.prepare(*this);
+}
+
+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::AxisInterpolation::AxisInterpolation(const float *axis1, const float *axis2)
{
// Compute a normalized vector halfway between the two endpoints
- float half[3];
float a1_len = 0;
float h_len = 0;
+ float cos_half = 0;
for(unsigned i=0; i<3; ++i)
{
- half[i] = (axis1[i]+axis2[i])/2;
+ float half_i = (axis1[i]+axis2[i])/2;
+ cos_half += axis1[i]*half_i;
a1_len += axis1[i]*axis1[i];
- h_len += half[i]*half[i];
+ h_len += half_i*half_i;
}
// Compute correction factors for smooth interpolation
- float cos_half = (axis1[0]*half[0]+axis1[1]*half[1]+axis1[2]*half[2])/sqrt(a1_len*h_len);
+ cos_half = min(max(cos_half/sqrt(a1_len*h_len), -1.0f), 1.0f);
float angle = acos(cos_half);
slope = (angle ? angle/tan(angle) : 1);
scale = cos_half;
}
-Animation::TimedKeyFrame::TimedKeyFrame(const Animation &a):
- animation(a),
+Animation::TimedKeyFrame::TimedKeyFrame():
prev(0)
{ }
-void Animation::TimedKeyFrame::prepare()
+void Animation::TimedKeyFrame::prepare(const Animation &animation)
{
const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
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)
return Matrix();
}
- // We must redo the base point correction since interpolation throws if off
+ // We must redo the base point correction since interpolation throws it off
// XXX This should probably be done on local matrices
Matrix result = iter->pose_matrices[link].get(time_since_keyframe/iter->delta_t);
const Vector3 &base = animation->armature->get_link(link).get_base();
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::interval(float t)
+{
+ current_time += t*Time::sec;
+}
+
void Animation::Loader::keyframe(const string &n)
{
obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n));
else
load_sub(*kf);
- TimedKeyFrame tkf(obj);
- tkf.time = current_time;
- tkf.keyframe = kf;
- obj.prepare_keyframe(tkf);
- obj.keyframes.push_back(tkf);
-}
-
-void Animation::Loader::interval(float t)
-{
- current_time += t*Time::sec;
+ obj.add_keyframe(current_time, kf);
}
} // namespace GL