X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=blobdiff_plain;f=source%2Fanimation.cpp;h=37f583d5ec53b43324e67f7fcd1237a25bbefa80;hp=aa3e1b86893b43258ccc6059e62d69ee8c6a0f33;hb=HEAD;hpb=a126d48791f0ee697c11e44efaa17fe9dc6e07cf diff --git a/source/animation.cpp b/source/animation.cpp deleted file mode 100644 index aa3e1b86..00000000 --- a/source/animation.cpp +++ /dev/null @@ -1,542 +0,0 @@ -#include -#include -#include -#include -#include "animation.h" -#include "animationeventobserver.h" -#include "armature.h" -#include "error.h" -#include "pose.h" - -using namespace std; - -namespace Msp { -namespace GL { - -Animation::Animation(): - armature(0), - looping(false) -{ } - -// Avoid synthesizing ~RefPtr in files including animation.h -Animation::~Animation() -{ } - -void Animation::set_armature(const Armature &a) -{ - if(!keyframes.empty() && &a!=armature) - throw invalid_operation("Animation::set_armature"); - armature = &a; -} - -unsigned Animation::get_slot_for_uniform(const string &n) const -{ - for(unsigned i=0; i=uniforms.size()) - throw out_of_range("Animation::get_uniform_name"); - return uniforms[i].name; -} - -void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf) -{ - add_keyframe(t, &kf, false, false); - 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_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; csecond.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"); - if(!keyframes.empty() && tget_pose() && armature && kf->get_pose()->get_armature()!=armature) - throw invalid_argument("Animation::add_keyframe"); - - const KeyFrame::UniformMap &kf_uniforms = kf->get_uniforms(); - for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - { - KeyFrame::UniformMap::const_iterator j = kf_uniforms.find(i->name); - if(j!=kf_uniforms.end() && j->second.size!=i->size) - throw invalid_argument("Animation::add_keyframe"); - } - - if(kf->get_pose() && !armature) - armature = kf->get_pose()->get_armature(); - - TimedKeyFrame tkf; - tkf.time = t; - tkf.keyframe = kf; - if(!owned) - tkf.keyframe.keep(); - tkf.control = c; - - keyframes.push_back(tkf); - - for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i) - { - bool found = false; - for(vector::const_iterator j=uniforms.begin(); (!found && j!=uniforms.end()); ++j) - found = (j->name==i->first); - - if(!found) - uniforms.push_back(UniformInfo(i->first, i->second.size)); - } -} - -void Animation::create_curves() -{ - for(vector::iterator i=curves.begin(); i!=curves.end(); ++i) - delete *i; - curves.clear(); - - curves.reserve(3+uniforms.size()); - create_curve<3>(POSITION, &extract_position); - create_curve<3>(EULER, &extract_euler); - create_curve<3>(SCALE, &extract_scale); - - for(vector::const_iterator i=uniforms.begin(); i!=uniforms.end(); ++i) - { - if(i->size==1) - create_curve<1>(UNIFORM, ExtractUniform<1>(i->name)); - else if(i->size==2) - create_curve<2>(UNIFORM, ExtractUniform<2>(i->name)); - else if(i->size==3) - create_curve<3>(UNIFORM, ExtractUniform<3>(i->name)); - else if(i->size==4) - create_curve<4>(UNIFORM, ExtractUniform<4>(i->name)); - } -} - -template -void Animation::create_curve(CurveTarget target, const T &extract) -{ - typedef typename ValueCurve::Knot Knot; - - vector knots; - unsigned n_control = 0; - for(vector::const_iterator i=keyframes.begin(); i!=keyframes.end(); ++i) - { - if(i->control && knots.empty()) - continue; - - typename Interpolate::SplineValue::Type value; - if(extract(*i->keyframe, 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(target, knots)); -} - -bool Animation::extract_position(const KeyFrame &kf, Vector3 &value) -{ - value = kf.get_transform().get_position(); - return true; -} - -bool Animation::extract_euler(const KeyFrame &kf, Vector3 &value) -{ - const Transform::AngleVector3 &euler = kf.get_transform().get_euler(); - value = Vector3(euler.x.radians(), euler.y.radians(), euler.z.radians()); - return true; -} - -bool Animation::extract_scale(const KeyFrame &kf, Vector3 &value) -{ - value = kf.get_transform().get_scale(); - return true; -} - -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); -} - -const Time::TimeDelta &Animation::get_duration() const -{ - if(keyframes.empty()) - return Time::zero; - - return keyframes.back().time; -} - -void Animation::set_looping(bool l) -{ - looping = l; -} - - -Animation::Curve::Curve(CurveTarget t): - target(t) -{ } - - -template -Animation::ValueCurve::ValueCurve(CurveTarget t, const vector &k): - Curve(t), - spline(Interpolate::BezierSpline(k)) -{ } - -template -void Animation::ValueCurve::apply(float, Matrix &) const -{ - throw invalid_operation("ValueCurve::apply"); -} - -template<> -void Animation::ValueCurve<3>::apply(float x, Matrix &matrix) const -{ - Vector3 value = spline(x); - if(target==POSITION) - matrix.translate(value); - else if(target==EULER) - { - matrix.rotate(value.z, Vector3(0, 0, 1)); - matrix.rotate(value.y, Vector3(0, 1, 0)); - matrix.rotate(value.x, Vector3(1, 0, 0)); - } - else if(target==SCALE) - matrix.scale(value); - else - throw invalid_operation("ValueCurve::apply"); -} - -template -void Animation::ValueCurve::apply(float x, KeyFrame::AnimatedUniform &uni) const -{ - uni.size = N; - typename Interpolate::Spline::Value value = spline(x); - for(unsigned i=0; i::get(value, i); -} - - -template -bool Animation::ExtractUniform::operator()(const KeyFrame &kf, typename Interpolate::SplineValue::Type &value) const -{ - const KeyFrame::UniformMap &kf_uniforms = kf.get_uniforms(); - const KeyFrame::UniformMap::const_iterator i = kf_uniforms.find(name); - if(i==kf_uniforms.end()) - return false; - - value = Interpolate::SplineValue::make(i->second.values); - return true; -} - - -Animation::UniformInfo::UniformInfo(const string &n, unsigned s): - name(n), - size(s) -{ } - - -Animation::Iterator::Iterator(const Animation &a): - animation(&a), - event_iter(animation->events.begin()), - end(false) -{ -} - -Animation::Iterator &Animation::Iterator::operator+=(const Time::TimeDelta &t) -{ - const Time::TimeDelta &duration = animation->get_duration(); - if(!duration) - return *this; - - elapsed += t; - if(animation->looping) - { - while(elapsed>=duration) - elapsed -= duration; - } - else if(elapsed>=duration) - { - end = true; - elapsed = duration; - } - - return *this; -} - -void Animation::Iterator::dispatch_events(AnimationEventObserver &observer) -{ - for(; (event_iter!=animation->events.end() && event_iter->time<=elapsed); ++event_iter) - observer.animation_event(0, event_iter->name, event_iter->value); -} - -Matrix Animation::Iterator::get_matrix() const -{ - Matrix matrix; - for(unsigned i=0; i<3; ++i) - animation->curves[i]->apply(elapsed/Time::sec, matrix); - return matrix; -} - -KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const -{ - if(i>=animation->uniforms.size()) - throw out_of_range("Animation::Iterator::get_uniform"); - - KeyFrame::AnimatedUniform uni(animation->uniforms[i].size, 0.0f); - animation->curves[3+i]->apply(elapsed/Time::sec, uni); - return uni; -} - -Matrix Animation::Iterator::get_pose_matrix(unsigned link) const -{ - if(!animation->armature) - throw invalid_operation("Animation::Iterator::get_pose_matrix"); - if(link>animation->armature->get_max_link_index()) - throw out_of_range("Animation::Iterator::get_pose_matrix"); - - throw logic_error("pose animations are currently unimplemented"); -} - - -Animation::Loader::Loader(Animation &a): - DataFile::CollectionObjectLoader(a, 0) -{ - init(); -} - -Animation::Loader::Loader(Animation &a, Collection &c): - DataFile::CollectionObjectLoader(a, &c) -{ - init(); -} - -void Animation::Loader::init() -{ - start_slope = 1; - end_slope = 1; - slopes_set = 0; - 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); - 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); - add("slopes", &Loader::slopes); -} - -void Animation::Loader::finish() -{ - obj.create_curves(); -} - -void Animation::Loader::check_slopes_and_control(bool s, bool c) -{ - if(s && c) - throw logic_error("can't use both slopes and control keyframes in same segment"); -} - -void Animation::Loader::add_kf(const KeyFrame *kf, bool c, bool owned) -{ - if(slopes_set && !c) - obj.add_keyframe(current_time, kf, start_slope, end_slope, owned); - else - obj.add_keyframe(current_time, kf, c, owned); - - start_slope = end_slope; - end_slope = 1; - slopes_set = (slopes_set<<1)&3; -} - -void Animation::Loader::load_kf(const string &n, bool c) -{ - add_kf(&get_collection().get(n), c, false); -} - -void Animation::Loader::load_kf_inline(bool c) -{ - RefPtr kf = new KeyFrame; - if(coll) - load_sub(*kf, get_collection()); - else - load_sub(*kf); - - add_kf(kf.get(), c, true); - kf.release(); -} - -void Animation::Loader::control_keyframe(const string &n) -{ - slopes_set &= 1; - check_slopes_and_control(slopes_set, true); - load_kf(n, true); -} - -void Animation::Loader::control_keyframe_inline() -{ - slopes_set &= 1; - check_slopes_and_control(slopes_set, true); - load_kf_inline(true); -} - -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::interval(float t) -{ - current_time += t*Time::sec; -} - -void Animation::Loader::keyframe(const string &n) -{ - load_kf(n, false); -} - -void Animation::Loader::keyframe_inline() -{ - load_kf_inline(false); -} - -void Animation::Loader::slopes(float s, float e) -{ - check_slopes_and_control(true, (!obj.keyframes.empty() && obj.keyframes.back().control)); - - start_slope = s; - end_slope = e; - slopes_set = 1; -} - -} // namespace GL -} // namespace Msp