]> git.tdb.fi Git - libs/gl.git/commitdiff
Support animation of uniform variables
authorMikko Rasa <tdb@tdb.fi>
Fri, 31 Jul 2015 11:21:46 +0000 (14:21 +0300)
committerMikko Rasa <tdb@tdb.fi>
Fri, 31 Jul 2015 11:21:46 +0000 (14:21 +0300)
source/animatedobject.cpp
source/animatedobject.h
source/animation.cpp
source/animation.h
source/animationplayer.cpp
source/keyframe.cpp
source/keyframe.h

index 8b030978eecda6a6a10af0cb5dab83f121e1334f..269665f6d12ff834a6f2827fba10c444bfb2fad5 100644 (file)
@@ -1,6 +1,7 @@
 #include <algorithm>
 #include <msp/strings/format.h>
 #include "animatedobject.h"
+#include "error.h"
 #include "object.h"
 #include "programdata.h"
 #include "renderer.h"
@@ -41,6 +42,23 @@ void AnimatedObject::set_pose_matrix(unsigned link, const Matrix &m)
        }
 }
 
+void AnimatedObject::set_uniform(const string &name, const KeyFrame::AnimatedUniform &uni)
+{
+       if(!shdata)
+               throw invalid_operation("AnimatedObject::set_uniform");
+
+       if(uni.size==1)
+               shdata->uniform(name, uni.values[0]);
+       else if(uni.size==2)
+               shdata->uniform2(name, uni.values);
+       else if(uni.size==3)
+               shdata->uniform3(name, uni.values);
+       else if(uni.size==4)
+               shdata->uniform4(name, uni.values);
+       else
+               throw invalid_argument("AnimatedObject::set_uniform");
+}
+
 void AnimatedObject::setup_render(Renderer &renderer, const Tag &) const
 {
        renderer.transform(matrix);
index 4782951d10fb9207a77e26a6d32cff367a27c3db..b7f480054275d44148ca714c659af2ad548ce0d2 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <vector>
 #include <msp/datafile/objectloader.h>
+#include "keyframe.h"
 #include "matrix.h"
 #include "objectinstance.h"
 
@@ -39,6 +40,7 @@ public:
 
        void set_matrix(const Matrix &);
        void set_pose_matrix(unsigned, const Matrix &);
+       void set_uniform(const std::string &, const KeyFrame::AnimatedUniform &);
 
        virtual const Matrix *get_matrix() const { return &matrix; }
 
index b1d639e7c957dbffb3ce73f43256be5e0ba52c8a..8f7dea03bd90e8c8513c5e2ac77379699072ed16 100644 (file)
@@ -1,10 +1,10 @@
 #include <cmath>
+#include <msp/core/maputils.h>
 #include <msp/datafile/collection.h>
 #include <msp/time/units.h>
 #include "animation.h"
 #include "armature.h"
 #include "error.h"
-#include "keyframe.h"
 #include "pose.h"
 
 using namespace std;
@@ -26,6 +26,21 @@ void Animation::set_armature(const Armature &a)
        armature = &a;
 }
 
+unsigned Animation::get_slot_for_uniform(const string &n) const
+{
+       for(unsigned i=0; i<uniforms.size(); ++i)
+               if(uniforms[i].name==n)
+                       return i;
+       throw key_error(n);
+}
+
+const string &Animation::get_uniform_name(unsigned i) const
+{
+       if(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)
 {
        if(!keyframes.empty() && t<keyframes.back().time)
@@ -47,8 +62,22 @@ void Animation::set_looping(bool l)
 void Animation::prepare_keyframe(TimedKeyFrame &tkf)
 {
        tkf.prev = (keyframes.empty() ? 0 : &keyframes.back());
-       if(!tkf.prev)
-               return;
+
+       const KeyFrame::UniformMap &kf_uniforms = tkf.keyframe->get_uniforms();
+       for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
+       {
+               bool found = false;
+               for(unsigned j=0; (!found && j<uniforms.size()); ++j)
+                       if(uniforms[j].name==i->first)
+                       {
+                               if(uniforms[j].size!=i->second.size)
+                                       throw invalid_operation("Animation::prepare_keyframe");
+                               found = true;
+                       }
+
+               if(!found)
+                       uniforms.push_back(UniformInfo(i->first, i->second.size));
+       }
 
        tkf.prepare();
 }
@@ -148,8 +177,23 @@ Animation::TimedKeyFrame::TimedKeyFrame(const Animation &a):
 
 void Animation::TimedKeyFrame::prepare()
 {
+       const KeyFrame::UniformMap &kf_uniforms = keyframe->get_uniforms();
+       for(KeyFrame::UniformMap::const_iterator i=kf_uniforms.begin(); i!=kf_uniforms.end(); ++i)
+       {
+               unsigned j = animation.get_slot_for_uniform(i->first);
+               uniforms.reserve(j+1);
+               for(unsigned k=uniforms.size(); k<=j; ++k)
+                       uniforms.push_back(KeyFrame::AnimatedUniform(animation.uniforms[k].size, 0.0f));
+
+               uniforms[j] = i->second;
+       }
+
+       if(!prev)
+               return;
+
        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();
@@ -167,6 +211,12 @@ void Animation::TimedKeyFrame::prepare()
 }
 
 
+Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
+       name(n),
+       size(s)
+{ }
+
+
 Animation::Iterator::Iterator(const Animation &a):
        animation(a),
        iter(animation.keyframes.begin()),
@@ -207,6 +257,24 @@ Matrix Animation::Iterator::get_matrix() const
        return iter->matrix.get(time_since_keyframe/iter->delta_t);
 }
 
+KeyFrame::AnimatedUniform Animation::Iterator::get_uniform(unsigned i) const
+{
+       if(!iter->prev)
+       {
+               if(iter->uniforms.size()>i)
+                       return iter->uniforms[i];
+               else
+                       return KeyFrame::AnimatedUniform(animation.uniforms[i].size, 0.0f);
+       }
+
+       unsigned size = animation.uniforms[i].size;
+       float t = time_since_keyframe/iter->delta_t;
+       KeyFrame::AnimatedUniform result(size, 0.0f);
+       for(unsigned j=0; j<size; ++j)
+               result.values[j] = iter->prev->uniforms[i].values[j]*(1-t)+iter->uniforms[i].values[j]*t;
+       return result;
+}
+
 Matrix Animation::Iterator::get_pose_matrix(unsigned link) const
 {
        if(!animation.armature)
index 63b13f7224269443e9b562572be9447d263d6faf..1ae571e7db217e8e624c6475dc6c4731ebf08a9d 100644 (file)
@@ -4,12 +4,12 @@
 #include <msp/core/refptr.h>
 #include <msp/datafile/objectloader.h>
 #include <msp/time/timedelta.h>
+#include "keyframe.h"
 
 namespace Msp {
 namespace GL {
 
 class Armature;
-class KeyFrame;
 class Matrix;
 class Pose;
 
@@ -66,6 +66,7 @@ private:
                Time::TimeDelta delta_t;
                RefPtr<const KeyFrame> keyframe;
                MatrixInterpolation matrix;
+               std::vector<KeyFrame::AnimatedUniform> uniforms;
                std::vector<MatrixInterpolation> pose_matrices;
 
                TimedKeyFrame(const Animation &);
@@ -74,6 +75,14 @@ private:
 
        typedef std::list<TimedKeyFrame> KeyFrameList;
 
+       struct UniformInfo
+       {
+               std::string name;
+               unsigned size;
+
+               UniformInfo(const std::string &, unsigned);
+       };
+
 public:
        class Iterator
        {
@@ -90,6 +99,7 @@ public:
 
                bool is_end() const { return end; }
                Matrix get_matrix() const;
+               KeyFrame::AnimatedUniform get_uniform(unsigned) const;
                Matrix get_pose_matrix(unsigned) const;
        };
 
@@ -97,6 +107,7 @@ private:
        const Armature *armature;
        KeyFrameList keyframes;
        bool looping;
+       std::vector<UniformInfo> uniforms;
 
 public:
        Animation();
@@ -105,6 +116,10 @@ public:
        void set_armature(const Armature &);
        const Armature *get_armature() const { return armature; }
 
+       unsigned get_n_uniforms() const { return uniforms.size(); }
+       unsigned get_slot_for_uniform(const std::string &) const;
+       const std::string &get_uniform_name(unsigned) const;
+
        void add_keyframe(const Time::TimeDelta &, const KeyFrame &);
 private:
        void prepare_keyframe(TimedKeyFrame &);
index 6148ed006bd0ebdfe0e27b15c0971b2bc7f56ac9..9db88e78bb74ea6a5d01dc75e7cfa9ea1a88030a 100644 (file)
@@ -71,6 +71,11 @@ bool AnimationPlayer::tick_single(ObjectSlot &slot, const Time::TimeDelta &dt)
        AnimationSlot &anim = slot.animations.front();
        anim.iterator += dt;
        obj.set_matrix(anim.iterator.get_matrix());
+
+       unsigned n_uniforms = anim.animation.get_n_uniforms();
+       for(unsigned i=0; i<n_uniforms; ++i)
+               obj.set_uniform(anim.animation.get_uniform_name(i), anim.iterator.get_uniform(i));
+
        if(slot.armature)
        {
                unsigned max_index = slot.armature->get_max_link_index();
index 8e0d79044483f0fac6ba52c64476adb344e5b090..dd4adf16611efb7c2c05312d0428d949de7c6df5 100644 (file)
@@ -26,6 +26,16 @@ void KeyFrame::set_pose(const Pose &p)
 }
 
 
+KeyFrame::AnimatedUniform::AnimatedUniform(unsigned s, float v0, float v1, float v2, float v3):
+       size(s)
+{
+       values[0] = v0;
+       values[1] = v1;
+       values[2] = v2;
+       values[3] = v3;
+}
+
+
 KeyFrame::Loader::Loader(KeyFrame &k):
        DataFile::CollectionObjectLoader<KeyFrame>(k, 0)
 {
@@ -46,6 +56,7 @@ void KeyFrame::Loader::init()
        add("rotation", &Loader::rotation);
        add("scaling", &Loader::scaling_uniform);
        add("scaling", &Loader::scaling);
+       add("uniforms", &Loader::uniforms);
 }
 
 void KeyFrame::Loader::pose(const string &n)
@@ -81,5 +92,41 @@ void KeyFrame::Loader::scaling(float x, float y, float z)
        obj.matrix.scale(x, y, z);
 }
 
+void KeyFrame::Loader::uniforms()
+{
+       UniformsLoader ldr(obj);
+       load_sub_with(ldr);
+}
+
+
+KeyFrame::UniformsLoader::UniformsLoader(KeyFrame &k):
+       DataFile::ObjectLoader<KeyFrame>(k)
+{
+       add("uniform1f", &UniformsLoader::uniform1f);
+       add("uniform2f", &UniformsLoader::uniform2f);
+       add("uniform3f", &UniformsLoader::uniform3f);
+       add("uniform4f", &UniformsLoader::uniform4f);
+}
+
+void KeyFrame::UniformsLoader::uniform1f(const string &n, float v)
+{
+       obj.uniforms.insert(UniformMap::value_type(n, AnimatedUniform(1, v)));
+}
+
+void KeyFrame::UniformsLoader::uniform2f(const string &n, float v0, float v1)
+{
+       obj.uniforms.insert(UniformMap::value_type(n, AnimatedUniform(2, v0, v1)));
+}
+
+void KeyFrame::UniformsLoader::uniform3f(const string &n, float v0, float v1, float v2)
+{
+       obj.uniforms.insert(UniformMap::value_type(n, AnimatedUniform(3, v0, v1, v2)));
+}
+
+void KeyFrame::UniformsLoader::uniform4f(const string &n, float v0, float v1, float v2, float v3)
+{
+       obj.uniforms.insert(UniformMap::value_type(n, AnimatedUniform(4, v0, v1, v2, v3)));
+}
+
 } // namespace GL
 } // namespace Msp
index 6a8c5a447e60ab8c5f0575f47854e9019e145090..7854a928863c86ea7d2a30891d97a3687ac44b22 100644 (file)
@@ -30,10 +30,34 @@ public:
                void rotation(float, float, float, float);
                void scaling_uniform(float);
                void scaling(float, float, float);
+               void uniforms();
        };
 
+       class UniformsLoader: public DataFile::ObjectLoader<KeyFrame>
+       {
+       public:
+               UniformsLoader(KeyFrame &);
+
+       private:
+               void uniform1f(const std::string &, float);
+               void uniform2f(const std::string &, float, float);
+               void uniform3f(const std::string &, float, float, float);
+               void uniform4f(const std::string &, float, float, float, float);
+       };
+
+       struct AnimatedUniform
+       {
+               unsigned size;
+               float values[4];
+
+               AnimatedUniform(unsigned, float, float = 0.0f, float = 0.0f, float = 0.0f);
+       };
+
+       typedef std::map<std::string, AnimatedUniform> UniformMap;
+
 private:
        Matrix matrix;
+       UniformMap uniforms;
        RefPtr<const Pose> pose;
 
 public:
@@ -43,6 +67,7 @@ public:
        void set_matrix(const Matrix &);
        void set_pose(const Pose &);
        const Matrix &get_matrix() const { return matrix; }
+       const UniformMap &get_uniforms() const { return uniforms; }
        const Pose *get_pose() const { return pose.get(); }
 };