mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-09 06:04:03 +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;
|
fragment->begin = child - 1;
|
||||||
ctx->fragmenting = true;
|
ctx->fragmenting = true;
|
||||||
|
|
||||||
TVGERR("LOTTIE", "Rendering is fragmented.");
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -394,6 +392,7 @@ static void _updateRect(LottieGroup* parent, LottieObject** child, float frameNo
|
||||||
} else {
|
} else {
|
||||||
auto merging = _draw(parent, ctx);
|
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);
|
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 {
|
} else {
|
||||||
auto merging = _draw(parent, ctx);
|
auto merging = _draw(parent, ctx);
|
||||||
merging->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
|
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);
|
_repeat(parent, std::move(p), ctx);
|
||||||
} else {
|
} else {
|
||||||
auto merging = _draw(parent, ctx);
|
auto merging = _draw(parent, ctx);
|
||||||
|
|
||||||
if (path->pathset(frameNo, P(merging)->rs.path.cmds, P(merging)->rs.path.pts)) {
|
if (path->pathset(frameNo, P(merging)->rs.path.cmds, P(merging)->rs.path.pts)) {
|
||||||
P(merging)->update(RenderUpdateFlag::Path);
|
P(merging)->update(RenderUpdateFlag::Path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->roundness > 1.0f && P(merging)->rs.stroke) {
|
if (ctx->roundness > 1.0f && P(merging)->rs.stroke) {
|
||||||
TVGERR("LOTTIE", "FIXME: Path roundesss should be applied properly!");
|
TVGERR("LOTTIE", "FIXME: Path roundesss should be applied properly!");
|
||||||
P(merging)->rs.stroke->join = StrokeJoin::Round;
|
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 partialPointAmount = ptsCnt - floorf(ptsCnt);
|
||||||
auto longSegment = false;
|
auto longSegment = false;
|
||||||
auto numPoints = size_t(ceilf(ptsCnt) * 2);
|
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;
|
auto hasRoundness = false;
|
||||||
|
|
||||||
float x, y;
|
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 angle = -90.0f * MATH_PI / 180.0f;
|
||||||
auto anglePerPoint = 2.0f * MATH_PI / float(ptsCnt);
|
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 hasRoundness = false;
|
||||||
auto x = radius * cosf(angle);
|
auto x = radius * cosf(angle);
|
||||||
auto y = radius * sinf(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);
|
if (star->type == LottiePolyStar::Star) _updateStar(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
||||||
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
else _updatePolygon(parent, star, identity ? nullptr : &matrix, frameNo, merging);
|
||||||
P(merging)->update(RenderUpdateFlag::Path);
|
P(merging)->update(RenderUpdateFlag::Path);
|
||||||
|
if (star->direction == 2) merging->fill(FillRule::EvenOdd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -313,7 +313,7 @@ struct LottieTrimpath : LottieObject
|
||||||
struct LottieShape : LottieObject
|
struct LottieShape : LottieObject
|
||||||
{
|
{
|
||||||
virtual ~LottieShape() {}
|
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()
|
FillRule LottieParser::getFillRule()
|
||||||
{
|
{
|
||||||
switch (getInt()) {
|
switch (getInt()) {
|
||||||
case 2: return FillRule::EvenOdd;
|
case 1: return FillRule::Winding;
|
||||||
default: return FillRule::Winding;
|
default: return FillRule::EvenOdd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -484,8 +484,7 @@ LottieRect* LottieParser::parseRect()
|
||||||
if (!rect) return nullptr;
|
if (!rect) return nullptr;
|
||||||
|
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "d")) rect->cw = getInt();
|
if (!strcmp(key, "s")) parseProperty(rect->size);
|
||||||
else if (!strcmp(key, "s")) parseProperty(rect->size);
|
|
||||||
else if (!strcmp(key, "p")) parseProperty(rect->position);
|
else if (!strcmp(key, "p")) parseProperty(rect->position);
|
||||||
else if (!strcmp(key, "r")) parseProperty(rect->radius);
|
else if (!strcmp(key, "r")) parseProperty(rect->radius);
|
||||||
else if (!strcmp(key, "nm")) rect->name = getStringCopy();
|
else if (!strcmp(key, "nm")) rect->name = getStringCopy();
|
||||||
|
@ -506,7 +505,6 @@ LottieEllipse* LottieParser::parseEllipse()
|
||||||
if (!strcmp(key, "nm")) ellipse->name = getStringCopy();
|
if (!strcmp(key, "nm")) ellipse->name = getStringCopy();
|
||||||
else if (!strcmp(key, "p")) parseProperty(ellipse->position);
|
else if (!strcmp(key, "p")) parseProperty(ellipse->position);
|
||||||
else if (!strcmp(key, "s")) parseProperty(ellipse->size);
|
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 if (!strcmp(key, "hd")) ellipse->hidden = getBool();
|
||||||
else skip(key);
|
else skip(key);
|
||||||
}
|
}
|
||||||
|
@ -648,7 +646,6 @@ LottiePath* LottieParser::parsePath()
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "nm")) path->name = getStringCopy();
|
if (!strcmp(key, "nm")) path->name = getStringCopy();
|
||||||
else if (!strcmp(key, "ks")) getPathSet(path->pathset);
|
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 if (!strcmp(key, "hd")) path->hidden = getBool();
|
||||||
else skip(key);
|
else skip(key);
|
||||||
}
|
}
|
||||||
|
@ -672,7 +669,6 @@ LottiePolyStar* LottieParser::parsePolyStar()
|
||||||
else if (!strcmp(key, "os")) parseProperty(star->outerRoundness);
|
else if (!strcmp(key, "os")) parseProperty(star->outerRoundness);
|
||||||
else if (!strcmp(key, "r")) parseProperty(star->rotation);
|
else if (!strcmp(key, "r")) parseProperty(star->rotation);
|
||||||
else if (!strcmp(key, "sy")) star->type = (LottiePolyStar::Type) getInt();
|
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 if (!strcmp(key, "hd")) star->hidden = getBool();
|
||||||
else skip(key);
|
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)
|
void LottieParser::parseShapes(Array<LottieObject*>& parent)
|
||||||
{
|
{
|
||||||
|
uint8_t direction;
|
||||||
|
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) {
|
while (nextArrayValue()) {
|
||||||
|
direction = 0;
|
||||||
enterObject();
|
enterObject();
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "it")) {
|
if (!strcmp(key, "it")) {
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) parseObject(parent);
|
while (nextArrayValue()) parseObject(parent);
|
||||||
|
} else if (!strcmp(key, "d")) {
|
||||||
|
direction = getDirection();
|
||||||
} else if (!strcmp(key, "ty")) {
|
} else if (!strcmp(key, "ty")) {
|
||||||
if (auto child = parseObject()) {
|
if (auto child = parseObject()) {
|
||||||
if (child->hidden) delete(child);
|
if (child->hidden) delete(child);
|
||||||
else parent.push(child);
|
else parent.push(child);
|
||||||
|
if (direction > 0) static_cast<LottieShape*>(child)->direction = direction;
|
||||||
}
|
}
|
||||||
} else skip(key);
|
} else skip(key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ private:
|
||||||
StrokeJoin getStrokeJoin();
|
StrokeJoin getStrokeJoin();
|
||||||
CompositeMethod getMaskMethod(bool inversed);
|
CompositeMethod getMaskMethod(bool inversed);
|
||||||
LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out);
|
LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out);
|
||||||
|
uint8_t getDirection();
|
||||||
|
|
||||||
void getInperpolatorPoint(Point& pt);
|
void getInperpolatorPoint(Point& pt);
|
||||||
void getPathSet(LottiePathSet& path);
|
void getPathSet(LottiePathSet& path);
|
||||||
|
|
Loading…
Add table
Reference in a new issue