#include <algorithm>
#include <msp/strings/format.h>
#include "animatedobject.h"
+#include "error.h"
#include "object.h"
#include "programdata.h"
#include "renderer.h"
}
}
+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);
#include <vector>
#include <msp/datafile/objectloader.h>
+#include "keyframe.h"
#include "matrix.h"
#include "objectinstance.h"
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; }
#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;
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)
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();
}
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();
}
+Animation::UniformInfo::UniformInfo(const string &n, unsigned s):
+ name(n),
+ size(s)
+{ }
+
+
Animation::Iterator::Iterator(const Animation &a):
animation(a),
iter(animation.keyframes.begin()),
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)
#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;
Time::TimeDelta delta_t;
RefPtr<const KeyFrame> keyframe;
MatrixInterpolation matrix;
+ std::vector<KeyFrame::AnimatedUniform> uniforms;
std::vector<MatrixInterpolation> pose_matrices;
TimedKeyFrame(const Animation &);
typedef std::list<TimedKeyFrame> KeyFrameList;
+ struct UniformInfo
+ {
+ std::string name;
+ unsigned size;
+
+ UniformInfo(const std::string &, unsigned);
+ };
+
public:
class Iterator
{
bool is_end() const { return end; }
Matrix get_matrix() const;
+ KeyFrame::AnimatedUniform get_uniform(unsigned) const;
Matrix get_pose_matrix(unsigned) const;
};
const Armature *armature;
KeyFrameList keyframes;
bool looping;
+ std::vector<UniformInfo> uniforms;
public:
Animation();
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 &);
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();
}
+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)
{
add("rotation", &Loader::rotation);
add("scaling", &Loader::scaling_uniform);
add("scaling", &Loader::scaling);
+ add("uniforms", &Loader::uniforms);
}
void KeyFrame::Loader::pose(const string &n)
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
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:
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(); }
};