lottie: offset does not depend on shape direction

According to tests in AE, the offset direction should
not depend on the direction of the shape. A positive
offset value expands the shape, while a negative value
contracts it. Fixed.
This commit is contained in:
Mira Grudzinska 2024-10-17 18:30:36 +07:00 committed by Hermet Park
parent fa49f14412
commit 269e6c4d10
5 changed files with 41 additions and 21 deletions

View file

@ -174,6 +174,12 @@ void operator*=(Point& pt, const Matrix& m);
Point operator*(const Point& pt, const Matrix& m);
Point normal(const Point& p1, const Point& p2);
static inline float cross(const Point& lhs, const Point& rhs)
{
return lhs.x * rhs.y - rhs.x * lhs.y;
}
static inline bool zero(const Point& p)
{
return tvg::zero(p.x) && tvg::zero(p.y);

View file

@ -407,7 +407,7 @@ static void _appendRect(Shape* shape, float x, float y, float w, float h, float
}
}
if (offsetPath) offsetPath->modifyRect(commands, 5, points, 4, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, clockwise);
if (offsetPath) offsetPath->modifyRect(commands, 5, points, 4, P(shape)->rs.path.cmds, P(shape)->rs.path.pts);
else shape->appendPath(commands, 5, points, 4);
//round rect
} else {
@ -460,7 +460,7 @@ static void _appendRect(Shape* shape, float x, float y, float w, float h, float
}
}
if (offsetPath) offsetPath->modifyRect(commands, cmdCnt, points, ptsCnt, P(shape)->rs.path.cmds, P(shape)->rs.path.pts, clockwise);
if (offsetPath) offsetPath->modifyRect(commands, cmdCnt, points, ptsCnt, P(shape)->rs.path.cmds, P(shape)->rs.path.pts);
else shape->appendPath(commands, cmdCnt, points, ptsCnt);
}
}
@ -555,7 +555,7 @@ void LottieBuilder::updateEllipse(LottieGroup* parent, LottieObject** child, flo
void LottieBuilder::updatePath(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
{
auto path = static_cast<LottiePath*>(*child);
//TODO: use direction for paths' offsetPath
if (!ctx->repeaters.empty()) {
auto shape = path->pooling();
shape->reset();
@ -690,11 +690,11 @@ static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Ma
if (offsetPath) {
auto intermediate = Shape::gen();
roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, outerRoundness, hasRoundness);
offsetPath->modifyPolystar(P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, star->clockwise);
offsetPath->modifyPolystar(P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts);
} else {
roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, outerRoundness, hasRoundness);
}
} else if (offsetPath) offsetPath->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, star->clockwise);
} else if (offsetPath) offsetPath->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts);
}
@ -776,11 +776,11 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr
if (offsetPath) {
auto intermediate = Shape::gen();
roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, 0.0f, false);
offsetPath->modifyPolystar(P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, star->clockwise);
offsetPath->modifyPolystar(P(intermediate)->rs.path.cmds, P(intermediate)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts);
} else {
roundness->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, 0.0f, false);
}
} else if (offsetPath) offsetPath->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts, star->clockwise);
} else if (offsetPath) offsetPath->modifyPolystar(P(shape)->rs.path.cmds, P(shape)->rs.path.pts, P(merging)->rs.path.cmds, P(merging)->rs.path.pts);
}

View file

@ -79,7 +79,20 @@ static bool _intersect(const Line& line1, const Line& line2, Point& intersection
static Line _offset(const Point& p1, const Point& p2, float offset)
{
auto scaledNormal = normal(p1, p2) * offset;
return {p1 - scaledNormal, p2 - scaledNormal};
return {p1 + scaledNormal, p2 + scaledNormal};
}
static bool _clockwise(const Point* pts, uint32_t n)
{
auto area = 0.0f;
for (uint32_t i = 0; i < n - 1; i++) {
area += cross(pts[i], pts[i + 1]);
}
area += cross(pts[n - 1], pts[0]);;
return area < 0.0f;
}
@ -113,6 +126,7 @@ void LottieOffsetModifier::corner(const Line& line, const Line& nextLine, uint32
} else outPts.push(line.pt2);
}
void LottieOffsetModifier::line(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t& currentPt, uint32_t currentCmd, State& state, bool degenerated, Array<PathCommand>& outCmds, Array<Point>& outPts, float offset) const
{
if (tvg::zero(inPts[currentPt - 1] - inPts[currentPt])) {
@ -288,14 +302,14 @@ bool LottieRoundnessModifier::modifyRect(const Point& size, float& r) const
}
bool LottieOffsetModifier::modifyPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array<PathCommand>& outCmds, Array<Point>& outPts, bool clockwise) const
bool LottieOffsetModifier::modifyPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array<PathCommand>& outCmds, Array<Point>& outPts) const
{
outCmds.reserve(inCmdsCnt * 2);
outPts.reserve(inPtsCnt * (join == StrokeJoin::Round ? 4 : 2));
Array<Bezier> stack{5};
State state;
auto offset = clockwise ? this->offset : -this->offset;
auto offset = _clockwise(inPts, inPtsCnt) ? this->offset : -this->offset;
auto threshold = 1.0f / fabsf(offset) + 1.0f;
for (uint32_t iCmd = 0, iPt = 0; iCmd < inCmdsCnt; ++iCmd) {
@ -362,14 +376,14 @@ bool LottieOffsetModifier::modifyPath(const PathCommand* inCmds, uint32_t inCmds
}
bool LottieOffsetModifier::modifyPolystar(const Array<PathCommand>& inCmds, const Array<Point>& inPts, Array<PathCommand>& outCmds, Array<Point>& outPts, bool clockwise) const {
return modifyPath(inCmds.data, inCmds.count, inPts.data, inPts.count, outCmds, outPts, clockwise);
bool LottieOffsetModifier::modifyPolystar(const Array<PathCommand>& inCmds, const Array<Point>& inPts, Array<PathCommand>& outCmds, Array<Point>& outPts) const {
return modifyPath(inCmds.data, inCmds.count, inPts.data, inPts.count, outCmds, outPts);
}
bool LottieOffsetModifier::modifyRect(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array<PathCommand>& outCmds, Array<Point>& outPts, bool clockwise) const
bool LottieOffsetModifier::modifyRect(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array<PathCommand>& outCmds, Array<Point>& outPts) const
{
return modifyPath(inCmds, inCmdsCnt, inPts, inPtsCnt, outCmds, outPts, clockwise);
return modifyPath(inCmds, inCmdsCnt, inPts, inPtsCnt, outCmds, outPts);
}

View file

@ -49,9 +49,9 @@ struct LottieOffsetModifier
LottieOffsetModifier(float offset, float miter = 4.0f, StrokeJoin join = StrokeJoin::Round) : offset(offset), miterLimit(miter), join(join) {};
bool modifyPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array<PathCommand>& outCmds, Array<Point>& outPts, bool clockwise) const;
bool modifyPolystar(const Array<PathCommand>& inCmds, const Array<Point>& inPts, Array<PathCommand>& outCmds, Array<Point>& outPts, bool clockwise) const;
bool modifyRect(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array<PathCommand>& outCmds, Array<Point>& outPts, bool clockwise) const;
bool modifyPath(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array<PathCommand>& outCmds, Array<Point>& outPts) const;
bool modifyPolystar(const Array<PathCommand>& inCmds, const Array<Point>& inPts, Array<PathCommand>& outCmds, Array<Point>& outPts) const;
bool modifyRect(const PathCommand* inCmds, uint32_t inCmdsCnt, const Point* inPts, uint32_t inPtsCnt, Array<PathCommand>& outCmds, Array<Point>& outPts) const;
bool modifyEllipse(float& rx, float& ry) const;
private:

View file

@ -438,11 +438,11 @@ struct LottiePathSet : LottieProperty
Array<PathCommand> cmds1(path->cmdsCnt);
Array<Point> pts1(path->ptsCnt);
roundness->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, cmds1, pts1, transform);
return offsetPath->modifyPath(cmds1.data, cmds1.count, pts1.data, pts1.count, cmds, pts, true);
return offsetPath->modifyPath(cmds1.data, cmds1.count, pts1.data, pts1.count, cmds, pts);
}
return roundness->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, cmds, pts, transform);
}
if (offsetPath) return offsetPath->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, cmds, pts, true);
if (offsetPath) return offsetPath->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, cmds, pts);
_copy(path, cmds);
_copy(path, pts, transform);
@ -474,9 +474,9 @@ struct LottiePathSet : LottieProperty
Array<PathCommand> cmds1;
Array<Point> pts1;
roundness->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, cmds1, pts1, nullptr);
offsetPath->modifyPath(cmds1.data, cmds1.count, pts1.data, pts1.count, cmds, pts, true);
offsetPath->modifyPath(cmds1.data, cmds1.count, pts1.data, pts1.count, cmds, pts);
} else roundness->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, cmds, pts, nullptr);
} else if (offsetPath) offsetPath->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, cmds, pts, true);
} else if (offsetPath) offsetPath->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, cmds, pts);
free(interpPts);