Simplify Mat2D api
diff --git a/include/rive/math/mat2d.hpp b/include/rive/math/mat2d.hpp
index c2876dc..0e492ab 100644
--- a/include/rive/math/mat2d.hpp
+++ b/include/rive/math/mat2d.hpp
@@ -32,11 +32,21 @@
return *this;
}
- static Mat2D scale(const Mat2D& mat, const Vec2D& vec);
+ // If returns true, result holds the inverse.
+ // If returns false, result is unchnaged.
+ bool invert(Mat2D* result) const;
+
+ Mat2D invertOrIdentity() const {
+ Mat2D inverse; // initialized to identity
+ (void)invert(&inverse); // inverse is unchanged if invert() fails
+ return inverse;
+ }
+
+ TransformComponents decompose() const;
+ static Mat2D compose(const TransformComponents&);
+ Mat2D scale(Vec2D) const;
+
static Mat2D multiply(const Mat2D& a, const Mat2D& b);
- static bool invert(Mat2D& result, const Mat2D& a);
- static void decompose(TransformComponents& result, const Mat2D& m);
- static void compose(Mat2D& result, const TransformComponents& components);
float xx() const { return m_Buffer[0]; }
float xy() const { return m_Buffer[1]; }
diff --git a/include/rive/math/transform_components.hpp b/include/rive/math/transform_components.hpp
index 44e9d4b..1fc74f9 100644
--- a/include/rive/math/transform_components.hpp
+++ b/include/rive/math/transform_components.hpp
@@ -37,22 +37,17 @@
float skew() const { return m_Skew; }
void skew(float value) { m_Skew = value; }
- void translation(Vec2D& result) const {
- result[0] = m_X;
- result[1] = m_Y;
- }
- void scale(Vec2D& result) const {
- result[0] = m_ScaleX;
- result[1] = m_ScaleY;
- }
+ Vec2D translation() const { return {m_X, m_Y}; }
+ Vec2D scale() const { return {m_ScaleX, m_ScaleY}; }
- static void copy(TransformComponents& result, const TransformComponents& a) {
- result.m_X = a.m_X;
- result.m_Y = a.m_Y;
- result.m_ScaleX = a.m_ScaleX;
- result.m_ScaleY = a.m_ScaleY;
- result.m_Rotation = a.m_Rotation;
- result.m_Skew = a.m_Skew;
+ TransformComponents& operator=(const TransformComponents& a) {
+ m_X = a.m_X;
+ m_Y = a.m_Y;
+ m_ScaleX = a.m_ScaleX;
+ m_ScaleY = a.m_ScaleY;
+ m_Rotation = a.m_Rotation;
+ m_Skew = a.m_Skew;
+ return *this;
}
};
} // namespace rive
diff --git a/skia/viewer/src/main.cpp b/skia/viewer/src/main.cpp
index 0115a33..8568137 100644
--- a/skia/viewer/src/main.cpp
+++ b/skia/viewer/src/main.cpp
@@ -289,7 +289,7 @@
artboardInstance->bounds());
renderer.transform(viewTransform);
// Store the inverse view so we can later go from screen to world.
- rive::Mat2D::invert(gInverseViewTransform, viewTransform);
+ gInverseViewTransform = viewTransform.invertOrIdentity();
// post_mouse_event(artboard.get(), canvas->getTotalMatrix());
artboardInstance->draw(&renderer);
diff --git a/src/bones/tendon.cpp b/src/bones/tendon.cpp
index 9e66364..6e8d204 100644
--- a/src/bones/tendon.cpp
+++ b/src/bones/tendon.cpp
@@ -14,7 +14,7 @@
bind[4] = tx();
bind[5] = ty();
- if (!Mat2D::invert(m_InverseBind, bind)) {
+ if (!bind.invert(&m_InverseBind)) {
return StatusCode::FailedInversion;
}
diff --git a/src/constraints/ik_constraint.cpp b/src/constraints/ik_constraint.cpp
index c2c3613..fc75ff0 100644
--- a/src/constraints/ik_constraint.cpp
+++ b/src/constraints/ik_constraint.cpp
@@ -205,11 +205,11 @@
for (BoneChainLink& item : m_FkChain) {
auto bone = item.bone;
const Mat2D& parentWorld = getParentWorld(*bone);
- Mat2D::invert(item.parentWorldInverse, parentWorld);
+ item.parentWorldInverse = parentWorld.invertOrIdentity();
Mat2D& boneTransform = bone->mutableTransform();
boneTransform = item.parentWorldInverse * bone->worldTransform();
- Mat2D::decompose(item.transformComponents, boneTransform);
+ item.transformComponents = boneTransform.decompose();
}
int count = (int)m_FkChain.size();
@@ -228,7 +228,7 @@
solve2(item, tip, worldTargetTranslation);
for (int j = item->index + 1, end = m_FkChain.size() - 1; j < end; j++) {
BoneChainLink& fk = m_FkChain[j];
- Mat2D::invert(fk.parentWorldInverse, getParentWorld(*fk.bone));
+ fk.parentWorldInverse = getParentWorld(*fk.bone).invertOrIdentity();
}
}
break;
diff --git a/src/constraints/rotation_constraint.cpp b/src/constraints/rotation_constraint.cpp
index 798f4b7..7122ac7 100644
--- a/src/constraints/rotation_constraint.cpp
+++ b/src/constraints/rotation_constraint.cpp
@@ -8,22 +8,22 @@
void RotationConstraint::constrain(TransformComponent* component) {
const Mat2D& transformA = component->worldTransform();
Mat2D transformB;
- Mat2D::decompose(m_ComponentsA, transformA);
+ m_ComponentsA = transformA.decompose();
if (m_Target == nullptr) {
transformB = transformA;
- TransformComponents::copy(m_ComponentsB, m_ComponentsA);
+ m_ComponentsB = m_ComponentsA;
} else {
transformB = m_Target->worldTransform();
if (sourceSpace() == TransformSpace::local) {
Mat2D inverse;
- if (!Mat2D::invert(inverse, getParentWorld(*m_Target))) {
+ if (!getParentWorld(*m_Target).invert(&inverse)) {
return;
}
transformB = inverse * transformB;
}
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsB = transformB.decompose();
if (!doesCopy()) {
m_ComponentsB.rotation(destSpace() == TransformSpace::local ? 0.0f
@@ -40,22 +40,21 @@
// the parent local transform and get it in world, then decompose
// the world for interpolation.
- Mat2D::compose(transformB, m_ComponentsB);
+ transformB = Mat2D::compose(m_ComponentsB);
transformB = getParentWorld(*component) * transformB;
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsB = transformB.decompose();
}
}
bool clampLocal = minMaxSpace() == TransformSpace::local;
if (clampLocal) {
// Apply min max in local space, so transform to local coordinates
// first.
- Mat2D::compose(transformB, m_ComponentsB);
- Mat2D inverse = Mat2D();
- if (!Mat2D::invert(inverse, getParentWorld(*component))) {
+ transformB = Mat2D::compose(m_ComponentsB);
+ Mat2D inverse;
+ if (!getParentWorld(*component).invert(&inverse)) {
return;
}
- transformB = inverse * transformB;
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsB = (inverse * transformB).decompose();
}
if (max() && m_ComponentsB.rotation() > maxValue()) {
m_ComponentsB.rotation(maxValue());
@@ -65,9 +64,9 @@
}
if (clampLocal) {
// Transform back to world.
- Mat2D::compose(transformB, m_ComponentsB);
+ transformB = Mat2D::compose(m_ComponentsB);
transformB = getParentWorld(*component) * transformB;
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsB = transformB.decompose();
}
float angleA = std::fmod(m_ComponentsA.rotation(), (float)M_PI * 2);
@@ -87,5 +86,5 @@
m_ComponentsB.scaleY(m_ComponentsA.scaleY());
m_ComponentsB.skew(m_ComponentsA.skew());
- Mat2D::compose(component->mutableWorldTransform(), m_ComponentsB);
+ component->mutableWorldTransform() = Mat2D::compose(m_ComponentsB);
}
diff --git a/src/constraints/scale_constraint.cpp b/src/constraints/scale_constraint.cpp
index 891fd29..1396d15 100644
--- a/src/constraints/scale_constraint.cpp
+++ b/src/constraints/scale_constraint.cpp
@@ -8,20 +8,20 @@
void ScaleConstraint::constrain(TransformComponent* component) {
const Mat2D& transformA = component->worldTransform();
Mat2D transformB;
- Mat2D::decompose(m_ComponentsA, transformA);
+ m_ComponentsA = transformA.decompose();
if (m_Target == nullptr) {
transformB = transformA;
- TransformComponents::copy(m_ComponentsB, m_ComponentsA);
+ m_ComponentsB = m_ComponentsA;
} else {
transformB = m_Target->worldTransform();
if (sourceSpace() == TransformSpace::local) {
Mat2D inverse;
- if (!Mat2D::invert(inverse, getParentWorld(*m_Target))) {
+ if (!getParentWorld(*m_Target).invert(&inverse)) {
return;
}
transformB = inverse * transformB;
}
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsB = transformB.decompose();
if (!doesCopy()) {
m_ComponentsB.scaleX(destSpace() == TransformSpace::local ? 1.0f
@@ -48,9 +48,9 @@
// the parent local transform and get it in world, then decompose
// the world for interpolation.
- Mat2D::compose(transformB, m_ComponentsB);
+ transformB = Mat2D::compose(m_ComponentsB);
transformB = getParentWorld(*component) * transformB;
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsB = transformB.decompose();
}
}
@@ -58,13 +58,13 @@
if (clamplocal) {
// Apply min max in local space, so transform to local coordinates
// first.
- Mat2D::compose(transformB, m_ComponentsB);
+ transformB = Mat2D::compose(m_ComponentsB);
Mat2D inverse;
- if (!Mat2D::invert(inverse, getParentWorld(*component))) {
+ if (!getParentWorld(*component).invert(&inverse)) {
return;
}
transformB = inverse * transformB;
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsB = transformB.decompose();
}
if (max() && m_ComponentsB.scaleX() > maxValue()) {
m_ComponentsB.scaleX(maxValue());
@@ -80,9 +80,9 @@
}
if (clamplocal) {
// Transform back to world.
- Mat2D::compose(transformB, m_ComponentsB);
+ transformB = Mat2D::compose(m_ComponentsB);
transformB = getParentWorld(*component) * transformB;
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsB = transformB.decompose();
}
float t = strength();
@@ -95,5 +95,5 @@
m_ComponentsB.scaleY(m_ComponentsA.scaleY() * ti + m_ComponentsB.scaleY() * t);
m_ComponentsB.skew(m_ComponentsA.skew());
- Mat2D::compose(component->mutableWorldTransform(), m_ComponentsB);
+ component->mutableWorldTransform() = Mat2D::compose(m_ComponentsB);
}
diff --git a/src/constraints/transform_constraint.cpp b/src/constraints/transform_constraint.cpp
index d92d824..988c34a 100644
--- a/src/constraints/transform_constraint.cpp
+++ b/src/constraints/transform_constraint.cpp
@@ -16,7 +16,7 @@
const Mat2D& targetParentWorld = getParentWorld(*m_Target);
Mat2D inverse;
- if (!Mat2D::invert(inverse, targetParentWorld)) {
+ if (!targetParentWorld.invert(&inverse)) {
return;
}
transformB = inverse * transformB;
@@ -26,8 +26,8 @@
transformB = targetParentWorld * transformB;
}
- Mat2D::decompose(m_ComponentsA, transformA);
- Mat2D::decompose(m_ComponentsB, transformB);
+ m_ComponentsA = transformA.decompose();
+ m_ComponentsB = transformB.decompose();
float angleA = std::fmod(m_ComponentsA.rotation(), (float)M_PI * 2);
float angleB = std::fmod(m_ComponentsB.rotation(), (float)M_PI * 2);
@@ -48,5 +48,5 @@
m_ComponentsB.scaleY(m_ComponentsA.scaleY() * ti + m_ComponentsB.scaleY() * t);
m_ComponentsB.skew(m_ComponentsA.skew() * ti + m_ComponentsB.skew() * t);
- Mat2D::compose(component->mutableWorldTransform(), m_ComponentsB);
+ component->mutableWorldTransform() = Mat2D::compose(m_ComponentsB);
}
diff --git a/src/constraints/translation_constraint.cpp b/src/constraints/translation_constraint.cpp
index 1c12267..4ade22b 100644
--- a/src/constraints/translation_constraint.cpp
+++ b/src/constraints/translation_constraint.cpp
@@ -18,7 +18,7 @@
const Mat2D& targetParentWorld = getParentWorld(*m_Target);
Mat2D inverse;
- if (!Mat2D::invert(inverse, targetParentWorld)) {
+ if (!targetParentWorld.invert(&inverse)) {
return;
}
transformB = inverse * transformB;
@@ -55,12 +55,12 @@
if (clampLocal) {
// Apply min max in local space, so transform to local coordinates
// first.
- Mat2D invert;
- if (!Mat2D::invert(invert, getParentWorld(*component))) {
+ Mat2D inverse;
+ if (!getParentWorld(*component).invert(&inverse)) {
return;
}
// Get our target world coordinates in parent local.
- translationB = invert * translationB;
+ translationB = inverse * translationB;
}
if (max() && translationB[0] > maxValue()) {
translationB[0] = maxValue();
diff --git a/src/math/mat2d.cpp b/src/math/mat2d.cpp
index 7d62d59..eb9b8ec 100644
--- a/src/math/mat2d.cpp
+++ b/src/math/mat2d.cpp
@@ -14,21 +14,20 @@
return {c, s, -s, c, 0, 0};
}
-Mat2D Mat2D::scale(const Mat2D& mat, const Vec2D& vec) {
- const float v0 = vec[0], v1 = vec[1];
+Mat2D Mat2D::scale(Vec2D vec) const {
return {
- mat[0] * v0,
- mat[1] * v0,
- mat[2] * v1,
- mat[3] * v1,
- mat[4],
- mat[5],
+ m_Buffer[0] * vec.x(),
+ m_Buffer[1] * vec.x(),
+ m_Buffer[2] * vec.y(),
+ m_Buffer[3] * vec.y(),
+ m_Buffer[4],
+ m_Buffer[5],
};
}
Mat2D Mat2D::multiply(const Mat2D& a, const Mat2D& b) {
- float a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5], b0 = b[0], b1 = b[1],
- b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
+ float a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], a4 = a[4], a5 = a[5],
+ b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3], b4 = b[4], b5 = b[5];
return {
a0 * b0 + a2 * b1,
a1 * b0 + a3 * b1,
@@ -39,8 +38,9 @@
};
}
-bool Mat2D::invert(Mat2D& result, const Mat2D& a) {
- float aa = a[0], ab = a[1], ac = a[2], ad = a[3], atx = a[4], aty = a[5];
+bool Mat2D::invert(Mat2D* result) const {
+ float aa = m_Buffer[0], ab = m_Buffer[1], ac = m_Buffer[2],
+ ad = m_Buffer[3], atx = m_Buffer[4], aty = m_Buffer[5];
float det = aa * ad - ab * ac;
if (det == 0.0f) {
@@ -48,17 +48,20 @@
}
det = 1.0f / det;
- result[0] = ad * det;
- result[1] = -ab * det;
- result[2] = -ac * det;
- result[3] = aa * det;
- result[4] = (ac * aty - ad * atx) * det;
- result[5] = (ab * atx - aa * aty) * det;
+ *result = {
+ ad * det,
+ -ab * det,
+ -ac * det,
+ aa * det,
+ (ac * aty - ad * atx) * det,
+ (ab * atx - aa * aty) * det,
+ };
return true;
}
-void Mat2D::decompose(TransformComponents& result, const Mat2D& m) {
- float m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3];
+TransformComponents Mat2D::decompose() const {
+ float m0 = m_Buffer[0], m1 = m_Buffer[1],
+ m2 = m_Buffer[2], m3 = m_Buffer[3];
float rotation = (float)std::atan2(m1, m0);
float denom = m0 * m0 + m1 * m1;
@@ -66,27 +69,28 @@
float scaleY = (m0 * m3 - m2 * m1) / scaleX;
float skewX = (float)std::atan2(m0 * m2 + m1 * m3, denom);
- result.x(m[4]);
- result.y(m[5]);
+ TransformComponents result;
+ result.x(m_Buffer[4]);
+ result.y(m_Buffer[5]);
result.scaleX(scaleX);
result.scaleY(scaleY);
result.rotation(rotation);
result.skew(skewX);
+ return result;
}
-void Mat2D::compose(Mat2D& result, const TransformComponents& components) {
- result = Mat2D::fromRotation(components.rotation());
+Mat2D Mat2D::compose(const TransformComponents& components) {
+ auto result = Mat2D::fromRotation(components.rotation());
result[4] = components.x();
result[5] = components.y();
- Vec2D scale;
- components.scale(scale);
- result = Mat2D::scale(result, scale);
+ result = result.scale(components.scale());
float sk = components.skew();
if (sk != 0.0f) {
result[2] = result[0] * sk + result[2];
result[3] = result[1] * sk + result[3];
}
+ return result;
}
void Mat2D::scaleByValues(float sx, float sy) {
diff --git a/src/shapes/path.cpp b/src/shapes/path.cpp
index 243d758..942cf86 100644
--- a/src/shapes/path.cpp
+++ b/src/shapes/path.cpp
@@ -257,11 +257,7 @@
if (transformToParent && parent()->is<TransformComponent>()) {
// Put the transform in parent space.
auto world = parent()->as<TransformComponent>()->worldTransform();
- Mat2D inverseWorld;
- if (!Mat2D::invert(inverseWorld, world)) {
- inverseWorld = Mat2D();
- }
- transform = inverseWorld * transform;
+ transform = world.invertOrIdentity() * transform;
}
FlattenedPath* flat = new FlattenedPath();
diff --git a/src/shapes/path_composer.cpp b/src/shapes/path_composer.cpp
index ff843d6..7c2d20d 100644
--- a/src/shapes/path_composer.cpp
+++ b/src/shapes/path_composer.cpp
@@ -28,10 +28,7 @@
m_LocalPath->reset();
}
auto world = m_Shape->worldTransform();
- Mat2D inverseWorld;
- if (!Mat2D::invert(inverseWorld, world)) {
- inverseWorld = Mat2D();
- }
+ Mat2D inverseWorld = world.invertOrIdentity();
// Get all the paths into local shape space.
for (auto path : m_Shape->paths()) {
const auto localTransform = inverseWorld * path->pathTransform();
diff --git a/test/rotation_constraint_test.cpp b/test/rotation_constraint_test.cpp
index 007f6f9..974e284 100644
--- a/test/rotation_constraint_test.cpp
+++ b/test/rotation_constraint_test.cpp
@@ -20,10 +20,8 @@
auto rectangle = artboard->find<rive::TransformComponent>("rect");
artboard->advance(0.0f);
- rive::TransformComponents targetComponents;
- rive::Mat2D::decompose(targetComponents, target->worldTransform());
- rive::TransformComponents rectComponents;
- rive::Mat2D::decompose(rectComponents, rectangle->worldTransform());
+ auto targetComponents = target->worldTransform().decompose();
+ auto rectComponents = rectangle->worldTransform().decompose();
REQUIRE(targetComponents.rotation() == rectComponents.rotation());
}
diff --git a/test/scale_constraint_test.cpp b/test/scale_constraint_test.cpp
index bd9827b..edf96f5 100644
--- a/test/scale_constraint_test.cpp
+++ b/test/scale_constraint_test.cpp
@@ -21,10 +21,8 @@
artboard->advance(0.0f);
- rive::TransformComponents targetComponents;
- rive::Mat2D::decompose(targetComponents, target->worldTransform());
- rive::TransformComponents rectComponents;
- rive::Mat2D::decompose(rectComponents, rectangle->worldTransform());
+ auto targetComponents = target->worldTransform().decompose();
+ auto rectComponents = rectangle->worldTransform().decompose();
REQUIRE(targetComponents.scaleX() == rectComponents.scaleX());
REQUIRE(targetComponents.scaleY() == rectComponents.scaleY());
diff --git a/test/translation_constraint_test.cpp b/test/translation_constraint_test.cpp
index d01f15b..e8a0eb8 100644
--- a/test/translation_constraint_test.cpp
+++ b/test/translation_constraint_test.cpp
@@ -21,10 +21,8 @@
artboard->advance(0.0f);
- rive::TransformComponents targetComponents;
- rive::Mat2D::decompose(targetComponents, target->worldTransform());
- rive::TransformComponents rectComponents;
- rive::Mat2D::decompose(rectComponents, rectangle->worldTransform());
+ auto targetComponents = target->worldTransform().decompose();
+ auto rectComponents = rectangle->worldTransform().decompose();
REQUIRE(targetComponents.x() == rectComponents.x());
REQUIRE(targetComponents.y() == rectComponents.y());