mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
lottie/slot: revise gradient fill support
Revise gradient fill data parsing by adding support for the color stop count (p) parameter in slot data. issue: https://github.com/thorvg/thorvg/issues/2795
This commit is contained in:
parent
2207c8ce5e
commit
f42559e613
7 changed files with 43 additions and 29 deletions
|
@ -96,7 +96,7 @@ struct UserExample : tvgexam::Example
|
||||||
auto picture = slotAnimation->picture();
|
auto picture = slotAnimation->picture();
|
||||||
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample.json"))) return false;
|
if (!tvgexam::verify(picture->load(EXAMPLE_DIR"/lottie/extensions/slotsample.json"))) return false;
|
||||||
|
|
||||||
const char* slotJson = R"({"gradient_fill":{"p":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}})";
|
const char* slotJson = R"({"gradient_fill":{"p":{"p":2,"k":{"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0,0,1,1]}}}})";
|
||||||
if (!tvgexam::verify(slotAnimation->override(slotJson))) return false;
|
if (!tvgexam::verify(slotAnimation->override(slotJson))) return false;
|
||||||
|
|
||||||
sizing(picture, 0);
|
sizing(picture, 0);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.0.2","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":121,"w":550,"h":550,"nm":"C","assets":[],"layers":[{"ind":1,"ty":4,"nm":"S","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":120,"s":[360]}]},"p":{"a":0,"k":[275,275,0]},"a":{"a":0,"k":[-7.886,88.719,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[282.019,134.888]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"nm":"R"},{"ty":"st","c":{"a":0,"k":[0.991,0,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":3},"lc":1,"lj":1,"ml":4,"nm":"S"},{"ty":"gf","o":{"a":0,"k":100},"r":1,"g":{"p":9,"k":{"a":0,"k":[0,0.514,0.373,0.984,0.141,0.478,0.412,0.984,0.283,0.443,0.451,0.984,0.379,0.408,0.49,0.984,0.475,0.373,0.529,0.984,0.606,0.278,0.647,0.925,0.737,0.184,0.765,0.867,0.868,0.092,0.882,0.808,1,0,1,0.749],"sid":"gradient_fill"}},"s":{"a":0,"k":[-159.51,23.531]},"e":{"a":0,"k":[183.084,8.059]},"t":1,"nm":"G"},{"ty":"tr","p":{"a":0,"k":[-7.886,88.719]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"T"}],"nm":"R"}],"ip":0,"op":300,"st":0}],"slots":{"gradient_fill":{"p":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}},"markers":[]}
|
{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.0.2","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":121,"w":550,"h":550,"nm":"C","assets":[],"layers":[{"ind":1,"ty":4,"nm":"S","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":120,"s":[360]}]},"p":{"a":0,"k":[275,275,0]},"a":{"a":0,"k":[-7.886,88.719,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[282.019,134.888]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"nm":"R"},{"ty":"st","c":{"a":0,"k":[0.991,0,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":3},"lc":1,"lj":1,"ml":4,"nm":"S"},{"ty":"gf","o":{"a":0,"k":100},"r":1,"g":{"p":9,"k":{"a":0,"k":[0,0.514,0.373,0.984,0.141,0.478,0.412,0.984,0.283,0.443,0.451,0.984,0.379,0.408,0.49,0.984,0.475,0.373,0.529,0.984,0.606,0.278,0.647,0.925,0.737,0.184,0.765,0.867,0.868,0.092,0.882,0.808,1,0,1,0.749]},"sid":"gradient_fill"},"s":{"a":0,"k":[-159.51,23.531]},"e":{"a":0,"k":[183.084,8.059]},"t":1,"nm":"G"},{"ty":"tr","p":{"a":0,"k":[-7.886,88.719]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"T"}],"nm":"R"}],"ip":0,"op":300,"st":0}],"slots":{"gradient_fill":{"p":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}},"markers":[]}
|
|
@ -485,26 +485,31 @@ void LottieParser::parsePropertyInternal(T& prop)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template<LottieProperty::Type type>
|
||||||
|
void LottieParser::registerSlot(LottieObject* obj)
|
||||||
|
{
|
||||||
|
auto sid = getStringCopy();
|
||||||
|
|
||||||
|
//append object if the slot already exists.
|
||||||
|
for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) {
|
||||||
|
if (strcmp((*slot)->sid, sid)) continue;
|
||||||
|
(*slot)->pairs.push({obj});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
comp->slots.push(new LottieSlot(sid, obj, type));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template<LottieProperty::Type type, typename T>
|
template<LottieProperty::Type type, typename T>
|
||||||
void LottieParser::parseProperty(T& prop, LottieObject* obj)
|
void LottieParser::parseProperty(T& prop, LottieObject* obj)
|
||||||
{
|
{
|
||||||
enterObject();
|
enterObject();
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (KEY_AS("k")) parsePropertyInternal(prop);
|
if (KEY_AS("k")) parsePropertyInternal(prop);
|
||||||
else if (obj && KEY_AS("sid")) {
|
else if (obj && KEY_AS("sid")) registerSlot<type>(obj);
|
||||||
auto sid = getStringCopy();
|
else if (KEY_AS("x")) prop.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &prop);
|
||||||
//append object if the slot already exists.
|
else if (KEY_AS("ix")) prop.ix = getInt();
|
||||||
for (auto slot = comp->slots.begin(); slot < comp->slots.end(); ++slot) {
|
else skip(key);
|
||||||
if (strcmp((*slot)->sid, sid)) continue;
|
|
||||||
(*slot)->pairs.push({obj});
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
comp->slots.push(new LottieSlot(sid, obj, type));
|
|
||||||
} else if (KEY_AS("x")) {
|
|
||||||
prop.exp = _expression(getStringCopy(), comp, context.layer, context.parent, &prop);
|
|
||||||
} else if (KEY_AS("ix")) {
|
|
||||||
prop.ix = getInt();
|
|
||||||
} else skip(key);
|
|
||||||
}
|
}
|
||||||
prop.type = type;
|
prop.type = type;
|
||||||
}
|
}
|
||||||
|
@ -750,19 +755,23 @@ LottieRoundedCorner* LottieParser::parseRoundedCorner()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LottieParser::parseGradient(LottieGradient* gradient, const char* key)
|
void LottieParser::parseColorStop(LottieGradient* gradient)
|
||||||
{
|
{
|
||||||
if (KEY_AS("t")) gradient->id = getInt();
|
|
||||||
else if (KEY_AS("o")) parseProperty<LottieProperty::Type::Opacity>(gradient->opacity, gradient);
|
|
||||||
else if (KEY_AS("g"))
|
|
||||||
{
|
|
||||||
enterObject();
|
enterObject();
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (KEY_AS("p")) gradient->colorStops.count = getInt();
|
if (KEY_AS("p")) gradient->colorStops.count = getInt();
|
||||||
else if (KEY_AS("k")) parseProperty<LottieProperty::Type::ColorStop>(gradient->colorStops, gradient);
|
else if (KEY_AS("k")) parseProperty<LottieProperty::Type::ColorStop>(gradient->colorStops, gradient);
|
||||||
|
else if (KEY_AS("sid")) registerSlot<LottieProperty::Type::ColorStop>(gradient);
|
||||||
else skip(key);
|
else skip(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LottieParser::parseGradient(LottieGradient* gradient, const char* key)
|
||||||
|
{
|
||||||
|
if (KEY_AS("t")) gradient->id = getInt();
|
||||||
|
else if (KEY_AS("o")) parseProperty<LottieProperty::Type::Opacity>(gradient->opacity, gradient);
|
||||||
|
else if (KEY_AS("g")) parseColorStop(gradient);
|
||||||
else if (KEY_AS("s")) parseProperty<LottieProperty::Type::Point>(gradient->start, gradient);
|
else if (KEY_AS("s")) parseProperty<LottieProperty::Type::Point>(gradient->start, gradient);
|
||||||
else if (KEY_AS("e")) parseProperty<LottieProperty::Type::Point>(gradient->end, gradient);
|
else if (KEY_AS("e")) parseProperty<LottieProperty::Type::Point>(gradient->end, gradient);
|
||||||
else if (KEY_AS("h")) parseProperty<LottieProperty::Type::Float>(gradient->height, gradient);
|
else if (KEY_AS("h")) parseProperty<LottieProperty::Type::Float>(gradient->height, gradient);
|
||||||
|
@ -1438,7 +1447,10 @@ bool LottieParser::apply(LottieSlot* slot)
|
||||||
case LottieProperty::Type::ColorStop: {
|
case LottieProperty::Type::ColorStop: {
|
||||||
obj = new LottieGradient;
|
obj = new LottieGradient;
|
||||||
context.parent = obj;
|
context.parent = obj;
|
||||||
parseSlotProperty<LottieProperty::Type::ColorStop>(static_cast<LottieGradient*>(obj)->colorStops);
|
while (auto key = nextObjectKey()) {
|
||||||
|
if (KEY_AS("p")) parseColorStop(static_cast<LottieGradient*>(obj));
|
||||||
|
else skip(key);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LottieProperty::Type::Color: {
|
case LottieProperty::Type::Color: {
|
||||||
|
|
|
@ -38,6 +38,7 @@ public:
|
||||||
bool parse();
|
bool parse();
|
||||||
bool apply(LottieSlot* slot);
|
bool apply(LottieSlot* slot);
|
||||||
const char* sid(bool first = false);
|
const char* sid(bool first = false);
|
||||||
|
template<LottieProperty::Type type = LottieProperty::Type::Invalid> void registerSlot(LottieObject* obj);
|
||||||
|
|
||||||
LottieComposition* comp = nullptr;
|
LottieComposition* comp = nullptr;
|
||||||
const char* dirName = nullptr; //base resource directory
|
const char* dirName = nullptr; //base resource directory
|
||||||
|
@ -107,6 +108,7 @@ private:
|
||||||
void parseTimeRemap(LottieLayer* layer);
|
void parseTimeRemap(LottieLayer* layer);
|
||||||
void parseStrokeDash(LottieStroke* stroke);
|
void parseStrokeDash(LottieStroke* stroke);
|
||||||
void parseGradient(LottieGradient* gradient, const char* key);
|
void parseGradient(LottieGradient* gradient, const char* key);
|
||||||
|
void parseColorStop(LottieGradient* gradient);
|
||||||
void parseTextRange(LottieText* text);
|
void parseTextRange(LottieText* text);
|
||||||
void parseAssets();
|
void parseAssets();
|
||||||
void parseFonts();
|
void parseFonts();
|
||||||
|
|
|
@ -41,7 +41,7 @@ TEST_CASE("Lottie Slot", "[capiLottie]")
|
||||||
REQUIRE(tvg_paint_get_type(picture, &type) == TVG_RESULT_SUCCESS);
|
REQUIRE(tvg_paint_get_type(picture, &type) == TVG_RESULT_SUCCESS);
|
||||||
REQUIRE(type == TVG_TYPE_PICTURE);
|
REQUIRE(type == TVG_TYPE_PICTURE);
|
||||||
|
|
||||||
const char* slotJson = R"({"gradient_fill":{"p":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}})";
|
const char* slotJson = R"({"gradient_fill":{"p":{"p":2,"k":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}}})";
|
||||||
|
|
||||||
//Slot override before loaded
|
//Slot override before loaded
|
||||||
REQUIRE(tvg_lottie_animation_override(animation, slotJson) == TVG_RESULT_INSUFFICIENT_CONDITION);
|
REQUIRE(tvg_lottie_animation_override(animation, slotJson) == TVG_RESULT_INSUFFICIENT_CONDITION);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.0.2","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":121,"w":550,"h":550,"nm":"C","assets":[],"layers":[{"ind":1,"ty":4,"nm":"S","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":120,"s":[360]}]},"p":{"a":0,"k":[275,275,0]},"a":{"a":0,"k":[-7.886,88.719,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[282.019,134.888]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"nm":"R"},{"ty":"st","c":{"a":0,"k":[0.991,0,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":3},"lc":1,"lj":1,"ml":4,"nm":"S"},{"ty":"gf","o":{"a":0,"k":100},"r":1,"g":{"p":9,"k":{"a":0,"k":[0,0.514,0.373,0.984,0.141,0.478,0.412,0.984,0.283,0.443,0.451,0.984,0.379,0.408,0.49,0.984,0.475,0.373,0.529,0.984,0.606,0.278,0.647,0.925,0.737,0.184,0.765,0.867,0.868,0.092,0.882,0.808,1,0,1,0.749],"sid":"gradient_fill"}},"s":{"a":0,"k":[-159.51,23.531]},"e":{"a":0,"k":[183.084,8.059]},"t":1,"nm":"G"},{"ty":"tr","p":{"a":0,"k":[-7.886,88.719]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"T"}],"nm":"R"}],"ip":0,"op":300,"st":0}],"slots":{"gradient_fill":{"p":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}},"markers":[]}
|
{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.0.2","a":"","k":"","d":"","tc":""},"fr":60,"ip":0,"op":121,"w":550,"h":550,"nm":"C","assets":[],"layers":[{"ind":1,"ty":4,"nm":"S","sr":1,"ks":{"o":{"a":0,"k":100},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":120,"s":[360]}]},"p":{"a":0,"k":[275,275,0]},"a":{"a":0,"k":[-7.886,88.719,0]},"s":{"a":0,"k":[100,100,100]}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[282.019,134.888]},"p":{"a":0,"k":[0,0]},"r":{"a":0,"k":0},"nm":"R"},{"ty":"st","c":{"a":0,"k":[0.991,0,1,1]},"o":{"a":0,"k":100},"w":{"a":0,"k":3},"lc":1,"lj":1,"ml":4,"nm":"S"},{"ty":"gf","o":{"a":0,"k":100},"r":1,"g":{"p":9,"k":{"a":0,"k":[0,0.514,0.373,0.984,0.141,0.478,0.412,0.984,0.283,0.443,0.451,0.984,0.379,0.408,0.49,0.984,0.475,0.373,0.529,0.984,0.606,0.278,0.647,0.925,0.737,0.184,0.765,0.867,0.868,0.092,0.882,0.808,1,0,1,0.749]},"sid":"gradient_fill"},"s":{"a":0,"k":[-159.51,23.531]},"e":{"a":0,"k":[183.084,8.059]},"t":1,"nm":"G"},{"ty":"tr","p":{"a":0,"k":[-7.886,88.719]},"a":{"a":0,"k":[0,0]},"s":{"a":0,"k":[100,100]},"r":{"a":0,"k":0},"o":{"a":0,"k":100},"sk":{"a":0,"k":0},"sa":{"a":0,"k":0},"nm":"T"}],"nm":"R"}],"ip":0,"op":300,"st":0}],"slots":{"gradient_fill":{"p":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}},"markers":[]}
|
|
@ -44,7 +44,7 @@ TEST_CASE("Lottie Slot", "[tvgLottie]")
|
||||||
auto picture = animation->picture();
|
auto picture = animation->picture();
|
||||||
REQUIRE(picture->type() == Type::Picture);
|
REQUIRE(picture->type() == Type::Picture);
|
||||||
|
|
||||||
const char* slotJson = R"({"gradient_fill":{"p":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}})";
|
const char* slotJson = R"({"gradient_fill":{"p":{"p":2,"k":{"a":0,"k":[0,0.1,0.1,0.2,1,1,0.1,0.2,0.1,1]}}}})";
|
||||||
|
|
||||||
//Slot override before loaded
|
//Slot override before loaded
|
||||||
REQUIRE(animation->override(slotJson) == Result::InsufficientCondition);
|
REQUIRE(animation->override(slotJson) == Result::InsufficientCondition);
|
||||||
|
|
Loading…
Add table
Reference in a new issue