From 9abfb801dbceb59272f6561731d066ed516340e5 Mon Sep 17 00:00:00 2001 From: Mikko Rasa Date: Sun, 12 Aug 2012 11:25:55 +0300 Subject: [PATCH] Add classes for armature-based deformation For now, link rotations in a pose must be specified in hierarchial order, or the matrices will be wrong. --- source/armature.cpp | 90 +++++++++++++++++++++++++++++++++++++++++++++ source/armature.h | 71 +++++++++++++++++++++++++++++++++++ source/pose.cpp | 85 ++++++++++++++++++++++++++++++++++++++++++ source/pose.h | 57 ++++++++++++++++++++++++++++ 4 files changed, 303 insertions(+) create mode 100644 source/armature.cpp create mode 100644 source/armature.h create mode 100644 source/pose.cpp create mode 100644 source/pose.h diff --git a/source/armature.cpp b/source/armature.cpp new file mode 100644 index 00000000..d7a944ed --- /dev/null +++ b/source/armature.cpp @@ -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::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::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::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(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(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 index 00000000..1d01ff0a --- /dev/null +++ b/source/armature.h @@ -0,0 +1,71 @@ +#ifndef ARMATURE_H_ +#define ARMATURE_H_ + +#include +#include +#include +#include "pose.h" +#include "vector.h" + +namespace Msp { +namespace GL { + +class Armature +{ +public: + class Loader: public DataFile::ObjectLoader + { + public: + Loader(Armature &); + private: + void link(const std::string &); + }; + + class Link + { + public: + class Loader: public DataFile::ObjectLoader + { + 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 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 index 00000000..b5c5781b --- /dev/null +++ b/source/pose.cpp @@ -0,0 +1,85 @@ +#include +#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(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(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 index 00000000..5f37c414 --- /dev/null +++ b/source/pose.h @@ -0,0 +1,57 @@ +#ifndef MSP_GL_POSE_H_ +#define MSP_GL_POSE_H_ + +#include +#include +#include "matrix.h" + +namespace Msp { +namespace GL { + +class Armature; + +class Pose +{ +public: + class Loader: public DataFile::CollectionObjectLoader + { + public: + Loader(Pose &, Collection &); + private: + void link(const std::string &); + }; + +private: + struct Link + { + Matrix matrix; + Matrix local_matrix; + }; + + class LinkLoader: public DataFile::ObjectLoader + { + private: + unsigned link_index; + + public: + LinkLoader(Pose &, unsigned); + private: + void rotation(float, float, float, float); + }; + + const Armature *armature; + std::vector 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 -- 2.45.2