mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-13 19:44:28 +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
|
||||
|
||||
//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);
|
||||
|
||||
view = createSwView(1440, 1440);
|
||||
view = createSwView(1280, 1280);
|
||||
ecore_animator_add(animatorCb, view);
|
||||
|
||||
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 */
|
||||
/************************************************************************/
|
||||
|
||||
static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseShape, bool reset);
|
||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo, bool reset);
|
||||
static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseShape);
|
||||
static void _updateLayer(LottieLayer* root, LottieLayer* layer, int32_t frameNo);
|
||||
static bool _buildPrecomp(LottieComposition* comp, LottieGroup* parent);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
auto scale = transform->scale(frameNo);
|
||||
mathScale(&matrix, scale.x * 0.01f, scale.y * 0.01f);
|
||||
|
||||
auto angle = 0.0f;
|
||||
if (autoOrient) angle = transform->position.angle(frameNo);
|
||||
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.
|
||||
auto anchor = transform->anchor(frameNo);
|
||||
matrix.e13 -= (anchor.x * matrix.e11 + anchor.y * matrix.e12);
|
||||
matrix.e23 -= (anchor.x * matrix.e21 + anchor.y * matrix.e22);
|
||||
mathTranslateR(&matrix, -anchor.x, -anchor.y);
|
||||
|
||||
opacity = transform->opacity(frameNo);
|
||||
|
||||
|
@ -97,7 +96,8 @@ static void _updateTransform(LottieLayer* layer, int32_t frameNo)
|
|||
|
||||
auto& matrix = layer->cache.matrix;
|
||||
uint8_t opacity;
|
||||
_updateTransform(transform, layer->remap(frameNo), layer->autoOrient, matrix, opacity);
|
||||
|
||||
_updateTransform(transform, frameNo, layer->autoOrient, matrix, opacity);
|
||||
|
||||
if (parent) {
|
||||
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
|
||||
if (reset || !group->scene) {
|
||||
auto scene = Scene::gen();
|
||||
group->scene = scene.get();
|
||||
static_cast<Scene*>(parent->scene)->push(std::move(scene));
|
||||
} else {
|
||||
static_cast<Scene*>(group->scene)->clear();
|
||||
reset = true;
|
||||
}
|
||||
auto scene = Scene::gen();
|
||||
group->scene = scene.get();
|
||||
parent->scene->push(std::move(scene));
|
||||
|
||||
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->opacity(opacity);
|
||||
}
|
||||
_updateChildren(group, frameNo, baseShape, reset);
|
||||
_updateChildren(group, frameNo, baseShape);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -214,7 +209,7 @@ static Shape* _updateRect(LottieGroup* parent, LottieRect* rect, int32_t frameNo
|
|||
if (!mergingShape) {
|
||||
auto newShape = cast<Shape>(baseShape->duplicate());
|
||||
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);
|
||||
return mergingShape;
|
||||
|
@ -228,7 +223,7 @@ static Shape* _updateEllipse(LottieGroup* parent, LottieEllipse* ellipse, int32_
|
|||
if (!mergingShape) {
|
||||
auto newShape = cast<Shape>(baseShape->duplicate());
|
||||
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);
|
||||
return mergingShape;
|
||||
|
@ -240,7 +235,7 @@ static Shape* _updatePath(LottieGroup* parent, LottiePath* path, int32_t frameNo
|
|||
if (!mergingShape) {
|
||||
auto newShape = cast<Shape>(baseShape->duplicate());
|
||||
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)) {
|
||||
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;
|
||||
|
||||
|
@ -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) {
|
||||
switch ((*child)->type) {
|
||||
case LottieObject::Group: {
|
||||
mergingShape = _updateGroup(parent, static_cast<LottieGroup*>(*child), frameNo, baseShape, reset);
|
||||
mergingShape = _updateGroup(parent, static_cast<LottieGroup*>(*child), frameNo, baseShape);
|
||||
break;
|
||||
}
|
||||
case LottieObject::Transform: {
|
||||
|
@ -341,11 +336,14 @@ static void _updateChildren(LottieGroup* parent, int32_t frameNo, Shape* baseSha
|
|||
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.
|
||||
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();
|
||||
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));
|
||||
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 (reset || !layer->scene) {
|
||||
auto scene = Scene::gen();
|
||||
layer->scene = scene.get();
|
||||
static_cast<Scene*>(root->scene)->push(std::move(scene));
|
||||
}
|
||||
//else if (layer->statical) return; //FIXME: rendering is skipped due to no update?
|
||||
else {
|
||||
static_cast<Scene*>(layer->scene)->clear();
|
||||
reset = true;
|
||||
if (layer->masks.count == 0) return;
|
||||
|
||||
//maskings+clipping
|
||||
Shape* mergingMask = nullptr;
|
||||
|
||||
for (auto m = layer->masks.data; m < layer->masks.end(); ++m) {
|
||||
auto mask = static_cast<LottieMask*>(*m);
|
||||
auto shape = Shape::gen().release();
|
||||
shape->fill(255, 255, 255, mask->opacity(frameNo));
|
||||
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;
|
||||
|
||||
//Prepare render data
|
||||
layer->scene = Scene::gen().release();
|
||||
|
||||
_updateTransform(layer, frameNo);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
frameNo = layer->remap(frameNo);
|
||||
auto rFrameNo = layer->remap(frameNo);
|
||||
|
||||
switch (layer->type) {
|
||||
case LottieLayer::Precomp: {
|
||||
_updatePrecomp(layer, frameNo, reset);
|
||||
_updatePrecomp(layer, rFrameNo);
|
||||
break;
|
||||
}
|
||||
case LottieLayer::Solid: {
|
||||
_updateSolid(layer, frameNo);
|
||||
_updateSolid(layer, rFrameNo);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
_updateChildren(layer, frameNo, nullptr, reset);
|
||||
_updateChildren(layer, rFrameNo, nullptr);
|
||||
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)
|
||||
{
|
||||
if (parent->children.count == 0) return false;
|
||||
|
||||
for (auto c = parent->children.data; c < parent->children.end(); ++c) {
|
||||
auto child = static_cast<LottieLayer*>(*c);
|
||||
|
||||
//compact layer size
|
||||
_buildSize(comp, child);
|
||||
|
||||
//attach the referencing layer.
|
||||
if (child->refId) _buildReference(comp, child);
|
||||
|
||||
if (child->pid == -1) continue;
|
||||
|
||||
//parenting
|
||||
for (auto p = parent->children.data; p < parent->children.end(); ++p) {
|
||||
if (c == p) continue;
|
||||
auto parent = static_cast<LottieLayer*>(*p);
|
||||
if (child->pid == parent->id) {
|
||||
child->parent = parent;
|
||||
parent->statical &= child->statical;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (child->matte.target) _bulidHierarchy(parent, child->matte.target);
|
||||
if (child->pid != -1) _bulidHierarchy(parent, child);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -466,12 +539,14 @@ bool LottieBuilder::update(LottieComposition* comp, int32_t frameNo)
|
|||
auto scene = Scene::gen();
|
||||
root->scene = scene.get();
|
||||
comp->scene->push(std::move(scene));
|
||||
} else {
|
||||
root->scene->clear();
|
||||
}
|
||||
|
||||
//update children layers
|
||||
//TODO: skip if the layer is static.
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
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
|
||||
{
|
||||
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
|
||||
{
|
||||
//return zero if the visibility is false.
|
||||
|
@ -380,16 +382,22 @@ struct LottieLayer : LottieGroup
|
|||
return LottieGroup::opacity(frameNo);
|
||||
}
|
||||
|
||||
void prepare();
|
||||
int32_t remap(int32_t frameNo);
|
||||
|
||||
//Optimize: compact data??
|
||||
RGB24 color = {255, 255, 255};
|
||||
|
||||
CompositeMethod matteType = CompositeMethod::None;
|
||||
struct {
|
||||
CompositeMethod type = CompositeMethod::None;
|
||||
LottieLayer* target = nullptr;
|
||||
} matte;
|
||||
|
||||
BlendMethod blendMethod = BlendMethod::Normal;
|
||||
LottieLayer* parent = nullptr;
|
||||
LottieFloat timeRemap = 0.0f;
|
||||
LottieComposition* comp = nullptr;
|
||||
Array<LottieMask*> masks;
|
||||
|
||||
float timeStretch = 1.0f;
|
||||
uint32_t w, h;
|
||||
|
@ -409,8 +417,9 @@ struct LottieLayer : LottieGroup
|
|||
|
||||
Type type = Null;
|
||||
bool autoOrient = false;
|
||||
bool mask = 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()
|
||||
{
|
||||
switch (getInt()) {
|
||||
|
@ -493,7 +508,7 @@ LottieTransform* LottieParser::parseTransform(bool ddd)
|
|||
auto transform = new LottieTransform;
|
||||
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()) {
|
||||
if (!strcmp(key, "p"))
|
||||
|
@ -754,7 +769,7 @@ LottieObject* LottieParser::parseObject()
|
|||
} else if (!strcmp(type, "sh")) {
|
||||
return parsePath();
|
||||
} else if (!strcmp(type, "sr")) {
|
||||
TVGLOG("LOTTIE", "Polystar(sr) is not supported");
|
||||
TVGERR("LOTTIE", "Polystar(sr) is not supported");
|
||||
return parsePolyStar();
|
||||
} else if (!strcmp(type, "rd")) {
|
||||
return parseRoundedCorner();
|
||||
|
@ -763,11 +778,11 @@ LottieObject* LottieParser::parseObject()
|
|||
} else if (!strcmp(type, "gs")) {
|
||||
return parseGradientStroke();
|
||||
} else if (!strcmp(type, "tm")) {
|
||||
TVGLOG("LOTTIE", "Trimpath(tm) is not supported");
|
||||
TVGERR("LOTTIE", "Trimpath(tm) is not supported");
|
||||
} 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")) {
|
||||
TVGLOG("LOTTIE", "MergePath(mm) is not supported yet");
|
||||
TVGERR("LOTTIE", "MergePath(mm) is not supported yet");
|
||||
} else {
|
||||
TVGERR("LOTTIE", "Unkown object type(%s) is given", type);
|
||||
}
|
||||
|
@ -904,7 +919,6 @@ LottieObject* LottieParser::parseGroup()
|
|||
|
||||
void LottieParser::parseTimeRemap(LottieLayer* layer)
|
||||
{
|
||||
layer->comp = comp;
|
||||
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()
|
||||
{
|
||||
auto layer = new LottieLayer;
|
||||
if (!layer) return nullptr;
|
||||
|
||||
layer->comp = comp;
|
||||
context->layer = layer;
|
||||
|
||||
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, "h") || !strcmp(key, "sh")) getLayerSize(layer->h);
|
||||
else if (!strcmp(key, "sc")) layer->color = getColor(getString());
|
||||
else if (!strcmp(key, "tt")) layer->matteType = getMatteType();
|
||||
else if (!strcmp(key, "hasMask")) layer->mask = getBool();
|
||||
else if (!strcmp(key, "masksProperties"))
|
||||
{
|
||||
TVGLOG("LOTTIE", "Masking(maskProperties) is not supported");
|
||||
skip(key);
|
||||
}
|
||||
else if (!strcmp(key, "tt")) layer->matte.type = getMatteType();
|
||||
else if (!strcmp(key, "masksProperties")) parseMasks(layer);
|
||||
else if (!strcmp(key, "hd")) layer->hidden = getBool();
|
||||
else if (!strcmp(key, "refId")) layer->refId = getStringCopy();
|
||||
else if (!strcmp(key, "td")) layer->matteSrc = getInt(); //used for matte layer
|
||||
else skip(key);
|
||||
}
|
||||
|
||||
|
@ -995,15 +1032,22 @@ LottieLayer* LottieParser::parseLayers()
|
|||
if (!root) return nullptr;
|
||||
|
||||
root->type = LottieLayer::Precomp;
|
||||
root->comp = comp;
|
||||
|
||||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
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->children.push(layer);
|
||||
}
|
||||
}
|
||||
|
||||
root->prepare();
|
||||
return root;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ private:
|
|||
FillRule getFillRule();
|
||||
StrokeCap getStrokeCap();
|
||||
StrokeJoin getStrokeJoin();
|
||||
CompositeMethod getMaskMethod(bool inversed);
|
||||
LottieInterpolator* getInterpolator(const char* key, Point& in, Point& out);
|
||||
|
||||
void getInperpolatorPoint(Point& pt);
|
||||
|
@ -81,9 +82,11 @@ private:
|
|||
LottieRoundedCorner* parseRoundedCorner();
|
||||
LottieGradientFill* parseGradientFill();
|
||||
LottieLayer* parseLayers();
|
||||
LottieMask* parseMask();
|
||||
|
||||
void parseObject(LottieGroup* parent);
|
||||
void parseShapes(LottieLayer* layer);
|
||||
void parseMasks(LottieLayer* layer);
|
||||
void parseTimeRemap(LottieLayer* layer);
|
||||
void parseStrokeDash(LottieStroke* stroke);
|
||||
void parseGradient(LottieGradient* gradient, const char* key);
|
||||
|
|
|
@ -221,7 +221,7 @@ const char* LookaheadParserHandler::nextObjectKey()
|
|||
|
||||
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) {
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
return {lhs.x - rhs.x, lhs.y - rhs.y};
|
||||
|
|
Loading…
Add table
Reference in a new issue