Adding Actor Transform Constraint.
diff --git a/Source/Actor.cpp b/Source/Actor.cpp
index e5e7fab..fde80c7 100644
--- a/Source/Actor.cpp
+++ b/Source/Actor.cpp
@@ -6,6 +6,7 @@
 #include "ActorScaleConstraint.hpp"
 #include "ActorTranslationConstraint.hpp"
 #include "ActorRotationConstraint.hpp"
+#include "ActorTransformConstraint.hpp"
 #include "ActorEvent.hpp"
 #include "ActorNodeSolo.hpp"
 #include "CustomProperty.hpp"
@@ -469,7 +470,9 @@
 			case BlockType::ActorRotationConstraint:
 				component = ActorRotationConstraint::read(this, componentBlock);
 				break;
-
+			case BlockType::ActorTransformConstraint:
+				component = ActorTransformConstraint::read(this, componentBlock);
+				break;
 			default:
 				// Not handled/expected block.
 				break;
diff --git a/Source/ActorIKConstraint.hpp b/Source/ActorIKConstraint.hpp
index 5d08ca0..57bdbd3 100644
--- a/Source/ActorIKConstraint.hpp
+++ b/Source/ActorIKConstraint.hpp
@@ -53,7 +53,7 @@
             void completeResolve() override;
             void constrain(ActorNode* node) override;
 
-			static ActorIKConstraint* read(Actor* actor, BlockReader* reader, ActorIKConstraint* node = NULL);
+			static ActorIKConstraint* read(Actor* actor, BlockReader* reader, ActorIKConstraint* node = nullptr);
     };
 }
 
diff --git a/Source/ActorTransformConstraint.cpp b/Source/ActorTransformConstraint.cpp
new file mode 100644
index 0000000..b7d844a
--- /dev/null
+++ b/Source/ActorTransformConstraint.cpp
@@ -0,0 +1,99 @@
+#include "ActorTransformConstraint.hpp"
+#include "BlockReader.hpp"
+#include "ActorNode.hpp"
+#include <cmath>
+
+using namespace nima;
+
+ActorTransformConstraint::ActorTransformConstraint() : Base(nullptr, ComponentType::ActorTransformConstraint)
+{
+
+}
+			
+ActorComponent* ActorTransformConstraint::makeInstance(Actor* resetActor)
+{
+	ActorTransformConstraint* instanceNode = new ActorTransformConstraint();
+	instanceNode->copy(this, resetActor);
+	return instanceNode;
+}
+
+void ActorTransformConstraint::copy(ActorTransformConstraint* node, Actor* resetActor)
+{
+	Base::copy(node, resetActor);
+
+	m_SourceSpace = node->m_SourceSpace;
+	m_DestSpace = node->m_DestSpace;
+}
+
+void ActorTransformConstraint::constrain(ActorNode* node)
+{
+	// TODO: Should ActorTargetedConstraint just store targets as nodes?
+    ActorNode* target = static_cast<ActorNode*>(m_Target);
+    if(target == nullptr)
+    {
+        return;
+    }
+
+	const Mat2D& transformA = m_Parent->worldTransform();
+	Mat2D transformB(target->worldTransform());
+	if(m_SourceSpace == TransformSpace::Local)
+	{
+		ActorNode* grandParent = target->parent();
+		if(grandParent != nullptr)
+		{
+			Mat2D inverse;
+			if(!Mat2D::invert(inverse, grandParent->worldTransform()))
+			{
+				return;
+			}
+			Mat2D::multiply(transformB, inverse, transformB);
+		}
+	}
+	if(m_DestSpace == TransformSpace::Local)
+	{
+		ActorNode* grandParent = m_Parent->parent();
+		if(grandParent != nullptr)
+		{
+			Mat2D::multiply(transformB, grandParent->worldTransform(), transformB);
+		}
+	}
+	Mat2D::decompose(m_ComponentsA, transformA);
+	Mat2D::decompose(m_ComponentsB, transformB);
+
+	float angleA = std::fmod(m_ComponentsA.rotation(), (float)M_PI_2);
+	float angleB = std::fmod(m_ComponentsB.rotation(),  (float)M_PI_2);
+	float diff = angleB - angleA;
+	if(diff > M_PI)
+	{
+		diff -= M_PI_2;
+	}
+	else if(diff < -M_PI)
+	{
+		diff += M_PI_2;
+	}
+
+	float ti = 1.0f-m_Strength;
+
+	m_ComponentsB.rotation(angleA + diff * m_Strength);
+	m_ComponentsB.x(m_ComponentsA.x() * ti + m_ComponentsB.x() * m_Strength);
+	m_ComponentsB.y(m_ComponentsA.y() * ti + m_ComponentsB.y() * m_Strength);
+	m_ComponentsB.scaleX(m_ComponentsA.scaleX() * ti + m_ComponentsB.scaleX() * m_Strength);
+	m_ComponentsB.scaleY(m_ComponentsA.scaleY() * ti + m_ComponentsB.scaleY() * m_Strength);
+	m_ComponentsB.skew(m_ComponentsA.skew() * ti + m_ComponentsB.skew() * m_Strength);
+
+	Mat2D::compose(m_Parent->mutableWorldTransform(), m_ComponentsB);
+}
+
+ActorTransformConstraint* ActorTransformConstraint::read(Actor* actor, BlockReader* reader, ActorTransformConstraint* constraint)
+{
+	if(constraint == nullptr)
+	{
+		constraint = new ActorTransformConstraint();
+	}
+	ActorTargetedConstraint::read(actor, reader, constraint);
+
+	constraint->m_SourceSpace = (TransformSpace)reader->readByte();
+	constraint->m_DestSpace = (TransformSpace)reader->readByte();
+
+	return constraint;
+}
\ No newline at end of file
diff --git a/Source/ActorTransformConstraint.hpp b/Source/ActorTransformConstraint.hpp
new file mode 100644
index 0000000..2bfbb9e
--- /dev/null
+++ b/Source/ActorTransformConstraint.hpp
@@ -0,0 +1,36 @@
+#ifndef _NIMA_ACTORTRANSFORMCONSTRAINT_HPP_
+#define _NIMA_ACTORTRANSFORMCONSTRAINT_HPP_
+
+#include "ActorTargetedConstraint.hpp"
+#include "nima/Mat2D.hpp"
+#include "nima/TransformComponents.hpp"
+#include "TransformSpace.hpp"
+#include <vector>
+
+namespace nima
+{
+	class Actor;
+
+    class ActorTransformConstraint : public ActorTargetedConstraint
+	{
+		typedef ActorTargetedConstraint Base;
+
+		private:
+            TransformSpace m_SourceSpace;
+            TransformSpace m_DestSpace;
+            TransformComponents m_ComponentsA;
+            TransformComponents m_ComponentsB;
+
+
+        public:
+            ActorTransformConstraint();
+            
+            ActorComponent* makeInstance(Actor* resetActor) override;
+			void copy(ActorTransformConstraint* node, Actor* resetActor);
+            void constrain(ActorNode* node) override;
+
+			static ActorTransformConstraint* read(Actor* actor, BlockReader* reader, ActorTransformConstraint* node = nullptr);
+    };
+}
+
+#endif
\ No newline at end of file