mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
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:
parent
fa49f14412
commit
269e6c4d10
5 changed files with 41 additions and 21 deletions
|
@ -174,6 +174,12 @@ void operator*=(Point& pt, const Matrix& m);
|
||||||
Point operator*(const Point& pt, const Matrix& m);
|
Point operator*(const Point& pt, const Matrix& m);
|
||||||
Point normal(const Point& p1, const Point& p2);
|
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)
|
static inline bool zero(const Point& p)
|
||||||
{
|
{
|
||||||
return tvg::zero(p.x) && tvg::zero(p.y);
|
return tvg::zero(p.x) && tvg::zero(p.y);
|
||||||
|
|
|
@ -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);
|
else shape->appendPath(commands, 5, points, 4);
|
||||||
//round rect
|
//round rect
|
||||||
} else {
|
} 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);
|
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)
|
void LottieBuilder::updatePath(LottieGroup* parent, LottieObject** child, float frameNo, TVG_UNUSED Inlist<RenderContext>& contexts, RenderContext* ctx)
|
||||||
{
|
{
|
||||||
auto path = static_cast<LottiePath*>(*child);
|
auto path = static_cast<LottiePath*>(*child);
|
||||||
//TODO: use direction for paths' offsetPath
|
|
||||||
if (!ctx->repeaters.empty()) {
|
if (!ctx->repeaters.empty()) {
|
||||||
auto shape = path->pooling();
|
auto shape = path->pooling();
|
||||||
shape->reset();
|
shape->reset();
|
||||||
|
@ -690,11 +690,11 @@ static void _updateStar(TVG_UNUSED LottieGroup* parent, LottiePolyStar* star, Ma
|
||||||
if (offsetPath) {
|
if (offsetPath) {
|
||||||
auto intermediate = Shape::gen();
|
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);
|
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 {
|
} 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);
|
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) {
|
if (offsetPath) {
|
||||||
auto intermediate = Shape::gen();
|
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);
|
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 {
|
} 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);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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)
|
static Line _offset(const Point& p1, const Point& p2, float offset)
|
||||||
{
|
{
|
||||||
auto scaledNormal = normal(p1, p2) * 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);
|
} 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
|
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])) {
|
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);
|
outCmds.reserve(inCmdsCnt * 2);
|
||||||
outPts.reserve(inPtsCnt * (join == StrokeJoin::Round ? 4 : 2));
|
outPts.reserve(inPtsCnt * (join == StrokeJoin::Round ? 4 : 2));
|
||||||
|
|
||||||
Array<Bezier> stack{5};
|
Array<Bezier> stack{5};
|
||||||
State state;
|
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;
|
auto threshold = 1.0f / fabsf(offset) + 1.0f;
|
||||||
|
|
||||||
for (uint32_t iCmd = 0, iPt = 0; iCmd < inCmdsCnt; ++iCmd) {
|
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 {
|
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, clockwise);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,9 @@ struct LottieOffsetModifier
|
||||||
|
|
||||||
LottieOffsetModifier(float offset, float miter = 4.0f, StrokeJoin join = StrokeJoin::Round) : offset(offset), miterLimit(miter), join(join) {};
|
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 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, bool clockwise) 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, bool clockwise) 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;
|
bool modifyEllipse(float& rx, float& ry) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -438,11 +438,11 @@ struct LottiePathSet : LottieProperty
|
||||||
Array<PathCommand> cmds1(path->cmdsCnt);
|
Array<PathCommand> cmds1(path->cmdsCnt);
|
||||||
Array<Point> pts1(path->ptsCnt);
|
Array<Point> pts1(path->ptsCnt);
|
||||||
roundness->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, cmds1, pts1, transform);
|
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);
|
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, cmds);
|
||||||
_copy(path, pts, transform);
|
_copy(path, pts, transform);
|
||||||
|
@ -474,9 +474,9 @@ struct LottiePathSet : LottieProperty
|
||||||
Array<PathCommand> cmds1;
|
Array<PathCommand> cmds1;
|
||||||
Array<Point> pts1;
|
Array<Point> pts1;
|
||||||
roundness->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, cmds1, pts1, nullptr);
|
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 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);
|
free(interpPts);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue