Skip to content

Commit

Permalink
lottie: implement skew transformation
Browse files Browse the repository at this point in the history
Added support for skew transformation by
a specified angle around a specified axis.
Applied to layers and shapes, not to repeaters.

@issue: #2262
  • Loading branch information
mgrudzinska authored and hermet committed May 17, 2024
1 parent abe820d commit 0e2dc12
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 2 deletions.
46 changes: 46 additions & 0 deletions src/loaders/lottie/tvgLottieBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,42 @@ static void _rotationZ(Matrix* m, float degree)
}


static void _skew(Matrix* m, float angleDeg, float axisDeg)
{
auto angle = -mathDeg2Rad(angleDeg);
float tanVal = tanf(angle);

axisDeg = fmod(axisDeg, 180.0f);
if (fabsf(axisDeg) < 0.01f || fabsf(axisDeg - 180.0f) < 0.01f || fabsf(axisDeg + 180.0f) < 0.01f) {
float cosVal = cosf(mathDeg2Rad(axisDeg));
auto B = cosVal * cosVal * tanVal;
m->e12 += B * m->e11;
m->e22 += B * m->e21;
return;
} else if (fabsf(axisDeg - 90.0f) < 0.01f || fabsf(axisDeg + 90.0f) < 0.01f) {
float sinVal = -sinf(mathDeg2Rad(axisDeg));
auto C = sinVal * sinVal * tanVal;
m->e11 -= C * m->e12;
m->e21 -= C * m->e22;
return;
}

auto axis = -mathDeg2Rad(axisDeg);
float cosVal = cosf(axis);
float sinVal = sinf(axis);
auto A = sinVal * cosVal * tanVal;
auto B = cosVal * cosVal * tanVal;
auto C = sinVal * sinVal * tanVal;

auto e11 = m->e11;
auto e21 = m->e21;
m->e11 = (1.0f - A) * e11 - C * m->e12;
m->e12 = B * e11 + (1.0f + A) * m->e12;
m->e21 = (1.0f - A) * e21 - C * m->e22;
m->e22 = B * e21 + (1.0f + A) * m->e22;
}


static bool _updateTransform(LottieTransform* transform, float frameNo, bool autoOrient, Matrix& matrix, uint8_t& opacity, LottieExpressions* exps)
{
mathIdentity(&matrix);
Expand All @@ -154,6 +190,16 @@ static bool _updateTransform(LottieTransform* transform, float frameNo, bool aut
_rotateX(&matrix, transform->rotationEx->x(frameNo, exps));
}

auto skewAngle = transform->skewAngle(frameNo, exps);
if (fabsf(skewAngle) > 0.01f) {
// For angles where tangent explodes, the shape degenerates into an infinitely thin line.
// This is handled by zeroing out the matrix due to finite numerical precision.
skewAngle = fmod(skewAngle, 180.0f);
if (fabsf(skewAngle - 90.0f) < 0.01f || fabsf(skewAngle + 90.0f) < 0.01f) return false;
auto skewAxis = transform->skewAxis(frameNo, exps);
_skew(&matrix, skewAngle, skewAxis);
}

auto scale = transform->scale(frameNo, exps);
mathScaleR(&matrix, scale.x * 0.01f, scale.y * 0.01f);

Expand Down
2 changes: 2 additions & 0 deletions src/loaders/lottie/tvgLottieModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,8 @@ struct LottieTransform : LottieObject
LottiePoint scale = Point{100.0f, 100.0f};
LottiePoint anchor = Point{0.0f, 0.0f};
LottieOpacity opacity = 255;
LottieFloat skewAngle = 0.0f;
LottieFloat skewAxis = 0.0f;

SeparateCoord* coords = nullptr; //either a position or separate coordinates
RotationEx* rotationEx = nullptr; //extension for 3d rotation
Expand Down
4 changes: 2 additions & 2 deletions src/loaders/lottie/tvgLottieParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,8 @@ LottieTransform* LottieParser::parseTransform(bool ddd)
else if (transform->rotationEx && KEY_AS("ry")) parseProperty<LottieProperty::Type::Float>(transform->rotationEx->y);
else if (transform->rotationEx && KEY_AS("rz")) parseProperty<LottieProperty::Type::Float>(transform->rotation);
else if (KEY_AS("nm")) transform->name = getStringCopy();
//else if (KEY_AS("sk")) //TODO: skew
//else if (KEY_AS("sa")) //TODO: skew axis
else if (KEY_AS("sk")) parseProperty<LottieProperty::Type::Float>(transform->skewAngle);
else if (KEY_AS("sa")) parseProperty<LottieProperty::Type::Float>(transform->skewAxis);
else skip(key);
}
transform->prepare();
Expand Down

0 comments on commit 0e2dc12

Please sign in to comment.