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());