lottie: revised the shape modifiers

- use a decoration style for path-modification chaining.
- use a reusable buffer for intermediate path generation.
This commit is contained in:
Hermet Park 2025-02-06 01:34:39 +09:00 committed by Hermet Park
parent f4a2c922be
commit 2a4dfcd10e
6 changed files with 160 additions and 115 deletions

View file

@ -233,7 +233,7 @@ static void _updateStroke(LottieStroke* stroke, float frameNo, RenderContext* ct
}
static bool _fragmented(LottieGroup* parent, LottieObject** child, Inlist<RenderContext>& contexts, RenderContext* ctx)
bool LottieBuilder::fragmented(LottieGroup* parent, LottieObject** child, Inlist<RenderContext>& contexts, RenderContext* ctx)
{
if (!ctx->reqFragment) return false;
if (ctx->fragmenting) return true;
@ -249,7 +249,7 @@ static bool _fragmented(LottieGroup* parent, LottieObject** child, Inlist<Render
void LottieBuilder::updateSolidStroke(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx)
{
if (_fragmented(parent, child, contexts, ctx)) return;
if (fragmented(parent, child, contexts, ctx)) return;
auto stroke = static_cast<LottieSolidStroke*>(*child);
@ -262,7 +262,7 @@ void LottieBuilder::updateSolidStroke(LottieGroup* parent, LottieObject** child,
void LottieBuilder::updateGradientStroke(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx)
{
if (_fragmented(parent, child, contexts, ctx)) return;
if (fragmented(parent, child, contexts, ctx)) return;
auto stroke = static_cast<LottieGradientStroke*>(*child);
@ -274,7 +274,7 @@ void LottieBuilder::updateGradientStroke(LottieGroup* parent, LottieObject** chi
void LottieBuilder::updateSolidFill(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx)
{
if (_fragmented(parent, child, contexts, ctx)) return;
if (fragmented(parent, child, contexts, ctx)) return;
auto fill = static_cast<LottieSolidFill*>(*child);
@ -289,7 +289,7 @@ void LottieBuilder::updateSolidFill(LottieGroup* parent, LottieObject** child, f
void LottieBuilder::updateGradientFill(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& contexts, RenderContext* ctx)
{
if (_fragmented(parent, child, contexts, ctx)) return;
if (fragmented(parent, child, contexts, ctx)) return;
auto fill = static_cast<LottieGradientFill*>(*child);
@ -547,11 +547,11 @@ void LottieBuilder::updatePath(LottieGroup* parent, LottieObject** child, float
if (!ctx->repeaters.empty()) {
auto shape = path->pooling();
shape->reset();
path->pathset(frameNo, SHAPE(shape)->rs.path, ctx->transform, exps, ctx->roundness, ctx->offset);
path->pathset(frameNo, SHAPE(shape)->rs.path, ctx->transform, exps, ctx->modifier);
_repeat(parent, shape, ctx);
} else {
_draw(parent, path, ctx);
if (path->pathset(frameNo, SHAPE(ctx->merging)->rs.path, ctx->transform, exps, ctx->roundness, ctx->offset)) {
if (path->pathset(frameNo, SHAPE(ctx->merging)->rs.path, ctx->transform, exps, ctx->modifier)) {
PAINT(ctx->merging)->update(RenderUpdateFlag::Path);
}
}
@ -674,13 +674,7 @@ void LottieBuilder::updateStar(LottiePolyStar* star, float frameNo, Matrix* tran
}
shape->close();
if (roundedCorner) {
if (ctx->offset) {
buffer.clear();
ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, buffer, outerRoundness, hasRoundness);
ctx->offset->modifyPolystar(buffer, SHAPE(merging)->rs.path);
} else ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, outerRoundness, hasRoundness);
} else if (ctx->offset) ctx->offset->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path);
if (ctx->modifier) ctx->modifier->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, outerRoundness, hasRoundness);
}
@ -758,13 +752,7 @@ void LottieBuilder::updatePolygon(LottieGroup* parent, LottiePolyStar* star, flo
}
shape->close();
if (roundedCorner) {
if (ctx->offset) {
buffer.clear();
ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, buffer, 0.0f, false);
ctx->offset->modifyPolystar(buffer, SHAPE(merging)->rs.path);
} else ctx->roundness->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, 0.0f, false);
} else if (ctx->offset) ctx->offset->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path);
if (ctx->modifier) ctx->modifier->modifyPolystar(SHAPE(shape)->rs.path, SHAPE(merging)->rs.path, 0.0f, false);
}
@ -803,8 +791,10 @@ void LottieBuilder::updateRoundedCorner(TVG_UNUSED LottieGroup* parent, LottieOb
auto r = roundedCorner->radius(frameNo, exps);
if (r < LottieRoundnessModifier::ROUNDNESS_EPSILON) return;
if (!ctx->roundness) ctx->roundness = new LottieRoundnessModifier(r);
if (!ctx->roundness) ctx->roundness = new LottieRoundnessModifier(&buffer, r);
else if (ctx->roundness->r < r) ctx->roundness->r = r;
ctx->update(ctx->roundness);
}
@ -812,6 +802,8 @@ void LottieBuilder::updateOffsetPath(TVG_UNUSED LottieGroup* parent, LottieObjec
{
auto offset = static_cast<LottieOffsetPath*>(*child);
if (!ctx->offset) ctx->offset = new LottieOffsetModifier(offset->offset(frameNo, exps), offset->miterLimit(frameNo, exps), offset->join);
ctx->update(ctx->offset);
}
@ -1261,7 +1253,7 @@ void LottieBuilder::updateMasks(LottieLayer* layer, float frameNo)
} else {
//TODO: Once path direction support is implemented, ensure that the direction is ignored here
auto offset = LottieOffsetModifier(expand);
mask->pathset(frameNo, SHAPE(pShape)->rs.path, nullptr, exps, nullptr, &offset);
mask->pathset(frameNo, SHAPE(pShape)->rs.path, nullptr, exps, &offset);
}
if (fastTrack) return;
@ -1309,7 +1301,7 @@ void LottieBuilder::updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effec
auto idx = static_cast<uint32_t>(effect->mask(frameNo) - 1);
if (idx < 0 || idx >= layer->masks.count) return;
auto mask = layer->masks[idx];
mask->pathset(frameNo, SHAPE(shape)->rs.path, nullptr, exps, nullptr, nullptr);
mask->pathset(frameNo, SHAPE(shape)->rs.path, nullptr, exps);
}
shape->transform(layer->cache.matrix);

View file

@ -57,6 +57,7 @@ struct RenderContext
Matrix* transform = nullptr;
LottieRoundnessModifier* roundness = nullptr;
LottieOffsetModifier* offset = nullptr;
LottieModifier* modifier = nullptr;
bool fragmenting = false; //render context has been fragmented by filling
bool reqFragment = false; //requirement to fragment the render context
@ -81,8 +82,20 @@ struct RenderContext
propagator->ref();
this->propagator = propagator;
repeaters = rhs.repeaters;
if (rhs.roundness) roundness = new LottieRoundnessModifier(rhs.roundness->r);
if (rhs.offset) offset = new LottieOffsetModifier(rhs.offset->offset, rhs.offset->miterLimit, rhs.offset->join);
if (rhs.roundness) {
roundness = new LottieRoundnessModifier(rhs.roundness->buffer, rhs.roundness->r);
update(roundness);
}
if (rhs.offset) {
offset = new LottieOffsetModifier(rhs.offset->offset, rhs.offset->miterLimit, rhs.offset->join);
update(offset);
}
}
void update(LottieModifier* next)
{
if (modifier) modifier = modifier->decorate(next);
else modifier = next;
}
};
@ -108,6 +121,7 @@ struct LottieBuilder
private:
void appendRect(Shape* shape, Point& pos, Point& size, float r, bool clockwise, RenderContext* ctx);
bool fragmented(LottieGroup* parent, LottieObject** child, Inlist<RenderContext>& contexts, RenderContext* ctx);
void updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo);
void updateEffect(LottieLayer* layer, float frameNo);

View file

@ -29,8 +29,7 @@
struct LottieExpression;
struct LottieComposition;
struct LottieLayer;
struct LottieRoundnessModifier;
struct LottieOffsetModifier;
struct LottieModifier;
#ifdef THORVG_LOTTIE_EXPRESSIONS_SUPPORT
@ -112,13 +111,13 @@ public:
}
template<typename Property>
bool result(float frameNo, RenderPath& out, Matrix* transform, LottieRoundnessModifier* roundness, LottieOffsetModifier* offset, LottieExpression* exp)
bool result(float frameNo, RenderPath& out, Matrix* transform, LottieModifier* modifier, LottieExpression* exp)
{
auto bm_rt = evaluate(frameNo, exp);
if (jerry_value_is_undefined(bm_rt)) return false;
if (auto pathset = static_cast<Property*>(jerry_object_get_native_ptr(bm_rt, nullptr))) {
(*pathset)(frameNo, out, transform, nullptr, roundness, offset);
(*pathset)(frameNo, out, transform, nullptr, modifier);
}
jerry_value_free(bm_rt);
return true;
@ -157,7 +156,7 @@ struct LottieExpressions
template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED Point&, LottieExpression*) { return false; }
template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED RGB24&, TVG_UNUSED LottieExpression*) { return false; }
template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED Fill*, TVG_UNUSED LottieExpression*) { return false; }
template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED RenderPath&, TVG_UNUSED Matrix*, TVG_UNUSED LottieRoundnessModifier*, TVG_UNUSED LottieOffsetModifier*, TVG_UNUSED LottieExpression*) { return false; }
template<typename Property> bool result(TVG_UNUSED float, TVG_UNUSED RenderPath&, TVG_UNUSED Matrix*, TVG_UNUSED LottieModifier*, TVG_UNUSED LottieExpression*) { return false; }
void update(TVG_UNUSED float) {}
static LottieExpressions* instance() { return nullptr; }
static void retrieve(TVG_UNUSED LottieExpressions* instance) {}

View file

@ -96,7 +96,7 @@ static bool _clockwise(Point* pts, uint32_t n)
}
void LottieOffsetModifier::corner(RenderPath& out, Line& line, Line& nextLine, uint32_t movetoOutIndex, bool nextClose) const
void LottieOffsetModifier::corner(RenderPath& out, Line& line, Line& nextLine, uint32_t movetoOutIndex, bool nextClose)
{
bool inside{};
Point intersect{};
@ -127,7 +127,7 @@ void LottieOffsetModifier::corner(RenderPath& out, Line& line, Line& nextLine, u
}
void LottieOffsetModifier::line(RenderPath& out, PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t& curPt, uint32_t curCmd, State& state, float offset, bool degenerated) const
void LottieOffsetModifier::line(RenderPath& out, PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t& curPt, uint32_t curCmd, State& state, float offset, bool degenerated)
{
if (tvg::zero(inPts[curPt - 1] - inPts[curPt])) {
++curPt;
@ -172,19 +172,23 @@ void LottieOffsetModifier::line(RenderPath& out, PathCommand* inCmds, uint32_t i
/* External Class Implementation */
/************************************************************************/
bool LottieRoundnessModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, Matrix* transform, RenderPath& out) const
bool LottieRoundnessModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, Matrix* transform, RenderPath& out)
{
out.cmds.reserve(inCmdsCnt * 2);
out.pts.reserve((uint32_t)(inPtsCnt * 1.5));
auto ptsCnt = out.pts.count;
buffer->clear();
auto& path = (next) ? *buffer : out;
path.cmds.reserve(inCmdsCnt * 2);
path.pts.reserve((uint32_t)(inPtsCnt * 1.5));
auto pivot = path.pts.count;
uint32_t startIndex = 0;
for (uint32_t iCmds = 0, iPts = 0; iCmds < inCmdsCnt; ++iCmds) {
switch (inCmds[iCmds]) {
case PathCommand::MoveTo: {
startIndex = out.pts.count;
out.cmds.push(PathCommand::MoveTo);
out.pts.push(inPts[iPts++]);
startIndex = path.pts.count;
path.cmds.push(PathCommand::MoveTo);
path.pts.push(inPts[iPts++]);
break;
}
case PathCommand::CubicTo: {
@ -196,52 +200,59 @@ bool LottieRoundnessModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt
if (inCmds[iCmds + 1] == PathCommand::CubicTo &&
tvg::zero(inPts[iPts + 2] - inPts[iPts + 3]) &&
tvg::zero(inPts[iPts + 4] - inPts[iPts + 5])) {
_roundCorner(out.cmds, out.pts, prev, curr, inPts[iPts + 5], r);
_roundCorner(path.cmds, path.pts, prev, curr, inPts[iPts + 5], r);
iPts += 3;
break;
} else if (inCmds[iCmds + 1] == PathCommand::Close) {
_roundCorner(out.cmds, out.pts, prev, curr, inPts[2], r);
out.pts[startIndex] = out.pts.last();
_roundCorner(path.cmds, path.pts, prev, curr, inPts[2], r);
path.pts[startIndex] = path.pts.last();
iPts += 3;
break;
}
}
out.cmds.push(PathCommand::CubicTo);
out.pts.push(inPts[iPts++]);
out.pts.push(inPts[iPts++]);
out.pts.push(inPts[iPts++]);
path.cmds.push(PathCommand::CubicTo);
path.pts.push(inPts[iPts++]);
path.pts.push(inPts[iPts++]);
path.pts.push(inPts[iPts++]);
break;
}
case PathCommand::Close: {
out.cmds.push(PathCommand::Close);
path.cmds.push(PathCommand::Close);
break;
}
default: break;
}
}
if (transform) {
for (auto i = ptsCnt; i < out.pts.count; ++i) {
out.pts[i] *= *transform;
for (auto i = pivot; i < path.pts.count; ++i) {
path.pts[i] *= *transform;
}
}
if (next) return next->modifyPath(path.cmds.data, path.cmds.count, path.pts.data, path.pts.count, transform, out);
return true;
}
bool LottieRoundnessModifier::modifyPolystar(RenderPath& in, RenderPath& out, float outerRoundness, bool hasRoundness) const
bool LottieRoundnessModifier::modifyPolystar(RenderPath& in, RenderPath& out, float outerRoundness, bool hasRoundness)
{
static constexpr auto ROUNDED_POLYSTAR_MAGIC_NUMBER = 0.47829f;
constexpr auto ROUNDED_POLYSTAR_MAGIC_NUMBER = 0.47829f;
buffer->clear();
auto& path = (next) ? *buffer : out;
auto len = length(in.pts[1] - in.pts[2]);
auto r = len > 0.0f ? ROUNDED_POLYSTAR_MAGIC_NUMBER * std::min(len * 0.5f, this->r) / len : 0.0f;
if (hasRoundness) {
out.cmds.grow((uint32_t)(1.5 * in.cmds.count));
out.pts.grow((uint32_t)(4.5 * in.cmds.count));
path.cmds.grow((uint32_t)(1.5 * in.cmds.count));
path.pts.grow((uint32_t)(4.5 * in.cmds.count));
int start = 3 * tvg::zero(outerRoundness);
out.cmds.push(PathCommand::MoveTo);
out.pts.push(in.pts[start]);
path.cmds.push(PathCommand::MoveTo);
path.pts.push(in.pts[start]);
for (uint32_t i = 1 + start; i < in.pts.count; i += 6) {
auto& prev = in.pts[i];
@ -256,21 +267,21 @@ bool LottieRoundnessModifier::modifyPolystar(RenderPath& in, RenderPath& out, fl
auto p2 = curr - dNext;
auto p3 = curr - 2.0f * dNext;
out.cmds.push(PathCommand::CubicTo);
out.pts.push(prev); out.pts.push(p0); out.pts.push(p0);
out.cmds.push(PathCommand::CubicTo);
out.pts.push(p1); out.pts.push(p2); out.pts.push(p3);
out.cmds.push(PathCommand::CubicTo);
out.pts.push(p3); out.pts.push(next); out.pts.push(nextCtrl);
path.cmds.push(PathCommand::CubicTo);
path.pts.push(prev); path.pts.push(p0); path.pts.push(p0);
path.cmds.push(PathCommand::CubicTo);
path.pts.push(p1); path.pts.push(p2); path.pts.push(p3);
path.cmds.push(PathCommand::CubicTo);
path.pts.push(p3); path.pts.push(next); path.pts.push(nextCtrl);
}
} else {
out.cmds.grow(2 * in.cmds.count);
out.pts.grow(4 * in.cmds.count);
path.cmds.grow(2 * in.cmds.count);
path.pts.grow(4 * in.cmds.count);
auto dPrev = r * (in.pts[1] - in.pts[0]);
auto p = in.pts[0] + 2.0f * dPrev;
out.cmds.push(PathCommand::MoveTo);
out.pts.push(p);
path.cmds.push(PathCommand::MoveTo);
path.pts.push(p);
for (uint32_t i = 1; i < in.pts.count; ++i) {
auto& curr = in.pts[i];
@ -282,28 +293,33 @@ bool LottieRoundnessModifier::modifyPolystar(RenderPath& in, RenderPath& out, fl
auto p2 = curr - dNext;
auto p3 = curr - 2.0f * dNext;
out.cmds.push(PathCommand::LineTo);
out.pts.push(p0);
out.cmds.push(PathCommand::CubicTo);
out.pts.push(p1); out.pts.push(p2); out.pts.push(p3);
path.cmds.push(PathCommand::LineTo);
path.pts.push(p0);
path.cmds.push(PathCommand::CubicTo);
path.pts.push(p1); path.pts.push(p2); path.pts.push(p3);
dPrev = -1.0f * dNext;
}
}
out.cmds.push(PathCommand::Close);
path.cmds.push(PathCommand::Close);
if (next) return next->modifyPolystar(path, out, outerRoundness, hasRoundness);
return true;
}
bool LottieRoundnessModifier::modifyRect(Point& size, float& r) const
bool LottieRoundnessModifier::modifyRect(Point& size, float& r)
{
r = std::min(this->r, std::max(size.x, size.y) * 0.5f);
return true;
}
bool LottieOffsetModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, RenderPath& out) const
bool LottieOffsetModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, TVG_UNUSED Matrix* transform, RenderPath& out)
{
if (next) TVGERR("LOTTIE", "Offset has a next modifier?");
out.cmds.reserve(inCmdsCnt * 2);
out.pts.reserve(inPtsCnt * (join == StrokeJoin::Round ? 4 : 2));
@ -376,18 +392,19 @@ bool LottieOffsetModifier::modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, P
}
bool LottieOffsetModifier::modifyPolystar(RenderPath& in, RenderPath& out) const {
return modifyPath(in.cmds.data, in.cmds.count, in.pts.data, in.pts.count, out);
}
bool LottieOffsetModifier::modifyRect(RenderPath& in, RenderPath& out) const
bool LottieOffsetModifier::modifyPolystar(RenderPath& in, RenderPath& out, TVG_UNUSED float, TVG_UNUSED bool)
{
return modifyPath(in.cmds.data, in.cmds.count, in.pts.data, in.pts.count, out);
return modifyPath(in.cmds.data, in.cmds.count, in.pts.data, in.pts.count, nullptr, out);
}
bool LottieOffsetModifier::modifyEllipse(Point& radius) const
bool LottieOffsetModifier::modifyRect(RenderPath& in, RenderPath& out)
{
return modifyPath(in.cmds.data, in.cmds.count, in.pts.data, in.pts.count, nullptr, out);
}
bool LottieOffsetModifier::modifyEllipse(Point& radius)
{
radius.x += offset;
radius.y += offset;

View file

@ -28,31 +28,69 @@
#include "tvgMath.h"
#include "tvgRender.h"
struct LottieRoundnessModifier
struct LottieModifier
{
enum Type : uint8_t {Roundness = 0, Offset};
LottieModifier* next = nullptr;
Type type;
virtual ~LottieModifier() {}
virtual bool modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, Matrix* transform, RenderPath& out) = 0;
virtual bool modifyPolystar(RenderPath& in, RenderPath& out, float outerRoundness, bool hasRoundness) = 0;
LottieModifier* decorate(LottieModifier* next)
{
/* TODO: build the decorative chaining here.
currently we only have roundness and offset. */
//roundness -> offset
if (next->type == Roundness) {
next->next = this;
return next;
}
//just in the order.
this->next = next;
return this;
}
};
struct LottieRoundnessModifier : LottieModifier
{
static constexpr float ROUNDNESS_EPSILON = 1.0f;
RenderPath* buffer;
float r;
LottieRoundnessModifier(float r) : r(r) {};
LottieRoundnessModifier(RenderPath* buffer, float r) : buffer(buffer), r(r)
{
type = Roundness;
}
bool modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, Matrix* transform, RenderPath& out) const;
bool modifyPolystar(RenderPath& in, RenderPath& out, float outerRoundness, bool hasRoundness) const;
bool modifyRect(Point& size, float& r) const;
bool modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, Matrix* transform, RenderPath& out) override;
bool modifyPolystar(RenderPath& in, RenderPath& out, float outerRoundness, bool hasRoundness) override;
bool modifyRect(Point& size, float& r);
};
struct LottieOffsetModifier
struct LottieOffsetModifier : LottieModifier
{
float offset;
float miterLimit;
StrokeJoin join;
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)
{
type = Offset;
}
bool modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, RenderPath& out) const;
bool modifyPolystar(RenderPath& in, RenderPath& out) const;
bool modifyRect(RenderPath& in, RenderPath& out) const;
bool modifyEllipse(Point& radius) const;
bool modifyPath(PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t inPtsCnt, Matrix* transform, RenderPath& out) override;
bool modifyPolystar(RenderPath& in, RenderPath& out, float outerRoundness, bool hasRoundness) override;
bool modifyRect(RenderPath& in, RenderPath& out);
bool modifyEllipse(Point& radius);
private:
struct State
@ -64,8 +102,8 @@ private:
uint32_t movetoInIndex = 0;
};
void line(RenderPath& out, PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t& curPt, uint32_t curCmd, State& state, float offset, bool degenerated) const;
void corner(RenderPath& out, Line& line, Line& nextLine, uint32_t movetoIndex, bool nextClose) const;
void line(RenderPath& out, PathCommand* inCmds, uint32_t inCmdsCnt, Point* inPts, uint32_t& curPt, uint32_t curCmd, State& state, float offset, bool degenerated);
void corner(RenderPath& out, Line& line, Line& nextLine, uint32_t movetoIndex, bool nextClose);
};
#endif

View file

@ -467,7 +467,7 @@ struct LottiePathSet : LottieProperty
return true;
}
bool modifiedPath(float frameNo, RenderPath& out, Matrix* transform, const LottieRoundnessModifier* roundness, const LottieOffsetModifier* offset)
bool modifiedPath(float frameNo, RenderPath& out, Matrix* transform, LottieModifier* modifier)
{
PathSet* path;
LottieScalarFrame<PathSet>* frame;
@ -475,17 +475,7 @@ struct LottiePathSet : LottieProperty
float t;
if (dispatch(frameNo, path, frame, t)) {
if (roundness) {
if (offset) {
temp.cmds = Array<PathCommand>(path->cmdsCnt);
temp.pts = Array<Point>(path->ptsCnt);
roundness->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, transform, temp);
return offset->modifyPath(temp.cmds.data, temp.cmds.count, temp.pts.data, temp.pts.count, out);
}
return roundness->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, transform, out);
}
if (offset) return offset->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, out);
if (modifier) return modifier->modifyPath(path->cmds, path->cmdsCnt, path->pts, path->ptsCnt, transform, out);
_copy(path, out.cmds);
_copy(path, out.pts, transform);
return true;
@ -502,12 +492,7 @@ struct LottiePathSet : LottieProperty
if (transform) *p *= *transform;
}
if (roundness) {
if (offset) {
roundness->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, nullptr, temp);
offset->modifyPath(temp.cmds.data, temp.cmds.count, temp.pts.data, temp.pts.count, out);
} else roundness->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, nullptr, out);
} else if (offset) offset->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, out);
if (modifier) modifier->modifyPath(frame->value.cmds, frame->value.cmdsCnt, interpPts, frame->value.ptsCnt, nullptr, out);
free(interpPts);
@ -539,15 +524,15 @@ struct LottiePathSet : LottieProperty
return true;
}
bool operator()(float frameNo, RenderPath& out, Matrix* transform, LottieExpressions* exps, LottieRoundnessModifier* roundness = nullptr, LottieOffsetModifier* offset = nullptr)
bool operator()(float frameNo, RenderPath& out, Matrix* transform, LottieExpressions* exps, LottieModifier* modifier = nullptr)
{
//overriding with expressions
if (exps && exp) {
frameNo = _loop(frames, frameNo, exp);
if (exps->result<LottiePathSet>(frameNo, out, transform, roundness, offset, exp)) return true;
if (exps->result<LottiePathSet>(frameNo, out, transform, modifier, exp)) return true;
}
if (roundness || offset) return modifiedPath(frameNo, out, transform, roundness, offset);
if (modifier) return modifiedPath(frameNo, out, transform, modifier);
else return defaultPath(frameNo, out, transform);
}