]> git.tdb.fi Git - libs/gl.git/commitdiff
Support for armature-based animation
authorMikko Rasa <tdb@tdb.fi>
Sun, 12 Aug 2012 09:21:05 +0000 (12:21 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 12 Aug 2012 09:21:05 +0000 (12:21 +0300)
source/animatedobject.cpp
source/animatedobject.h
source/animation.cpp
source/animation.h
source/animationplayer.cpp
source/keyframe.cpp
source/keyframe.h

index df0217aeb022bb2def2d733450e054cec91a623f..0cc367861e905faa3023aa2d8a79dd266ef4f0cc 100644 (file)
@@ -1,21 +1,42 @@
+#include <msp/strings/format.h>
 #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
index 4f6085ff84ce146974bcfa2e64f84b23fa672c64..acec4322af1d08ee15c755fe1cdea9368c9af41e 100644 (file)
@@ -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;
 };
index 9f93a8d494222424dcc276e9547b29d488f9cd81..e7174adc1bdab351a9799edb9af197d1b840c25f 100644 (file)
@@ -2,19 +2,25 @@
 #include <msp/datafile/collection.h>
 #include <msp/time/units.h>
 #include "animation.h"
+#include "armature.h"
 #include "keyframe.h"
+#include "pose.h"
 
 using namespace std;
 
-#include <msp/io/print.h>
-
 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() && t<keyframes.back().time)
@@ -141,6 +147,20 @@ void Animation::TimedKeyFrame::prepare()
 {
        delta_t = time-prev->time;
        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<Animation>(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);
index a4bdabdd95401757b32c032ca56b646c2e58c92b..6b890ea369811d58ee7ae1aae42046dfef6cf173 100644 (file)
@@ -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<const KeyFrame> keyframe;
                MatrixInterpolation matrix;
+               std::vector<MatrixInterpolation> 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 &);
index 9537960c8d86875f749bf2257d4ea34de8905d9a..a929f3c233e846bcc39eedae496bbd7a860e0988 100644 (file)
@@ -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; j<max_index; ++j)
+                               i->object.set_pose_matrix(j, i->iterator.get_pose_matrix(j));
+               }
 
                if(i->iterator.is_end())
                        slots.erase(i++);
index 429d893c1afa513fd351913d66833cfd7c9ccc3f..e0d35ad80c7546a74f00754657a283a5e4583520 100644 (file)
@@ -1,4 +1,8 @@
+#include <msp/datafile/collection.h>
 #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<KeyFrame>(k)
+       DataFile::CollectionObjectLoader<KeyFrame>(k, 0)
 {
+       init();
+}
+
+KeyFrame::Loader::Loader(KeyFrame &k, Collection &c):
+       DataFile::CollectionObjectLoader<KeyFrame>(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<Pose>(n);
+       obj.pose.keep();
+}
+
+void KeyFrame::Loader::pose_inline()
+{
+       RefPtr<Pose> 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);
index bc3d65ecbfa80fec692d21f326f4e016e2bd5df7..ccfbda9a4f0cdf3dd2107f7e60ed028dd77f0021 100644 (file)
@@ -1,23 +1,31 @@
 #ifndef MSP_GL_KEYFRAME_H_
 #define MSP_GL_KEYFRAME_H_
 
+#include <msp/core/refptr.h>
 #include <msp/datafile/objectloader.h>
 #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<KeyFrame>
+       class Loader: public DataFile::CollectionObjectLoader<KeyFrame>
        {
        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<const Pose> 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