lottie: ensuring rectangle closure

A rectangle with roundness = 0 is the only shape where
one of its sides is created using a close command. This
exceptional case requires additional handling of the close
command for every modifier. By adding an extra lineTo
command to the rectangle path, its becomes consistent with
other shapes, eliminating the special case inside modifiers
algorithms.
This commit is contained in:
Mira Grudzinska 2025-06-23 23:27:27 +02:00
parent 1ac6f3d09f
commit f8064f3b31
2 changed files with 20 additions and 15 deletions

View file

@ -392,12 +392,29 @@ static void _repeat(LottieGroup* parent, Shape* path, RenderContext* ctx)
}
static void _close(RenderPath& path, const Point& p, bool round, bool rect = false)
{
//the only case where the shape was truly closed via a 'close' command - change important for modifiers to ensure consistency with other cases
if (rect) {
if (!round) {
path.pts.push(p);
path.cmds.last() = PathCommand::LineTo;
path.cmds.push(PathCommand::Close);
}
return;
}
if (round && tvg::zero(path.pts.last() - path.pts[path.pts.count - 2])) path.pts[path.pts.count - 2] = p;
path.pts.last() = p;
}
void LottieBuilder::appendRect(Shape* shape, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx)
{
auto temp = (ctx->offset) ? Shape::gen() : shape;
auto cnt = SHAPE(temp)->rs.path.pts.count;
temp->appendRect(pos.x, pos.y, size.x, size.y, r, r, clockwise);
_close(SHAPE(temp)->rs.path, SHAPE(temp)->rs.path.pts[cnt], r > 0.0f, true);
if (ctx->transform) {
for (auto i = cnt; i < SHAPE(temp)->rs.path.pts.count; ++i) {
@ -489,13 +506,6 @@ void LottieBuilder::updatePath(LottieGroup* parent, LottieObject** child, float
}
static void _close(Array<Point>& pts, const Point& p, bool round)
{
if (round && tvg::zero(pts.last() - pts[pts.count - 2])) pts[pts.count - 2] = p;
pts.last() = p;
}
void LottieBuilder::updateStar(LottiePolyStar* star, float frameNo, Matrix* transform, Shape* merging, RenderContext* ctx, Tween& tween, LottieExpressions* exps)
{
static constexpr auto POLYSTAR_MAGIC_NUMBER = 0.47829f / 0.28f;
@ -604,7 +614,7 @@ void LottieBuilder::updateStar(LottiePolyStar* star, float frameNo, Matrix* tran
longSegment = !longSegment;
}
//ensure proper shape closure - important for modifiers that behave differently for degenerate (linear) vs curved cubics
_close(SHAPE(shape)->rs.path.pts, in, hasRoundness);
_close(SHAPE(shape)->rs.path, in, hasRoundness);
shape->close();
if (ctx->modifier) ctx->modifier->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, outerRoundness, hasRoundness);
@ -674,7 +684,7 @@ void LottieBuilder::updatePolygon(LottieGroup* parent, LottiePolyStar* star, flo
angle += anglePerPoint * direction;
}
//ensure proper shape closure - important for modifiers that behave differently for degenerate (linear) vs curved cubics
_close(SHAPE(shape)->rs.path.pts, in, hasRoundness);
_close(SHAPE(shape)->rs.path, in, hasRoundness);
shape->close();
if (ctx->modifier) ctx->modifier->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, 0.0f, false);

View file

@ -377,12 +377,7 @@ bool LottieOffsetModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, P
}
iPt += 3;
}
else {
if (!tvg::zero(inPts[iPt - 1] - inPts[state.movetoInIndex])) {
out.cmds.push(PathCommand::LineTo);
corner(out, state.line, state.firstLine, state.movetoOutIndex, true);
}
} else {
out.cmds.push(PathCommand::Close);
}
}