#include <cmath>
#include <msp/core/maputils.h>
#include <msp/datafile/collection.h>
-#include <msp/interpolate/linearspline.h>
+#include <msp/interpolate/bezierspline.h>
#include "animation.h"
#include "animationeventobserver.h"
#include "armature.h"
void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf)
{
- add_keyframe(t, kf, 1.0f, 1.0f);
+ RefPtr<const KeyFrame> kfr(&kf);
+ kfr.keep();
+ add_keyframe(t, kfr, false);
+ create_curves();
}
void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float slope)
add_keyframe(t, kf, slope, slope);
}
-void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float ss, float es)
+void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf, float, float)
+{
+ add_keyframe(t, kf);
+}
+
+void Animation::add_control_keyframe(const KeyFrame &kf)
{
+ if(keyframes.empty())
+ throw invalid_operation("Animation::add_control_keyframe");
+
RefPtr<const KeyFrame> kfr(&kf);
kfr.keep();
- add_keyframe(t, kfr, ss, es);
- create_curves();
+ add_keyframe(keyframes.back().time, kfr, true);
}
-void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf, float ss, float es)
+void Animation::add_keyframe(const Time::TimeDelta &t, const RefPtr<const KeyFrame> &kf, bool c)
{
+ if(c && keyframes.empty())
+ throw invalid_argument("Animation::add_keyframe");
if(keyframes.empty() && t!=Time::zero)
throw invalid_argument("Animation::add_keyframe");
if(!keyframes.empty() && t<keyframes.back().time)
TimedKeyFrame tkf;
tkf.time = t;
- tkf.start_slope = ss;
- tkf.end_slope = es;
tkf.keyframe = kf;
+ tkf.control = c;
keyframes.push_back(tkf);
typedef typename ValueCurve<N>::Knot Knot;
vector<Knot> knots;
+ unsigned n_control = 0;
for(vector<TimedKeyFrame>::const_iterator i=keyframes.begin(); i!=keyframes.end(); ++i)
{
+ if(i->control && knots.empty())
+ continue;
+
typename Interpolate::SplineValue<float, N>::Type value;
if(extract(*i->keyframe, value))
- knots.push_back(Knot(i->time/Time::sec, value));
+ {
+ float x = i->time/Time::sec;
+ if(i->control)
+ {
+ ++n_control;
+ if(n_control>2)
+ throw logic_error("too many control keyframes");
+ }
+ else
+ {
+ if(n_control==1)
+ {
+ typename Knot::Value cv = knots.back().y;
+ knots.back().y = (knots[knots.size()-2].y+cv*2.0f)/3.0f;
+ knots.push_back(Knot(x, (value+cv*2.0f)/3.0f));
+ }
+ else if(n_control==0 && !knots.empty())
+ {
+ typename Knot::Value prev = knots.back().y;
+ knots.push_back(Knot(knots.back().x, (prev*2.0f+value)/3.0f));
+ knots.push_back(Knot(x, (prev+value*2.0f)/3.0f));
+ }
+ n_control = 0;
+ }
+ knots.push_back(Knot(x, value));
+ }
}
+
+ while(n_control--)
+ knots.pop_back();
curves.push_back(new ValueCurve<N>(target, knots));
}
template<unsigned N>
Animation::ValueCurve<N>::ValueCurve(CurveTarget t, const vector<Knot> &k):
Curve(t),
- spline(Interpolate::LinearSpline<float, N>(k))
+ spline(Interpolate::BezierSpline<float, 3, N>(k))
{ }
template<unsigned N>
start_slope = 1;
end_slope = 1;
add("armature", &Animation::armature);
+ add("control_keyframe", &Loader::control_keyframe);
+ add("control_keyframe", &Loader::control_keyframe_inline);
add("event", &Loader::event);
add("event", &Loader::event1i);
add("event", &Loader::event1f);
obj.create_curves();
}
+void Animation::Loader::load_kf(const string &n, bool c)
+{
+ obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), c);
+}
+
+void Animation::Loader::load_kf_inline(bool c)
+{
+ RefPtr<KeyFrame> kf = new KeyFrame;
+ if(coll)
+ load_sub(*kf, get_collection());
+ else
+ load_sub(*kf);
+
+ obj.add_keyframe(current_time, kf, c);
+}
+
+void Animation::Loader::control_keyframe(const string &n)
+{
+ load_kf(n, true);
+}
+
+void Animation::Loader::control_keyframe_inline()
+{
+ load_kf_inline(true);
+}
+
void Animation::Loader::event(const string &n)
{
obj.add_event(current_time, n);
void Animation::Loader::keyframe(const string &n)
{
- obj.add_keyframe(current_time, get_collection().get<KeyFrame>(n), start_slope, end_slope);
- start_slope = end_slope;
- end_slope = 1;
+ load_kf(n, false);
}
void Animation::Loader::keyframe_inline()
{
- RefPtr<KeyFrame> kf = new KeyFrame;
- if(coll)
- load_sub(*kf, get_collection());
- else
- load_sub(*kf);
-
- obj.add_keyframe(current_time, kf, start_slope, end_slope);
- start_slope = end_slope;
- end_slope = 1;
+ load_kf_inline(false);
}
void Animation::Loader::slopes(float s, float e)
void init();
virtual void finish();
+ void load_kf(const std::string &, bool);
+ void load_kf_inline(bool);
+
+ void control_keyframe(const std::string &);
+ void control_keyframe_inline();
void event(const std::string &);
void event1i(const std::string &, int);
void event1f(const std::string &, float);
typedef typename Interpolate::SplineKnot<float, N> Knot;
private:
- Interpolate::Spline<float, 1, N> spline;
+ Interpolate::Spline<float, 3, N> spline;
public:
ValueCurve(CurveTarget, const std::vector<Knot> &);
struct TimedKeyFrame
{
Time::TimeDelta time;
- float start_slope;
- float end_slope;
RefPtr<const KeyFrame> keyframe;
+ bool control;
};
struct Event
void add_keyframe(const Time::TimeDelta &, const KeyFrame &);
void add_keyframe(const Time::TimeDelta &, const KeyFrame &, float);
void add_keyframe(const Time::TimeDelta &, const KeyFrame &, float, float);
+ void add_control_keyframe(const KeyFrame &);
private:
- void add_keyframe(const Time::TimeDelta &, const RefPtr<const KeyFrame> &, float, float);
+ void add_keyframe(const Time::TimeDelta &, const RefPtr<const KeyFrame> &, bool);
void prepare_keyframe(TimedKeyFrame &);
void create_curves();
template<unsigned N, typename T>