mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
lottie: support stroke layer effect
issue: https://github.com/thorvg/thorvg/issues/2718
This commit is contained in:
parent
713840eb42
commit
b041bdab4a
6 changed files with 138 additions and 27 deletions
|
@ -1220,7 +1220,7 @@ void LottieBuilder::updateText(LottieLayer* layer, float frameNo)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void LottieBuilder::updateMaskings(LottieLayer* layer, float frameNo)
|
void LottieBuilder::updateMasks(LottieLayer* layer, float frameNo)
|
||||||
{
|
{
|
||||||
if (layer->masks.count == 0) return;
|
if (layer->masks.count == 0) return;
|
||||||
|
|
||||||
|
@ -1306,6 +1306,60 @@ bool LottieBuilder::updateMatte(LottieComposition* comp, float frameNo, Scene* s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LottieBuilder::updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo)
|
||||||
|
{
|
||||||
|
if (layer->masks.count == 0) return;
|
||||||
|
|
||||||
|
auto shape = layer->pooling();
|
||||||
|
shape->reset();
|
||||||
|
|
||||||
|
//FIXME: all mask
|
||||||
|
if (effect->allMask(frameNo)) {
|
||||||
|
for (auto m = layer->masks.begin(); m < layer->masks.end(); ++m) {
|
||||||
|
auto mask = *m;
|
||||||
|
mask->pathset(frameNo, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, nullptr, nullptr, nullptr, exps);
|
||||||
|
}
|
||||||
|
//A specific mask
|
||||||
|
} else {
|
||||||
|
auto idx = static_cast<uint32_t>(effect->mask(frameNo) - 1);
|
||||||
|
if (idx < 0 || idx >= layer->masks.count) return;
|
||||||
|
auto mask = layer->masks[idx];
|
||||||
|
mask->pathset(frameNo, SHAPE(shape)->rs.path.cmds, SHAPE(shape)->rs.path.pts, nullptr, nullptr, nullptr, exps);
|
||||||
|
}
|
||||||
|
|
||||||
|
shape->transform(layer->cache.matrix);
|
||||||
|
shape->strokeTrim(effect->begin(frameNo) * 0.01f, effect->end(frameNo) * 0.01f);
|
||||||
|
shape->strokeFill(255, 255, 255, (int)(effect->opacity(frameNo) * 255.0f));
|
||||||
|
shape->strokeJoin(StrokeJoin::Round);
|
||||||
|
shape->strokeCap(StrokeCap::Round);
|
||||||
|
|
||||||
|
auto size = effect->size(frameNo) * 2.0f;
|
||||||
|
shape->strokeWidth(size);
|
||||||
|
|
||||||
|
//fill the color to the layer shapes if any
|
||||||
|
auto color = effect->color(frameNo);
|
||||||
|
if (color.rgb[0] != 255 || color.rgb[1] != 255 || color.rgb[2] != 255) {
|
||||||
|
auto accessor = tvg::Accessor::gen();
|
||||||
|
auto stroke = (layer->type == LottieLayer::Type::Shape) ? true : false;
|
||||||
|
auto f = [color, size, stroke](const tvg::Paint* paint, void* data) -> bool {
|
||||||
|
if (paint->type() == tvg::Type::Shape) {
|
||||||
|
auto shape = (tvg::Shape*) paint;
|
||||||
|
//expand shape to fill the stroke region
|
||||||
|
if (stroke) {
|
||||||
|
shape->strokeWidth(size);
|
||||||
|
shape->strokeFill(color.rgb[0], color.rgb[1], color.rgb[2], 255);
|
||||||
|
}
|
||||||
|
shape->fill(color.rgb[0], color.rgb[1], color.rgb[2], 255);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
accessor->set(layer->scene, f, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
layer->scene->mask(shape, MaskMethod::Alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo)
|
void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo)
|
||||||
{
|
{
|
||||||
constexpr int QUALITY = 25;
|
constexpr int QUALITY = 25;
|
||||||
|
@ -1329,6 +1383,11 @@ void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo)
|
||||||
layer->scene->push(SceneEffect::Fill, color.rgb[0], color.rgb[1], color.rgb[2], (int)(255.0f * effect->opacity(frameNo)));
|
layer->scene->push(SceneEffect::Fill, color.rgb[0], color.rgb[1], color.rgb[2], (int)(255.0f * effect->opacity(frameNo)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LottieEffect::Stroke: {
|
||||||
|
auto effect = static_cast<LottieFxStroke*>(*ef);
|
||||||
|
updateStrokeEffect(layer, effect, frameNo);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LottieEffect::Tritone: {
|
case LottieEffect::Tritone: {
|
||||||
auto effect = static_cast<LottieFxTritone*>(*ef);
|
auto effect = static_cast<LottieFxTritone*>(*ef);
|
||||||
auto dark = effect->dark(frameNo);
|
auto dark = effect->dark(frameNo);
|
||||||
|
@ -1406,7 +1465,7 @@ void LottieBuilder::updateLayer(LottieComposition* comp, Scene* scene, LottieLay
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateMaskings(layer, frameNo);
|
updateMasks(layer, frameNo);
|
||||||
|
|
||||||
layer->scene->blend(layer->blendMethod);
|
layer->scene->blend(layer->blendMethod);
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,7 @@ struct LottieBuilder
|
||||||
void build(LottieComposition* comp);
|
void build(LottieComposition* comp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo);
|
||||||
void updateEffect(LottieLayer* layer, float frameNo);
|
void updateEffect(LottieLayer* layer, float frameNo);
|
||||||
void updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo);
|
void updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo);
|
||||||
bool updateMatte(LottieComposition* comp, float frameNo, Scene* scene, LottieLayer* layer);
|
bool updateMatte(LottieComposition* comp, float frameNo, Scene* scene, LottieLayer* layer);
|
||||||
|
@ -109,7 +110,7 @@ private:
|
||||||
void updateSolid(LottieLayer* layer);
|
void updateSolid(LottieLayer* layer);
|
||||||
void updateImage(LottieGroup* layer);
|
void updateImage(LottieGroup* layer);
|
||||||
void updateText(LottieLayer* layer, float frameNo);
|
void updateText(LottieLayer* layer, float frameNo);
|
||||||
void updateMaskings(LottieLayer* layer, float frameNo);
|
void updateMasks(LottieLayer* layer, float frameNo);
|
||||||
void updateTransform(LottieLayer* layer, float frameNo);
|
void updateTransform(LottieLayer* layer, float frameNo);
|
||||||
void updateChildren(LottieGroup* parent, float frameNo, Inlist<RenderContext>& contexts);
|
void updateChildren(LottieGroup* parent, float frameNo, Inlist<RenderContext>& contexts);
|
||||||
void updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& pcontexts, RenderContext* ctx);
|
void updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& pcontexts, RenderContext* ctx);
|
||||||
|
|
|
@ -76,10 +76,9 @@ struct LottieStroke
|
||||||
StrokeJoin join = StrokeJoin::Round;
|
StrokeJoin join = StrokeJoin::Round;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
struct LottieEffect
|
struct LottieEffect
|
||||||
{
|
{
|
||||||
enum Type : uint8_t {Tint = 20, Fill, Tritone = 23, DropShadow = 25, GaussianBlur = 29};
|
enum Type : uint8_t {Tint = 20, Fill, Stroke, Tritone, DropShadow = 25, GaussianBlur = 29};
|
||||||
|
|
||||||
virtual ~LottieEffect() {}
|
virtual ~LottieEffect() {}
|
||||||
Type type;
|
Type type;
|
||||||
|
@ -88,13 +87,13 @@ struct LottieEffect
|
||||||
|
|
||||||
struct LottieFxFill : LottieEffect
|
struct LottieFxFill : LottieEffect
|
||||||
{
|
{
|
||||||
//int16_t mask layer
|
//LottieInteger mask;
|
||||||
//LottieDropDown allMask?
|
//LottieInteger allMask;
|
||||||
LottieColor color;
|
LottieColor color;
|
||||||
//LottieDropDown inverted
|
//LottieInteger invert;
|
||||||
//LottieSlider horizontalFeather
|
//LottieSlider hFeather;
|
||||||
//LottieSlider verticalFeather
|
//LottieSlider vFeather;
|
||||||
LottieSlider opacity;
|
LottieFloat opacity;
|
||||||
|
|
||||||
LottieFxFill()
|
LottieFxFill()
|
||||||
{
|
{
|
||||||
|
@ -102,11 +101,31 @@ struct LottieFxFill : LottieEffect
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LottieFxStroke : LottieEffect
|
||||||
|
{
|
||||||
|
LottieInteger mask;
|
||||||
|
LottieInteger allMask;
|
||||||
|
//LottieInteger sequential;
|
||||||
|
LottieColor color;
|
||||||
|
LottieFloat size;
|
||||||
|
//LottieFloat hardness; //should support with the blurness?
|
||||||
|
LottieFloat opacity;
|
||||||
|
LottieFloat begin;
|
||||||
|
LottieFloat end;
|
||||||
|
//LottieFloat space;
|
||||||
|
//LottieInteger style;
|
||||||
|
|
||||||
|
LottieFxStroke()
|
||||||
|
{
|
||||||
|
type = LottieEffect::Stroke;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct LottieFxTint : LottieEffect
|
struct LottieFxTint : LottieEffect
|
||||||
{
|
{
|
||||||
LottieColor black;
|
LottieColor black;
|
||||||
LottieColor white;
|
LottieColor white;
|
||||||
LottieSlider intensity;
|
LottieFloat intensity;
|
||||||
|
|
||||||
LottieFxTint()
|
LottieFxTint()
|
||||||
{
|
{
|
||||||
|
@ -129,10 +148,10 @@ struct LottieFxTritone : LottieEffect
|
||||||
struct LottieFxDropShadow : LottieEffect
|
struct LottieFxDropShadow : LottieEffect
|
||||||
{
|
{
|
||||||
LottieColor color;
|
LottieColor color;
|
||||||
LottieSlider opacity = 0;
|
LottieFloat opacity = 0;
|
||||||
LottieAngle angle = 0.0f;
|
LottieFloat angle = 0.0f;
|
||||||
LottieSlider distance = 0.0f;
|
LottieFloat distance = 0.0f;
|
||||||
LottieSlider blurness = 0.0f;
|
LottieFloat blurness = 0.0f;
|
||||||
|
|
||||||
LottieFxDropShadow()
|
LottieFxDropShadow()
|
||||||
{
|
{
|
||||||
|
@ -142,9 +161,9 @@ struct LottieFxDropShadow : LottieEffect
|
||||||
|
|
||||||
struct LottieFxGaussianBlur : LottieEffect
|
struct LottieFxGaussianBlur : LottieEffect
|
||||||
{
|
{
|
||||||
LottieSlider blurness = 0.0f;
|
LottieFloat blurness = 0.0f;
|
||||||
LottieCheckbox direction = 0;
|
LottieInteger direction = 0;
|
||||||
LottieCheckbox wrap = 0;
|
LottieInteger wrap = 0;
|
||||||
|
|
||||||
LottieFxGaussianBlur()
|
LottieFxGaussianBlur()
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,6 +62,7 @@ LottieEffect* LottieParser::getEffect(int type)
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LottieEffect::Tint: return new LottieFxTint;
|
case LottieEffect::Tint: return new LottieFxTint;
|
||||||
case LottieEffect::Fill: return new LottieFxFill;
|
case LottieEffect::Fill: return new LottieFxFill;
|
||||||
|
case LottieEffect::Stroke: return new LottieFxStroke;
|
||||||
case LottieEffect::Tritone: return new LottieFxTritone;
|
case LottieEffect::Tritone: return new LottieFxTritone;
|
||||||
case LottieEffect::DropShadow: return new LottieFxDropShadow;
|
case LottieEffect::DropShadow: return new LottieFxDropShadow;
|
||||||
case LottieEffect::GaussianBlur: return new LottieFxGaussianBlur;
|
case LottieEffect::GaussianBlur: return new LottieFxGaussianBlur;
|
||||||
|
@ -1261,7 +1262,7 @@ void LottieParser::parseMasks(LottieLayer* layer)
|
||||||
|
|
||||||
void LottieParser::parseTint(LottieFxTint* effect)
|
void LottieParser::parseTint(LottieFxTint* effect)
|
||||||
{
|
{
|
||||||
int idx = 0; //black -> white -> intenstiy
|
int idx = 0;
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) {
|
while (nextArrayValue()) {
|
||||||
enterObject();
|
enterObject();
|
||||||
|
@ -1285,7 +1286,7 @@ void LottieParser::parseTint(LottieFxTint* effect)
|
||||||
|
|
||||||
void LottieParser::parseTritone(LottieFxTritone* effect)
|
void LottieParser::parseTritone(LottieFxTritone* effect)
|
||||||
{
|
{
|
||||||
int idx = 0; //bright, midtone, dark
|
int idx = 0;
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) {
|
while (nextArrayValue()) {
|
||||||
enterObject();
|
enterObject();
|
||||||
|
@ -1310,7 +1311,7 @@ void LottieParser::parseTritone(LottieFxTritone* effect)
|
||||||
|
|
||||||
void LottieParser::parseFill(LottieFxFill* effect)
|
void LottieParser::parseFill(LottieFxFill* effect)
|
||||||
{
|
{
|
||||||
int idx = 0; //fill mask -> all mask -> color -> invert -> h feather -> v feather -> opacity
|
int idx = 0;
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) {
|
while (nextArrayValue()) {
|
||||||
enterObject();
|
enterObject();
|
||||||
|
@ -1333,7 +1334,7 @@ void LottieParser::parseFill(LottieFxFill* effect)
|
||||||
|
|
||||||
void LottieParser::parseGaussianBlur(LottieFxGaussianBlur* effect)
|
void LottieParser::parseGaussianBlur(LottieFxGaussianBlur* effect)
|
||||||
{
|
{
|
||||||
int idx = 0; //blurness -> direction -> wrap
|
int idx = 0;
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) {
|
while (nextArrayValue()) {
|
||||||
enterObject();
|
enterObject();
|
||||||
|
@ -1357,7 +1358,7 @@ void LottieParser::parseGaussianBlur(LottieFxGaussianBlur* effect)
|
||||||
|
|
||||||
void LottieParser::parseDropShadow(LottieFxDropShadow* effect)
|
void LottieParser::parseDropShadow(LottieFxDropShadow* effect)
|
||||||
{
|
{
|
||||||
int idx = 0; //color -> opacity -> angle -> distance -> blur
|
int idx = 0;
|
||||||
enterArray();
|
enterArray();
|
||||||
while (nextArrayValue()) {
|
while (nextArrayValue()) {
|
||||||
enterObject();
|
enterObject();
|
||||||
|
@ -1381,6 +1382,34 @@ void LottieParser::parseDropShadow(LottieFxDropShadow* effect)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void LottieParser::parseStroke(LottieFxStroke* effect)
|
||||||
|
{
|
||||||
|
int idx = 0;
|
||||||
|
enterArray();
|
||||||
|
while (nextArrayValue()) {
|
||||||
|
enterObject();
|
||||||
|
while (auto key = nextObjectKey()) {
|
||||||
|
if (KEY_AS("v")) {
|
||||||
|
enterObject();
|
||||||
|
while (auto key = nextObjectKey()) {
|
||||||
|
if (KEY_AS("k")) {
|
||||||
|
if (idx == 0) parsePropertyInternal(effect->mask);
|
||||||
|
else if (idx == 1) parsePropertyInternal(effect->allMask);
|
||||||
|
else if (idx == 3) parsePropertyInternal(effect->color);
|
||||||
|
else if (idx == 4) parsePropertyInternal(effect->size);
|
||||||
|
else if (idx == 6) parsePropertyInternal(effect->opacity);
|
||||||
|
else if (idx == 7) parsePropertyInternal(effect->begin);
|
||||||
|
else if (idx == 8) parsePropertyInternal(effect->end);
|
||||||
|
else skip();
|
||||||
|
++idx;
|
||||||
|
} else skip();
|
||||||
|
}
|
||||||
|
} else skip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void LottieParser::parseEffect(LottieEffect* effect)
|
void LottieParser::parseEffect(LottieEffect* effect)
|
||||||
{
|
{
|
||||||
switch (effect->type) {
|
switch (effect->type) {
|
||||||
|
@ -1392,6 +1421,10 @@ void LottieParser::parseEffect(LottieEffect* effect)
|
||||||
parseFill(static_cast<LottieFxFill*>(effect));
|
parseFill(static_cast<LottieFxFill*>(effect));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case LottieEffect::Stroke: {
|
||||||
|
parseStroke(static_cast<LottieFxStroke*>(effect));
|
||||||
|
break;
|
||||||
|
}
|
||||||
case LottieEffect::Tritone: {
|
case LottieEffect::Tritone: {
|
||||||
parseTritone(static_cast<LottieFxTritone*>(effect));
|
parseTritone(static_cast<LottieFxTritone*>(effect));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -98,6 +98,7 @@ private:
|
||||||
LottieFont* parseFont();
|
LottieFont* parseFont();
|
||||||
LottieMarker* parseMarker();
|
LottieMarker* parseMarker();
|
||||||
|
|
||||||
|
void parseStroke(LottieFxStroke* effect);
|
||||||
void parseTritone(LottieFxTritone* effect);
|
void parseTritone(LottieFxTritone* effect);
|
||||||
void parseTint(LottieFxTint* effect);
|
void parseTint(LottieFxTint* effect);
|
||||||
void parseFill(LottieFxFill* effect);
|
void parseFill(LottieFxFill* effect);
|
||||||
|
|
|
@ -920,8 +920,6 @@ using LottiePoint = LottieGenericProperty<Point>;
|
||||||
using LottieFloat = LottieGenericProperty<float>;
|
using LottieFloat = LottieGenericProperty<float>;
|
||||||
using LottieOpacity = LottieGenericProperty<uint8_t>;
|
using LottieOpacity = LottieGenericProperty<uint8_t>;
|
||||||
using LottieColor = LottieGenericProperty<RGB24>;
|
using LottieColor = LottieGenericProperty<RGB24>;
|
||||||
using LottieSlider = LottieFloat;
|
using LottieInteger = LottieGenericProperty<int8_t>;
|
||||||
using LottieAngle = LottieFloat;
|
|
||||||
using LottieCheckbox = LottieGenericProperty<int8_t>;
|
|
||||||
|
|
||||||
#endif //_TVG_LOTTIE_PROPERTY_H_
|
#endif //_TVG_LOTTIE_PROPERTY_H_
|
||||||
|
|
Loading…
Add table
Reference in a new issue