blob: 05dcfcb6e1c939c4c4556f9464fabf94bdd04b3f [file]
#include "rive/constraints/constraint.hpp"
#include "rive/container_component.hpp"
#include "rive/transform_component.hpp"
#include "rive/core_context.hpp"
#include "rive/math/mat2d.hpp"
using namespace rive;
StatusCode Constraint::onAddedDirty(CoreContext* context)
{
StatusCode result = Super::onAddedDirty(context);
#ifndef WITH_RIVE_EDITOR
// Runtime-only path; editor build registers via
// `editorParentChanged` (dispatcher Pass 4.5).
if (!parent()->is<TransformComponent>())
{
return StatusCode::InvalidObject;
}
parent()->as<TransformComponent>()->addConstraint(this);
#endif
return result;
}
void Constraint::markConstraintDirty()
{
parent()->as<TransformComponent>()->markTransformDirty();
}
void Constraint::strengthChanged() { markConstraintDirty(); }
void Constraint::buildDependencies()
{
Super::buildDependencies();
parent()->addDependent(this);
}
void Constraint::onDirty(ComponentDirt dirt)
{
// Whenever the constraint gets any dirt, make sure to mark the constrained
// component dirty.
markConstraintDirty();
}
static Mat2D identity;
const Mat2D& rive::getParentWorld(const TransformComponent& component)
{
auto parent = component.parent();
if (parent->is<WorldTransformComponent>())
{
return parent->as<WorldTransformComponent>()->worldTransform();
}
return identity;
}
void Constraint::composeKeepingAnchor(TransformComponent* component,
const TransformComponents& composed)
{
Mat2D& world = component->mutableWorldTransform();
const Vec2D anchor = component->localAnchor();
if (anchor.x == 0.0f && anchor.y == 0.0f)
{
world = Mat2D::compose(composed);
return;
}
const Vec2D before = world * anchor;
Mat2D result = Mat2D::compose(composed);
const Vec2D after = result * anchor;
result[4] += before.x - after.x;
result[5] += before.y - after.y;
world = result;
}
void Constraint::landAnchor(TransformComponent* component, float strength)
{
const Vec2D anchor = component->localAnchor();
if (anchor.x == 0.0f && anchor.y == 0.0f)
{
return;
}
Mat2D& world = component->mutableWorldTransform();
world[4] -= (world[0] * anchor.x + world[2] * anchor.y) * strength;
world[5] -= (world[1] * anchor.x + world[3] * anchor.y) * strength;
}
void Constraint::composeLandingAnchor(TransformComponent* component,
const TransformComponents& composed,
float strength)
{
component->mutableWorldTransform() = Mat2D::compose(composed);
landAnchor(component, strength);
}
Mat2D Constraint::offsetInParentFrame(TransformComponent* component,
const Mat2D& offset)
{
const Mat2D& parentWorld = getParentWorld(*component);
const Vec2D delta =
(parentWorld * offset).translation() - parentWorld.translation();
Mat2D result = component->worldTransform();
result[4] += delta.x;
result[5] += delta.y;
return result;
}