From: Mikko Rasa Date: Sun, 12 Aug 2012 09:21:05 +0000 (+0300) Subject: Support for armature-based animation X-Git-Url: http://git.tdb.fi/?p=libs%2Fgl.git;a=commitdiff_plain;h=57fc4142e0b19a21f61c60b00f8310d5d2c27871 Support for armature-based animation --- diff --git a/source/animatedobject.cpp b/source/animatedobject.cpp index df0217ae..0cc36786 100644 --- a/source/animatedobject.cpp +++ b/source/animatedobject.cpp @@ -1,21 +1,42 @@ +#include #include "animatedobject.h" +#include "object.h" +#include "programdata.h" #include "renderer.h" +#include "technique.h" namespace Msp { namespace GL { AnimatedObject::AnimatedObject(const Object &o): - ObjectInstance(o) -{ } + ObjectInstance(o), + shdata(0) +{ + if(const Technique *tech = object.get_technique()) + { + // XXX Should create separate ProgramData for each pass + const RenderPass &pass = tech->get_pass(Tag()); + if(const Program *shprog = pass.get_shader_program()) + shdata = new ProgramData(*shprog); + } +} void AnimatedObject::set_matrix(const Matrix &m) { matrix = m; } +void AnimatedObject::set_pose_matrix(unsigned link, const Matrix &m) +{ + if(shdata) + shdata->uniform_matrix4(format("pose[%d]", link), m); +} + void AnimatedObject::setup_render(Renderer &renderer, const Tag &) const { renderer.matrix_stack() *= matrix; + if(shdata) + renderer.add_shader_data(shdata); } } // namespace GL diff --git a/source/animatedobject.h b/source/animatedobject.h index 4f6085ff..acec4322 100644 --- a/source/animatedobject.h +++ b/source/animatedobject.h @@ -15,11 +15,13 @@ class AnimatedObject: public ObjectInstance { private: Matrix matrix; + ProgramData *shdata; public: AnimatedObject(const Object &); void set_matrix(const Matrix &); + void set_pose_matrix(unsigned, const Matrix &); virtual void setup_render(Renderer &, const Tag &) const; }; diff --git a/source/animation.cpp b/source/animation.cpp index 9f93a8d4..e7174adc 100644 --- a/source/animation.cpp +++ b/source/animation.cpp @@ -2,19 +2,25 @@ #include #include #include "animation.h" +#include "armature.h" #include "keyframe.h" +#include "pose.h" using namespace std; -#include - namespace Msp { namespace GL { Animation::Animation(): + armature(0), looping(false) { } +void Animation::set_armature(const Armature &a) +{ + armature = &a; +} + void Animation::add_keyframe(const Time::TimeDelta &t, const KeyFrame &kf) { if(!keyframes.empty() && ttime; matrix = MatrixInterpolation(prev->keyframe->get_matrix(), keyframe->get_matrix()); + if(animation.armature) + { + unsigned max_index = animation.armature->get_max_link_index(); + pose_matrices.resize(max_index+1); + const Pose *pose1 = prev->keyframe->get_pose(); + const Pose *pose2 = keyframe->get_pose(); + Matrix identity; + for(unsigned i=0; i<=max_index; ++i) + { + const Matrix &matrix1 = (pose1 ? pose1->get_link_matrix(i) : identity); + const Matrix &matrix2 = (pose2 ? pose2->get_link_matrix(i) : identity); + pose_matrices[i] = MatrixInterpolation(matrix1, matrix2); + } + } } @@ -184,6 +204,16 @@ Matrix Animation::Iterator::get_matrix() const return iter->matrix.get(time_since_keyframe/iter->delta_t); } +Matrix Animation::Iterator::get_pose_matrix(unsigned link) const +{ + if(!animation.armature) + throw logic_error("Animation::Iterator::get_pose_matrix"); + if(link>animation.armature->get_max_link_index()) + throw out_of_range("Animation::Iterator::get_pose_matrix"); + + return iter->pose_matrices[link].get(time_since_keyframe/iter->delta_t); +} + Animation::Loader::Loader(Animation &a): DataFile::CollectionObjectLoader(a, 0) @@ -199,6 +229,7 @@ Animation::Loader::Loader(Animation &a, Collection &c): void Animation::Loader::init() { + add("armature", &Animation::armature); add("interval", &Loader::interval); add("keyframe", &Loader::keyframe); add("keyframe", &Loader::keyframe_inline); diff --git a/source/animation.h b/source/animation.h index a4bdabdd..6b890ea3 100644 --- a/source/animation.h +++ b/source/animation.h @@ -8,8 +8,10 @@ namespace Msp { namespace GL { +class Armature; class KeyFrame; class Matrix; +class Pose; /** An Animation is a sequence of KeyFrames combined with timing information. The @@ -64,6 +66,7 @@ private: Time::TimeDelta delta_t; RefPtr keyframe; MatrixInterpolation matrix; + std::vector pose_matrices; TimedKeyFrame(const Animation &); void prepare(); @@ -87,15 +90,20 @@ public: bool is_end() const { return end; } Matrix get_matrix() const; + Matrix get_pose_matrix(unsigned) const; }; private: + const Armature *armature; KeyFrameList keyframes; bool looping; public: Animation(); + void set_armature(const Armature &); + const Armature *get_armature() const { return armature; } + void add_keyframe(const Time::TimeDelta &, const KeyFrame &); private: void prepare_keyframe(TimedKeyFrame &); diff --git a/source/animationplayer.cpp b/source/animationplayer.cpp index 9537960c..a929f3c2 100644 --- a/source/animationplayer.cpp +++ b/source/animationplayer.cpp @@ -1,5 +1,6 @@ #include "animatedobject.h" #include "animationplayer.h" +#include "armature.h" using namespace std; @@ -17,6 +18,12 @@ void AnimationPlayer::tick(const Time::TimeDelta &dt) { i->iterator += dt; i->object.set_matrix(i->iterator.get_matrix()); + if(const Armature *armature = i->animation.get_armature()) + { + unsigned max_index = armature->get_max_link_index(); + for(unsigned j=0; jobject.set_pose_matrix(j, i->iterator.get_pose_matrix(j)); + } if(i->iterator.is_end()) slots.erase(i++); diff --git a/source/keyframe.cpp b/source/keyframe.cpp index 429d893c..e0d35ad8 100644 --- a/source/keyframe.cpp +++ b/source/keyframe.cpp @@ -1,4 +1,8 @@ +#include #include "keyframe.h" +#include "pose.h" + +using namespace std; namespace Msp { namespace GL { @@ -8,15 +12,48 @@ void KeyFrame::set_matrix(const Matrix &m) matrix = m; } +void KeyFrame::set_pose(const Pose &p) +{ + pose = &p; + pose.keep(); +} + + KeyFrame::Loader::Loader(KeyFrame &k): - DataFile::ObjectLoader(k) + DataFile::CollectionObjectLoader(k, 0) { + init(); +} + +KeyFrame::Loader::Loader(KeyFrame &k, Collection &c): + DataFile::CollectionObjectLoader(k, &c) +{ + init(); +} + +void KeyFrame::Loader::init() +{ + add("pose", &Loader::pose); + add("pose", &Loader::pose_inline); add("position", &Loader::position); add("rotation", &Loader::rotation); add("scaling", &Loader::scaling_uniform); add("scaling", &Loader::scaling); } +void KeyFrame::Loader::pose(const string &n) +{ + obj.pose = &get_collection().get(n); + obj.pose.keep(); +} + +void KeyFrame::Loader::pose_inline() +{ + RefPtr p = new Pose; + load_sub(*p, get_collection()); + obj.pose = p; +} + void KeyFrame::Loader::position(float x, float y, float z) { obj.matrix.translate(x, y, z); diff --git a/source/keyframe.h b/source/keyframe.h index bc3d65ec..ccfbda9a 100644 --- a/source/keyframe.h +++ b/source/keyframe.h @@ -1,23 +1,31 @@ #ifndef MSP_GL_KEYFRAME_H_ #define MSP_GL_KEYFRAME_H_ +#include #include #include "matrix.h" namespace Msp { namespace GL { +class Pose; + /** Keyframes are used to encapsulate object state for animation. */ class KeyFrame { public: - class Loader: public DataFile::ObjectLoader + class Loader: public DataFile::CollectionObjectLoader { public: Loader(KeyFrame &); + Loader(KeyFrame &, Collection &); private: + void init(); + + void pose(const std::string &); + void pose_inline(); void position(float, float, float); void rotation(float, float, float, float); void scaling_uniform(float); @@ -26,10 +34,13 @@ public: private: Matrix matrix; + RefPtr pose; public: void set_matrix(const Matrix &); + void set_pose(const Pose &); const Matrix &get_matrix() const { return matrix; } + const Pose *get_pose() const { return pose.get(); } }; } // namespace GL