mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-15 12:34:30 +00:00
lottie/loader: support the masking features.
Enhancing the basic masking options by providing additional support.
This commit is contained in:
parent
3b2c040f70
commit
994c1b99a5
38 changed files with 278 additions and 95 deletions
|
@ -149,11 +149,11 @@ int main(int argc, char **argv)
|
||||||
if (threads > 0) --threads; //Allow the designated main thread capacity
|
if (threads > 0) --threads; //Allow the designated main thread capacity
|
||||||
|
|
||||||
//Initialize ThorVG Engine
|
//Initialize ThorVG Engine
|
||||||
if (tvg::Initializer::init(tvg::CanvasEngine::Sw, threads) == tvg::Result::Success) {
|
if (tvg::Initializer::init(tvg::CanvasEngine::Sw, 3) == tvg::Result::Success) {
|
||||||
|
|
||||||
elm_init(argc, argv);
|
elm_init(argc, argv);
|
||||||
|
|
||||||
view = createSwView(1440, 1440);
|
view = createSwView(1280, 1280);
|
||||||
ecore_animator_add(animatorCb, view);
|
ecore_animator_add(animatorCb, view);
|
||||||
|
|
||||||
elm_run();
|
elm_run();
|
||||||
|
|
1
src/examples/images/1643-exploding-star.json
Normal file
1
src/examples/images/1643-exploding-star.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/1667-firework.json
Normal file
1
src/examples/images/1667-firework.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/examples/images/a_mountain.json
Normal file
1
src/examples/images/a_mountain.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/examples/images/card_hover.json
Normal file
1
src/examples/images/card_hover.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/coin.json
Normal file
1
src/examples/images/coin.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/dancing_star.json
Normal file
1
src/examples/images/dancing_star.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/eid_mubarak.json
Normal file
1
src/examples/images/eid_mubarak.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/emoji.json
Normal file
1
src/examples/images/emoji.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/fleche.json
Normal file
1
src/examples/images/fleche.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/frog_vr.json
Normal file
1
src/examples/images/frog_vr.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/generator.json
Normal file
1
src/examples/images/generator.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/gradient_background.json
Normal file
1
src/examples/images/gradient_background.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/examples/images/hola.json
Normal file
1
src/examples/images/hola.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/examples/images/loading_rectangle.json
Normal file
1
src/examples/images/loading_rectangle.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/examples/images/merging_shapes.json
Normal file
1
src/examples/images/merging_shapes.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/examples/images/personal_character.json
Normal file
1
src/examples/images/personal_character.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/property_market.json
Normal file
1
src/examples/images/property_market.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/examples/images/rufo.json
Normal file
1
src/examples/images/rufo.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/seawalk.json
Normal file
1
src/examples/images/seawalk.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/examples/images/traveling.json
Normal file
1
src/examples/images/traveling.json
Normal file
File diff suppressed because one or more lines are too long
1
src/examples/images/water_filling.json
Normal file
1
src/examples/images/water_filling.json
Normal file
File diff suppressed because one or more lines are too long
|
@ -31,8 +31,8 @@
|
||||||
/* Internal Class Implementation */
|
/* Internal Class Implementation */
|
||||||
/************************************************************************/
|
/************************************************************************/
|
||||||
|
|
||||||
static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseShape, bool reset);
|
static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseShape);
|
||||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo, bool reset);
|
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo);
|
||||||
static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent);
|
static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent);
|
||||||
|
|
||||||
static bool _invisible(LottieGroup* group, int32_t frameNo)
|
static bool _invisible(LottieGroup* group, int32_t frameNo)
|
||||||
|
@ -68,17 +68,16 @@ static bool _updateTransform(LottieTransform* transform, int32_t frameNo, bool a
|
||||||
mathTranslate(&matrix, position.x, position.y);
|
mathTranslate(&matrix, position.x, position.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto scale = transform->scale(frameNo);
|
|
||||||
mathScale(&matrix, scale.x * 0.01f, scale.y * 0.01f);
|
|
||||||
|
|
||||||
auto angle = 0.0f;
|
auto angle = 0.0f;
|
||||||
if (autoOrient) angle = transform->position.angle(frameNo);
|
if (autoOrient) angle = transform->position.angle(frameNo);
|
||||||
mathRotate(&matrix, transform->rotation(frameNo) + angle);
|
mathRotate(&matrix, transform->rotation(frameNo) + angle);
|
||||||
|
|
||||||
|
auto scale = transform->scale(frameNo);
|
||||||
|
mathScaleR(&matrix, scale.x * 0.01f, scale.y * 0.01f);
|
||||||
|
|
||||||
//Lottie specific anchor transform.
|
//Lottie specific anchor transform.
|
||||||
auto anchor = transform->anchor(frameNo);
|
auto anchor = transform->anchor(frameNo);
|
||||||
matrix.e13 -= (anchor.x * matrix.e11 + anchor.y * matrix.e12);
|
mathTranslateR(&matrix, -anchor.x, -anchor.y);
|
||||||
matrix.e23 -= (anchor.x * matrix.e21 + anchor.y * matrix.e22);
|
|
||||||
|
|
||||||
opacity = transform->opacity(frameNo);
|
opacity = transform->opacity(frameNo);
|
||||||
|
|
||||||
|
@ -97,7 +96,8 @@ static void _updateTransform(LottieLayer* layer, int32_t frameNo)
|
||||||
|
|
||||||
auto& matrix = layer->cache.matrix;
|
auto& matrix = layer->cache.matrix;
|
||||||
uint8_t opacity;
|
uint8_t opacity;
|
||||||
_updateTransform(transform, layer->remap(frameNo), layer->autoOrient, matrix, opacity);
|
|
||||||
|
_updateTransform(transform, frameNo, layer->autoOrient, matrix, opacity);
|
||||||
|
|
||||||
if (parent) {
|
if (parent) {
|
||||||
layer->cache.matrix = mathMultiply(&parent->cache.matrix, &matrix);
|
layer->cache.matrix = mathMultiply(&parent->cache.matrix, &matrix);
|
||||||
|
@ -124,17 +124,12 @@ static Shape* _updateTransform(Paint* paint, LottieTransform* transform, int32_t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static Shape* _updateGroup(LottieGroup* parent, LottieGroup* group, int32_t frameNo, Shape* baseShape, bool reset)
|
static Shape* _updateGroup(LottieGroup* parent, LottieGroup* group, int32_t frameNo, Shape* baseShape)
|
||||||
{
|
{
|
||||||
//Prepare render data
|
//Prepare render data
|
||||||
if (reset || !group->scene) {
|
auto scene = Scene::gen();
|
||||||
auto scene = Scene::gen();
|
group->scene = scene.get();
|
||||||
group->scene = scene.get();
|
parent->scene->push(std::move(scene));
|
||||||
static_cast<Scene*>(parent->scene)->push(std::move(scene));
|
|
||||||
} else {
|
|
||||||
static_cast<Scene*>(group->scene)->clear();
|
|
||||||
reset = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_invisible(group, frameNo)) return nullptr;
|
if (_invisible(group, frameNo)) return nullptr;
|
||||||
|
|
||||||
|
@ -145,7 +140,7 @@ static Shape* _updateGroup(LottieGroup* parent, LottieGroup* group, int32_t fram
|
||||||
group->scene->transform(matrix);
|
group->scene->transform(matrix);
|
||||||
group->scene->opacity(opacity);
|
group->scene->opacity(opacity);
|
||||||
}
|
}
|
||||||
_updateChildren(group, frameNo, baseShape, reset);
|
_updateChildren(group, frameNo, baseShape);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -214,7 +209,7 @@ static Shape* _updateRect(LottieGroup* parent, LottieRect* rect, int32_t frameNo
|
||||||
if (!mergingShape) {
|
if (!mergingShape) {
|
||||||
auto newShape = cast<Shape>(baseShape->duplicate());
|
auto newShape = cast<Shape>(baseShape->duplicate());
|
||||||
mergingShape = newShape.get();
|
mergingShape = newShape.get();
|
||||||
static_cast<Scene*>(parent->scene)->push(std::move(newShape));
|
parent->scene->push(std::move(newShape));
|
||||||
}
|
}
|
||||||
mergingShape->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness);
|
mergingShape->appendRect(position.x - size.x * 0.5f, position.y - size.y * 0.5f, size.x, size.y, roundness, roundness);
|
||||||
return mergingShape;
|
return mergingShape;
|
||||||
|
@ -228,7 +223,7 @@ static Shape* _updateEllipse(LottieGroup* parent, LottieEllipse* ellipse, int32_
|
||||||
if (!mergingShape) {
|
if (!mergingShape) {
|
||||||
auto newShape = cast<Shape>(baseShape->duplicate());
|
auto newShape = cast<Shape>(baseShape->duplicate());
|
||||||
mergingShape = newShape.get();
|
mergingShape = newShape.get();
|
||||||
static_cast<Scene*>(parent->scene)->push(std::move(newShape));
|
parent->scene->push(std::move(newShape));
|
||||||
}
|
}
|
||||||
mergingShape->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
|
mergingShape->appendCircle(position.x, position.y, size.x * 0.5f, size.y * 0.5f);
|
||||||
return mergingShape;
|
return mergingShape;
|
||||||
|
@ -240,7 +235,7 @@ static Shape* _updatePath(LottieGroup* parent, LottiePath* path, int32_t frameNo
|
||||||
if (!mergingShape) {
|
if (!mergingShape) {
|
||||||
auto newShape = cast<Shape>(baseShape->duplicate());
|
auto newShape = cast<Shape>(baseShape->duplicate());
|
||||||
mergingShape = newShape.get();
|
mergingShape = newShape.get();
|
||||||
static_cast<Scene*>(parent->scene)->push(std::move(newShape));
|
parent->scene->push(std::move(newShape));
|
||||||
}
|
}
|
||||||
if (path->pathset(frameNo, P(mergingShape)->rs.path.cmds, P(mergingShape)->rs.path.pts)) {
|
if (path->pathset(frameNo, P(mergingShape)->rs.path.cmds, P(mergingShape)->rs.path.pts)) {
|
||||||
P(mergingShape)->update(RenderUpdateFlag::Path);
|
P(mergingShape)->update(RenderUpdateFlag::Path);
|
||||||
|
@ -276,7 +271,7 @@ static void _updateImage(LottieGroup* parent, LottieImage* image, int32_t frameN
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseShape, bool reset)
|
static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseShape)
|
||||||
{
|
{
|
||||||
if (parent->children.empty()) return;
|
if (parent->children.empty()) return;
|
||||||
|
|
||||||
|
@ -290,7 +285,7 @@ static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseSha
|
||||||
for (auto child = parent->children.end() - 1; child >= parent->children.data; --child) {
|
for (auto child = parent->children.end() - 1; child >= parent->children.data; --child) {
|
||||||
switch ((*child)->type) {
|
switch ((*child)->type) {
|
||||||
case LottieObject::Group: {
|
case LottieObject::Group: {
|
||||||
mergingShape = _updateGroup(parent, static_cast<LottieGroup*>(*child), frameNo, baseShape, reset);
|
mergingShape = _updateGroup(parent, static_cast<LottieGroup*>(*child), frameNo, baseShape);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LottieObject::Transform: {
|
case LottieObject::Transform: {
|
||||||
|
@ -341,11 +336,14 @@ static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseSha
|
||||||
delete(baseShape);
|
delete(baseShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _updatePrecomp(LottieLayer* precomp, int32_t frameNo, bool reset)
|
|
||||||
|
static void _updatePrecomp(LottieLayer* precomp, int32_t frameNo)
|
||||||
{
|
{
|
||||||
|
if (precomp->children.count == 0) return;
|
||||||
|
|
||||||
//TODO: skip if the layer is static.
|
//TODO: skip if the layer is static.
|
||||||
for (auto child = precomp->children.end() - 1; child >= precomp->children.data; --child) {
|
for (auto child = precomp->children.end() - 1; child >= precomp->children.data; --child) {
|
||||||
_updateLayer(precomp, static_cast<LottieLayer*>(*child), frameNo, reset);
|
_updateLayer(precomp, static_cast<LottieLayer*>(*child), frameNo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -355,26 +353,48 @@ static void _updateSolid(LottieLayer* layer, int32_t frameNo)
|
||||||
auto shape = Shape::gen();
|
auto shape = Shape::gen();
|
||||||
shape->appendRect(0, 0, layer->w, layer->h);
|
shape->appendRect(0, 0, layer->w, layer->h);
|
||||||
shape->fill(layer->color.rgb[0], layer->color.rgb[1], layer->color.rgb[2], layer->opacity(frameNo));
|
shape->fill(layer->color.rgb[0], layer->color.rgb[1], layer->color.rgb[2], layer->opacity(frameNo));
|
||||||
static_cast<Scene*>(layer->scene)->push(std::move(shape));
|
layer->scene->push(std::move(shape));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo, bool reset)
|
static void _updateMaskings(LottieLayer* layer, int32_t frameNo)
|
||||||
{
|
{
|
||||||
//Prepare render data
|
if (layer->masks.count == 0) return;
|
||||||
if (reset || !layer->scene) {
|
|
||||||
auto scene = Scene::gen();
|
//maskings+clipping
|
||||||
layer->scene = scene.get();
|
Shape* mergingMask = nullptr;
|
||||||
static_cast<Scene*>(root->scene)->push(std::move(scene));
|
|
||||||
}
|
for (auto m = layer->masks.data; m < layer->masks.end(); ++m) {
|
||||||
//else if (layer->statical) return; //FIXME: rendering is skipped due to no update?
|
auto mask = static_cast<LottieMask*>(*m);
|
||||||
else {
|
auto shape = Shape::gen().release();
|
||||||
static_cast<Scene*>(layer->scene)->clear();
|
shape->fill(255, 255, 255, mask->opacity(frameNo));
|
||||||
reset = true;
|
shape->transform(layer->cache.matrix);
|
||||||
|
if (mask->pathset(frameNo, P(shape)->rs.path.cmds, P(shape)->rs.path.pts)) {
|
||||||
|
P(shape)->update(RenderUpdateFlag::Path);
|
||||||
|
}
|
||||||
|
if (mergingMask) {
|
||||||
|
mergingMask->composite(cast<Shape>(shape), mask->method);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
auto method = mask->method;
|
||||||
|
if (method == CompositeMethod::AddMask) method = CompositeMethod::AlphaMask;
|
||||||
|
if (method == CompositeMethod::SubtractMask) method = CompositeMethod::InvAlphaMask;
|
||||||
|
layer->scene->composite(cast<Shape>(shape), method);
|
||||||
|
}
|
||||||
|
mergingMask = shape;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo)
|
||||||
|
{
|
||||||
|
layer->scene = nullptr;
|
||||||
|
|
||||||
if (_invisible(layer, frameNo)) return;
|
if (_invisible(layer, frameNo)) return;
|
||||||
|
|
||||||
|
//Prepare render data
|
||||||
|
layer->scene = Scene::gen().release();
|
||||||
|
|
||||||
_updateTransform(layer, frameNo);
|
_updateTransform(layer, frameNo);
|
||||||
|
|
||||||
layer->scene->transform(layer->cache.matrix);
|
layer->scene->transform(layer->cache.matrix);
|
||||||
|
@ -384,22 +404,49 @@ static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo,
|
||||||
layer->scene->opacity(layer->cache.opacity);
|
layer->scene->opacity(layer->cache.opacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
frameNo = layer->remap(frameNo);
|
auto rFrameNo = layer->remap(frameNo);
|
||||||
|
|
||||||
switch (layer->type) {
|
switch (layer->type) {
|
||||||
case LottieLayer::Precomp: {
|
case LottieLayer::Precomp: {
|
||||||
_updatePrecomp(layer, frameNo, reset);
|
_updatePrecomp(layer, rFrameNo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LottieLayer::Solid: {
|
case LottieLayer::Solid: {
|
||||||
_updateSolid(layer, frameNo);
|
_updateSolid(layer, rFrameNo);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
_updateChildren(layer, frameNo, nullptr, reset);
|
_updateChildren(layer, rFrameNo, nullptr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (layer->matte.target && layer->masks.count > 0) {
|
||||||
|
TVGERR("LOTTIE", "FIXME: Matte + Masking??");
|
||||||
|
}
|
||||||
|
|
||||||
|
//matte masking layer
|
||||||
|
if (layer->matte.target) {
|
||||||
|
_updateLayer(root, layer->matte.target, frameNo);
|
||||||
|
layer->scene->composite(cast<Scene>(layer->matte.target->scene), layer->matte.type);
|
||||||
|
}
|
||||||
|
|
||||||
|
_updateMaskings(layer, rFrameNo);
|
||||||
|
|
||||||
|
//clip the layer viewport
|
||||||
|
if (layer->clipself) {
|
||||||
|
//TODO: remove the intermediate scene....
|
||||||
|
auto cscene = Scene::gen();
|
||||||
|
auto clipper = Shape::gen();
|
||||||
|
clipper->appendRect(0, 0, layer->w, layer->h);
|
||||||
|
clipper->transform(layer->cache.matrix);
|
||||||
|
cscene->composite(move(clipper), CompositeMethod::ClipPath);
|
||||||
|
cscene->push(cast<Scene>(layer->scene));
|
||||||
|
layer->scene = cscene.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
//the given matte source was composited by the target earlier.
|
||||||
|
if (!layer->matteSrc) root->scene->push(cast<Scene>(layer->scene));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -421,27 +468,53 @@ static void _buildReference(LottieComposition* comp, LottieLayer* layer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _bulidHierarchy(LottieGroup* parent, LottieLayer* child)
|
||||||
|
{
|
||||||
|
if (child->pid == -1) return;
|
||||||
|
|
||||||
|
for (auto p = parent->children.data; p < parent->children.end(); ++p) {
|
||||||
|
auto parent = static_cast<LottieLayer*>(*p);
|
||||||
|
if (child == parent) continue;
|
||||||
|
if (child->pid == parent->id) {
|
||||||
|
child->parent = parent;
|
||||||
|
parent->statical &= child->statical;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void _buildSize(LottieComposition* comp, LottieLayer* layer)
|
||||||
|
{
|
||||||
|
// default size is 0x0
|
||||||
|
if (layer->w == 0 || layer->h == 0) return;
|
||||||
|
|
||||||
|
//compact layer size
|
||||||
|
if (layer->w > comp->w) layer->w = comp->w;
|
||||||
|
if (layer->h > comp->h) layer->h = comp->h;
|
||||||
|
|
||||||
|
if (layer->w < comp->w || layer->h < comp->h) {
|
||||||
|
layer->clipself = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent)
|
static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent)
|
||||||
{
|
{
|
||||||
if (parent->children.count == 0) return false;
|
if (parent->children.count == 0) return false;
|
||||||
|
|
||||||
for (auto c = parent->children.data; c < parent->children.end(); ++c) {
|
for (auto c = parent->children.data; c < parent->children.end(); ++c) {
|
||||||
auto child = static_cast<LottieLayer*>(*c);
|
auto child = static_cast<LottieLayer*>(*c);
|
||||||
|
|
||||||
|
//compact layer size
|
||||||
|
_buildSize(comp, child);
|
||||||
|
|
||||||
//attach the referencing layer.
|
//attach the referencing layer.
|
||||||
if (child->refId) _buildReference(comp, child);
|
if (child->refId) _buildReference(comp, child);
|
||||||
|
|
||||||
if (child->pid == -1) continue;
|
|
||||||
|
|
||||||
//parenting
|
//parenting
|
||||||
for (auto p = parent->children.data; p < parent->children.end(); ++p) {
|
if (child->matte.target) _bulidHierarchy(parent, child->matte.target);
|
||||||
if (c == p) continue;
|
if (child->pid != -1) _bulidHierarchy(parent, child);
|
||||||
auto parent = static_cast<LottieLayer*>(*p);
|
|
||||||
if (child->pid == parent->id) {
|
|
||||||
child->parent = parent;
|
|
||||||
parent->statical &= child->statical;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -466,12 +539,14 @@ bool LottieBuilder::update(LottieComposition* comp, int32_t frameNo)
|
||||||
auto scene = Scene::gen();
|
auto scene = Scene::gen();
|
||||||
root->scene = scene.get();
|
root->scene = scene.get();
|
||||||
comp->scene->push(std::move(scene));
|
comp->scene->push(std::move(scene));
|
||||||
|
} else {
|
||||||
|
root->scene->clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
//update children layers
|
//update children layers
|
||||||
//TODO: skip if the layer is static.
|
//TODO: skip if the layer is static.
|
||||||
for (auto child = root->children.end() - 1; child >= root->children.data; --child) {
|
for (auto child = root->children.end() - 1; child >= root->children.data; --child) {
|
||||||
_updateLayer(root, static_cast<LottieLayer*>(*child), frameNo, false);
|
_updateLayer(root, static_cast<LottieLayer*>(*child), frameNo);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,6 +74,18 @@ void LottieGroup::prepare(LottieObject::Type type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LottieLayer::prepare()
|
||||||
|
{
|
||||||
|
LottieGroup::prepare(LottieObject::Layer);
|
||||||
|
|
||||||
|
/* if layer is hidden, only useulf data is its transform matrix.
|
||||||
|
so force it to be a Null Layer and release all resource. */
|
||||||
|
if (!hidden) return;
|
||||||
|
type = LottieLayer::Null;
|
||||||
|
children.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int32_t LottieLayer::remap(int32_t frameNo)
|
int32_t LottieLayer::remap(int32_t frameNo)
|
||||||
{
|
{
|
||||||
if (timeRemap.frames) {
|
if (timeRemap.frames) {
|
||||||
|
|
|
@ -99,6 +99,21 @@ struct LottieGradient
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct LottieMask
|
||||||
|
{
|
||||||
|
LottiePathSet pathset = PathSet{nullptr, nullptr, 0, 0};
|
||||||
|
LottieOpacity opacity = 255;
|
||||||
|
CompositeMethod method;
|
||||||
|
bool inverse = false;
|
||||||
|
|
||||||
|
bool dynamic()
|
||||||
|
{
|
||||||
|
if (opacity.frames || pathset.frames) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct LottieObject
|
struct LottieObject
|
||||||
{
|
{
|
||||||
enum Type : uint8_t
|
enum Type : uint8_t
|
||||||
|
@ -359,19 +374,6 @@ struct LottieLayer : LottieGroup
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare()
|
|
||||||
{
|
|
||||||
LottieGroup::prepare(LottieObject::Layer);
|
|
||||||
|
|
||||||
/* if layer is hidden, only useulf data is its transform matrix.
|
|
||||||
so force it to be a Null Layer and release all resource. */
|
|
||||||
if (hidden) {
|
|
||||||
type = LottieLayer::Null;
|
|
||||||
children.reset();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t opacity(int32_t frameNo) override
|
uint8_t opacity(int32_t frameNo) override
|
||||||
{
|
{
|
||||||
//return zero if the visibility is false.
|
//return zero if the visibility is false.
|
||||||
|
@ -380,16 +382,22 @@ struct LottieLayer : LottieGroup
|
||||||
return LottieGroup::opacity(frameNo);
|
return LottieGroup::opacity(frameNo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void prepare();
|
||||||
int32_t remap(int32_t frameNo);
|
int32_t remap(int32_t frameNo);
|
||||||
|
|
||||||
//Optimize: compact data??
|
//Optimize: compact data??
|
||||||
RGB24 color = {255, 255, 255};
|
RGB24 color = {255, 255, 255};
|
||||||
|
|
||||||
CompositeMethod matteType = CompositeMethod::None;
|
struct {
|
||||||
|
CompositeMethod type = CompositeMethod::None;
|
||||||
|
LottieLayer* target = nullptr;
|
||||||
|
} matte;
|
||||||
|
|
||||||
BlendMethod blendMethod = BlendMethod::Normal;
|
BlendMethod blendMethod = BlendMethod::Normal;
|
||||||
LottieLayer* parent = nullptr;
|
LottieLayer* parent = nullptr;
|
||||||
LottieFloat timeRemap = 0.0f;
|
LottieFloat timeRemap = 0.0f;
|
||||||
LottieComposition* comp = nullptr;
|
LottieComposition* comp = nullptr;
|
||||||
|
Array<LottieMask*> masks;
|
||||||
|
|
||||||
float timeStretch = 1.0f;
|
float timeStretch = 1.0f;
|
||||||
uint32_t w, h;
|
uint32_t w, h;
|
||||||
|
@ -409,8 +417,9 @@ struct LottieLayer : LottieGroup
|
||||||
|
|
||||||
Type type = Null;
|
Type type = Null;
|
||||||
bool autoOrient = false;
|
bool autoOrient = false;
|
||||||
bool mask = false;
|
|
||||||
bool roundedCorner = false;
|
bool roundedCorner = false;
|
||||||
|
bool clipself = false; //clip the layer viewport
|
||||||
|
bool matteSrc = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,21 @@ static void _updateRoundedCorner(LottieGroup* parent, LottieRoundedCorner* round
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CompositeMethod LottieParser::getMaskMethod(bool inversed)
|
||||||
|
{
|
||||||
|
switch (getString()[0]) {
|
||||||
|
case 'a': {
|
||||||
|
if (inversed) return CompositeMethod::InvAlphaMask;
|
||||||
|
else return CompositeMethod::AddMask;
|
||||||
|
}
|
||||||
|
case 's': return CompositeMethod::SubtractMask;
|
||||||
|
case 'i': return CompositeMethod::IntersectMask;
|
||||||
|
case 'f': return CompositeMethod::DifferenceMask;
|
||||||
|
default: return CompositeMethod::None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
BlendMethod LottieParser::getBlendMethod()
|
BlendMethod LottieParser::getBlendMethod()
|
||||||
{
|
{
|
||||||
switch (getInt()) {
|
switch (getInt()) {
|
||||||
|
@ -493,7 +508,7 @@ LottieTransform* LottieParser::parseTransform(bool ddd)
|
||||||
auto transform = new LottieTransform;
|
auto transform = new LottieTransform;
|
||||||
if (!transform) return nullptr;
|
if (!transform) return nullptr;
|
||||||
|
|
||||||
if (ddd) TVGLOG("LOTTIE", "3d transform(ddd) is not supported");
|
if (ddd) TVGERR("LOTTIE", "3d transform(ddd) is not supported");
|
||||||
|
|
||||||
while (auto key = nextObjectKey()) {
|
while (auto key = nextObjectKey()) {
|
||||||
if (!strcmp(key, "p"))
|
if (!strcmp(key, "p"))
|
||||||
|
@ -754,7 +769,7 @@ LottieObject* LottieParser::parseObject()
|
||||||
} else if (!strcmp(type, "sh")) {
|
} else if (!strcmp(type, "sh")) {
|
||||||
return parsePath();
|
return parsePath();
|
||||||
} else if (!strcmp(type, "sr")) {
|
} else if (!strcmp(type, "sr")) {
|
||||||
TVGLOG("LOTTIE", "Polystar(sr) is not supported");
|
TVGERR("LOTTIE", "Polystar(sr) is not supported");
|
||||||
return parsePolyStar();
|
return parsePolyStar();
|
||||||
} else if (!strcmp(type, "rd")) {
|
} else if (!strcmp(type, "rd")) {
|
||||||
return parseRoundedCorner();
|
return parseRoundedCorner();
|
||||||
|
@ -763,11 +778,11 @@ LottieObject* LottieParser::parseObject()
|
||||||
} else if (!strcmp(type, "gs")) {
|
} else if (!strcmp(type, "gs")) {
|
||||||
return parseGradientStroke();
|
return parseGradientStroke();
|
||||||
} else if (!strcmp(type, "tm")) {
|
} else if (!strcmp(type, "tm")) {
|
||||||
TVGLOG("LOTTIE", "Trimpath(tm) is not supported");
|
TVGERR("LOTTIE", "Trimpath(tm) is not supported");
|
||||||
} else if (!strcmp(type, "rp")) {
|
} else if (!strcmp(type, "rp")) {
|
||||||
TVGLOG("LOTTIE", "Repeater(rp) is not supported yet");
|
TVGERR("LOTTIE", "Repeater(rp) is not supported yet");
|
||||||
} else if (!strcmp(type, "mm")) {
|
} else if (!strcmp(type, "mm")) {
|
||||||
TVGLOG("LOTTIE", "MergePath(mm) is not supported yet");
|
TVGERR("LOTTIE", "MergePath(mm) is not supported yet");
|
||||||
} else {
|
} else {
|
||||||
TVGERR("LOTTIE", "Unkown object type(%s) is given", type);
|
TVGERR("LOTTIE", "Unkown object type(%s) is given", type);
|
||||||
}
|
}
|
||||||
|
@ -904,7 +919,6 @@ LottieObject* LottieParser::parseGroup()
|
||||||
|
|
||||||
void LottieParser::parseTimeRemap(LottieLayer* layer)
|
void LottieParser::parseTimeRemap(LottieLayer* layer)
|
||||||
{
|
{
|
||||||
layer->comp = comp;
|
|
||||||
parseProperty(layer->timeRemap);
|
parseProperty(layer->timeRemap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -930,12 +944,39 @@ void LottieParser::getLayerSize(uint32_t& val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LottieMask* LottieParser::parseMask()
|
||||||
|
{
|
||||||
|
auto mask = new LottieMask;
|
||||||
|
if (!mask) return nullptr;
|
||||||
|
|
||||||
|
enterObject();
|
||||||
|
while (auto key = nextObjectKey()) {
|
||||||
|
if (!strcmp(key, "inv")) mask->inverse = getBool();
|
||||||
|
else if (!strcmp(key, "mode")) mask->method = getMaskMethod(mask->inverse);
|
||||||
|
else if (!strcmp(key, "pt")) getPathSet(mask->pathset);
|
||||||
|
else if (!strcmp(key, "o")) parseProperty(mask->opacity);
|
||||||
|
else skip(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LottieParser::parseMasks(LottieLayer* layer)
|
||||||
|
{
|
||||||
|
enterArray();
|
||||||
|
while (nextArrayValue()) {
|
||||||
|
layer->masks.push(parseMask());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
LottieLayer* LottieParser::parseLayer()
|
LottieLayer* LottieParser::parseLayer()
|
||||||
{
|
{
|
||||||
auto layer = new LottieLayer;
|
auto layer = new LottieLayer;
|
||||||
if (!layer) return nullptr;
|
if (!layer) return nullptr;
|
||||||
|
|
||||||
|
layer->comp = comp;
|
||||||
context->layer = layer;
|
context->layer = layer;
|
||||||
|
|
||||||
auto ddd = false;
|
auto ddd = false;
|
||||||
|
@ -964,15 +1005,11 @@ LottieLayer* LottieParser::parseLayer()
|
||||||
else if (!strcmp(key, "w") || !strcmp(key, "sw")) getLayerSize(layer->w);
|
else if (!strcmp(key, "w") || !strcmp(key, "sw")) getLayerSize(layer->w);
|
||||||
else if (!strcmp(key, "h") || !strcmp(key, "sh")) getLayerSize(layer->h);
|
else if (!strcmp(key, "h") || !strcmp(key, "sh")) getLayerSize(layer->h);
|
||||||
else if (!strcmp(key, "sc")) layer->color = getColor(getString());
|
else if (!strcmp(key, "sc")) layer->color = getColor(getString());
|
||||||
else if (!strcmp(key, "tt")) layer->matteType = getMatteType();
|
else if (!strcmp(key, "tt")) layer->matte.type = getMatteType();
|
||||||
else if (!strcmp(key, "hasMask")) layer->mask = getBool();
|
else if (!strcmp(key, "masksProperties")) parseMasks(layer);
|
||||||
else if (!strcmp(key, "masksProperties"))
|
|
||||||
{
|
|
||||||
TVGLOG("LOTTIE", "Masking(maskProperties) is not supported");
|
|
||||||
skip(key);
|
|
||||||
}
|
|
||||||
else if (!strcmp(key, "hd")) layer->hidden = getBool();
|
else if (!strcmp(key, "hd")) layer->hidden = getBool();
|
||||||
else if (!strcmp(key, "refId")) layer->refId = getStringCopy();
|
else if (!strcmp(key, "refId")) layer->refId = getStringCopy();
|
||||||
|
else if (!strcmp(key, "td")) layer->matteSrc = getInt(); //used for matte layer
|
||||||
else skip(key);
|
else skip(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -995,15 +1032,22 @@ LottieLayer* LottieParser::parseLayers()
|
||||||
if (!root) return nullptr;
|
if (!root) return nullptr;
|
||||||
|
|
||||||
root->type = LottieLayer::Precomp;
|
root->type = LottieLayer::Precomp;
|
||||||
|
root->comp = comp;
|
||||||
|
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) {
|
while (nextArrayValue()) {
|
||||||
if (auto layer = parseLayer()) {
|
if (auto layer = parseLayer()) {
|
||||||
|
if (layer->matte.type == CompositeMethod::None) {
|
||||||
|
root->children.push(layer);
|
||||||
|
} else {
|
||||||
|
//matte source must be located in the right previous.
|
||||||
|
layer->matte.target = static_cast<LottieLayer*>(root->children.last());
|
||||||
|
layer->statical &= layer->matte.target->statical;
|
||||||
|
root->children.last() = layer;
|
||||||
|
}
|
||||||
root->statical &= layer->statical;
|
root->statical &= layer->statical;
|
||||||
root->children.push(layer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
root->prepare();
|
root->prepare();
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,7 @@ private:
|
||||||
FillRule getFillRule();
|
FillRule getFillRule();
|
||||||
StrokeCap getStrokeCap();
|
StrokeCap getStrokeCap();
|
||||||
StrokeJoin getStrokeJoin();
|
StrokeJoin getStrokeJoin();
|
||||||
|
CompositeMethod getMaskMethod(bool inversed);
|
||||||
LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out);
|
LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out);
|
||||||
|
|
||||||
void getInperpolatorPoint(Point& pt);
|
void getInperpolatorPoint(Point& pt);
|
||||||
|
@ -81,9 +82,11 @@ private:
|
||||||
LottieRoundedCorner* parseRoundedCorner();
|
LottieRoundedCorner* parseRoundedCorner();
|
||||||
LottieGradientFill* parseGradientFill();
|
LottieGradientFill* parseGradientFill();
|
||||||
LottieLayer* parseLayers();
|
LottieLayer* parseLayers();
|
||||||
|
LottieMask* parseMask();
|
||||||
|
|
||||||
void parseObject(LottieGroup* parent);
|
void parseObject(LottieGroup* parent);
|
||||||
void parseShapes(LottieLayer* layer);
|
void parseShapes(LottieLayer* layer);
|
||||||
|
void parseMasks(LottieLayer* layer);
|
||||||
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);
|
||||||
|
|
|
@ -221,7 +221,7 @@ const char* LookaheadParserHandler::nextObjectKey()
|
||||||
|
|
||||||
void LookaheadParserHandler::skip(const char* key)
|
void LookaheadParserHandler::skip(const char* key)
|
||||||
{
|
{
|
||||||
if (key) TVGLOG("LOTTIE", "Skipped parsing value = %s", key);
|
//if (key) TVGLOG("LOTTIE", "Skipped parsing value = %s", key);
|
||||||
|
|
||||||
if (peekType() == kArrayType) {
|
if (peekType() == kArrayType) {
|
||||||
enterArray();
|
enterArray();
|
||||||
|
|
|
@ -97,6 +97,19 @@ static inline void mathScale(Matrix* m, float sx, float sy)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mathScaleR(Matrix* m, float x, float y)
|
||||||
|
{
|
||||||
|
if (x != 1.0f) {
|
||||||
|
m->e11 *= x;
|
||||||
|
m->e21 *= x;
|
||||||
|
}
|
||||||
|
if (y != 1.0f) {
|
||||||
|
m->e22 *= y;
|
||||||
|
m->e12 *= y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline void mathTranslate(Matrix* m, float x, float y)
|
static inline void mathTranslate(Matrix* m, float x, float y)
|
||||||
{
|
{
|
||||||
m->e13 += x;
|
m->e13 += x;
|
||||||
|
@ -104,6 +117,20 @@ static inline void mathTranslate(Matrix* m, float x, float y)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mathTranslateR(Matrix* m, float x, float y)
|
||||||
|
{
|
||||||
|
if (x == 0.0f && y == 0.0f) return;
|
||||||
|
m->e13 += (x * m->e11 + y * m->e12);
|
||||||
|
m->e23 += (x * m->e21 + y * m->e22);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void mathLog(Matrix* m)
|
||||||
|
{
|
||||||
|
TVGLOG("MATH", "Matrix: [%f %f %f] [%f %f %f] [%f %f %f]", m->e11, m->e12, m->e13, m->e21, m->e22, m->e23, m->e31, m->e32, m->e33);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline Point operator-(const Point& lhs, const Point& rhs)
|
static inline Point operator-(const Point& lhs, const Point& rhs)
|
||||||
{
|
{
|
||||||
return {lhs.x - rhs.x, lhs.y - rhs.y};
|
return {lhs.x - rhs.x, lhs.y - rhs.y};
|
||||||
|
|
Loading…
Add table
Reference in a new issue