blob: 3dbad73e8e82d9befb830937b48c99531a0a094e [file] [log] [blame]
#include "ActorTranslationConstraint.hpp"
using namespace nima;
ActorTranslationConstraint::ActorTranslationConstraint() : Base(nullptr, ComponentType::ActorTranslationConstraint)
{
}
ActorComponent* ActorTranslationConstraint::makeInstance(Actor* resetActor)
{
ActorTranslationConstraint* instanceNode = new ActorTranslationConstraint();
instanceNode->copy(this, resetActor);
return instanceNode;
}
ActorTranslationConstraint* ActorTranslationConstraint::read(Actor* actor, BlockReader* reader, ActorTranslationConstraint* constraint)
{
if(constraint == nullptr)
{
constraint = new ActorTranslationConstraint();
}
Base::read(actor, reader, constraint);
return constraint;
}
void ActorTranslationConstraint::constrain(ActorNode* node)
{
// TODO: Should ActorTargetedConstraint just store targets as nodes?
ActorNode* target = static_cast<ActorNode*>(m_Target);
ActorNode* grandParent = m_Parent->parent();
Mat2D& transformA = m_Parent->mutableWorldTransform();
Vec2D translationA(transformA[4], transformA[5]);
Vec2D translationB;
if(target == nullptr)
{
Vec2D::copy(translationB, translationA);
}
else
{
Mat2D transformB(target->worldTransform());
if(m_SourceSpace == TransformSpace::Local)
{
ActorNode* sourceGrandParent = target->parent();
if(sourceGrandParent != nullptr)
{
Mat2D inverse;
if(!Mat2D::invert(inverse, sourceGrandParent->worldTransform()))
{
return;
}
Mat2D::multiply(transformB, inverse, transformB);
}
}
translationB[0] = transformB[4];
translationB[1] = transformB[5];
if(!m_CopyX)
{
translationB[0] = m_DestSpace == TransformSpace::Local ? 0.0f : translationA[0];
}
else
{
translationB[0] *= m_ScaleX;
if(m_Offset)
{
translationB[0] += m_Parent->x();
}
}
if(!m_CopyY)
{
translationB[1] = m_DestSpace == TransformSpace::Local ? 0.0f : translationA[1];
}
else
{
translationB[1] *= m_ScaleY;
if(m_Offset)
{
translationB[1] += m_Parent->y();
}
}
if(m_DestSpace == TransformSpace::Local)
{
// Destination space is in parent transform coordinates.
if(grandParent != nullptr)
{
Vec2D::transform(translationB, translationB, grandParent->worldTransform());
}
}
}
bool clampLocal = m_MinMaxSpace == TransformSpace::Local && grandParent != nullptr;
if(clampLocal)
{
// Apply min max in local space, so transform to local coordinates first.
Mat2D invert;
if(!Mat2D::invert(invert, grandParent->worldTransform()))
{
return;
}
// Get our target world coordinates in parent local.
Vec2D::transform(translationB, translationB, invert);
}
if(m_EnableMaxX && translationB[0] > m_MaxX)
{
translationB[0] = m_MaxX;
}
if(m_EnableMinX && translationB[0] < m_MinX)
{
translationB[0] = m_MinX;
}
if(m_EnableMaxY && translationB[1] > m_MaxY)
{
translationB[1] = m_MaxY;
}
if(m_EnableMinY && translationB[1] < m_MinY)
{
translationB[1] = m_MinY;
}
if(clampLocal)
{
// Transform back to world.
Vec2D::transform(translationB, translationB, grandParent->worldTransform());
}
float ti = 1.0f-m_Strength;
// Just interpolate world translation
transformA[4] = translationA[0] * ti + translationB[0] * m_Strength;
transformA[5] = translationA[1] * ti + translationB[1] * m_Strength;
}