loader/lottie: correct a polystar transform.

Properly propagate the transform information to the merged shapes.
This corrects the incorrect transformation applied to the subsequent shapes.
This commit is contained in:
Hermet Park 2023-08-24 00:48:45 +09:00
parent 3d5c5ef0fa
commit 7b40c741ac
3 changed files with 68 additions and 55 deletions

View file

@ -232,7 +232,7 @@ static Shape* _updatePath(LottieGroup* parent, LottiePath* path, int32_t frameNo
}
static void _updateStar(LottieGroup* parent, LottiePolyStar* star, int32_t frameNo, Shape* mergingShape)
static void _updateStar(LottieGroup* parent, LottiePolyStar* star, Matrix* transform, int32_t frameNo, Shape* mergingShape)
{
static constexpr auto K_PI = 3.141592f;
static constexpr auto POLYSTAR_MAGIC_NUMBER = 0.47829f / 0.28f;
@ -279,7 +279,9 @@ static void _updateStar(LottieGroup* parent, LottiePolyStar* star, int32_t frame
hasRoundness = true;
}
mergingShape->moveTo(x, y);
Point in = {x, y};
if (transform) mathTransform(transform, &in);
mergingShape->moveTo(in.x, in.y);
for (size_t i = 0; i < numPoints; i++) {
auto radius = longSegment ? outerRadius : innerRadius;
@ -319,22 +321,30 @@ static void _updateStar(LottieGroup* parent, LottiePolyStar* star, int32_t frame
cp2x *= partialPointAmount;
cp2y *= partialPointAmount;
}
mergingShape->cubicTo(previousX - cp1x, previousY - cp1y, x + cp2x, y + cp2y, x, y);
} else {
mergingShape->lineTo(x, y);
Point in2 = {previousX - cp1x, previousY - cp1y};
Point in3 = {x + cp2x, y + cp2y};
Point in4 = {x, y};
if (transform) {
mathTransform(transform, &in2);
mathTransform(transform, &in3);
mathTransform(transform, &in4);
}
mergingShape->cubicTo(in2.x, in2.y, in3.x, in3.y, in4.x, in4.y);
} else {
Point in = {x, y};
if (transform) mathTransform(transform, &in);
mergingShape->lineTo(in.x, in.y);
}
angle += dTheta * direction;
longSegment = !longSegment;
}
mergingShape->close();
}
static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, int32_t frameNo, Shape* mergingShape)
static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* transform, int32_t frameNo, Shape* mergingShape)
{
const static auto POLYGON_MAGIC_NUMBER = 0.25f;
static constexpr auto POLYGON_MAGIC_NUMBER = 0.25f;
static constexpr auto K_PI = 3.141592f;
auto ptsCnt = size_t(floor(star->ptsCnt(frameNo)));
@ -359,7 +369,9 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, int32_t fr
hasRoundness = true;
}
mergingShape->moveTo(x, y);
Point in = {x, y};
if (transform) mathTransform(transform, &in);
mergingShape->moveTo(in.x, in.y);
for (size_t i = 0; i < ptsCnt; i++) {
auto previousX = x;
@ -380,9 +392,19 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, int32_t fr
auto cp2x = radius * roundness * POLYGON_MAGIC_NUMBER * cp2Dx;
auto cp2y = radius * roundness * POLYGON_MAGIC_NUMBER * cp2Dy;
mergingShape->cubicTo(previousX - cp1x, previousY - cp1y, x + cp2x, y + cp2y, x, y);
Point in2 = {previousX - cp1x, previousY - cp1y};
Point in3 = {x + cp2x, y + cp2y};
Point in4 = {x, y};
if (transform) {
mathTransform(transform, &in2);
mathTransform(transform, &in3);
mathTransform(transform, &in4);
}
mergingShape->cubicTo(in2.x, in2.y, in3.x, in3.y, in4.x, in4.y);
} else {
mergingShape->lineTo(x, y);
Point in = {x, y};
if (transform) mathTransform(transform, &in);
mergingShape->lineTo(in.x, in.y);
}
angle += anglePerPoint * direction;
}
@ -398,21 +420,20 @@ static Shape* _updatePolystar(LottieGroup* parent, LottiePolyStar* star, int32_t
parent->scene->push(std::move(newShape));
}
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, frameNo, mergingShape);
else _updatePolygon(parent, star, frameNo, mergingShape);
//Optimize: Can we skip the individual coords transform?
Matrix matrix;
mathIdentity(&matrix);
auto position = star->position(frameNo);
mathTranslate(&matrix, position.x, position.y);
mathRotate(&matrix, star->rotation(frameNo) * 2.0f);
auto identity = mathIdentity((const Matrix*)&matrix);
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, mergingShape);
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, mergingShape);
P(mergingShape)->update(RenderUpdateFlag::Path);
auto pos = star->position(frameNo);
auto rotation = star->rotation(frameNo);
if (rotation == 0.0f && pos.x == 0.0f && pos.y == 0.0f) return mergingShape;
auto matrix = mergingShape->transform();
mathTranslate(&matrix, pos.x, pos.y);
mathRotate(&matrix, rotation * 2.0f);
mergingShape->transform(matrix);
return mergingShape;
}

View file

@ -754,38 +754,21 @@ LottieObject* LottieParser::parseObject()
auto type = getString();
if (!type) return nullptr;
if (!strcmp(type, "gr")) {
return parseGroup();
} else if (!strcmp(type, "rc")) {
return parseRect();
} else if (!strcmp(type, "el")) {
return parseEllipse();
} else if (!strcmp(type, "tr")) {
return parseTransform();
} else if (!strcmp(type, "fl")) {
return parseSolidFill();
} else if (!strcmp(type, "st")) {
return parseSolidStroke();
} else if (!strcmp(type, "sh")) {
return parsePath();
} else if (!strcmp(type, "sr")) {
TVGERR("LOTTIE", "Polystar(sr) is not supported");
return parsePolyStar();
} else if (!strcmp(type, "rd")) {
return parseRoundedCorner();
} else if (!strcmp(type, "gf")) {
return parseGradientFill();
} else if (!strcmp(type, "gs")) {
return parseGradientStroke();
} else if (!strcmp(type, "tm")) {
TVGERR("LOTTIE", "Trimpath(tm) is not supported");
} else if (!strcmp(type, "rp")) {
TVGERR("LOTTIE", "Repeater(rp) is not supported yet");
} else if (!strcmp(type, "mm")) {
TVGERR("LOTTIE", "MergePath(mm) is not supported yet");
} else {
TVGERR("LOTTIE", "Unkown object type(%s) is given", type);
}
if (!strcmp(type, "gr")) return parseGroup();
else if (!strcmp(type, "rc")) return parseRect();
else if (!strcmp(type, "el")) return parseEllipse();
else if (!strcmp(type, "tr")) return parseTransform();
else if (!strcmp(type, "fl")) return parseSolidFill();
else if (!strcmp(type, "st")) return parseSolidStroke();
else if (!strcmp(type, "sh")) return parsePath();
else if (!strcmp(type, "sr")) return parsePolyStar();
else if (!strcmp(type, "rd")) return parseRoundedCorner();
else if (!strcmp(type, "gf")) return parseGradientFill();
else if (!strcmp(type, "gs")) return parseGradientStroke();
else if (!strcmp(type, "tm")) TVGERR("LOTTIE", "Trimpath(tm) is not supported");
else if (!strcmp(type, "rp")) TVGERR("LOTTIE", "Repeater(rp) is not supported yet");
else if (!strcmp(type, "mm")) TVGERR("LOTTIE", "MergePath(mm) is not supported yet");
else TVGERR("LOTTIE", "Unkown object type(%s) is given", type);
return nullptr;
}

View file

@ -90,6 +90,15 @@ static inline void mathIdentity(Matrix* m)
}
static inline void mathTransform(Matrix* transform, Point* coord)
{
auto x = coord->x;
auto y = coord->y;
coord->x = x * transform->e11 + y * transform->e12 + transform->e13;
coord->y = x * transform->e21 + y * transform->e22 + transform->e23;
}
static inline void mathScale(Matrix* m, float sx, float sy)
{
m->e11 *= sx;