+ add_keyframe(t, &kf, false, false);
+ create_curves();
+}
+
+void Animation::add_keyframe_owned(const Time::TimeDelta &t, const KeyFrame *kf)
+{
+ add_keyframe(t, kf, false, true);
+ create_curves();
+}
+
+void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope)
+{
+ add_keyframe(t, &kf, slope, slope, false);
+ create_curves();
+}
+
+void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es)
+{
+ add_keyframe(t, &kf, ss, es, false);
+ create_curves();
+}
+
+void Animation::add_control_keyframe(const KeyFrame &kf)
+{
+ if(keyframes.empty())
+ throw invalid_operation("Animation::add_control_keyframe");
+
+ add_keyframe(keyframes.back().time, &kf, true, false);
+}
+
+void Animation::add_control_keyframe_owned(const KeyFrame *kf)
+{
+ if(keyframes.empty())
+ throw invalid_operation("Animation::add_control_keyframe_owned");
+
+ add_keyframe(keyframes.back().time, kf, true, true);
+}
+
+void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame *kf, float ss, float es, bool owned)
+{
+ if(keyframes.empty())
+ return add_keyframe(t, kf, false, owned);
+
+ if(keyframes.back().control)
+ throw invalid_operation("Animation::add_keyframe");
+
+ const KeyFrame &last = *keyframes.back().keyframe;
+ const Transform &trn = kf->get_transform();
+ const Transform &last_trn = last.get_transform();
+ const KeyFrame::UniformMap &kf_unis = kf->get_uniforms();
+ const KeyFrame::UniformMap &last_unis = last.get_uniforms();
+ for(unsigned i=1; i<=2; ++i)
+ {
+ float x = (i==1 ? ss/3 : 1-es/3);
+ KeyFrame *ckf = new KeyFrame;
+ Transform ctrn;
+ ctrn.set_position(last_trn.get_position()*(1-x)+trn.get_position()*x);
+ const Transform::AngleVector3 &e1 = last_trn.get_euler();
+ const Transform::AngleVector3 &e2 = trn.get_euler();
+ ctrn.set_euler(Transform::AngleVector3(e1.x*(1-x)+e2.x*x, e1.y*(1-x)+e2.y*x, e1.z*(1-x)+e2.z*x));
+ ctrn.set_scale(last_trn.get_scale()*(1-x)+trn.get_scale()*x);
+ ckf->set_transform(ctrn);
+
+ for(KeyFrame::UniformMap::const_iterator j=kf_unis.begin(); j!=kf_unis.end(); ++j)
+ {
+ KeyFrame::UniformMap::const_iterator k = last_unis.find(j->first);
+ if(k==last_unis.end())
+ continue;
+
+ KeyFrame::AnimatedUniform uni(j->second.size, 0.0f);
+ for(unsigned c=0; c<uni.size; ++c)
+ uni.values[c] = k->second.values[c]*(1-x)+j->second.values[c]*x;
+
+ ckf->set_uniform(j->first, uni);
+ }
+
+ add_keyframe(t, ckf, true, true);
+ }
+
+ add_keyframe(t, kf, false, owned);
+}
+
+void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame *kf, bool c, bool owned)
+{
+ if(c && keyframes.empty())
+ throw invalid_argument("Animation::add_keyframe");
+ if(keyframes.empty() && t!=Time::zero)
+ throw invalid_argument("Animation::add_keyframe");