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
e0588d39f0
commit
d00b727cd4
6 changed files with 138 additions and 27 deletions
|
@ -1225,7 +1225,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;
|
||||
|
||||
|
@ -1311,6 +1311,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, P(shape)->rs.path.cmds, P(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, P(shape)->rs.path.cmds, P(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->stroke(255, 255, 255, (int)(effect->opacity(frameNo) * 255.0f));
|
||||
shape->stroke(StrokeJoin::Round);
|
||||
shape->stroke(StrokeCap::Round);
|
||||
|
||||
auto size = effect->size(frameNo) * 2.0f;
|
||||
shape->stroke(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->stroke(size);
|
||||
shape->stroke(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->composite(cast(shape), CompositeMethod::AlphaMask);
|
||||
}
|
||||
|
||||
|
||||
void LottieBuilder::updateEffect(LottieLayer* layer, float frameNo)
|
||||
{
|
||||
constexpr int QUALITY = 25;
|
||||
|
@ -1334,6 +1388,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)));
|
||||
break;
|
||||
}
|
||||
case LottieEffect::Stroke: {
|
||||
auto effect = static_cast<LottieFxStroke*>(*ef);
|
||||
updateStrokeEffect(layer, effect, frameNo);
|
||||
break;
|
||||
}
|
||||
case LottieEffect::Tritone: {
|
||||
auto effect = static_cast<LottieFxTritone*>(*ef);
|
||||
auto dark = effect->dark(frameNo);
|
||||
|
@ -1411,7 +1470,7 @@ void LottieBuilder::updateLayer(LottieComposition* comp, Scene* scene, LottieLay
|
|||
}
|
||||
}
|
||||
|
||||
updateMaskings(layer, frameNo);
|
||||
updateMasks(layer, frameNo);
|
||||
|
||||
layer->scene->blend(layer->blendMethod);
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ struct LottieBuilder
|
|||
void build(LottieComposition* comp);
|
||||
|
||||
private:
|
||||
void updateStrokeEffect(LottieLayer* layer, LottieFxStroke* effect, float frameNo);
|
||||
void updateEffect(LottieLayer* layer, float frameNo);
|
||||
void updateLayer(LottieComposition* comp, Scene* scene, LottieLayer* layer, float frameNo);
|
||||
bool updateMatte(LottieComposition* comp, float frameNo, Scene* scene, LottieLayer* layer);
|
||||
|
@ -110,7 +111,7 @@ private:
|
|||
void updateSolid(LottieLayer* layer);
|
||||
void updateImage(LottieGroup* layer);
|
||||
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 updateChildren(LottieGroup* parent, float frameNo, Inlist<RenderContext>& contexts);
|
||||
void updateGroup(LottieGroup* parent, LottieObject** child, float frameNo, Inlist<RenderContext>& pcontexts, RenderContext* ctx);
|
||||
|
|
|
@ -76,10 +76,9 @@ struct LottieStroke
|
|||
StrokeJoin join = StrokeJoin::Round;
|
||||
};
|
||||
|
||||
|
||||
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() {}
|
||||
Type type;
|
||||
|
@ -88,13 +87,13 @@ struct LottieEffect
|
|||
|
||||
struct LottieFxFill : LottieEffect
|
||||
{
|
||||
//int16_t mask layer
|
||||
//LottieDropDown allMask?
|
||||
//LottieInteger mask;
|
||||
//LottieInteger allMask;
|
||||
LottieColor color;
|
||||
//LottieDropDown inverted
|
||||
//LottieSlider horizontalFeather
|
||||
//LottieSlider verticalFeather
|
||||
LottieSlider opacity;
|
||||
//LottieInteger invert;
|
||||
//LottieSlider hFeather;
|
||||
//LottieSlider vFeather;
|
||||
LottieFloat opacity;
|
||||
|
||||
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
|
||||
{
|
||||
LottieColor black;
|
||||
LottieColor white;
|
||||
LottieSlider intensity;
|
||||
LottieFloat intensity;
|
||||
|
||||
LottieFxTint()
|
||||
{
|
||||
|
@ -129,10 +148,10 @@ struct LottieFxTritone : LottieEffect
|
|||
struct LottieFxDropShadow : LottieEffect
|
||||
{
|
||||
LottieColor color;
|
||||
LottieSlider opacity = 0;
|
||||
LottieAngle angle = 0.0f;
|
||||
LottieSlider distance = 0.0f;
|
||||
LottieSlider blurness = 0.0f;
|
||||
LottieFloat opacity = 0;
|
||||
LottieFloat angle = 0.0f;
|
||||
LottieFloat distance = 0.0f;
|
||||
LottieFloat blurness = 0.0f;
|
||||
|
||||
LottieFxDropShadow()
|
||||
{
|
||||
|
@ -142,9 +161,9 @@ struct LottieFxDropShadow : LottieEffect
|
|||
|
||||
struct LottieFxGaussianBlur : LottieEffect
|
||||
{
|
||||
LottieSlider blurness = 0.0f;
|
||||
LottieCheckbox direction = 0;
|
||||
LottieCheckbox wrap = 0;
|
||||
LottieFloat blurness = 0.0f;
|
||||
LottieInteger direction = 0;
|
||||
LottieInteger wrap = 0;
|
||||
|
||||
LottieFxGaussianBlur()
|
||||
{
|
||||
|
|
|
@ -62,6 +62,7 @@ LottieEffect* LottieParser::getEffect(int type)
|
|||
switch (type) {
|
||||
case LottieEffect::Tint: return new LottieFxTint;
|
||||
case LottieEffect::Fill: return new LottieFxFill;
|
||||
case LottieEffect::Stroke: return new LottieFxStroke;
|
||||
case LottieEffect::Tritone: return new LottieFxTritone;
|
||||
case LottieEffect::DropShadow: return new LottieFxDropShadow;
|
||||
case LottieEffect::GaussianBlur: return new LottieFxGaussianBlur;
|
||||
|
@ -1261,7 +1262,7 @@ void LottieParser::parseMasks(LottieLayer* layer)
|
|||
|
||||
void LottieParser::parseTint(LottieFxTint* effect)
|
||||
{
|
||||
int idx = 0; //black -> white -> intenstiy
|
||||
int idx = 0;
|
||||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
enterObject();
|
||||
|
@ -1285,7 +1286,7 @@ void LottieParser::parseTint(LottieFxTint* effect)
|
|||
|
||||
void LottieParser::parseTritone(LottieFxTritone* effect)
|
||||
{
|
||||
int idx = 0; //bright, midtone, dark
|
||||
int idx = 0;
|
||||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
enterObject();
|
||||
|
@ -1309,7 +1310,7 @@ void LottieParser::parseTritone(LottieFxTritone* effect)
|
|||
|
||||
void LottieParser::parseFill(LottieFxFill* effect)
|
||||
{
|
||||
int idx = 0; //fill mask -> all mask -> color -> invert -> h feather -> v feather -> opacity
|
||||
int idx = 0;
|
||||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
enterObject();
|
||||
|
@ -1332,7 +1333,7 @@ void LottieParser::parseFill(LottieFxFill* effect)
|
|||
|
||||
void LottieParser::parseGaussianBlur(LottieFxGaussianBlur* effect)
|
||||
{
|
||||
int idx = 0; //blurness -> direction -> wrap
|
||||
int idx = 0;
|
||||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
enterObject();
|
||||
|
@ -1356,7 +1357,7 @@ void LottieParser::parseGaussianBlur(LottieFxGaussianBlur* effect)
|
|||
|
||||
void LottieParser::parseDropShadow(LottieFxDropShadow* effect)
|
||||
{
|
||||
int idx = 0; //color -> opacity -> angle -> distance -> blur
|
||||
int idx = 0;
|
||||
enterArray();
|
||||
while (nextArrayValue()) {
|
||||
enterObject();
|
||||
|
@ -1380,6 +1381,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(key);
|
||||
++idx;
|
||||
} else skip(key);
|
||||
}
|
||||
} else skip(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LottieParser::parseEffect(LottieEffect* effect)
|
||||
{
|
||||
switch (effect->type) {
|
||||
|
@ -1391,6 +1420,10 @@ void LottieParser::parseEffect(LottieEffect* effect)
|
|||
parseFill(static_cast<LottieFxFill*>(effect));
|
||||
break;
|
||||
}
|
||||
case LottieEffect::Stroke: {
|
||||
parseStroke(static_cast<LottieFxStroke*>(effect));
|
||||
break;
|
||||
}
|
||||
case LottieEffect::Tritone: {
|
||||
parseTritone(static_cast<LottieFxTritone*>(effect));
|
||||
break;
|
||||
|
|
|
@ -98,6 +98,7 @@ private:
|
|||
LottieFont* parseFont();
|
||||
LottieMarker* parseMarker();
|
||||
|
||||
void parseStroke(LottieFxStroke* effect);
|
||||
void parseTritone(LottieFxTritone* effect);
|
||||
void parseTint(LottieFxTint* effect);
|
||||
void parseFill(LottieFxFill* effect);
|
||||
|
|
|
@ -920,8 +920,6 @@ using LottiePoint = LottieGenericProperty<Point>;
|
|||
using LottieFloat = LottieGenericProperty<float>;
|
||||
using LottieOpacity = LottieGenericProperty<uint8_t>;
|
||||
using LottieColor = LottieGenericProperty<RGB24>;
|
||||
using LottieSlider = LottieFloat;
|
||||
using LottieAngle = LottieFloat;
|
||||
using LottieCheckbox = LottieGenericProperty<int8_t>;
|
||||
using LottieInteger = LottieGenericProperty<int8_t>;
|
||||
|
||||
#endif //_TVG_LOTTIE_PROPERTY_H_
|
||||
|
|
Loading…
Add table
Reference in a new issue