]> git.tdb.fi Git - libs/gl.git/commitdiff
Add classes for armature-based deformation
authorMikko Rasa <tdb@tdb.fi>
Sun, 12 Aug 2012 08:25:55 +0000 (11:25 +0300)
committerMikko Rasa <tdb@tdb.fi>
Sun, 12 Aug 2012 08:38:59 +0000 (11:38 +0300)
For now, link rotations in a pose must be specified in hierarchial order,
or the matrices will be wrong.

source/armature.cpp [new file with mode: 0644]
source/armature.h [new file with mode: 0644]
source/pose.cpp [new file with mode: 0644]
source/pose.h [new file with mode: 0644]

diff --git a/source/armature.cpp b/source/armature.cpp
new file mode 100644 (file)
index 0000000..d7a944e
--- /dev/null
@@ -0,0 +1,90 @@
+#include "armature.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Armature::Link &Armature::add_link()
+{
+       links.push_back(Link(string(), links.size()));
+       return links.back();
+}
+
+const Armature::Link &Armature::get_link(unsigned index) const
+{
+       for(list<Link>::const_iterator i=links.begin(); i!=links.end(); ++i)
+               if(i->get_index()==index)
+                       return *i;
+       throw invalid_argument("Armature::get_link");
+}
+
+const Armature::Link &Armature::get_link(const string &name) const
+{
+       for(list<Link>::const_iterator i=links.begin(); i!=links.end(); ++i)
+               if(i->get_name()==name)
+                       return *i;
+       throw invalid_argument("Armature::get_link");
+}
+
+unsigned Armature::get_max_link_index() const
+{
+       unsigned max_index = 0;
+       for(list<Link>::const_iterator i=links.begin(); i!=links.end(); ++i)
+               max_index = max(max_index, i->get_index());
+       return max_index;
+}
+
+
+Armature::Link::Link(const string &n, unsigned i):
+       name(n),
+       index(i),
+       parent(0)
+{ }
+
+void Armature::Link::set_parent(const Link *p)
+{
+       parent = p;
+}
+
+void Armature::Link::set_base(const Vector3 &b)
+{
+       base = b;
+}
+
+
+Armature::Loader::Loader(Armature &a):
+       DataFile::ObjectLoader<Armature>(a)
+{
+       add("link", &Loader::link);
+}
+
+void Armature::Loader::link(const string &n)
+{
+       Link lnk(n, obj.links.size());
+       load_sub(lnk, obj);
+       obj.links.push_back(lnk);
+}
+
+
+Armature::Link::Loader::Loader(Link &l, const Armature &a):
+       DataFile::ObjectLoader<Link>(l),
+       armature(a)
+{
+       add("base",   &Loader::base);
+       add("index",  &Link::index);
+       add("parent", &Loader::parent);
+}
+
+void Armature::Link::Loader::base(float x, float y, float z)
+{
+       obj.base = Vector3(x, y, z);
+}
+
+void Armature::Link::Loader::parent(const string &n)
+{
+       obj.parent = &armature.get_link(n);
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/armature.h b/source/armature.h
new file mode 100644 (file)
index 0000000..1d01ff0
--- /dev/null
@@ -0,0 +1,71 @@
+#ifndef ARMATURE_H_
+#define ARMATURE_H_
+
+#include <list>
+#include <string>
+#include <msp/datafile/objectloader.h>
+#include "pose.h"
+#include "vector.h"
+
+namespace Msp {
+namespace GL {
+
+class Armature
+{
+public:
+       class Loader: public DataFile::ObjectLoader<Armature>
+       {
+       public:
+               Loader(Armature &);
+       private:
+               void link(const std::string &);
+       };
+
+       class Link
+       {
+       public:
+               class Loader: public DataFile::ObjectLoader<Link>
+               {
+               private:
+                       const Armature &armature;
+
+               public:
+                       Loader(Link &, const Armature &);
+               private:
+                       void base(float, float, float);
+                       void parent(const std::string &);
+               };
+
+       private:
+               std::string name;
+               unsigned index;
+               const Link *parent;
+               Vector3 base;
+
+       public:
+               Link(const std::string &, unsigned);
+
+               void set_parent(const Link *);
+               void set_base(const Vector3 &);
+
+               const std::string &get_name() const { return name; }
+               unsigned get_index() const { return index; }
+               const Link *get_parent() const { return parent; }
+               const Vector3 &get_base() const { return base; }
+       };
+
+private:
+       std::list<Link> links;
+
+public:
+       Link &add_link();
+
+       const Link &get_link(unsigned) const;
+       const Link &get_link(const std::string &) const;
+       unsigned get_max_link_index() const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif
diff --git a/source/pose.cpp b/source/pose.cpp
new file mode 100644 (file)
index 0000000..b5c5781
--- /dev/null
@@ -0,0 +1,85 @@
+#include <msp/datafile/collection.h>
+#include "armature.h"
+#include "error.h"
+#include "pose.h"
+
+using namespace std;
+
+namespace Msp {
+namespace GL {
+
+Pose::Pose():
+       armature(0)
+{ }
+
+Pose::Pose(const Armature &a):
+       armature(0)
+{
+       set_armature(a);
+}
+
+void Pose::set_armature(const Armature &a)
+{
+       if(armature)
+               throw invalid_operation("Pose::set_armature");
+       armature = &a;
+       links.resize(armature->get_max_link_index()+1);
+}
+
+void Pose::rotate_link(unsigned i, float angle, const Vector3 &axis)
+{
+       if(i>=links.size())
+               throw out_of_range("Pose::rotate_link");
+
+       const Armature::Link &arm_link = armature->get_link(i);
+       links[i].local_matrix.rotate(angle, axis);
+
+       // Keep the base point stationary
+       Vector3 base = arm_link.get_base();
+       Vector3 new_base = links[i].local_matrix*base;
+       links[i].local_matrix.translate(base.x-new_base.x, base.y-new_base.y, base.z-new_base.z);
+
+       if(const Armature::Link *parent = arm_link.get_parent())
+               links[i].matrix = links[parent->get_index()].matrix*links[i].local_matrix;
+
+       // XXX apply matrix to descendants of the link
+}
+
+const Matrix &Pose::get_link_matrix(unsigned i) const
+{
+       if(i>=links.size())
+               throw out_of_range("Pose::get_link_matrix");
+       return links[i].matrix;
+}
+
+
+Pose::Loader::Loader(Pose &p, Collection &c):
+       DataFile::CollectionObjectLoader<Pose>(p, &c)
+{
+       add("armature", &Pose::armature);
+       add("link",     &Loader::link);
+}
+
+void Pose::Loader::link(const string &n)
+{
+       if(!obj.armature)
+               error("Armature must be specified first");
+       LinkLoader ldr(obj, obj.armature->get_link(n).get_index());
+       load_sub_with(ldr);
+}
+
+
+Pose::LinkLoader::LinkLoader(Pose &p, unsigned l):
+       DataFile::ObjectLoader<Pose>(p),
+       link_index(l)
+{
+       add("rotation", &LinkLoader::rotation);
+}
+
+void Pose::LinkLoader::rotation(float a, float x, float y, float z)
+{
+       obj.rotate_link(link_index, a, Vector3(x, y, z));
+}
+
+} // namespace GL
+} // namespace Msp
diff --git a/source/pose.h b/source/pose.h
new file mode 100644 (file)
index 0000000..5f37c41
--- /dev/null
@@ -0,0 +1,57 @@
+#ifndef MSP_GL_POSE_H_
+#define MSP_GL_POSE_H_
+
+#include <map>
+#include <msp/datafile/objectloader.h>
+#include "matrix.h"
+
+namespace Msp {
+namespace GL {
+
+class Armature;
+
+class Pose
+{
+public:
+       class Loader: public DataFile::CollectionObjectLoader<Pose>
+       {
+       public:
+               Loader(Pose &, Collection &);
+       private:
+               void link(const std::string &);
+       };
+
+private:
+       struct Link
+       {
+               Matrix matrix;
+               Matrix local_matrix;
+       };
+
+       class LinkLoader: public DataFile::ObjectLoader<Pose>
+       {
+       private:
+               unsigned link_index;
+
+       public:
+               LinkLoader(Pose &, unsigned);
+       private:
+               void rotation(float, float, float, float);
+       };
+
+       const Armature *armature;
+       std::vector<Link> links;
+
+public:
+       Pose();
+       Pose(const Armature &);
+
+       void set_armature(const Armature &);
+       void rotate_link(unsigned, float, const Vector3 &);
+       const Matrix &get_link_matrix(unsigned) const;
+};
+
+} // namespace GL
+} // namespace Msp
+
+#endif