mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 21:53:41 +00:00
lottie: Improve feature coverage by correctly handling XOR shapes
XOR when the shape's direction property is set to a value of 2. Currently, the direction property is expected to have either 1 for clockwise or 3 for counterclockwise orientation. Just found out the number 2 use-case...
This commit is contained in:
parent
27b49dcf45
commit
6944633f41
4 changed files with 26 additions and 14 deletions
|
@ -250,8 +250,6 @@ static bool _fragmented(LottieObject** child, Inlist<RenderContext>& contexts, R
|
|||
fragment->begin = child - 1;
|
||||
ctx->fragmenting = true;
|
||||
|
||||
TVGERR("LOTTIE", "Rendering is fragmented.");
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -394,6 +392,7 @@ static void _updateRect(LottieGroup* parent, LottieObject** child, float frameNo
|
|||
} else {
|
||||
auto merging = _draw(parent, ctx);
|
||||
merging->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness);
|
||||
if (rect->direction == 2) merging->fill(FillRule::EvenOdd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -412,6 +411,7 @@ static void _updateEllipse(LottieGroup* parent, LottieObject** child, float fram
|
|||
} else {
|
||||
auto merging = _draw(parent, ctx);
|
||||
merging->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
|
||||
if (ellipse->direction == 2) merging->fill(FillRule::EvenOdd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,15 +426,14 @@ static void _updatePath(LottieGroup* parent, LottieObject** child, float frameNo
|
|||
_repeat(parent, std::move(p), ctx);
|
||||
} else {
|
||||
auto merging = _draw(parent, ctx);
|
||||
|
||||
if (path->pathset(frameNo, P(merging)->rs.path.cmds, P(merging)->rs.path.pts)) {
|
||||
P(merging)->update(RenderUpdateFlag::Path);
|
||||
}
|
||||
|
||||
if (ctx->roundness > 1.0f && P(merging)->rs.stroke) {
|
||||
TVGERR("LOTTIE", "FIXME: Path roundesss should be applied properly!");
|
||||
P(merging)->rs.stroke->join = StrokeJoin::Round;
|
||||
}
|
||||
if (path->direction == 2) merging->fill(FillRule::EvenOdd);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -527,7 +526,7 @@ static void _updateStar(LottieGroup* parent, LottiePolyStar* star, Matrix* trans
|
|||
auto partialPointAmount = ptsCnt - floorf(ptsCnt);
|
||||
auto longSegment = false;
|
||||
auto numPoints = size_t(ceilf(ptsCnt) * 2);
|
||||
auto direction = star->cw ? 1.0f : -1.0f;
|
||||
auto direction = (star->direction == 0) ? 1.0f : -1.0f;
|
||||
auto hasRoundness = false;
|
||||
|
||||
float x, y;
|
||||
|
@ -629,7 +628,7 @@ static void _updatePolygon(LottieGroup* parent, LottiePolyStar* star, Matrix* tr
|
|||
|
||||
auto angle = -90.0f * MATH_PI / 180.0f;
|
||||
auto anglePerPoint = 2.0f * MATH_PI / float(ptsCnt);
|
||||
auto direction = star->cw ? 1.0f : -1.0f;
|
||||
auto direction = (star->direction == 0) ? 1.0f : -1.0f;
|
||||
auto hasRoundness = false;
|
||||
auto x = radius * cosf(angle);
|
||||
auto y = radius * sinf(angle);
|
||||
|
@ -711,6 +710,7 @@ static void _updatePolystar(LottieGroup* parent, LottieObject** child, float fra
|
|||
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
||||
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
||||
P(merging)->update(RenderUpdateFlag::Path);
|
||||
if (star->direction == 2) merging->fill(FillRule::EvenOdd);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -313,7 +313,7 @@ struct LottieTrimpath : LottieObject
|
|||
struct LottieShape : LottieObject
|
||||
{
|
||||
virtual ~LottieShape() {}
|
||||
bool cw = true; //path direction (clock wise vs coutner clock wise)
|
||||
uint8_t direction = 0; //0: clockwise, 2: counter-clockwise, 3: xor(?)
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -115,8 +115,8 @@ RGB24 LottieParser::getColor(const char *str)
|
|||
FillRule LottieParser::getFillRule()
|
||||
{
|
||||
switch (getInt()) {
|
||||
case 2: return FillRule::EvenOdd;
|
||||
default: return FillRule::Winding;
|
||||
case 1: return FillRule::Winding;
|
||||
default: return FillRule::EvenOdd;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -484,8 +484,7 @@ LottieRect* LottieParser::parseRect()
|
|||
if (!rect) return nullptr;
|
||||
|
||||
while (auto key = nextObjectKey()) {
|
||||
if (!strcmp(key, "d")) rect->cw = getInt();
|
||||
else if (!strcmp(key, "s")) parseProperty(rect->size);
|
||||
if (!strcmp(key, "s")) parseProperty(rect->size);
|
||||
else if (!strcmp(key, "p")) parseProperty(rect->position);
|
||||
else if (!strcmp(key, "r")) parseProperty(rect->radius);
|
||||
else if (!strcmp(key, "nm")) rect->name = getStringCopy();
|
||||
|
@ -506,7 +505,6 @@ LottieEllipse* LottieParser::parseEllipse()
|
|||
if (!strcmp(key, "nm")) ellipse->name = getStringCopy();
|
||||
else if (!strcmp(key, "p")) parseProperty(ellipse->position);
|
||||
else if (!strcmp(key, "s")) parseProperty(ellipse->size);
|
||||
else if (!strcmp(key, "d")) ellipse->cw = getInt();
|
||||
else if (!strcmp(key, "hd")) ellipse->hidden = getBool();
|
||||
else skip(key);
|
||||
}
|
||||
|
@ -648,7 +646,6 @@ LottiePath* LottieParser::parsePath()
|
|||
while (auto key = nextObjectKey()) {
|
||||
if (!strcmp(key, "nm")) path->name = getStringCopy();
|
||||
else if (!strcmp(key, "ks")) getPathSet(path->pathset);
|
||||
else if (!strcmp(key, "d")) path->cw = getInt();
|
||||
else if (!strcmp(key, "hd")) path->hidden = getBool();
|
||||
else skip(key);
|
||||
}
|
||||
|
@ -672,7 +669,6 @@ LottiePolyStar* LottieParser::parsePolyStar()
|
|||
else if (!strcmp(key, "os")) parseProperty(star->outerRoundness);
|
||||
else if (!strcmp(key, "r")) parseProperty(star->rotation);
|
||||
else if (!strcmp(key, "sy")) star->type = (LottiePolyStar::Type) getInt();
|
||||
else if (!strcmp(key, "d")) star->cw = getInt();
|
||||
else if (!strcmp(key, "hd")) star->hidden = getBool();
|
||||
else skip(key);
|
||||
}
|
||||
|
@ -1041,19 +1037,34 @@ void LottieParser::parseTimeRemap(LottieLayer* layer)
|
|||
}
|
||||
|
||||
|
||||
uint8_t LottieParser::getDirection()
|
||||
{
|
||||
auto v = getInt();
|
||||
if (v == 1) return 0;
|
||||
if (v == 2) return 3;
|
||||
if (v == 3) return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LottieParser::parseShapes(Array<LottieObject*>& parent)
|
||||
{
|
||||
uint8_t direction;
|
||||
|
||||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
direction = 0;
|
||||
enterObject();
|
||||
while (auto key = nextObjectKey()) {
|
||||
if (!strcmp(key, "it")) {
|
||||
enterArray();
|
||||
while (nextArrayValue()) parseObject(parent);
|
||||
} else if (!strcmp(key, "d")) {
|
||||
direction = getDirection();
|
||||
} else if (!strcmp(key, "ty")) {
|
||||
if (auto child = parseObject()) {
|
||||
if (child->hidden) delete(child);
|
||||
else parent.push(child);
|
||||
if (direction > 0) static_cast<LottieShape*>(child)->direction = direction;
|
||||
}
|
||||
} else skip(key);
|
||||
}
|
||||
|
|
|
@ -48,6 +48,7 @@ private:
|
|||
StrokeJoin getStrokeJoin();
|
||||
CompositeMethod getMaskMethod(bool inversed);
|
||||
LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out);
|
||||
uint8_t getDirection();
|
||||
|
||||
void getInperpolatorPoint(Point& pt);
|
||||
void getPathSet(LottiePathSet& path);
|
||||
|
|
Loading…
Add table
Reference in a new issue