Started adding support for new constraints.
diff --git a/Nima-Math-Cpp b/Nima-Math-Cpp
index e0c1277..fafd42e 160000
--- a/Nima-Math-Cpp
+++ b/Nima-Math-Cpp
@@ -1 +1 @@
-Subproject commit e0c12772093fa8860f55358274515b86885f0108
+Subproject commit fafd42ef2b3763f2bf6960cc2dfefa2fa4f71a76
diff --git a/Source/Actor.cpp b/Source/Actor.cpp
index 4c64de9..8456121 100644
--- a/Source/Actor.cpp
+++ b/Source/Actor.cpp
@@ -19,9 +19,10 @@
 using namespace nima;
 
 Actor::Actor() :
-	m_Flags(IsDrawOrderDirty | IsVertexDeformDirty),
+	m_Flags(Flags::IsDrawOrderDirty | Flags::IsVertexDeformDirty),
 	m_ComponentCount(0),
 	m_NodeCount(0),
+	m_DirtDepth(0),
 	m_Components(nullptr),
 	m_Nodes(nullptr),
 	m_Root(nullptr),
@@ -30,13 +31,11 @@
 	m_MaxTextureIndex(-1),
 	m_ImageNodeCount(0),
 	m_RenderNodeCount(0),
-	m_SolverNodeCount(0),
 	m_AnimationsCount(0),
 	m_NestedActorAssetCount(0),
 	m_NestedActorNodeCount(0),
 	m_ImageNodes(nullptr),
 	m_RenderNodes(nullptr),
-	m_Solvers(nullptr),
 	m_Animations(nullptr),
 	m_NestedActorAssets(nullptr),
 	m_NestedActorNodes(nullptr)
@@ -60,9 +59,8 @@
 	delete [] m_Nodes;
 	delete [] m_ImageNodes;
 	delete [] m_NestedActorNodes;
-	delete [] m_Solvers;
 	delete [] m_RenderNodes;
-	if ((m_Flags & IsInstance) == 0x0)
+	if ((m_Flags & Flags::IsInstance) == Flags::IsInstance)
 	{
 		delete [] m_Animations;
 
@@ -79,14 +77,12 @@
 	m_MaxTextureIndex = -1;
 	m_ImageNodeCount = 0;
 	m_RenderNodeCount = 0;
-	m_SolverNodeCount = 0;
 	m_AnimationsCount = 0;
 	m_NestedActorAssetCount = 0;
 	m_Components = nullptr;
 	m_Nodes = nullptr;
 	m_ImageNodes = nullptr;
 	m_RenderNodes = nullptr;
-	m_Solvers = nullptr;
 	m_Animations = nullptr;
 	m_NestedActorAssets = nullptr;
 	m_Root = nullptr;
@@ -134,13 +130,18 @@
 {
 	DependencySorter sorter;
 	sorter.sort(m_Root, m_DependencyOrder);
-	//unsigned int graphOrder = 0;
-	// foreach(ActorComponent component in m_DependencyOrder)
-	// {
-	// 	component.m_GraphOrder = graphOrder++;
-	// 	component.m_DirtMask = 255;
-	// }
-	// m_Flags |= Flags.IsDirty;
+	unsigned int graphOrder = 0;
+	for (unsigned int i = 0; i < m_ComponentCount; i++)
+	{
+		ActorComponent* component = m_Components[i];
+		if(component == nullptr)
+		{
+			continue;
+		}
+		component->m_GraphOrder = graphOrder++;
+		component->m_DirtMask = 255;
+	}
+	m_Flags |= Flags::IsDirty;
 }
 
 bool Actor::addDependency(ActorComponent* a, ActorComponent* b)
@@ -416,7 +417,6 @@
 				break;
 			}
 			case BlockType::ActorIKTarget:
-				m_SolverNodeCount++;
 				component = ActorIKTarget::read(this, componentBlock);
 				break;
 			case BlockType::ActorEvent:
@@ -469,14 +469,12 @@
 	m_Nodes = new ActorNode*[m_NodeCount];
 	m_ImageNodes = new ActorImage*[m_ImageNodeCount];
 	m_RenderNodes = new ActorRenderNode*[m_RenderNodeCount];
-	m_Solvers = new Solver*[m_SolverNodeCount];
 	m_NestedActorNodes = new NestedActorNode*[m_NestedActorNodeCount];
 	m_Nodes[0] = m_Root;
 
 	// Resolve nodes.
 	int imdIdx = 0;
 	int rndIdx = 0;
-	int slvIdx = 0;
 	int ndeIdx = 1;
 	int nanIdx = 0;
 
@@ -500,9 +498,6 @@
 					m_RenderNodes[rndIdx++] = static_cast<ActorImage*>(component);
 					m_ImageNodes[imdIdx++] = static_cast<ActorImage*>(component);
 					break;
-				case ComponentType::ActorIKTarget:
-					m_Solvers[slvIdx++] = static_cast<ActorIKTarget*>(component);
-					break;
 				default:
 					break;
 			}
@@ -514,7 +509,15 @@
 		}
 	}
 
-	// Todo: Add complete resolve.
+	for (unsigned int i = 1; i < m_ComponentCount; i++)
+	{
+		ActorComponent* component = m_Components[i];
+		if (component != nullptr)
+		{
+			component->completeResolve();
+		}
+	}
+
 	sortDependencies();
 }
 
@@ -523,21 +526,15 @@
 	return a->drawOrder() < b->drawOrder();
 }
 
-static bool SolverComparer(Solver* a, Solver* b)
-{
-	return a->order() < b->order();
-}
-
 void Actor::copy(const Actor& actor)
 {
 	m_Flags = actor.m_Flags;
-	m_Flags |= IsInstance;
+	m_Flags |= Flags::IsInstance;
 	m_Animations = actor.m_Animations;
 	m_AnimationsCount = actor.m_AnimationsCount;
 	m_MaxTextureIndex = actor.m_MaxTextureIndex;
 	m_ImageNodeCount = actor.m_ImageNodeCount;
 	m_RenderNodeCount = actor.m_RenderNodeCount;
-	m_SolverNodeCount = actor.m_SolverNodeCount;
 	m_ComponentCount = actor.m_ComponentCount;
 	m_NodeCount = actor.m_NodeCount;
 	m_NestedActorAssetCount = actor.m_NestedActorAssetCount;
@@ -561,10 +558,6 @@
 	{
 		m_ImageNodes = new ActorImage*[m_ImageNodeCount];
 	}
-	if (m_SolverNodeCount != 0)
-	{
-		m_Solvers = new Solver*[m_SolverNodeCount];
-	}
 	if (m_NestedActorNodeCount != 0)
 	{
 		m_NestedActorNodes = new NestedActorNode*[m_NestedActorNodeCount];
@@ -575,7 +568,6 @@
 		int idx = 0;
 		int rndIdx = 0;
 		int imgIdx = 0;
-		int slvIdx = 0;
 		int ndeIdx = 0;
 		int nanIdx = 0;
 
@@ -602,9 +594,6 @@
 					m_RenderNodes[rndIdx++] = static_cast<ActorImage*>(instanceComponent);
 					m_ImageNodes[imgIdx++] = static_cast<ActorImage*>(instanceComponent);
 					break;
-				case ComponentType::ActorIKTarget:
-					m_Solvers[slvIdx++] = static_cast<ActorIKTarget*>(instanceComponent);
-					break;
 				default:
 					break;
 			}
@@ -627,13 +616,17 @@
 			component->resolveComponentIndices(m_Components);
 		}
 
-		if (m_Solvers != nullptr)
+		for (unsigned int i = 1; i < m_ComponentCount; i++)
 		{
-			std::sort(m_Solvers, m_Solvers + m_SolverNodeCount, SolverComparer);
+			ActorComponent* component = m_Components[i];		
+			if (component == nullptr)
+			{
+				continue;
+			}
+			component->completeResolve();
 		}
 	}
 
-	// Todo: add complete resolve.
 	sortDependencies();
 }
 
@@ -654,92 +647,92 @@
 
 void Actor::markDrawOrderDirty()
 {
-	m_Flags |= IsDrawOrderDirty;
+	m_Flags |= Flags::IsDrawOrderDirty;
+}
+
+bool Actor::addDirt(ActorComponent* component, unsigned char value, bool recurse)
+{
+	if((component->m_DirtMask & value) == value)
+	{
+		// Already marked.
+		return false;
+	}
+
+	// Make sure dirt is set before calling anything that can set more dirt.
+	unsigned char dirt = (unsigned char)(component->m_DirtMask | value);
+	component->m_DirtMask = dirt;
+
+	m_Flags |= Flags::IsDirty;
+
+	component->onDirty(dirt);
+
+	// If the order of this component is less than the current dirt depth, update the dirt depth
+	// so that the update loop can break out early and re-run (something up the tree is dirty).
+	if(component->m_GraphOrder < m_DirtDepth)
+	{
+		m_DirtDepth = component->m_GraphOrder;	
+	}
+
+	if(!recurse)
+	{
+		return true;
+	}
+
+	auto dependents = component->dependents();
+	for(auto dependent : dependents)
+	{
+		addDirt(dependent, value, true);
+	}
+	
+	return true;
 }
 
 void Actor::advance(float elapsedSeconds)
 {
-	bool runSolvers = false;
-	for (int i = 0; i < m_SolverNodeCount; i++)
+	if((m_Flags & Flags::IsDirty) == Flags::IsDirty)
 	{
-		Solver* solver = m_Solvers[i];
-		if (solver != nullptr && solver->needsSolve())
+		const int maxSteps = 100;
+		int step = 0;
+		int count = m_DependencyOrder.size();
+		while((m_Flags & Flags::IsDirty) == Flags::IsDirty && step < maxSteps)
 		{
-			runSolvers = true;
-			break;
+			m_Flags &= ~Flags::IsDirty;
+			// Track dirt depth here so that if something else marks dirty, we restart.
+			for(int i = 0; i < count; i++)
+			{
+				ActorComponent* component = m_DependencyOrder[i];
+				m_DirtDepth = (unsigned int)i;
+				unsigned char d = component->m_DirtMask;
+				if(d == 0)
+				{
+					continue;
+				}
+				component->m_DirtMask = 0;
+				component->update(d);
+				if(m_DirtDepth < i)
+				{
+					break;
+				}
+			}
+			step++;
 		}
+
+		// Todo: Don't we want to always reset dirt depth to 0 here?
+		// m_DirtDepth = 0;
 	}
 
-	for (unsigned int i = 0; i < m_NodeCount; i++)
+	if ((m_Flags & Flags::IsDrawOrderDirty) == Flags::IsDrawOrderDirty)
 	{
-		ActorNode* node = m_Nodes[i];
-		if (node != nullptr)
-		{
-			node->updateTransforms();
-		}
-	}
-
-	if (runSolvers)
-	{
-
-		for (unsigned int i = 0; i < m_SolverNodeCount; i++)
-		{
-			Solver* solver = m_Solvers[i];
-			if (solver != nullptr)
-			{
-				solver->solveStart();
-			}
-		}
-
-		for (unsigned int i = 0; i < m_SolverNodeCount; i++)
-		{
-			Solver* solver = m_Solvers[i];
-			if (solver != nullptr)
-			{
-				solver->solve();
-			}
-		}
-
-		for (unsigned int i = 0; i < m_SolverNodeCount; i++)
-		{
-			Solver* solver = m_Solvers[i];
-			if (solver != nullptr)
-			{
-				solver->suppressMarkDirty(true);
-			}
-		}
-
-		for (unsigned int i = 0; i < m_NodeCount; i++)
-		{
-			ActorNode* node = m_Nodes[i];
-			if (node != nullptr)
-			{
-				node->updateTransforms();
-			}
-		}
-
-		for (unsigned int i = 0; i < m_SolverNodeCount; i++)
-		{
-			Solver* solver = m_Solvers[i];
-			if (solver != nullptr)
-			{
-				solver->suppressMarkDirty(false);
-			}
-		}
-	}
-
-	if ((m_Flags & IsDrawOrderDirty) != 0)
-	{
-		m_Flags &= ~IsDrawOrderDirty;
+		m_Flags &= ~Flags::IsDrawOrderDirty;
 
 		if (m_RenderNodes != nullptr)
 		{
 			std::sort(m_RenderNodes, m_RenderNodes + m_RenderNodeCount, DrawOrderComparer);
 		}
 	}
-	if ((m_Flags & IsVertexDeformDirty) != 0)
+	if ((m_Flags & Flags::IsVertexDeformDirty) == Flags::IsVertexDeformDirty)
 	{
-		m_Flags &= ~IsVertexDeformDirty;
+		m_Flags &= ~Flags::IsVertexDeformDirty;
 		for (unsigned int i = 0; i < m_ImageNodeCount; i++)
 		{
 			ActorImage* imageNode = m_ImageNodes[i];
diff --git a/Source/Actor.hpp b/Source/Actor.hpp
index 7521382..78455e4 100644
--- a/Source/Actor.hpp
+++ b/Source/Actor.hpp
@@ -5,7 +5,6 @@
 #include "ActorImage.hpp"
 #include "ActorStaticMesh.hpp"
 #include "BlockReader.hpp"
-#include "Solver.hpp"
 #include "Animation/ActorAnimation.hpp"
 #include "Animation/ActorAnimationInstance.hpp"
 #include "NestedActorAsset.hpp"
@@ -65,17 +64,20 @@
 			Actor();
 			virtual ~Actor();
 
-			enum Flags
+			enum class Flags : unsigned short
 			{
 				IsDrawOrderDirty = 1<<0,
 				IsVertexDeformDirty = 1<<1,
-				IsInstance = 1<<2
+				IsInstance = 1<<2,
+				IsDirty = 1<<3
 			};
+
 		private:
-			unsigned short m_Flags;
+			Flags m_Flags;
 			unsigned int m_ComponentCount;
 			unsigned int m_NodeCount;
 			std::vector<ActorComponent*> m_DependencyOrder;
+			unsigned int m_DirtDepth;
 			ActorComponent** m_Components;
 			ActorNode** m_Nodes;
 			ActorNode* m_Root;
@@ -90,7 +92,6 @@
 			int m_MaxTextureIndex;
 			unsigned int m_ImageNodeCount;
 			unsigned int m_RenderNodeCount;
-			unsigned int m_SolverNodeCount;
 			unsigned int m_AnimationsCount;
 			unsigned int m_NestedActorAssetCount;
 			unsigned int m_NestedActorNodeCount;
@@ -98,7 +99,6 @@
 
 			ActorImage** m_ImageNodes;
 			ActorRenderNode** m_RenderNodes;
-			Solver** m_Solvers;
 			ActorAnimation* m_Animations;
 			NestedActorAsset** m_NestedActorAssets;
 			NestedActorNode** m_NestedActorNodes;
@@ -140,6 +140,7 @@
 			const int textureCount() const;
 			const std::string& baseFilename() const;
 			virtual void advance(float elapsedSeconds);
+			bool addDirt(ActorComponent* component, unsigned char value, bool recurse = true);
 			void markDrawOrderDirty();
 
 			virtual Actor* makeInstance() const;
@@ -150,5 +151,45 @@
 				return dynamic_cast<T*>(makeInstance());
 			}
 	};
+
+	inline constexpr Actor::Flags operator&(Actor::Flags x, Actor::Flags y)
+	{
+		return static_cast<Actor::Flags>(static_cast<unsigned short>(x) & static_cast<unsigned short>(y));
+	}
+
+	inline constexpr Actor::Flags operator|(Actor::Flags x, Actor::Flags y)
+	{
+		return static_cast<Actor::Flags>
+		(static_cast<unsigned short>(x) | static_cast<unsigned short>(y));
+	}
+
+	inline constexpr Actor::Flags operator^(Actor::Flags x, Actor::Flags y)
+	{
+		return static_cast<Actor::Flags>
+		(static_cast<unsigned short>(x) ^ static_cast<unsigned short>(y));
+	}
+
+	inline constexpr Actor::Flags operator~(Actor::Flags x)
+	{
+		return static_cast<Actor::Flags>(~static_cast<unsigned short>(x));
+	}
+
+	inline Actor::Flags & operator&=(Actor::Flags & x, Actor::Flags y)
+	{
+		x = x & y;
+		return x;
+	}
+
+	inline Actor::Flags & operator|=(Actor::Flags & x, Actor::Flags y)
+	{
+		x = x | y;
+		return x;
+	}
+
+	inline Actor::Flags & operator^=(Actor::Flags & x, Actor::Flags y)
+	{
+		x = x ^ y;
+		return x;
+	}
 }
 #endif
\ No newline at end of file
diff --git a/Source/ActorBone.hpp b/Source/ActorBone.hpp
index 97b360e..80cc27f 100644
--- a/Source/ActorBone.hpp
+++ b/Source/ActorBone.hpp
@@ -2,9 +2,9 @@
 #define _NIMA_ACTORBONE_HPP_
 
 #include "ActorNode.hpp"
-
 #include <nima/Vec2D.hpp>
 
+
 namespace nima
 {
 	class Actor;
diff --git a/Source/ActorComponent.cpp b/Source/ActorComponent.cpp
index a4bc548..9e1cf05 100644
--- a/Source/ActorComponent.cpp
+++ b/Source/ActorComponent.cpp
@@ -16,6 +16,8 @@
 			m_Type(type),
 			m_Parent(nullptr),
 			m_Actor(actor),
+			m_GraphOrder(0),
+			m_DirtMask(0),
 			m_ParentIdx(0),
 			m_Idx(0)
 {
@@ -74,6 +76,11 @@
 	}
 }
 
+void ActorComponent::completeResolve()
+{
+
+}
+
 void ActorComponent::copy(ActorComponent* component, Actor* resetActor)
 {
 	m_Name = component->m_Name;
diff --git a/Source/ActorComponent.hpp b/Source/ActorComponent.hpp
index edced6a..3a05512 100644
--- a/Source/ActorComponent.hpp
+++ b/Source/ActorComponent.hpp
@@ -35,7 +35,15 @@
 		ColliderLine = 21, // TODO
 		ActorNodeSolo = 23,
 		NestedActorNode = 24,
-		ActorStaticMesh = 27
+		ActorStaticMesh = 27,
+		JellyComponent = 28,
+		ActorJellyBone = 29,
+		ActorIKConstraint = 30,
+		ActorDistanceConstraint = 31,
+		ActorTranslationConstraint = 32,
+		ActorRotationConstraint = 33,
+		ActorScaleConstraint = 34,
+		ActorTransformConstraint = 35
 	};
 
 
@@ -52,6 +60,11 @@
 			std::vector<CustomBooleanProperty*> m_CustomBooleanProperties;
 			std::vector<ActorComponent*> m_Dependents;
 
+		public:
+			// Used by the DAG in Actor.
+			unsigned int m_GraphOrder;
+			unsigned char m_DirtMask;
+
 		private:
 			unsigned short m_ParentIdx;
 			unsigned short m_Idx;
@@ -70,6 +83,7 @@
 			unsigned short parentIdx() const;
 			unsigned short idx() const;
 			virtual void resolveComponentIndices(ActorComponent** components);
+			virtual void completeResolve();
 			virtual ActorComponent* makeInstance(Actor* resetActor) = 0;
 			void copy(ActorComponent* node, Actor* resetActor);
 			virtual bool isNode() { return false; }
@@ -86,6 +100,9 @@
 			CustomStringProperty* getCustomStringProperty(const std::string& name);
 			CustomBooleanProperty* getCustomBooleanProperty(const std::string& name);
 			std::vector<ActorComponent*>& dependents() { return m_Dependents; }
+
+			virtual void onDirty(unsigned char dirt){}
+			virtual void update(unsigned char dirt){}
 	};
 }
 #endif
\ No newline at end of file
diff --git a/Source/ActorConstraint.cpp b/Source/ActorConstraint.cpp
new file mode 100644
index 0000000..02881d3
--- /dev/null
+++ b/Source/ActorConstraint.cpp
@@ -0,0 +1,41 @@
+#include "ActorConstraint.hpp"
+#include "Actor.hpp"
+using namespace nima;
+
+ActorConstraint::ActorConstraint(Actor* actor, ComponentType type) :
+    ActorComponent(actor, type),
+    m_IsEnabled(false),
+    m_Strength(1.0f)
+{
+
+}
+
+bool ActorConstraint::isEnabled() const
+{
+    return m_IsEnabled;
+}
+
+float ActorConstraint::strength() const
+{
+    return m_Strength;
+}
+
+void ActorConstraint::strength(float value)
+{
+    if(m_Strength == value)
+    {
+        return;
+    }
+    m_Strength = value;
+    m_Parent->markTransformDirty();
+}
+
+void ActorConstraint::resolveComponentIndices(ActorComponent** components)
+{
+    Base::resolveComponentIndices(components);
+    if(m_Parent != nullptr)
+    {
+        // This works because nodes are exported in hierarchy order, so we are assured constraints get added in order as we resolve indices.
+        m_Parent->addConstraint(this);
+    }
+}
\ No newline at end of file
diff --git a/Source/ActorConstraint.hpp b/Source/ActorConstraint.hpp
new file mode 100644
index 0000000..62a6527
--- /dev/null
+++ b/Source/ActorConstraint.hpp
@@ -0,0 +1,30 @@
+#ifndef _NIMA_ACTORCONSTRAINT_HPP_
+#define _NIMA_ACTORCONSTRAINT_HPP_
+
+#include "ActorComponent.hpp"
+
+namespace nima
+{
+    class ActorConstraint : public ActorComponent
+	{
+		typedef ActorComponent Base;
+        protected:
+            bool m_IsEnabled;
+            float m_Strength;
+
+        protected:
+            ActorConstraint(Actor* actor, ComponentType type);
+
+        public:
+            bool isEnabled() const;
+            float strength() const;
+            void strength(float value);
+
+            virtual void constrain(ActorNode* node) = 0;
+            void resolveComponentIndices(ActorComponent** components) override;
+            void copy(ActorConstraint* constraint, Actor* resetActor);
+            static ActorConstraint* read(Actor* actor, BlockReader* reader, ActorConstraint* constraint = nullptr);
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/Source/ActorIKConstraint.cpp b/Source/ActorIKConstraint.cpp
new file mode 100644
index 0000000..9102379
--- /dev/null
+++ b/Source/ActorIKConstraint.cpp
@@ -0,0 +1,169 @@
+#include "ActorIKConstraint.hpp"
+#include "Actor.hpp"
+
+using namespace nima;
+
+ActorIKConstraint::ActorIKConstraint() : Base(nullptr, ComponentType::ActorIKConstraint)
+{
+
+}
+
+ActorIKConstraint::ActorIKConstraint(ActorIKConstraint* target) : Base(nullptr, ComponentType::ActorIKConstraint)
+{
+
+}
+
+ActorComponent* ActorIKConstraint::makeInstance(Actor* resetActor)
+{
+	ActorIKConstraint* instanceNode = new ActorIKConstraint();
+	instanceNode->copy(this, resetActor);
+	return instanceNode;
+}
+
+void ActorIKConstraint::copy(ActorIKConstraint* constraint, Actor* resetActor)
+{
+    Base::copy(constraint, resetActor);
+
+    m_InvertDirection = constraint->m_InvertDirection;
+    m_InfluencedBones.resize(constraint->m_InfluencedBones.size());
+    for(int i = 0, length = m_InfluencedBones.size(); i < length; i++)
+    {
+        InfluencedBone& ib = m_InfluencedBones[i];
+        ib.boneIndex = constraint->m_InfluencedBones[i].boneIndex;
+    }
+}
+
+void ActorIKConstraint::resolveComponentIndices(ActorComponent** components)
+{
+    Base::resolveComponentIndices(components);
+    if(m_Parent != nullptr)
+    {
+        // This works because nodes are exported in hierarchy order, so we are assured constraints get added in order as we resolve indices.
+        m_Parent->addConstraint(this);
+    }
+
+    for(InfluencedBone& influenced : m_InfluencedBones)
+    {
+        influenced.bone = static_cast<ActorBone*>(components[influenced.boneIndex]);
+    }
+}
+
+void ActorIKConstraint::completeResolve()
+{
+    Base::completeResolve();
+    if(m_InfluencedBones.size() == 0)
+    {
+        return;
+    }
+
+    // Initialize solver.
+    ActorBone* start = m_InfluencedBones[0].bone;
+    ActorBone* end = m_InfluencedBones[m_InfluencedBones.size()-1].bone;
+    int count = 0;
+    while(end != nullptr && end != start->parent())
+    {
+        count++;
+        end = dynamic_cast<ActorBone*>(end->parent());
+    }
+
+    bool allIn = count < 3;
+    end = m_InfluencedBones[m_InfluencedBones.size()-1].bone;
+    m_FKChain.resize(count);
+    // Make sure bone data is cleared as it holds pointers to entries in the fk chain.
+    m_BoneData.clear();
+
+    int idx = count-1;
+    while(end != nullptr && end != start->parent())
+    {
+        BoneChain& bc = m_FKChain[idx--];
+        bc.bone = end;
+        bc.angle = 0.0f;
+        bc.included = allIn;
+        bc.index = idx+1;
+        end = dynamic_cast<ActorBone*>(end->parent());
+    }
+
+    // Make sure bones are good.
+    for(InfluencedBone& influenced : m_InfluencedBones)
+    {
+        auto result = std::find_if(m_FKChain.begin(), m_FKChain.end(),
+            [influenced](const BoneChain& chainItem) -> bool 
+            { 
+                return chainItem.bone == influenced.bone; 
+            });
+        if(result == m_FKChain.end())
+        {
+            printf("Bone not in chain %s\n", influenced.bone->name().c_str());
+            continue;
+        }
+        // Note this indirection here, bone data and fk chain are linked and must be treated accordingly.
+        m_BoneData.push_back(&(*result));
+    }
+    
+    if(!allIn)
+    {
+        // Influenced bones in bone data are in the IK chain.
+        for(BoneChain* bone : m_BoneData)
+        {
+            bone->included = true;
+        }
+    }
+    
+    // Finally mark dependencies.
+    for(InfluencedBone& influenced : m_InfluencedBones)
+    {
+        // Don't mark dependency on parent as ActorComponent already does this.
+        if(influenced.bone == m_Parent)
+        {
+            continue;
+        }
+
+        m_Actor->addDependency(this, influenced.bone);
+    }
+
+    if(m_Target != nullptr)
+    {
+        m_Actor->addDependency(this, m_Target);
+    }
+
+    // All the first level children of the influenced bones should depend on the final bone.
+    BoneChain& tip = *(m_FKChain.rbegin());
+    //BoneChain tip = m_FKChain[m_FKChain.Length-1];
+    for(BoneChain& fk : m_FKChain)
+    {
+        if(&fk == &tip)
+        {
+            continue;
+        }
+
+        ActorBone* bone = fk.bone;
+        for(ActorNode* boneChild : bone->children())
+        {
+            auto result = std::find_if(m_FKChain.begin(), m_FKChain.end(),
+                [boneChild](const BoneChain& chainItem) -> bool 
+                { 
+                    return chainItem.bone == boneChild; 
+                });
+            
+            if(result != m_FKChain.end())
+            {
+                // node is in the FK chain and is already dependent.
+                continue;
+            }
+            
+            m_Actor->addDependency(boneChild, tip.bone);
+        }
+    }
+}
+
+ActorIKConstraint* ActorIKConstraint::read(Actor* actor, BlockReader* reader, ActorIKConstraint* node)
+{
+    Base::read(actor, reader, node);
+
+    return node;
+}
+
+void ActorIKConstraint::constrain(ActorNode* node)
+{
+
+}
\ No newline at end of file
diff --git a/Source/ActorIKConstraint.hpp b/Source/ActorIKConstraint.hpp
new file mode 100644
index 0000000..efbc6b3
--- /dev/null
+++ b/Source/ActorIKConstraint.hpp
@@ -0,0 +1,57 @@
+#ifndef _NIMA_ACTORIKCONSTRAINT_HPP_
+#define _NIMA_ACTORIKCONSTRAINT_HPP_
+
+#include "ActorTargetedConstraint.hpp"
+#include "ActorBone.hpp"
+#include "nima/Mat2D.hpp"
+#include "nima/TransformComponents.hpp"
+#include <vector>
+
+namespace nima
+{
+	class Actor;
+    class ActorIKConstraint;
+
+    class ActorIKConstraint : public ActorTargetedConstraint
+	{
+			typedef ActorTargetedConstraint Base;
+		public:
+			struct InfluencedBone
+			{
+				unsigned short boneIndex;
+				ActorBone* bone;
+
+				InfluencedBone();
+			};
+
+            struct BoneChain
+            {
+                int index;
+                ActorBone* bone;
+                float angle;
+                bool included;
+                TransformComponents transformComponents;
+                Mat2D parentWorldInverse;
+            };
+
+		private:
+			std::vector<InfluencedBone> m_InfluencedBones;
+            std::vector<BoneChain> m_FKChain;
+            std::vector<BoneChain*> m_BoneData;
+			bool m_InvertDirection;
+
+        public:
+            ActorIKConstraint();
+            ActorIKConstraint(ActorIKConstraint* target); // Support old system.
+            
+            ActorComponent* makeInstance(Actor* resetActor) override;
+			void copy(ActorIKConstraint* node, Actor* resetActor);
+			void resolveComponentIndices(ActorComponent** nodes) override;
+            void completeResolve() override;
+            void constrain(ActorNode* node) override;
+
+			static ActorIKConstraint* read(Actor* actor, BlockReader* reader, ActorIKConstraint* node = NULL);
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/Source/ActorIKTarget.cpp b/Source/ActorIKTarget.cpp
index 1c9e8bb..dfa27f4 100644
--- a/Source/ActorIKTarget.cpp
+++ b/Source/ActorIKTarget.cpp
@@ -85,284 +85,240 @@
 void ActorIKTarget::resolveComponentIndices(ActorComponent** components)
 {
 	Base::resolveComponentIndices(components);
-	if (m_InfluencedBones != nullptr)
-	{
-		for (int i = 0; i < m_NumInfluencedBones; i++)
-		{
-			InfluencedBone& ib = m_InfluencedBones[i];
-			ib.bone = static_cast<ActorBone*>(components[ib.boneIndex]);
-			ib.bone->addDependent(this);
-		}
+	// if (m_InfluencedBones != nullptr)
+	// {
+	// 	for (int i = 0; i < m_NumInfluencedBones; i++)
+	// 	{
+	// 		InfluencedBone& ib = m_InfluencedBones[i];
+	// 		ib.bone = static_cast<ActorBone*>(components[ib.boneIndex]);
+	// 		ib.bone->addDependent(this);
+	// 	}
 
-		m_Bone1 = m_InfluencedBones[0].bone;
-		m_Bone2 = m_InfluencedBones[m_NumInfluencedBones - 1].bone;
-		ActorBone* b1c = m_Bone2;
-		ActorBone* b1 = m_Bone1;
+	// 	m_Bone1 = m_InfluencedBones[0].bone;
+	// 	m_Bone2 = m_InfluencedBones[m_NumInfluencedBones - 1].bone;
+	// 	ActorBone* b1c = m_Bone2;
+	// 	ActorBone* b1 = m_Bone1;
 
-		if(m_NumInfluencedBones > 1)
-		{
-			while (b1c != nullptr && b1c->parent() != b1)
-			{
-				ActorNode* n = b1c->parent();
-				if (n != nullptr && n->type() == ComponentType::ActorBone)
-				{
-					b1c = dynamic_cast<ActorBone*>(n);
-				}
-				else
-				{
-					break;
-				}
-			}
-		}
-		m_Bone1Child = b1c;
+	// 	if(m_NumInfluencedBones > 1)
+	// 	{
+	// 		while (b1c != nullptr && b1c->parent() != b1)
+	// 		{
+	// 			ActorNode* n = b1c->parent();
+	// 			if (n != nullptr && n->type() == ComponentType::ActorBone)
+	// 			{
+	// 				b1c = dynamic_cast<ActorBone*>(n);
+	// 			}
+	// 			else
+	// 			{
+	// 				break;
+	// 			}
+	// 		}
+	// 	}
+	// 	m_Bone1Child = b1c;
 
-		m_ChainLength = 0;
-		ActorNode* end = m_Bone2;
-		while (end != nullptr && end != b1->parent())
-		{
-			m_ChainLength++;
+	// 	m_ChainLength = 0;
+	// 	ActorNode* end = m_Bone2;
+	// 	while (end != nullptr && end != b1->parent())
+	// 	{
+	// 		m_ChainLength++;
 
-			ActorNode* n = end->parent();
-			if (n != nullptr && n->type() == ComponentType::ActorBone)
-			{
-				end = n;
-			}
-			else
-			{
-				end = nullptr;
-			}
-		}
+	// 		ActorNode* n = end->parent();
+	// 		if (n != nullptr && n->type() == ComponentType::ActorBone)
+	// 		{
+	// 			end = n;
+	// 		}
+	// 		else
+	// 		{
+	// 			end = nullptr;
+	// 		}
+	// 	}
 
-		m_Chain = new BoneChain[m_ChainLength];
-		end = m_Bone2;
-		int chainIndex = 0;
-		while (end != nullptr && end != b1->parent())
-		{
-			BoneChain& bc = m_Chain[chainIndex++];
-			bc.bone = reinterpret_cast<ActorBone*>(end);
-			bc.angle = 0.0f;
-			ActorNode* n = end->parent();
-			if (n != nullptr && n->type() == ComponentType::ActorBone)
-			{
-				end = n;
-			}
-			else
-			{
-				end = nullptr;
-			}
+	// 	m_Chain = new BoneChain[m_ChainLength];
+	// 	end = m_Bone2;
+	// 	int chainIndex = 0;
+	// 	while (end != nullptr && end != b1->parent())
+	// 	{
+	// 		BoneChain& bc = m_Chain[chainIndex++];
+	// 		bc.bone = reinterpret_cast<ActorBone*>(end);
+	// 		bc.angle = 0.0f;
+	// 		ActorNode* n = end->parent();
+	// 		if (n != nullptr && n->type() == ComponentType::ActorBone)
+	// 		{
+	// 			end = n;
+	// 		}
+	// 		else
+	// 		{
+	// 			end = nullptr;
+	// 		}
 
-			bc.included = doesInfluence(bc.bone) || doesInfluence(reinterpret_cast<ActorBone*>(end)); // end is either null or an actorbone (for sure) here.
+	// 		bc.included = doesInfluence(bc.bone) || doesInfluence(reinterpret_cast<ActorBone*>(end)); // end is either null or an actorbone (for sure) here.
 			
-		}
-	}
+	// 	}
+	//}
 }
 
-bool ActorIKTarget::doesInfluence(ActorBone* bone)
-{
-	if (bone == nullptr)
-	{
-		return false;
-	}
-	for (int i = 0; i < m_NumInfluencedBones; i++)
-	{
-		if (m_InfluencedBones[i].bone == bone)
-		{
-			return true;
-		}
-	}
-	return false;
-}
-
-int ActorIKTarget::order()
-{
-	return m_Order;
-}
-
-bool ActorIKTarget::needsSolve()
-{
-	return isWorldDirty() || isDirty();
-}
+// bool ActorIKTarget::doesInfluence(ActorBone* bone)
+// {
+// 	if (bone == nullptr)
+// 	{
+// 		return false;
+// 	}
+// 	for (int i = 0; i < m_NumInfluencedBones; i++)
+// 	{
+// 		if (m_InfluencedBones[i].bone == bone)
+// 		{
+// 			return true;
+// 		}
+// 	}
+// 	return false;
+// }
 
 float ActorIKTarget::strength() const
 {
-	return m_Strength;
+	// TODO
+	return 0.0f;
 }
 
 void ActorIKTarget::strength(float s)
 {
-	if (m_Strength != s)
-	{
-		m_Strength = s;
-		markDirty();
-	}
+	// TODO
 }
 
-bool ActorIKTarget::suppressMarkDirty()
-{
-	return Base::suppressMarkDirty();
-}
+// void ActorIKTarget::solve1(ActorBone* b1, Vec2D& worldTargetTranslation)
+// {
+// 	Mat2D iworld;
+// 	Mat2D::invert(iworld, b1->worldTransform());
 
-void ActorIKTarget::suppressMarkDirty(bool suppressIt)
-{
-	Base::suppressMarkDirty(suppressIt);
-}
+// 	Vec2D targetLocal;
+// 	Vec2D::transform(targetLocal, worldTargetTranslation, iworld);
 
-void ActorIKTarget::solveStart()
-{
-	if (m_Bone1 == nullptr)
-	{
-		return;
-	}
+// 	float a = atan2(targetLocal[1], targetLocal[0]);
 
-	// Reset all rotation overrides to FK ones,
-	if (m_Bone1Child != m_Bone2)
-	{
-		m_Bone1Child->setRotationOverride(m_Bone1Child->rotation());
-	}
+// 	b1->setRotationOverride(b1->overrideRotationValue() + a);
+// }
 
-	for (int i = 0; i < m_NumInfluencedBones; i++)
-	{
-		InfluencedBone& ib = m_InfluencedBones[i];
-		ib.bone->setRotationOverride(ib.bone->rotation());
-	}
-}
+// void ActorIKTarget::solve2(ActorBone* b1, ActorBone* b2, Vec2D& worldTargetTranslation, bool invert)
+// {
+// 	const Mat2D& world = b1->parent()->worldTransform();
+// 	Mat2D iworld;
+// 	ActorBone* b1c = b2;
+// 	while (b1c != nullptr && b1c->parent() != b1)
+// 	{
+// 		ActorNode* n = b1c->parent();
+// 		if (n != nullptr && n->type() == ComponentType::ActorBone)
+// 		{
+// 			b1c = reinterpret_cast<ActorBone*>(n);
+// 		}
+// 		else
+// 		{
+// 			b1c = nullptr;
+// 		}
+// 	}
 
+// 	ActorNode* b1pn = b1->parent();
+// 	// Get the world transform to the bone tip position.
+// 	if (b1pn->type() == ComponentType::ActorBone)
+// 	{
+// 		Mat2D t;
+// 		t[4] = reinterpret_cast<ActorBone*>(b1pn)->length();
+// 		Mat2D::multiply(t, world, t);
+// 		Mat2D::invert(iworld, t);
+// 	}
+// 	else
+// 	{
+// 		Mat2D::invert(iworld, world);
+// 	}
 
-void ActorIKTarget::solve1(ActorBone* b1, Vec2D& worldTargetTranslation)
-{
-	Mat2D iworld;
-	Mat2D::invert(iworld, b1->worldTransform());
+// 	Vec2D pA; b1->worldTranslation(pA);
+// 	Vec2D pC; b1->tipWorldTranslation(pC);
+// 	Vec2D pB; b2->tipWorldTranslation(pB);
+// 	Vec2D pBT(worldTargetTranslation);
 
-	Vec2D targetLocal;
-	Vec2D::transform(targetLocal, worldTargetTranslation, iworld);
+// 	Vec2D::transform(pA, pA, iworld);
+// 	Vec2D::transform(pC, pC, iworld);
+// 	Vec2D::transform(pB, pB, iworld);
+// 	Vec2D::transform(pBT, pBT, iworld);
 
-	float a = atan2(targetLocal[1], targetLocal[0]);
+// 	// http://mathworld.wolfram.com/LawofCosines.html
+// 	Vec2D av; Vec2D::subtract(av, pB, pC);
+// 	float a = Vec2D::length(av);
 
-	b1->setRotationOverride(b1->overrideRotationValue() + a);
-}
+// 	Vec2D bv; Vec2D::subtract(bv, pC, pA);
+// 	float b = Vec2D::length(bv);
 
-void ActorIKTarget::solve2(ActorBone* b1, ActorBone* b2, Vec2D& worldTargetTranslation, bool invert)
-{
-	const Mat2D& world = b1->parent()->worldTransform();
-	Mat2D iworld;
-	ActorBone* b1c = b2;
-	while (b1c != nullptr && b1c->parent() != b1)
-	{
-		ActorNode* n = b1c->parent();
-		if (n != nullptr && n->type() == ComponentType::ActorBone)
-		{
-			b1c = reinterpret_cast<ActorBone*>(n);
-		}
-		else
-		{
-			b1c = nullptr;
-		}
-	}
+// 	Vec2D cv; Vec2D::subtract(cv, pBT, pA);
+// 	float c = Vec2D::length(cv);
 
-	ActorNode* b1pn = b1->parent();
-	// Get the world transform to the bone tip position.
-	if (b1pn->type() == ComponentType::ActorBone)
-	{
-		Mat2D t;
-		t[4] = reinterpret_cast<ActorBone*>(b1pn)->length();
-		Mat2D::multiply(t, world, t);
-		Mat2D::invert(iworld, t);
-	}
-	else
-	{
-		Mat2D::invert(iworld, world);
-	}
+// 	float A = acos(std::max(-1.0f, std::min(1.0f, (-a * a + b * b + c * c) / (2.0f * b * c))));
+// 	float C = acos(std::max(-1.0f, std::min(1.0f, (a * a + b * b - c * c) / (2.0f * a * b))));
 
-	Vec2D pA; b1->worldTranslation(pA);
-	Vec2D pC; b1->tipWorldTranslation(pC);
-	Vec2D pB; b2->tipWorldTranslation(pB);
-	Vec2D pBT(worldTargetTranslation);
+// 	float angleCorrection = 0.0f;
+// 	if (b1c != b2)
+// 	{
+// 		Mat2D iworld2;
+// 		Mat2D::invert(iworld2, b1c->worldTransform());
 
-	Vec2D::transform(pA, pA, iworld);
-	Vec2D::transform(pC, pC, iworld);
-	Vec2D::transform(pB, pB, iworld);
-	Vec2D::transform(pBT, pBT, iworld);
+// 		Vec2D pa2; b2->tipWorldTranslation(pa2);
+// 		Vec2D tipBone2Local; Vec2D::transform(pa2, pa2, iworld2);
+// 		angleCorrection = -atan2(tipBone2Local[1], tipBone2Local[0]);
+// 	}
+// 	if (invert)
+// 	{
+// 		b1->setRotationOverride(atan2(pBT[1], pBT[0]) - A);
+// 		b1c->setRotationOverride(-C + M_PI + angleCorrection);
+// 	}
+// 	else
+// 	{
+// 		b1->setRotationOverride(A + atan2(pBT[1], pBT[0]));
+// 		b1c->setRotationOverride(C - M_PI + angleCorrection);
+// 	}
+// }
 
-	// http://mathworld.wolfram.com/LawofCosines.html
-	Vec2D av; Vec2D::subtract(av, pB, pC);
-	float a = Vec2D::length(av);
+// void ActorIKTarget::solve()
+// {
+// 	if (m_Chain == nullptr)
+// 	{
+// 		return;
+// 	}
 
-	Vec2D bv; Vec2D::subtract(bv, pC, pA);
-	float b = Vec2D::length(bv);
+// 	Vec2D worldTargetTranslation;
+// 	const Mat2D& wt = worldTransform();
+// 	worldTargetTranslation[0] = wt[4];
+// 	worldTargetTranslation[1] = wt[5];
 
-	Vec2D cv; Vec2D::subtract(cv, pBT, pA);
-	float c = Vec2D::length(cv);
+// 	for (int i = 0; i < m_ChainLength; i++)
+// 	{
+// 		BoneChain& fk = m_Chain[i];
+// 		fk.angle = fk.bone->overrideRotationValue();
+// 	}
 
-	float A = acos(std::max(-1.0f, std::min(1.0f, (-a * a + b * b + c * c) / (2.0f * b * c))));
-	float C = acos(std::max(-1.0f, std::min(1.0f, (a * a + b * b - c * c) / (2.0f * a * b))));
+// 	if (m_NumInfluencedBones == 1)
+// 	{
+// 		solve1(m_InfluencedBones[0].bone, worldTargetTranslation);
+// 	}
+// 	else if (m_NumInfluencedBones == 2)
+// 	{
+// 		solve2(m_InfluencedBones[0].bone, m_InfluencedBones[1].bone, worldTargetTranslation, m_InvertDirection);
+// 	}
+// 	else
+// 	{
+// 		for (int i = 0; i < m_NumInfluencedBones - 1; i++)
+// 		{
+// 			solve2(m_InfluencedBones[i].bone, m_Bone2, worldTargetTranslation, m_InvertDirection);
+// 		}
+// 	}
 
-	float angleCorrection = 0.0f;
-	if (b1c != b2)
-	{
-		Mat2D iworld2;
-		Mat2D::invert(iworld2, b1c->worldTransform());
-
-		Vec2D pa2; b2->tipWorldTranslation(pa2);
-		Vec2D tipBone2Local; Vec2D::transform(pa2, pa2, iworld2);
-		angleCorrection = -atan2(tipBone2Local[1], tipBone2Local[0]);
-	}
-	if (invert)
-	{
-		b1->setRotationOverride(atan2(pBT[1], pBT[0]) - A);
-		b1c->setRotationOverride(-C + M_PI + angleCorrection);
-	}
-	else
-	{
-		b1->setRotationOverride(A + atan2(pBT[1], pBT[0]));
-		b1c->setRotationOverride(C - M_PI + angleCorrection);
-	}
-}
-
-void ActorIKTarget::solve()
-{
-	if (m_Chain == nullptr)
-	{
-		return;
-	}
-
-	Vec2D worldTargetTranslation;
-	const Mat2D& wt = worldTransform();
-	worldTargetTranslation[0] = wt[4];
-	worldTargetTranslation[1] = wt[5];
-
-	for (int i = 0; i < m_ChainLength; i++)
-	{
-		BoneChain& fk = m_Chain[i];
-		fk.angle = fk.bone->overrideRotationValue();
-	}
-
-	if (m_NumInfluencedBones == 1)
-	{
-		solve1(m_InfluencedBones[0].bone, worldTargetTranslation);
-	}
-	else if (m_NumInfluencedBones == 2)
-	{
-		solve2(m_InfluencedBones[0].bone, m_InfluencedBones[1].bone, worldTargetTranslation, m_InvertDirection);
-	}
-	else
-	{
-		for (int i = 0; i < m_NumInfluencedBones - 1; i++)
-		{
-			solve2(m_InfluencedBones[i].bone, m_Bone2, worldTargetTranslation, m_InvertDirection);
-		}
-	}
-
-	// At the end, mix the FK angle with the IK angle by strength
-	if (m_Strength != 1.0f)
-	{
-		float im = 1.0f - m_Strength;
-		for (int i = 0; i < m_ChainLength; i++)
-		{
-			BoneChain& fk = m_Chain[i];
-			if (fk.included)
-			{
-				fk.bone->setRotationOverride(fk.bone->overrideRotationValue() * m_Strength + fk.angle * im);
-			}
-		}
-	}
-}
\ No newline at end of file
+// 	// At the end, mix the FK angle with the IK angle by strength
+// 	if (m_Strength != 1.0f)
+// 	{
+// 		float im = 1.0f - m_Strength;
+// 		for (int i = 0; i < m_ChainLength; i++)
+// 		{
+// 			BoneChain& fk = m_Chain[i];
+// 			if (fk.included)
+// 			{
+// 				fk.bone->setRotationOverride(fk.bone->overrideRotationValue() * m_Strength + fk.angle * im);
+// 			}
+// 		}
+// 	}
+// }
\ No newline at end of file
diff --git a/Source/ActorIKTarget.hpp b/Source/ActorIKTarget.hpp
index 7a15b87..d48720a 100644
--- a/Source/ActorIKTarget.hpp
+++ b/Source/ActorIKTarget.hpp
@@ -3,7 +3,6 @@
 
 #include "ActorNode.hpp"
 #include "ActorBone.hpp"
-#include "Solver.hpp"
 
 namespace nima
 {
@@ -11,7 +10,7 @@
 	class BlockReader;
 	class ActorNode;
 
-	class ActorIKTarget : public ActorNode, public Solver
+	class ActorIKTarget : public ActorNode
 	{
 			typedef ActorNode Base;
 		public:
@@ -52,12 +51,6 @@
 			ActorNode* makeInstance(Actor* resetActor) override;
 			void copy(ActorIKTarget* node, Actor* resetActor);
 
-			int order() override;
-			bool needsSolve() override;
-			bool suppressMarkDirty() override;
-			void suppressMarkDirty(bool suppressIt) override;
-			void solveStart() override;
-			void solve() override;
 			float strength() const;
 			void strength(float s);
 			void resolveComponentIndices(ActorComponent** nodes) override;
diff --git a/Source/ActorImage.cpp b/Source/ActorImage.cpp
index b9e63c6..9eb30f2 100644
--- a/Source/ActorImage.cpp
+++ b/Source/ActorImage.cpp
@@ -143,7 +143,7 @@
 	for (int i = 0; i < m_NumConnectedBones; i++)
 	{
 		BoneConnection& bc = m_BoneConnections[i];
-		bc.node->updateTransforms();
+
 		Mat2D::multiply(mat, bc.node->worldTransform(), bc.ibind);
 		m_BoneMatrices[bidx++] = mat[0];
 		m_BoneMatrices[bidx++] = mat[1];
diff --git a/Source/ActorNode.cpp b/Source/ActorNode.cpp
index 19ccdcb..bd22d2b 100644
--- a/Source/ActorNode.cpp
+++ b/Source/ActorNode.cpp
@@ -1,5 +1,6 @@
 #include "ActorNode.hpp"
 #include "BlockReader.hpp"
+#include "Actor.hpp"
 #include <algorithm>
 #include <cassert>
 using namespace nima;
@@ -22,14 +23,9 @@
 		m_Scale(1.0f, 1.0f),
 		m_Opacity(1.0f),
 		m_RenderOpacity(1.0f),
-		m_IsDirty(true),
-		m_IsWorldDirty(true),
-		m_SuppressMarkDirty(false),
 		m_OverrideWorldTransform(false),
-		m_OverrideRotation(false),
 		m_IsCollapsedVisibility(false),
-		m_RenderCollapsed(false),
-		m_OverrideRotationValue(0.0f)
+		m_RenderCollapsed(false)
 {
 
 }
@@ -44,41 +40,13 @@
 
 }
 
-bool ActorNode::suppressMarkDirty() const
-{
-	return m_SuppressMarkDirty;
-}
-
-void ActorNode::suppressMarkDirty(bool suppress)
-{
-	m_SuppressMarkDirty = suppress;
-}
-
-bool ActorNode::isWorldDirty() const
-{
-	return m_IsWorldDirty;
-}
-
-bool ActorNode::isDirty() const
-{
-	return m_IsDirty;
-}
-
 const Mat2D& ActorNode::transform()
 {
-	if(m_IsDirty)
-	{
-		updateTransform();
-	}
 	return m_Transform;
 }
 
 const Mat2D& ActorNode::worldTransform()
 {
-	if(m_IsWorldDirty)
-	{
-		updateWorldTransform();
-	}
 	return m_WorldTransform;
 }
 
@@ -86,7 +54,7 @@
 {
 	m_OverrideWorldTransform = true;
 	Mat2D::copy(m_WorldTransform, transform);
-	markWorldDirty();
+	markTransformDirty();
 }
 
 void ActorNode::clearWorldTransformOverride()
@@ -96,7 +64,7 @@
 		return;
 	}
 	m_OverrideWorldTransform = false;
-	markWorldDirty();
+	markTransformDirty();
 }
 
 float ActorNode::x() const
@@ -111,8 +79,7 @@
 		return;
 	}
 	m_Translation[0] = v;
-	markDirty();
-	markWorldDirty();
+	markTransformDirty();
 }
 
 float ActorNode::y() const
@@ -127,8 +94,7 @@
 		return;
 	}
 	m_Translation[1] = v;
-	markDirty();
-	markWorldDirty();
+	markTransformDirty();
 }
 
 float ActorNode::scaleX() const
@@ -143,8 +109,7 @@
 		return;
 	}
 	m_Scale[0] = v;
-	markDirty();
-	markWorldDirty();
+	markTransformDirty();
 }
 
 float ActorNode::scaleY() const
@@ -159,8 +124,7 @@
 		return;
 	}
 	m_Scale[1] = v;
-	markDirty();
-	markWorldDirty();
+	markTransformDirty();
 }
 
 float ActorNode::rotation() const
@@ -175,8 +139,7 @@
 		return;
 	}
 	m_Rotation = v;
-	markDirty();
-	markWorldDirty();
+	markTransformDirty();
 }
 
 float ActorNode::opacity() const
@@ -191,7 +154,7 @@
 		return;
 	}
 	m_Opacity = v;
-	markWorldDirty();
+	markTransformDirty();
 }
 
 float ActorNode::renderOpacity() const
@@ -209,8 +172,7 @@
 	if(m_IsCollapsedVisibility != v)
 	{
 		m_IsCollapsedVisibility = v;
-		markDirty();
-		markWorldDirty();
+		markTransformDirty();
 	}
 }
 
@@ -219,57 +181,23 @@
 	return m_RenderCollapsed;
 }
 
-void ActorNode::markDirty()
+void ActorNode::markTransformDirty()
 {
-	if(m_IsDirty)
+	if(m_Actor == nullptr)
+	{
+		// Still loading?
+		return;
+	}
+	if(!m_Actor->addDirt(this, TransformDirty))
 	{
 		return;
 	}
-	m_IsDirty = true;
-}
-
-void ActorNode::markWorldDirty()
-{
-	if(m_IsWorldDirty || m_SuppressMarkDirty)
-	{
-		return;
-	}
-	m_IsWorldDirty = true;
-	for(ActorNode* node : m_Children)
-	{
-		node->markWorldDirty();
-	}
-	for(ActorNode* node : m_Dependents)
-	{
-		node->markWorldDirty();
-	}
-}
-
-void ActorNode::addDependent(ActorNode* node)
-{
-	// Make sure it's not already a dependent.
-	assert(std::find(m_Dependents.begin(), m_Dependents.end(), node) == m_Dependents.end());
-
-	m_Dependents.push_back(node);
-}
-
-void ActorNode::removeDependent(ActorNode* node)
-{
-	auto itr = std::find(m_Dependents.begin(), m_Dependents.end(), node);
-	if(itr == m_Dependents.end())
-	{
-		return;
-	}
-	m_Dependents.erase(itr);
+	m_Actor->addDirt(this, WorldTransformDirty, true);
 }
 
 Vec2D ActorNode::worldTranslation()
 {
 	Vec2D result;
-	if(m_IsWorldDirty)
-	{
-		updateWorldTransform();
-	}
 	result[0] = m_WorldTransform[4];
 	result[1] = m_WorldTransform[5];
 	return result;
@@ -277,90 +205,32 @@
 
 void ActorNode::worldTranslation(Vec2D& result)
 {
-	if(m_IsWorldDirty)
-	{
-		updateWorldTransform();
-	}
 	result[0] = m_WorldTransform[4];
 	result[1] = m_WorldTransform[5];
 }
 
-void ActorNode::setRotationOverride(float v)
-{
-	if(!m_OverrideRotation || m_OverrideRotationValue != v)
-	{
-		m_OverrideRotation = true;
-		m_OverrideRotationValue = v;
-		markDirty();
-		markWorldDirty();
-	}
-}
-
-void ActorNode::clearRotationOverride()
-{
-	if(m_OverrideRotation)
-	{
-		m_OverrideRotation = false;
-		markDirty();
-		markWorldDirty();
-	}
-}
-
-float ActorNode::overrideRotationValue() const
-{
-	return m_OverrideRotationValue;	
-}
-
 void ActorNode::updateTransform()
 {
-	m_IsDirty = false;
-
-	Mat2D::fromRotation(m_Transform, m_OverrideRotation ? m_OverrideRotationValue : m_Rotation);
+	Mat2D::fromRotation(m_Transform, m_Rotation);
 	m_Transform[4] = m_Translation[0];
 	m_Transform[5] = m_Translation[1];
 	Mat2D::scale(m_Transform, m_Transform, m_Scale);
 }
 
-void ActorNode::updateTransforms()
-{
-	if(m_IsDirty)
-	{
-		updateTransform();
-	}
-	if(m_IsWorldDirty)
-	{
-		updateWorldTransform();
-	}
-}
-
 void ActorNode::updateWorldTransform()
 {
-	m_IsWorldDirty = false;
-
-	if(m_IsDirty)
-	{
-		updateTransform();
-	}
-
 	m_RenderOpacity = m_Opacity;
 
 	if(m_Parent != nullptr)
 	{
-		m_Parent->updateTransforms();
-
-		bool isRenderCollapsed = (m_IsCollapsedVisibility || m_Parent->renderCollapsed());
-		if(m_RenderCollapsed != isRenderCollapsed)
-		{
-			m_RenderCollapsed = isRenderCollapsed;
-		}
-
+		m_RenderCollapsed = (m_IsCollapsedVisibility || m_Parent->renderCollapsed());
 		m_RenderOpacity *= m_Parent->renderOpacity();
 		if(!m_OverrideWorldTransform)
 		{
 			Mat2D::multiply(m_WorldTransform, m_Parent->m_WorldTransform, m_Transform);
 		}
 	}
-	else if(!m_OverrideWorldTransform)
+	else
 	{
 		Mat2D::copy(m_WorldTransform, m_Transform);
 	}
@@ -404,8 +274,6 @@
 void ActorNode::copy(ActorNode* node, Actor* resetActor)
 {
 	Base::copy(node, resetActor);
-	m_IsDirty = true;
-	m_IsWorldDirty = true;
 	Mat2D::copy(m_Transform, node->m_Transform);
 	Mat2D::copy(m_WorldTransform, node->m_WorldTransform);
 	Vec2D::copy(m_Translation, node->m_Translation);
@@ -414,8 +282,6 @@
 	m_Opacity = node->m_Opacity;
 	m_RenderOpacity = node->m_RenderOpacity;
 	m_OverrideWorldTransform = node->m_OverrideWorldTransform;
-	m_OverrideRotation = node->m_OverrideRotation;
-	m_OverrideRotationValue = node->m_OverrideRotationValue;
 }
 
 ActorNode* ActorNode::read(Actor* actor, BlockReader* reader, ActorNode* node)
@@ -434,4 +300,44 @@
 	node->m_IsCollapsedVisibility = (reader->readByte() == 1);
 
 	return node;
+}
+
+bool ActorNode::addConstraint(ActorConstraint* constraint)
+{
+	auto itr = std::find(m_Constraints.begin(), m_Constraints.end(), constraint);
+	if(itr != m_Constraints.end())
+	{
+		return false;
+	}
+	m_Constraints.push_back(constraint);
+	return true;
+}
+
+void ActorNode::update(unsigned char dirt)
+{
+	if((dirt & TransformDirty) == TransformDirty)
+	{
+		updateTransform();
+	}
+	if((dirt & WorldTransformDirty) == WorldTransformDirty)
+	{
+		updateWorldTransform();
+		for(auto constraint : m_Constraints)
+		{
+			if(constraint->isEnabled())
+			{
+				constraint->constrain(this);
+			}
+		}
+		// if(m_Constraints != nullptr)
+		// {
+		// 	foreach(ActorConstraint constraint in m_Constraints)
+		// 	{
+		// 		if(constraint.IsEnabled)
+		// 		{
+		// 			constraint.Constrain(this);
+		// 		}
+		// 	}
+		// }
+	}
 }
\ No newline at end of file
diff --git a/Source/ActorNode.hpp b/Source/ActorNode.hpp
index 6bc4d92..1c975e0 100644
--- a/Source/ActorNode.hpp
+++ b/Source/ActorNode.hpp
@@ -5,6 +5,7 @@
 #include <nima/Mat2D.hpp>
 #include <nima/Vec2D.hpp>
 #include "ActorComponent.hpp"
+#include "ActorConstraint.hpp"
 
 namespace nima
 {
@@ -16,7 +17,7 @@
 		typedef ActorComponent Base;
 		protected:
 			std::vector<ActorNode*> m_Children;
-			std::vector<ActorNode*> m_Dependents;
+			std::vector<ActorConstraint*> m_Constraints;
 			Mat2D m_Transform;
 			Mat2D m_WorldTransform;
 			Vec2D m_Translation;
@@ -26,14 +27,9 @@
 			float m_RenderOpacity;
 
 		private:
-			bool m_IsDirty;
-			bool m_IsWorldDirty;
-			bool m_SuppressMarkDirty;
 			bool m_OverrideWorldTransform;
-			bool m_OverrideRotation;
 			bool m_IsCollapsedVisibility;
 			bool m_RenderCollapsed;
-			float m_OverrideRotationValue;
 
 		protected:
 			ActorNode(ComponentType type);
@@ -43,15 +39,14 @@
 			ActorNode(Actor* actor);
 			ActorNode();
 			virtual ~ActorNode();
-			bool suppressMarkDirty() const;
-			void suppressMarkDirty(bool suppress); 
-			bool isWorldDirty() const;
-			bool isDirty() const;
 			const Mat2D& transform();
 			const Mat2D& worldTransform();
 			void overrideWorldTransform(const Mat2D& transform);
 			void clearWorldTransformOverride();
 
+			static const unsigned char TransformDirty = 1<<0;
+			static const unsigned char WorldTransformDirty = 1<<1;
+
 			float x() const;
 			void x(float v);
 			float y() const;
@@ -68,17 +63,10 @@
 			bool collapsedVisibility() const;
 			void collapsedVisibility(bool v);
 			bool renderCollapsed() const;
-			void markDirty();
-			void markWorldDirty();
-			void addDependent(ActorNode* node);
-			void removeDependent(ActorNode* node);
+			void markTransformDirty();
 			void worldTranslation(Vec2D& result);
 			Vec2D worldTranslation();
-			void setRotationOverride(float v);
-			void clearRotationOverride();
-			float overrideRotationValue() const;
 			void updateTransform();
-			void updateTransforms();
 			virtual void updateWorldTransform();
 			void addChild(ActorNode* node);
 			void removeChild(ActorNode* node);
@@ -87,7 +75,12 @@
 			void copy(ActorNode* node, Actor* resetActor);
 			bool isNode() override { return true; }
 
-			static ActorNode* read(Actor* actor, BlockReader* reader, ActorNode* node = NULL);
+			static ActorNode* read(Actor* actor, BlockReader* reader, ActorNode* node = nullptr);
+
+			bool addConstraint(ActorConstraint* constraint);
+			void update(unsigned char dirt) override;
+
+			const std::vector<ActorNode*> children() const { return m_Children; }
 	};
 }
 #endif
\ No newline at end of file
diff --git a/Source/ActorTargetedConstraint.cpp b/Source/ActorTargetedConstraint.cpp
new file mode 100644
index 0000000..67ce326
--- /dev/null
+++ b/Source/ActorTargetedConstraint.cpp
@@ -0,0 +1,38 @@
+#include "ActorTargetedConstraint.hpp"
+#include "BlockReader.hpp"
+#include "Actor.hpp"
+
+using namespace nima;
+
+ActorTargetedConstraint::ActorTargetedConstraint(Actor* actor, ComponentType type) : Base(actor, type), m_TargetIdx(0), m_Target(nullptr)
+{
+
+}
+
+void ActorTargetedConstraint::resolveComponentIndices(ActorComponent** components)
+{
+    Base::resolveComponentIndices(components);
+    if(m_TargetIdx != 0)
+    {
+        m_Target = components[m_TargetIdx];
+        if(m_Target != nullptr)
+        {
+            m_Actor->addDependency(m_Parent, m_Target);
+        }
+    }
+}
+
+void ActorTargetedConstraint::copy(ActorTargetedConstraint* constraint, Actor* resetActor)
+{
+    Base::copy(constraint, resetActor);
+
+    m_TargetIdx = constraint->m_TargetIdx;
+}
+
+ActorTargetedConstraint* ActorTargetedConstraint::read(Actor* actor, BlockReader* reader, ActorTargetedConstraint* constraint)
+{
+    Base::read(actor, reader, constraint);
+    constraint->m_TargetIdx = reader->readUnsignedShort();
+
+    return constraint;
+}
\ No newline at end of file
diff --git a/Source/ActorTargetedConstraint.hpp b/Source/ActorTargetedConstraint.hpp
new file mode 100644
index 0000000..e23eb36
--- /dev/null
+++ b/Source/ActorTargetedConstraint.hpp
@@ -0,0 +1,26 @@
+#ifndef _NIMA_ACTORTARGETEDCONSTRAINT_HPP_
+#define _NIMA_ACTORTARGETEDCONSTRAINT_HPP_
+
+#include "ActorConstraint.hpp"
+
+namespace nima
+{
+    class ActorTargetedConstraint : public ActorConstraint
+	{
+		typedef ActorConstraint Base;
+        protected:
+            unsigned short m_TargetIdx;
+            ActorComponent* m_Target;
+            ActorTargetedConstraint(Actor* actor, ComponentType type);
+
+        public:
+            
+            ActorComponent* target() const { return m_Target; }
+            
+            void resolveComponentIndices(ActorComponent** components) override;
+            void copy(ActorTargetedConstraint* constraint, Actor* resetActor);
+            static ActorTargetedConstraint* read(Actor* actor, BlockReader* reader, ActorTargetedConstraint* constraint = nullptr);
+    };
+}
+
+#endif
\ No newline at end of file
diff --git a/Source/Solver.hpp b/Source/Solver.hpp
deleted file mode 100644
index 0f74ca2..0000000
--- a/Source/Solver.hpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef _NIMA_SOLVER_HPP_
-#define _NIMA_SOLVER_HPP_
-
-namespace nima
-{
-	class Solver
-	{
-		public:
-			virtual int order() = 0;
-			virtual bool needsSolve() = 0;
-			virtual bool suppressMarkDirty() = 0;
-			virtual void suppressMarkDirty(bool suppressIt) = 0;
-			virtual void solveStart() = 0;
-			virtual void solve() = 0;
-	};
-}
-#endif
\ No newline at end of file