diff --git a/src/loaders/lottie/tvgLottieBuilder.cpp b/src/loaders/lottie/tvgLottieBuilder.cpp index b4dd3266..ba50d8b0 100644 --- a/src/loaders/lottie/tvgLottieBuilder.cpp +++ b/src/loaders/lottie/tvgLottieBuilder.cpp @@ -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); + 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 += 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; } diff --git a/src/loaders/lottie/tvgLottieParser.cpp b/src/loaders/lottie/tvgLottieParser.cpp index 5f2ff7c2..53317ae6 100644 --- a/src/loaders/lottie/tvgLottieParser.cpp +++ b/src/loaders/lottie/tvgLottieParser.cpp @@ -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; } diff --git a/src/utils/tvgMath.h b/src/utils/tvgMath.h index 7e9781c2..1c64536a 100644 --- a/src/utils/tvgMath.h +++ b/src/utils/tvgMath.h @@ -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;