mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
[WIP] Lottie optimizations
This commit is contained in:
parent
ea4a203285
commit
e926ad9776
@ -58,18 +58,6 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*if (node->content()) {
|
|
||||||
RenderTreeNodeContent *shapeContent = node->content().get();
|
|
||||||
|
|
||||||
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, shapeContent->paths);
|
|
||||||
|
|
||||||
if (shapeContent->stroke) {
|
|
||||||
shapeBounds = shapeBounds.insetBy(-shapeContent->stroke->lineWidth / 2.0, -shapeContent->stroke->lineWidth / 2.0);
|
|
||||||
effectiveLocalBounds = shapeBounds;
|
|
||||||
} else if (shapeContent->fill) {
|
|
||||||
effectiveLocalBounds = shapeBounds;
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
|
|
||||||
bool isInvertedMatte = isInvertedMask;
|
bool isInvertedMatte = isInvertedMask;
|
||||||
if (isInvertedMatte) {
|
if (isInvertedMatte) {
|
||||||
@ -95,7 +83,7 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
if (item->renderData.isValid) {
|
if (item->renderData.isValid) {
|
||||||
drawContentDescendants += item->renderData.drawContentDescendants;
|
drawContentDescendants += item->renderData.drawContentDescendants;
|
||||||
|
|
||||||
if (item->content() || item->_contentItem) {
|
if (item->_contentItem) {
|
||||||
drawContentDescendants += 1;
|
drawContentDescendants += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,167 +188,6 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static void drawLottieRenderableItem(std::shared_ptr<lottieRendering::Canvas> context, std::shared_ptr<lottie::RenderTreeNodeContent> item) {
|
|
||||||
if (item->paths.empty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<lottie::CGPath> path = lottie::CGPath::makePath();
|
|
||||||
|
|
||||||
const auto iterate = [&](LottiePathItem const *pathItem) {
|
|
||||||
switch (pathItem->type) {
|
|
||||||
case LottiePathItemTypeMoveTo: {
|
|
||||||
path->moveTo(lottie::Vector2D(pathItem->points[0].x, pathItem->points[0].y));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LottiePathItemTypeLineTo: {
|
|
||||||
path->addLineTo(lottie::Vector2D(pathItem->points[0].x, pathItem->points[0].y));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LottiePathItemTypeCurveTo: {
|
|
||||||
path->addCurveTo(lottie::Vector2D(pathItem->points[2].x, pathItem->points[2].y), lottie::Vector2D(pathItem->points[0].x, pathItem->points[0].y), lottie::Vector2D(pathItem->points[1].x, pathItem->points[1].y));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case LottiePathItemTypeClose: {
|
|
||||||
path->closeSubpath();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LottiePathItem pathItem;
|
|
||||||
for (const auto &path : item->paths) {
|
|
||||||
std::optional<lottie::PathElement> previousElement;
|
|
||||||
for (const auto &element : path.elements()) {
|
|
||||||
if (previousElement.has_value()) {
|
|
||||||
if (previousElement->vertex.outTangentRelative().isZero() && element.vertex.inTangentRelative().isZero()) {
|
|
||||||
pathItem.type = LottiePathItemTypeLineTo;
|
|
||||||
pathItem.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
|
||||||
iterate(&pathItem);
|
|
||||||
} else {
|
|
||||||
pathItem.type = LottiePathItemTypeCurveTo;
|
|
||||||
pathItem.points[2] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
|
||||||
pathItem.points[1] = CGPointMake(element.vertex.inTangent.x, element.vertex.inTangent.y);
|
|
||||||
pathItem.points[0] = CGPointMake(previousElement->vertex.outTangent.x, previousElement->vertex.outTangent.y);
|
|
||||||
iterate(&pathItem);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pathItem.type = LottiePathItemTypeMoveTo;
|
|
||||||
pathItem.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y);
|
|
||||||
iterate(&pathItem);
|
|
||||||
}
|
|
||||||
previousElement = element;
|
|
||||||
}
|
|
||||||
if (path.closed().value_or(true)) {
|
|
||||||
pathItem.type = LottiePathItemTypeClose;
|
|
||||||
iterate(&pathItem);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->stroke) {
|
|
||||||
if (item->stroke->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Solid) {
|
|
||||||
lottie::RenderTreeNodeContent::SolidShading *solidShading = (lottie::RenderTreeNodeContent::SolidShading *)item->stroke->shading.get();
|
|
||||||
|
|
||||||
lottieRendering::LineJoin lineJoin = lottieRendering::LineJoin::Bevel;
|
|
||||||
switch (item->stroke->lineJoin) {
|
|
||||||
case lottie::LineJoin::Bevel: {
|
|
||||||
lineJoin = lottieRendering::LineJoin::Bevel;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case lottie::LineJoin::Round: {
|
|
||||||
lineJoin = lottieRendering::LineJoin::Round;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case lottie::LineJoin::Miter: {
|
|
||||||
lineJoin = lottieRendering::LineJoin::Miter;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lottieRendering::LineCap lineCap = lottieRendering::LineCap::Square;
|
|
||||||
switch (item->stroke->lineCap) {
|
|
||||||
case lottie::LineCap::Butt: {
|
|
||||||
lineCap = lottieRendering::LineCap::Butt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case lottie::LineCap::Round: {
|
|
||||||
lineCap = lottieRendering::LineCap::Round;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case lottie::LineCap::Square: {
|
|
||||||
lineCap = lottieRendering::LineCap::Square;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<double> dashPattern;
|
|
||||||
if (!item->stroke->dashPattern.empty()) {
|
|
||||||
dashPattern = item->stroke->dashPattern;
|
|
||||||
}
|
|
||||||
|
|
||||||
context->strokePath(path, item->stroke->lineWidth, lineJoin, lineCap, item->stroke->dashPhase, dashPattern, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
|
||||||
} else if (item->stroke->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
|
||||||
//TODO:gradient stroke
|
|
||||||
}
|
|
||||||
} else if (item->fill) {
|
|
||||||
lottieRendering::FillRule rule = lottieRendering::FillRule::NonZeroWinding;
|
|
||||||
switch (item->fill->rule) {
|
|
||||||
case lottie::FillRule::EvenOdd: {
|
|
||||||
rule = lottieRendering::FillRule::EvenOdd;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case lottie::FillRule::NonZeroWinding: {
|
|
||||||
rule = lottieRendering::FillRule::NonZeroWinding;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Solid) {
|
|
||||||
lottie::RenderTreeNodeContent::SolidShading *solidShading = (lottie::RenderTreeNodeContent::SolidShading *)item->fill->shading.get();
|
|
||||||
context->fillPath(path, rule, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
|
||||||
} else if (item->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
|
||||||
lottie::RenderTreeNodeContent::GradientShading *gradientShading = (lottie::RenderTreeNodeContent::GradientShading *)item->fill->shading.get();
|
|
||||||
|
|
||||||
std::vector<lottieRendering::Color> colors;
|
|
||||||
std::vector<double> locations;
|
|
||||||
for (const auto &color : gradientShading->colors) {
|
|
||||||
colors.push_back(lottieRendering::Color(color.r, color.g, color.b, color.a * gradientShading->opacity));
|
|
||||||
}
|
|
||||||
locations = gradientShading->locations;
|
|
||||||
|
|
||||||
lottieRendering::Gradient gradient(colors, locations);
|
|
||||||
lottie::Vector2D start(gradientShading->start.x, gradientShading->start.y);
|
|
||||||
lottie::Vector2D end(gradientShading->end.x, gradientShading->end.y);
|
|
||||||
|
|
||||||
switch (gradientShading->gradientType) {
|
|
||||||
case lottie::GradientType::Linear: {
|
|
||||||
context->linearGradientFillPath(path, rule, gradient, start, end);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case lottie::GradientType::Radial: {
|
|
||||||
context->radialGradientFillPath(path, rule, gradient, start, 0.0, start, start.distanceTo(end));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> context, std::shared_ptr<lottie::RenderTreeNodeContentItem> item) {
|
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> context, std::shared_ptr<lottie::RenderTreeNodeContentItem> item) {
|
||||||
if (item->shadings.empty()) {
|
if (item->shadings.empty()) {
|
||||||
return;
|
return;
|
||||||
@ -427,8 +254,8 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (shading->stroke) {
|
if (shading->stroke) {
|
||||||
if (shading->stroke->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Solid) {
|
if (shading->stroke->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Solid) {
|
||||||
lottie::RenderTreeNodeContent::SolidShading *solidShading = (lottie::RenderTreeNodeContent::SolidShading *)shading->stroke->shading.get();
|
lottie::RenderTreeNodeContentItem::SolidShading *solidShading = (lottie::RenderTreeNodeContentItem::SolidShading *)shading->stroke->shading.get();
|
||||||
|
|
||||||
if (solidShading->opacity != 0.0) {
|
if (solidShading->opacity != 0.0) {
|
||||||
lottieRendering::LineJoin lineJoin = lottieRendering::LineJoin::Bevel;
|
lottieRendering::LineJoin lineJoin = lottieRendering::LineJoin::Bevel;
|
||||||
@ -475,7 +302,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
|||||||
}
|
}
|
||||||
|
|
||||||
context->strokePath(path, shading->stroke->lineWidth, lineJoin, lineCap, shading->stroke->dashPhase, dashPattern, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
context->strokePath(path, shading->stroke->lineWidth, lineJoin, lineCap, shading->stroke->dashPhase, dashPattern, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
||||||
} else if (shading->stroke->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
} else if (shading->stroke->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Gradient) {
|
||||||
//TODO:gradient stroke
|
//TODO:gradient stroke
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -495,13 +322,13 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shading->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Solid) {
|
if (shading->fill->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Solid) {
|
||||||
lottie::RenderTreeNodeContent::SolidShading *solidShading = (lottie::RenderTreeNodeContent::SolidShading *)shading->fill->shading.get();
|
lottie::RenderTreeNodeContentItem::SolidShading *solidShading = (lottie::RenderTreeNodeContentItem::SolidShading *)shading->fill->shading.get();
|
||||||
if (solidShading->opacity != 0.0) {
|
if (solidShading->opacity != 0.0) {
|
||||||
context->fillPath(path, rule, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
context->fillPath(path, rule, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity));
|
||||||
}
|
}
|
||||||
} else if (shading->fill->shading->type() == lottie::RenderTreeNodeContent::ShadingType::Gradient) {
|
} else if (shading->fill->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Gradient) {
|
||||||
lottie::RenderTreeNodeContent::GradientShading *gradientShading = (lottie::RenderTreeNodeContent::GradientShading *)shading->fill->shading.get();
|
lottie::RenderTreeNodeContentItem::GradientShading *gradientShading = (lottie::RenderTreeNodeContentItem::GradientShading *)shading->fill->shading.get();
|
||||||
|
|
||||||
if (gradientShading->opacity != 0.0) {
|
if (gradientShading->opacity != 0.0) {
|
||||||
std::vector<lottieRendering::Color> colors;
|
std::vector<lottieRendering::Color> colors;
|
||||||
@ -600,10 +427,7 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
|
|||||||
|
|
||||||
currentContext->setAlpha(renderAlpha);
|
currentContext->setAlpha(renderAlpha);
|
||||||
|
|
||||||
if (node->content() && (int64_t)"" < 0) {
|
if (node->_contentItem) {
|
||||||
drawLottieRenderableItem(currentContext, node->content());
|
|
||||||
}
|
|
||||||
if (node->_contentItem) {//} && (int64_t)"" < 0) {
|
|
||||||
drawLottieContentItem(currentContext, node->_contentItem);
|
drawLottieContentItem(currentContext, node->_contentItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,9 +231,9 @@ public:
|
|||||||
CGRect bounds;
|
CGRect bounds;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderTreeNodeContentItem;
|
class RenderTreeNodeContentShadingVariant;
|
||||||
|
|
||||||
class RenderTreeNodeContent {
|
class RenderTreeNodeContentItem {
|
||||||
public:
|
public:
|
||||||
enum class ShadingType {
|
enum class ShadingType {
|
||||||
Solid,
|
Solid,
|
||||||
@ -339,20 +339,12 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RenderTreeNodeContent(
|
RenderTreeNodeContentItem() {
|
||||||
std::vector<BezierPath> paths_,
|
|
||||||
std::shared_ptr<Stroke> stroke_,
|
|
||||||
std::shared_ptr<Fill> fill_
|
|
||||||
) :
|
|
||||||
paths(paths_),
|
|
||||||
stroke(stroke_),
|
|
||||||
fill(fill_) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::vector<BezierPath> paths;
|
bool isGroup = false;
|
||||||
std::shared_ptr<Stroke> stroke;
|
std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings;
|
||||||
std::shared_ptr<Fill> fill;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderTreeNodeContentShadingVariant {
|
class RenderTreeNodeContentShadingVariant {
|
||||||
@ -361,24 +353,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<RenderTreeNodeContent::Stroke> stroke;
|
std::shared_ptr<RenderTreeNodeContentItem::Stroke> stroke;
|
||||||
std::shared_ptr<RenderTreeNodeContent::Fill> fill;
|
std::shared_ptr<RenderTreeNodeContentItem::Fill> fill;
|
||||||
std::optional<std::vector<BezierPath>> explicitPath;
|
std::optional<std::vector<BezierPath>> explicitPath;
|
||||||
|
|
||||||
size_t subItemLimit = 0;
|
size_t subItemLimit = 0;
|
||||||
bool isGroup = false;
|
bool isGroup = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
class RenderTreeNodeContentItem {
|
|
||||||
public:
|
|
||||||
RenderTreeNodeContentItem() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
bool isGroup = false;
|
|
||||||
std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ProcessedRenderTreeNodeData {
|
class ProcessedRenderTreeNodeData {
|
||||||
public:
|
public:
|
||||||
struct LayerParams {
|
struct LayerParams {
|
||||||
@ -468,7 +450,6 @@ public:
|
|||||||
double alpha_,
|
double alpha_,
|
||||||
bool masksToBounds_,
|
bool masksToBounds_,
|
||||||
bool isHidden_,
|
bool isHidden_,
|
||||||
std::shared_ptr<RenderTreeNodeContent> content_,
|
|
||||||
std::vector<std::shared_ptr<RenderTreeNode>> subnodes_,
|
std::vector<std::shared_ptr<RenderTreeNode>> subnodes_,
|
||||||
std::shared_ptr<RenderTreeNode> mask_,
|
std::shared_ptr<RenderTreeNode> mask_,
|
||||||
bool invertMask_
|
bool invertMask_
|
||||||
@ -479,7 +460,6 @@ public:
|
|||||||
_alpha(alpha_),
|
_alpha(alpha_),
|
||||||
_masksToBounds(masksToBounds_),
|
_masksToBounds(masksToBounds_),
|
||||||
_isHidden(isHidden_),
|
_isHidden(isHidden_),
|
||||||
_content(content_),
|
|
||||||
_subnodes(subnodes_),
|
_subnodes(subnodes_),
|
||||||
_mask(mask_),
|
_mask(mask_),
|
||||||
_invertMask(invertMask_) {
|
_invertMask(invertMask_) {
|
||||||
@ -513,10 +493,6 @@ public:
|
|||||||
return _isHidden;
|
return _isHidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent> const &content() const {
|
|
||||||
return _content;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<RenderTreeNode>> const &subnodes() const {
|
std::vector<std::shared_ptr<RenderTreeNode>> const &subnodes() const {
|
||||||
return _subnodes;
|
return _subnodes;
|
||||||
}
|
}
|
||||||
@ -536,7 +512,6 @@ public:
|
|||||||
double _alpha = 1.0;
|
double _alpha = 1.0;
|
||||||
bool _masksToBounds = false;
|
bool _masksToBounds = false;
|
||||||
bool _isHidden = false;
|
bool _isHidden = false;
|
||||||
std::shared_ptr<RenderTreeNodeContent> _content;
|
|
||||||
std::shared_ptr<RenderTreeNodeContentItem> _contentItem;
|
std::shared_ptr<RenderTreeNodeContentItem> _contentItem;
|
||||||
std::vector<std::shared_ptr<RenderTreeNode>> _subnodes;
|
std::vector<std::shared_ptr<RenderTreeNode>> _subnodes;
|
||||||
std::shared_ptr<RenderTreeNode> _mask;
|
std::shared_ptr<RenderTreeNode> _mask;
|
||||||
|
@ -109,7 +109,6 @@ public:
|
|||||||
1.0,
|
1.0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
|
||||||
std::vector<std::shared_ptr<RenderTreeNode>>(),
|
std::vector<std::shared_ptr<RenderTreeNode>>(),
|
||||||
nullptr,
|
nullptr,
|
||||||
false
|
false
|
||||||
@ -134,7 +133,6 @@ public:
|
|||||||
1.0,
|
1.0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
|
||||||
subnodes,
|
subnodes,
|
||||||
maskNode,
|
maskNode,
|
||||||
invertMask
|
invertMask
|
||||||
@ -165,7 +163,6 @@ public:
|
|||||||
1.0,
|
1.0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
|
||||||
renderTreeSubnodes,
|
renderTreeSubnodes,
|
||||||
nullptr,
|
nullptr,
|
||||||
false
|
false
|
||||||
|
@ -25,7 +25,7 @@ public:
|
|||||||
~FillOutput() = default;
|
~FillOutput() = default;
|
||||||
|
|
||||||
virtual void update(AnimationFrameTime frameTime) = 0;
|
virtual void update(AnimationFrameTime frameTime) = 0;
|
||||||
virtual std::shared_ptr<RenderTreeNodeContent::Fill> fill() = 0;
|
virtual std::shared_ptr<RenderTreeNodeContentItem::Fill> fill() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SolidFillOutput : public FillOutput {
|
class SolidFillOutput : public FillOutput {
|
||||||
@ -34,6 +34,11 @@ public:
|
|||||||
rule(fill.fillRule.value_or(FillRule::NonZeroWinding)),
|
rule(fill.fillRule.value_or(FillRule::NonZeroWinding)),
|
||||||
color(fill.color.keyframes),
|
color(fill.color.keyframes),
|
||||||
opacity(fill.opacity.keyframes) {
|
opacity(fill.opacity.keyframes) {
|
||||||
|
auto solid = std::make_shared<RenderTreeNodeContentItem::SolidShading>(Color(0.0, 0.0, 0.0, 0.0), 0.0);
|
||||||
|
_fill = std::make_shared<RenderTreeNodeContentItem::Fill>(
|
||||||
|
solid,
|
||||||
|
rule
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SolidFillOutput() = default;
|
virtual ~SolidFillOutput() = default;
|
||||||
@ -51,16 +56,14 @@ public:
|
|||||||
opacityValue = opacity.value(frameTime).value;
|
opacityValue = opacity.value(frameTime).value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_fill || hasUpdates) {
|
if (hasUpdates) {
|
||||||
auto solid = std::make_shared<RenderTreeNodeContent::SolidShading>(colorValue, opacityValue * 0.01);
|
RenderTreeNodeContentItem::SolidShading *solid = (RenderTreeNodeContentItem::SolidShading *)_fill->shading.get();
|
||||||
_fill = std::make_shared<RenderTreeNodeContent::Fill>(
|
solid->color = colorValue;
|
||||||
solid,
|
solid->opacity = opacityValue * 0.01;
|
||||||
rule
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::shared_ptr<RenderTreeNodeContent::Fill> fill() override {
|
virtual std::shared_ptr<RenderTreeNodeContentItem::Fill> fill() override {
|
||||||
return _fill;
|
return _fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,7 +76,7 @@ public:
|
|||||||
KeyframeInterpolator<Vector1D> opacity;
|
KeyframeInterpolator<Vector1D> opacity;
|
||||||
double opacityValue = 0.0;
|
double opacityValue = 0.0;
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent::Fill> _fill;
|
std::shared_ptr<RenderTreeNodeContentItem::Fill> _fill;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GradientFillOutput : public FillOutput {
|
class GradientFillOutput : public FillOutput {
|
||||||
@ -86,6 +89,18 @@ public:
|
|||||||
startPoint(gradientFill.startPoint.keyframes),
|
startPoint(gradientFill.startPoint.keyframes),
|
||||||
endPoint(gradientFill.endPoint.keyframes),
|
endPoint(gradientFill.endPoint.keyframes),
|
||||||
opacity(gradientFill.opacity.keyframes) {
|
opacity(gradientFill.opacity.keyframes) {
|
||||||
|
auto gradient = std::make_shared<RenderTreeNodeContentItem::GradientShading>(
|
||||||
|
0.0,
|
||||||
|
gradientType,
|
||||||
|
std::vector<Color>(),
|
||||||
|
std::vector<double>(),
|
||||||
|
Vector2D(0.0, 0.0),
|
||||||
|
Vector2D(0.0, 0.0)
|
||||||
|
);
|
||||||
|
_fill = std::make_shared<RenderTreeNodeContentItem::Fill>(
|
||||||
|
gradient,
|
||||||
|
rule
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GradientFillOutput() = default;
|
virtual ~GradientFillOutput() = default;
|
||||||
@ -113,27 +128,21 @@ public:
|
|||||||
opacityValue = opacity.value(frameTime).value;
|
opacityValue = opacity.value(frameTime).value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_fill || hasUpdates) {
|
if (hasUpdates) {
|
||||||
std::vector<Color> colors;
|
std::vector<Color> colors;
|
||||||
std::vector<double> locations;
|
std::vector<double> locations;
|
||||||
getGradientParameters(numberOfColors, colorsValue, colors, locations);
|
getGradientParameters(numberOfColors, colorsValue, colors, locations);
|
||||||
|
|
||||||
auto gradient = std::make_shared<RenderTreeNodeContent::GradientShading>(
|
RenderTreeNodeContentItem::GradientShading *gradient = ((RenderTreeNodeContentItem::GradientShading *)_fill->shading.get());
|
||||||
opacityValue * 0.01,
|
gradient->opacity = opacityValue * 0.01;
|
||||||
gradientType,
|
gradient->colors = colors;
|
||||||
colors,
|
gradient->locations = locations;
|
||||||
locations,
|
gradient->start = Vector2D(startPointValue.x, startPointValue.y);
|
||||||
Vector2D(startPointValue.x, startPointValue.y),
|
gradient->end = Vector2D(endPointValue.x, endPointValue.y);
|
||||||
Vector2D(endPointValue.x, endPointValue.y)
|
|
||||||
);
|
|
||||||
_fill = std::make_shared<RenderTreeNodeContent::Fill>(
|
|
||||||
gradient,
|
|
||||||
rule
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::shared_ptr<RenderTreeNodeContent::Fill> fill() override {
|
virtual std::shared_ptr<RenderTreeNodeContentItem::Fill> fill() override {
|
||||||
return _fill;
|
return _fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +163,7 @@ public:
|
|||||||
KeyframeInterpolator<Vector1D> opacity;
|
KeyframeInterpolator<Vector1D> opacity;
|
||||||
double opacityValue = 0.0;
|
double opacityValue = 0.0;
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent::Fill> _fill;
|
std::shared_ptr<RenderTreeNodeContentItem::Fill> _fill;
|
||||||
};
|
};
|
||||||
|
|
||||||
class StrokeOutput {
|
class StrokeOutput {
|
||||||
@ -164,7 +173,7 @@ public:
|
|||||||
~StrokeOutput() = default;
|
~StrokeOutput() = default;
|
||||||
|
|
||||||
virtual void update(AnimationFrameTime frameTime) = 0;
|
virtual void update(AnimationFrameTime frameTime) = 0;
|
||||||
virtual std::shared_ptr<RenderTreeNodeContent::Stroke> stroke() = 0;
|
virtual std::shared_ptr<RenderTreeNodeContentItem::Stroke> stroke() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SolidStrokeOutput : public StrokeOutput {
|
class SolidStrokeOutput : public StrokeOutput {
|
||||||
@ -184,6 +193,17 @@ public:
|
|||||||
dashPhase = std::make_unique<KeyframeInterpolator<Vector1D>>(dashConfiguration.dashPhase);
|
dashPhase = std::make_unique<KeyframeInterpolator<Vector1D>>(dashConfiguration.dashPhase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto solid = std::make_shared<RenderTreeNodeContentItem::SolidShading>(Color(0.0, 0.0, 0.0, 0.0), 0.0);
|
||||||
|
_stroke = std::make_shared<RenderTreeNodeContentItem::Stroke>(
|
||||||
|
solid,
|
||||||
|
0.0,
|
||||||
|
lineJoin,
|
||||||
|
lineCap,
|
||||||
|
miterLimit,
|
||||||
|
0.0,
|
||||||
|
std::vector<double>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~SolidStrokeOutput() = default;
|
virtual ~SolidStrokeOutput() = default;
|
||||||
@ -220,7 +240,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_stroke || hasUpdates) {
|
if (hasUpdates) {
|
||||||
bool hasNonZeroDashes = false;
|
bool hasNonZeroDashes = false;
|
||||||
if (!dashPatternValue.values.empty()) {
|
if (!dashPatternValue.values.empty()) {
|
||||||
for (const auto &value : dashPatternValue.values) {
|
for (const auto &value : dashPatternValue.values) {
|
||||||
@ -231,20 +251,17 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto solid = std::make_shared<RenderTreeNodeContent::SolidShading>(colorValue, opacityValue * 0.01);
|
RenderTreeNodeContentItem::SolidShading *solid = (RenderTreeNodeContentItem::SolidShading *)_stroke->shading.get();
|
||||||
_stroke = std::make_shared<RenderTreeNodeContent::Stroke>(
|
solid->color = colorValue;
|
||||||
solid,
|
solid->opacity = opacityValue * 0.01;
|
||||||
widthValue,
|
|
||||||
lineJoin,
|
_stroke->lineWidth = widthValue;
|
||||||
lineCap,
|
_stroke->dashPhase = hasNonZeroDashes ? dashPhaseValue : 0.0;
|
||||||
miterLimit,
|
_stroke->dashPattern = hasNonZeroDashes ? dashPatternValue.values : std::vector<double>();
|
||||||
hasNonZeroDashes ? dashPhaseValue : 0.0,
|
|
||||||
hasNonZeroDashes ? dashPatternValue.values : std::vector<double>()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::shared_ptr<RenderTreeNodeContent::Stroke> stroke() override {
|
virtual std::shared_ptr<RenderTreeNodeContentItem::Stroke> stroke() override {
|
||||||
return _stroke;
|
return _stroke;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -268,7 +285,7 @@ public:
|
|||||||
std::unique_ptr<KeyframeInterpolator<Vector1D>> dashPhase;
|
std::unique_ptr<KeyframeInterpolator<Vector1D>> dashPhase;
|
||||||
double dashPhaseValue = 0.0;
|
double dashPhaseValue = 0.0;
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent::Stroke> _stroke;
|
std::shared_ptr<RenderTreeNodeContentItem::Stroke> _stroke;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GradientStrokeOutput : public StrokeOutput {
|
class GradientStrokeOutput : public StrokeOutput {
|
||||||
@ -292,6 +309,24 @@ public:
|
|||||||
dashPhase = std::make_unique<KeyframeInterpolator<Vector1D>>(dashConfiguration.dashPhase);
|
dashPhase = std::make_unique<KeyframeInterpolator<Vector1D>>(dashConfiguration.dashPhase);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto gradient = std::make_shared<RenderTreeNodeContentItem::GradientShading>(
|
||||||
|
0.0,
|
||||||
|
gradientType,
|
||||||
|
std::vector<Color>(),
|
||||||
|
std::vector<double>(),
|
||||||
|
Vector2D(0.0, 0.0),
|
||||||
|
Vector2D(0.0, 0.0)
|
||||||
|
);
|
||||||
|
_stroke = std::make_shared<RenderTreeNodeContentItem::Stroke>(
|
||||||
|
gradient,
|
||||||
|
0.0,
|
||||||
|
lineJoin,
|
||||||
|
lineCap,
|
||||||
|
miterLimit,
|
||||||
|
0.0,
|
||||||
|
std::vector<double>()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~GradientStrokeOutput() = default;
|
virtual ~GradientStrokeOutput() = default;
|
||||||
@ -338,7 +373,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_stroke || hasUpdates) {
|
if (hasUpdates) {
|
||||||
bool hasNonZeroDashes = false;
|
bool hasNonZeroDashes = false;
|
||||||
if (!dashPatternValue.values.empty()) {
|
if (!dashPatternValue.values.empty()) {
|
||||||
for (const auto &value : dashPatternValue.values) {
|
for (const auto &value : dashPatternValue.values) {
|
||||||
@ -353,27 +388,20 @@ public:
|
|||||||
std::vector<double> locations;
|
std::vector<double> locations;
|
||||||
getGradientParameters(numberOfColors, colorsValue, colors, locations);
|
getGradientParameters(numberOfColors, colorsValue, colors, locations);
|
||||||
|
|
||||||
auto gradient = std::make_shared<RenderTreeNodeContent::GradientShading>(
|
RenderTreeNodeContentItem::GradientShading *gradient = ((RenderTreeNodeContentItem::GradientShading *)_stroke->shading.get());
|
||||||
opacityValue * 0.01,
|
gradient->opacity = opacityValue * 0.01;
|
||||||
gradientType,
|
gradient->colors = colors;
|
||||||
colors,
|
gradient->locations = locations;
|
||||||
locations,
|
gradient->start = Vector2D(startPointValue.x, startPointValue.y);
|
||||||
Vector2D(startPointValue.x, startPointValue.y),
|
gradient->end = Vector2D(endPointValue.x, endPointValue.y);
|
||||||
Vector2D(endPointValue.x, endPointValue.y)
|
|
||||||
);
|
_stroke->lineWidth = widthValue;
|
||||||
_stroke = std::make_shared<RenderTreeNodeContent::Stroke>(
|
_stroke->dashPhase = hasNonZeroDashes ? dashPhaseValue : 0.0;
|
||||||
gradient,
|
_stroke->dashPattern = hasNonZeroDashes ? dashPatternValue.values : std::vector<double>();
|
||||||
widthValue,
|
|
||||||
lineJoin,
|
|
||||||
lineCap,
|
|
||||||
miterLimit,
|
|
||||||
hasNonZeroDashes ? dashPhaseValue : 0.0,
|
|
||||||
hasNonZeroDashes ? dashPatternValue.values : std::vector<double>()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual std::shared_ptr<RenderTreeNodeContent::Stroke> stroke() override {
|
virtual std::shared_ptr<RenderTreeNodeContentItem::Stroke> stroke() override {
|
||||||
return _stroke;
|
return _stroke;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -406,7 +434,7 @@ public:
|
|||||||
std::unique_ptr<KeyframeInterpolator<Vector1D>> dashPhase;
|
std::unique_ptr<KeyframeInterpolator<Vector1D>> dashPhase;
|
||||||
double dashPhaseValue = 0.0;
|
double dashPhaseValue = 0.0;
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent::Stroke> _stroke;
|
std::shared_ptr<RenderTreeNodeContentItem::Stroke> _stroke;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TrimParams {
|
struct TrimParams {
|
||||||
@ -478,8 +506,6 @@ public:
|
|||||||
std::shared_ptr<FillOutput> fill;
|
std::shared_ptr<FillOutput> fill;
|
||||||
std::shared_ptr<StrokeOutput> stroke;
|
std::shared_ptr<StrokeOutput> stroke;
|
||||||
size_t subItemLimit = 0;
|
size_t subItemLimit = 0;
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNode> renderTree;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TransformedPath {
|
struct TransformedPath {
|
||||||
@ -981,7 +1007,6 @@ public:
|
|||||||
1.0,
|
1.0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
|
||||||
std::vector<std::shared_ptr<RenderTreeNode>>(),
|
std::vector<std::shared_ptr<RenderTreeNode>>(),
|
||||||
nullptr,
|
nullptr,
|
||||||
false
|
false
|
||||||
@ -998,38 +1023,12 @@ public:
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto shadingRenderTree = std::make_shared<RenderTreeNode>(
|
|
||||||
CGRect(0.0, 0.0, 0.0, 0.0),
|
|
||||||
Vector2D(0.0, 0.0),
|
|
||||||
CATransform3D::identity(),
|
|
||||||
1.0,
|
|
||||||
false,
|
|
||||||
false,
|
|
||||||
nullptr,
|
|
||||||
std::vector<std::shared_ptr<RenderTreeNode>>(),
|
|
||||||
nullptr,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
shadingVariant.renderTree = shadingRenderTree;
|
|
||||||
//_renderTree->_subnodes.push_back(shadingRenderTree);
|
|
||||||
|
|
||||||
auto itemShadingVariant = std::make_shared<RenderTreeNodeContentShadingVariant>();
|
auto itemShadingVariant = std::make_shared<RenderTreeNodeContentShadingVariant>();
|
||||||
if (shadingVariant.fill) {
|
if (shadingVariant.fill) {
|
||||||
itemShadingVariant->fill = std::make_shared<RenderTreeNodeContent::Fill>(
|
itemShadingVariant->fill = shadingVariant.fill->fill();
|
||||||
nullptr,
|
|
||||||
FillRule::NonZeroWinding
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if (shadingVariant.stroke) {
|
if (shadingVariant.stroke) {
|
||||||
itemShadingVariant->stroke = std::make_shared<RenderTreeNodeContent::Stroke>(
|
itemShadingVariant->stroke = shadingVariant.stroke->stroke();
|
||||||
nullptr,
|
|
||||||
0.0,
|
|
||||||
LineJoin::Bevel,
|
|
||||||
LineCap::Round,
|
|
||||||
0.0,
|
|
||||||
0.0,
|
|
||||||
std::vector<double>()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
itemShadingVariant->subItemLimit = shadingVariant.subItemLimit;
|
itemShadingVariant->subItemLimit = shadingVariant.subItemLimit;
|
||||||
|
|
||||||
@ -1052,7 +1051,6 @@ public:
|
|||||||
1.0,
|
1.0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
|
||||||
subItemNodes,
|
subItemNodes,
|
||||||
nullptr,
|
nullptr,
|
||||||
false
|
false
|
||||||
@ -1126,28 +1124,6 @@ public:
|
|||||||
resultPaths.push_back(path);
|
resultPaths.push_back(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent> content;
|
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent::Fill> fill;
|
|
||||||
if (shadingVariant.fill) {
|
|
||||||
fill = shadingVariant.fill->fill();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<RenderTreeNodeContent::Stroke> stroke;
|
|
||||||
if (shadingVariant.stroke) {
|
|
||||||
stroke = shadingVariant.stroke->stroke();
|
|
||||||
}
|
|
||||||
|
|
||||||
content = std::make_shared<RenderTreeNodeContent>(
|
|
||||||
resultPaths,
|
|
||||||
stroke,
|
|
||||||
fill
|
|
||||||
);
|
|
||||||
|
|
||||||
shadingVariant.renderTree->_content = content;
|
|
||||||
|
|
||||||
_renderTree->_contentItem->shadings[i]->stroke = stroke;
|
|
||||||
_renderTree->_contentItem->shadings[i]->fill = fill;
|
|
||||||
_renderTree->_contentItem->shadings[i]->explicitPath = resultPaths;
|
_renderTree->_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1358,7 +1334,6 @@ std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
|
|||||||
1.0,
|
1.0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
|
||||||
renderTreeValue,
|
renderTreeValue,
|
||||||
nullptr,
|
nullptr,
|
||||||
false
|
false
|
||||||
@ -1383,7 +1358,6 @@ std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
|
|||||||
1.0,
|
1.0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
|
||||||
subnodes,
|
subnodes,
|
||||||
maskNode,
|
maskNode,
|
||||||
invertMask
|
invertMask
|
||||||
|
@ -243,7 +243,6 @@ public:
|
|||||||
1.0,
|
1.0,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
nullptr,
|
|
||||||
subnodes,
|
subnodes,
|
||||||
nullptr,
|
nullptr,
|
||||||
false
|
false
|
||||||
|
@ -2,298 +2,8 @@
|
|||||||
|
|
||||||
#include "Lottie/Private/MainThread/LayerContainers/MainThreadAnimationLayer.hpp"
|
#include "Lottie/Private/MainThread/LayerContainers/MainThreadAnimationLayer.hpp"
|
||||||
#include "LottieAnimationInternal.h"
|
#include "LottieAnimationInternal.h"
|
||||||
#include "RenderNode.hpp"
|
|
||||||
#include "LottieRenderTreeInternal.h"
|
|
||||||
#include <LottieCpp/VectorsCocoa.h>
|
#include <LottieCpp/VectorsCocoa.h>
|
||||||
|
|
||||||
namespace lottie {
|
|
||||||
|
|
||||||
struct RenderNodeDesc {
|
|
||||||
struct LayerParams {
|
|
||||||
CGRect _bounds;
|
|
||||||
Vector2D _position;
|
|
||||||
CATransform3D _transform;
|
|
||||||
double _opacity;
|
|
||||||
bool _masksToBounds;
|
|
||||||
bool _isHidden;
|
|
||||||
|
|
||||||
LayerParams(
|
|
||||||
CGRect bounds_,
|
|
||||||
Vector2D position_,
|
|
||||||
CATransform3D transform_,
|
|
||||||
double opacity_,
|
|
||||||
bool masksToBounds_,
|
|
||||||
bool isHidden_
|
|
||||||
) :
|
|
||||||
_bounds(bounds_),
|
|
||||||
_position(position_),
|
|
||||||
_transform(transform_),
|
|
||||||
_opacity(opacity_),
|
|
||||||
_masksToBounds(masksToBounds_),
|
|
||||||
_isHidden(isHidden_) {
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect bounds() const {
|
|
||||||
return _bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2D position() const {
|
|
||||||
return _position;
|
|
||||||
}
|
|
||||||
|
|
||||||
CATransform3D transform() const {
|
|
||||||
return _transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
double opacity() const {
|
|
||||||
return _opacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masksToBounds() const {
|
|
||||||
return _masksToBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isHidden() const {
|
|
||||||
return _isHidden;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LayerParams layer;
|
|
||||||
CGRect globalRect;
|
|
||||||
CGRect localRect;
|
|
||||||
CATransform3D globalTransform;
|
|
||||||
bool drawsContent;
|
|
||||||
bool renderContent;
|
|
||||||
int drawContentDescendants;
|
|
||||||
bool isInvertedMatte;
|
|
||||||
std::shared_ptr<OutputRenderNode> mask;
|
|
||||||
|
|
||||||
explicit RenderNodeDesc(
|
|
||||||
LayerParams const &layer_,
|
|
||||||
CGRect const &globalRect_,
|
|
||||||
CGRect const &localRect_,
|
|
||||||
CATransform3D const &globalTransform_,
|
|
||||||
bool drawsContent_,
|
|
||||||
bool renderContent_,
|
|
||||||
int drawContentDescendants_,
|
|
||||||
bool isInvertedMatte_
|
|
||||||
) :
|
|
||||||
layer(layer_),
|
|
||||||
globalRect(globalRect_),
|
|
||||||
localRect(localRect_),
|
|
||||||
globalTransform(globalTransform_),
|
|
||||||
drawsContent(drawsContent_),
|
|
||||||
renderContent(renderContent_),
|
|
||||||
drawContentDescendants(drawContentDescendants_),
|
|
||||||
isInvertedMatte(isInvertedMatte_) {
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::shared_ptr<OutputRenderNode> convertRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vector2D const &globalSize, CATransform3D const &parentTransform, bool isInvertedMask, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
|
|
||||||
if (node->isHidden() || node->alpha() == 0.0f) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node->masksToBounds()) {
|
|
||||||
if (node->bounds().empty()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto currentTransform = parentTransform;
|
|
||||||
|
|
||||||
Vector2D localTranslation(node->position().x + -node->bounds().x, node->position().y + -node->bounds().y);
|
|
||||||
CATransform3D localTransform = node->transform();
|
|
||||||
localTransform = localTransform.translated(localTranslation);
|
|
||||||
|
|
||||||
currentTransform = localTransform * currentTransform;
|
|
||||||
|
|
||||||
if (!currentTransform.isInvertible()) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<CGRect> effectiveLocalBounds;
|
|
||||||
|
|
||||||
double alpha = node->alpha();
|
|
||||||
|
|
||||||
if (node->content()) {
|
|
||||||
RenderTreeNodeContent *shapeContent = node->content().get();
|
|
||||||
|
|
||||||
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, shapeContent->paths);
|
|
||||||
|
|
||||||
if (shapeContent->stroke) {
|
|
||||||
shapeBounds = shapeBounds.insetBy(-shapeContent->stroke->lineWidth / 2.0, -shapeContent->stroke->lineWidth / 2.0);
|
|
||||||
effectiveLocalBounds = shapeBounds;
|
|
||||||
|
|
||||||
switch (shapeContent->stroke->shading->type()) {
|
|
||||||
case RenderTreeNodeContent::ShadingType::Solid: {
|
|
||||||
RenderTreeNodeContent::SolidShading *solidShading = (RenderTreeNodeContent::SolidShading *)shapeContent->stroke->shading.get();
|
|
||||||
|
|
||||||
alpha *= solidShading->opacity;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RenderTreeNodeContent::ShadingType::Gradient: {
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if (shapeContent->fill) {
|
|
||||||
effectiveLocalBounds = shapeBounds;
|
|
||||||
|
|
||||||
switch (shapeContent->fill->shading->type()) {
|
|
||||||
case RenderTreeNodeContent::ShadingType::Solid: {
|
|
||||||
RenderTreeNodeContent::SolidShading *solidShading = (RenderTreeNodeContent::SolidShading *)shapeContent->fill->shading.get();
|
|
||||||
|
|
||||||
alpha *= solidShading->opacity;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case RenderTreeNodeContent::ShadingType::Gradient: {
|
|
||||||
RenderTreeNodeContent::GradientShading *gradientShading = (RenderTreeNodeContent::GradientShading *)shapeContent->fill->shading.get();
|
|
||||||
|
|
||||||
alpha *= gradientShading->opacity;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isInvertedMatte = isInvertedMask;
|
|
||||||
if (isInvertedMatte) {
|
|
||||||
effectiveLocalBounds = node->bounds();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (effectiveLocalBounds && effectiveLocalBounds->empty()) {
|
|
||||||
effectiveLocalBounds = std::nullopt;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<CGRect> effectiveLocalRect;
|
|
||||||
if (effectiveLocalBounds.has_value()) {
|
|
||||||
effectiveLocalRect = effectiveLocalBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<std::shared_ptr<OutputRenderNode>> subnodes;
|
|
||||||
std::optional<CGRect> subnodesGlobalRect;
|
|
||||||
bool masksToBounds = node->masksToBounds();
|
|
||||||
|
|
||||||
int drawContentDescendants = 0;
|
|
||||||
|
|
||||||
for (const auto &item : node->subnodes()) {
|
|
||||||
if (const auto subnode = convertRenderTree(item, globalSize, currentTransform, false, bezierPathsBoundingBoxContext)) {
|
|
||||||
subnodes.push_back(subnode);
|
|
||||||
|
|
||||||
drawContentDescendants += subnode->drawContentDescendants;
|
|
||||||
|
|
||||||
if (subnode->renderContent) {
|
|
||||||
drawContentDescendants += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!subnode->localRect.empty()) {
|
|
||||||
if (effectiveLocalRect.has_value()) {
|
|
||||||
effectiveLocalRect = effectiveLocalRect->unionWith(subnode->localRect);
|
|
||||||
} else {
|
|
||||||
effectiveLocalRect = subnode->localRect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subnodesGlobalRect) {
|
|
||||||
subnodesGlobalRect = subnodesGlobalRect->unionWith(subnode->globalRect);
|
|
||||||
} else {
|
|
||||||
subnodesGlobalRect = subnode->globalRect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (masksToBounds && effectiveLocalRect.has_value()) {
|
|
||||||
if (node->bounds().contains(effectiveLocalRect.value())) {
|
|
||||||
masksToBounds = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::optional<CGRect> fuzzyGlobalRect;
|
|
||||||
|
|
||||||
if (effectiveLocalBounds) {
|
|
||||||
CGRect effectiveGlobalBounds = effectiveLocalBounds->applyingTransform(currentTransform);
|
|
||||||
if (fuzzyGlobalRect) {
|
|
||||||
fuzzyGlobalRect = fuzzyGlobalRect->unionWith(effectiveGlobalBounds);
|
|
||||||
} else {
|
|
||||||
fuzzyGlobalRect = effectiveGlobalBounds;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subnodesGlobalRect) {
|
|
||||||
if (fuzzyGlobalRect) {
|
|
||||||
fuzzyGlobalRect = fuzzyGlobalRect->unionWith(subnodesGlobalRect.value());
|
|
||||||
} else {
|
|
||||||
fuzzyGlobalRect = subnodesGlobalRect;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!fuzzyGlobalRect) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect globalRect(
|
|
||||||
std::floor(fuzzyGlobalRect->x),
|
|
||||||
std::floor(fuzzyGlobalRect->y),
|
|
||||||
std::ceil(fuzzyGlobalRect->width + fuzzyGlobalRect->x - floor(fuzzyGlobalRect->x)),
|
|
||||||
std::ceil(fuzzyGlobalRect->height + fuzzyGlobalRect->y - floor(fuzzyGlobalRect->y))
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(globalRect)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (masksToBounds && effectiveLocalBounds) {
|
|
||||||
CGRect effectiveGlobalBounds = effectiveLocalBounds->applyingTransform(currentTransform);
|
|
||||||
if (effectiveGlobalBounds.contains(CGRect(0.0, 0.0, globalSize.x, globalSize.y))) {
|
|
||||||
masksToBounds = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::shared_ptr<OutputRenderNode> maskNode;
|
|
||||||
if (node->mask()) {
|
|
||||||
if (const auto maskNodeValue = convertRenderTree(node->mask(), globalSize, currentTransform, node->invertMask(), bezierPathsBoundingBoxContext)) {
|
|
||||||
if (!maskNodeValue->globalRect.intersects(globalRect)) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
maskNode = maskNodeValue;
|
|
||||||
} else {
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect localRect = effectiveLocalRect.value_or(CGRect(0.0, 0.0, 0.0, 0.0)).applyingTransform(localTransform);
|
|
||||||
|
|
||||||
return std::make_shared<OutputRenderNode>(
|
|
||||||
OutputRenderNode::LayerParams(
|
|
||||||
node->bounds(),
|
|
||||||
node->position(),
|
|
||||||
node->transform(),
|
|
||||||
alpha,
|
|
||||||
masksToBounds,
|
|
||||||
node->isHidden()
|
|
||||||
),
|
|
||||||
globalRect,
|
|
||||||
localRect,
|
|
||||||
currentTransform,
|
|
||||||
effectiveLocalBounds.has_value(),
|
|
||||||
node->content(),
|
|
||||||
drawContentDescendants,
|
|
||||||
isInvertedMatte,
|
|
||||||
subnodes,
|
|
||||||
maskNode
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@interface LottieAnimationContainer () {
|
@interface LottieAnimationContainer () {
|
||||||
@public
|
@public
|
||||||
std::shared_ptr<lottie::MainThreadAnimationLayer> _layer;
|
std::shared_ptr<lottie::MainThreadAnimationLayer> _layer;
|
||||||
@ -326,43 +36,9 @@ static std::shared_ptr<OutputRenderNode> convertRenderTree(std::shared_ptr<Rende
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (LottieRenderNode * _Nullable)getCurrentRenderTreeForSize:(CGSize)size {
|
- (LottieRenderNode * _Nullable)getCurrentRenderTreeForSize:(CGSize)size {
|
||||||
auto renderNode = _layer->renderTreeNode();
|
|
||||||
if (!renderNode) {
|
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size.width <= 0.0 || size.height <= 0.0) {
|
|
||||||
return nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto node = convertRenderTree(renderNode, lottie::Vector2D((int)size.width, (int)size.height), lottie::CATransform3D::identity().scaled(lottie::Vector2D(size.width / (double)_animation.size.width, size.height / (double)_animation.size.height)), false, *_bezierPathsBoundingBoxContext.get());
|
|
||||||
|
|
||||||
if (node) {
|
|
||||||
return [[LottieRenderNode alloc] initWithRenderNode:node];
|
|
||||||
} else {
|
|
||||||
node = std::make_shared<lottie::OutputRenderNode>(
|
|
||||||
lottie::OutputRenderNode::LayerParams(
|
|
||||||
lottie::CGRect(0.0, 0.0, size.width, size.height),
|
|
||||||
lottie::Vector2D(0.0, 0.0),
|
|
||||||
lottie::CATransform3D::identity(),
|
|
||||||
1.0,
|
|
||||||
false,
|
|
||||||
false
|
|
||||||
),
|
|
||||||
lottie::CGRect(0.0, 0.0, size.width, size.height),
|
|
||||||
lottie::CGRect(0.0, 0.0, size.width, size.height),
|
|
||||||
lottie::CATransform3D::identity(),
|
|
||||||
false,
|
|
||||||
nullptr,
|
|
||||||
true,
|
|
||||||
false,
|
|
||||||
std::vector<std::shared_ptr<lottie::OutputRenderNode>>(),
|
|
||||||
nullptr
|
|
||||||
);
|
|
||||||
return [[LottieRenderNode alloc] initWithRenderNode:node];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- (std::shared_ptr<lottie::RenderTreeNode>)internalGetRootRenderTreeNode {
|
- (std::shared_ptr<lottie::RenderTreeNode>)internalGetRootRenderTreeNode {
|
||||||
auto renderNode = _layer->renderTreeNode();
|
auto renderNode = _layer->renderTreeNode();
|
||||||
return renderNode;
|
return renderNode;
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include "LottieRenderTree.h"
|
#include "LottieRenderTree.h"
|
||||||
#include "LottieRenderTreeInternal.h"
|
|
||||||
|
|
||||||
#include <LottieCpp/CGPath.h>
|
#include <LottieCpp/CGPath.h>
|
||||||
#include <LottieCpp/CGPathCocoa.h>
|
#include <LottieCpp/CGPathCocoa.h>
|
||||||
@ -7,8 +6,6 @@
|
|||||||
#include "Lottie/Public/Primitives/CALayer.hpp"
|
#include "Lottie/Public/Primitives/CALayer.hpp"
|
||||||
#include <LottieCpp/VectorsCocoa.h>
|
#include <LottieCpp/VectorsCocoa.h>
|
||||||
|
|
||||||
#include "RenderNode.hpp"
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -192,7 +189,7 @@ static LottieColor lottieColorFromColor(lottie::Color color) {
|
|||||||
|
|
||||||
@implementation LottieRenderContentSolidShading
|
@implementation LottieRenderContentSolidShading
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithSolidShading:(lottie::RenderTreeNodeContent::SolidShading *)solidShading __attribute__((objc_direct)) {
|
- (instancetype _Nonnull)initWithSolidShading:(lottie::RenderTreeNodeContentItem::SolidShading *)solidShading __attribute__((objc_direct)) {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_color = lottieColorFromColor(solidShading->color);
|
_color = lottieColorFromColor(solidShading->color);
|
||||||
@ -214,7 +211,7 @@ static LottieColor lottieColorFromColor(lottie::Color color) {
|
|||||||
|
|
||||||
@implementation LottieRenderContentGradientShading
|
@implementation LottieRenderContentGradientShading
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithGradientShading:(lottie::RenderTreeNodeContent::GradientShading *)gradientShading __attribute__((objc_direct)) {
|
- (instancetype _Nonnull)initWithGradientShading:(lottie::RenderTreeNodeContentItem::GradientShading *)gradientShading __attribute__((objc_direct)) {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
_opacity = gradientShading->opacity;
|
_opacity = gradientShading->opacity;
|
||||||
@ -258,16 +255,16 @@ static LottieColor lottieColorFromColor(lottie::Color color) {
|
|||||||
|
|
||||||
@implementation LottieRenderContentFill
|
@implementation LottieRenderContentFill
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithFill:(std::shared_ptr<lottie::RenderTreeNodeContent::Fill> const &)fill __attribute__((objc_direct)) {
|
- (instancetype _Nonnull)initWithFill:(std::shared_ptr<lottie::RenderTreeNodeContentItem::Fill> const &)fill __attribute__((objc_direct)) {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
switch (fill->shading->type()) {
|
switch (fill->shading->type()) {
|
||||||
case lottie::RenderTreeNodeContent::ShadingType::Solid: {
|
case lottie::RenderTreeNodeContentItem::ShadingType::Solid: {
|
||||||
_shading = [[LottieRenderContentSolidShading alloc] initWithSolidShading:(lottie::RenderTreeNodeContent::SolidShading *)fill->shading.get()];
|
_shading = [[LottieRenderContentSolidShading alloc] initWithSolidShading:(lottie::RenderTreeNodeContentItem::SolidShading *)fill->shading.get()];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case lottie::RenderTreeNodeContent::ShadingType::Gradient: {
|
case lottie::RenderTreeNodeContentItem::ShadingType::Gradient: {
|
||||||
_shading = [[LottieRenderContentGradientShading alloc] initWithGradientShading:(lottie::RenderTreeNodeContent::GradientShading *)fill->shading.get()];
|
_shading = [[LottieRenderContentGradientShading alloc] initWithGradientShading:(lottie::RenderTreeNodeContentItem::GradientShading *)fill->shading.get()];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -302,16 +299,16 @@ static LottieColor lottieColorFromColor(lottie::Color color) {
|
|||||||
|
|
||||||
@implementation LottieRenderContentStroke
|
@implementation LottieRenderContentStroke
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithStroke:(std::shared_ptr<lottie::RenderTreeNodeContent::Stroke> const &)stroke __attribute__((objc_direct)) {
|
- (instancetype _Nonnull)initWithStroke:(std::shared_ptr<lottie::RenderTreeNodeContentItem::Stroke> const &)stroke __attribute__((objc_direct)) {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
switch (stroke->shading->type()) {
|
switch (stroke->shading->type()) {
|
||||||
case lottie::RenderTreeNodeContent::ShadingType::Solid: {
|
case lottie::RenderTreeNodeContentItem::ShadingType::Solid: {
|
||||||
_shading = [[LottieRenderContentSolidShading alloc] initWithSolidShading:(lottie::RenderTreeNodeContent::SolidShading *)stroke->shading.get()];
|
_shading = [[LottieRenderContentSolidShading alloc] initWithSolidShading:(lottie::RenderTreeNodeContentItem::SolidShading *)stroke->shading.get()];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case lottie::RenderTreeNodeContent::ShadingType::Gradient: {
|
case lottie::RenderTreeNodeContentItem::ShadingType::Gradient: {
|
||||||
_shading = [[LottieRenderContentGradientShading alloc] initWithGradientShading:(lottie::RenderTreeNodeContent::GradientShading *)stroke->shading.get()];
|
_shading = [[LottieRenderContentGradientShading alloc] initWithGradientShading:(lottie::RenderTreeNodeContentItem::GradientShading *)stroke->shading.get()];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -392,20 +389,6 @@ static LottieColor lottieColorFromColor(lottie::Color color) {
|
|||||||
|
|
||||||
@implementation LottieRenderContent
|
@implementation LottieRenderContent
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithRenderContent:(std::shared_ptr<lottie::RenderTreeNodeContent> const &)content __attribute__((objc_direct)) {
|
|
||||||
self = [super init];
|
|
||||||
if (self != nil) {
|
|
||||||
_path = [[LottiePath alloc] initWithPaths:content->paths];
|
|
||||||
if (content->stroke) {
|
|
||||||
_stroke = [[LottieRenderContentStroke alloc] initWithStroke:content->stroke];
|
|
||||||
}
|
|
||||||
if (content->fill) {
|
|
||||||
_fill = [[LottieRenderContentFill alloc] initWithFill:content->fill];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithPath:(LottiePath * _Nonnull)path stroke:(LottieRenderContentStroke * _Nullable)stroke fill:(LottieRenderContentFill * _Nullable)fill __attribute__((objc_direct)) {
|
- (instancetype _Nonnull)initWithPath:(LottiePath * _Nonnull)path stroke:(LottieRenderContentStroke * _Nullable)stroke fill:(LottieRenderContentFill * _Nullable)fill __attribute__((objc_direct)) {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
if (self != nil) {
|
if (self != nil) {
|
||||||
@ -441,50 +424,3 @@ static LottieColor lottieColorFromColor(lottie::Color color) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation LottieRenderNode (Internal)
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithRenderNode:(std::shared_ptr<lottie::OutputRenderNode> const &)renderNode __attribute__((objc_direct)) {
|
|
||||||
self = [super init];
|
|
||||||
if (self != nil) {
|
|
||||||
auto position = renderNode->layer.position();
|
|
||||||
_position = CGPointMake(position.x, position.y);
|
|
||||||
|
|
||||||
auto bounds = renderNode->layer.bounds();
|
|
||||||
_bounds = CGRectMake(bounds.x, bounds.y, bounds.width, bounds.height);
|
|
||||||
|
|
||||||
_transform = lottie::nativeTransform(renderNode->layer.transform());
|
|
||||||
_opacity = renderNode->layer.opacity();
|
|
||||||
_masksToBounds = renderNode->layer.masksToBounds();
|
|
||||||
_isHidden = renderNode->layer.isHidden();
|
|
||||||
|
|
||||||
auto globalRect = renderNode->globalRect;
|
|
||||||
_globalRect = CGRectMake(globalRect.x, globalRect.y, globalRect.width, globalRect.height);
|
|
||||||
|
|
||||||
_globalTransform = lottie::nativeTransform(renderNode->globalTransform);
|
|
||||||
|
|
||||||
if (renderNode->renderContent) {
|
|
||||||
_renderContent = [[LottieRenderContent alloc] initWithRenderContent:renderNode->renderContent];
|
|
||||||
}
|
|
||||||
|
|
||||||
_hasSimpleContents = renderNode->drawContentDescendants <= 1;
|
|
||||||
_isInvertedMatte = renderNode->isInvertedMatte;
|
|
||||||
|
|
||||||
if (!renderNode->subnodes.empty()) {
|
|
||||||
NSMutableArray<LottieRenderNode *> *subnodes = [[NSMutableArray alloc] init];
|
|
||||||
for (const auto &subnode : renderNode->subnodes) {
|
|
||||||
[subnodes addObject:[[LottieRenderNode alloc] initWithRenderNode:subnode]];
|
|
||||||
}
|
|
||||||
_subnodes = subnodes;
|
|
||||||
} else {
|
|
||||||
_subnodes = [[NSArray alloc] init];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (renderNode->mask) {
|
|
||||||
_mask = [[LottieRenderNode alloc] initWithRenderNode:renderNode->mask];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return self;
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
#ifndef LottieRenderTreeInternal_h
|
|
||||||
#define LottieRenderTreeInternal_h
|
|
||||||
|
|
||||||
#include <LottieCpp/LottieRenderTree.h>
|
|
||||||
#import "RenderNode.hpp"
|
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
@interface LottieRenderNode (Internal)
|
|
||||||
|
|
||||||
- (instancetype _Nonnull)initWithRenderNode:(std::shared_ptr<lottie::OutputRenderNode> const &)renderNode __attribute__((objc_direct));
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
#endif /* LottieRenderTreeInternal_h */
|
|
@ -1,29 +0,0 @@
|
|||||||
#include "RenderNode.hpp"
|
|
||||||
|
|
||||||
namespace lottie {
|
|
||||||
|
|
||||||
OutputRenderNode::OutputRenderNode(
|
|
||||||
LayerParams const &layer_,
|
|
||||||
CGRect const &globalRect_,
|
|
||||||
CGRect const &localRect_,
|
|
||||||
CATransform3D const &globalTransform_,
|
|
||||||
bool drawsContent_,
|
|
||||||
std::shared_ptr<RenderTreeNodeContent> renderContent_,
|
|
||||||
int drawContentDescendants_,
|
|
||||||
bool isInvertedMatte_,
|
|
||||||
std::vector<std::shared_ptr<OutputRenderNode>> const &subnodes_,
|
|
||||||
std::shared_ptr<OutputRenderNode> const &mask_
|
|
||||||
) :
|
|
||||||
layer(layer_),
|
|
||||||
globalRect(globalRect_),
|
|
||||||
localRect(localRect_),
|
|
||||||
globalTransform(globalTransform_),
|
|
||||||
drawsContent(drawsContent_),
|
|
||||||
renderContent(renderContent_),
|
|
||||||
drawContentDescendants(drawContentDescendants_),
|
|
||||||
isInvertedMatte(isInvertedMatte_),
|
|
||||||
subnodes(subnodes_),
|
|
||||||
mask(mask_) {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
#ifndef RenderNode_hpp
|
|
||||||
#define RenderNode_hpp
|
|
||||||
|
|
||||||
#include "Lottie/Public/Primitives/CALayer.hpp"
|
|
||||||
|
|
||||||
namespace lottie {
|
|
||||||
|
|
||||||
struct OutputRenderNode {
|
|
||||||
struct LayerParams {
|
|
||||||
CGRect _bounds;
|
|
||||||
Vector2D _position;
|
|
||||||
CATransform3D _transform;
|
|
||||||
double _opacity;
|
|
||||||
bool _masksToBounds;
|
|
||||||
bool _isHidden;
|
|
||||||
|
|
||||||
LayerParams(
|
|
||||||
CGRect bounds_,
|
|
||||||
Vector2D position_,
|
|
||||||
CATransform3D transform_,
|
|
||||||
double opacity_,
|
|
||||||
bool masksToBounds_,
|
|
||||||
bool isHidden_
|
|
||||||
) :
|
|
||||||
_bounds(bounds_),
|
|
||||||
_position(position_),
|
|
||||||
_transform(transform_),
|
|
||||||
_opacity(opacity_),
|
|
||||||
_masksToBounds(masksToBounds_),
|
|
||||||
_isHidden(isHidden_) {
|
|
||||||
}
|
|
||||||
|
|
||||||
LayerParams(std::shared_ptr<CALayer> const &layer) :
|
|
||||||
_bounds(layer->bounds()),
|
|
||||||
_position(layer->position()),
|
|
||||||
_transform(layer->transform()),
|
|
||||||
_opacity(layer->opacity()),
|
|
||||||
_masksToBounds(layer->masksToBounds()),
|
|
||||||
_isHidden(layer->isHidden()) {
|
|
||||||
}
|
|
||||||
|
|
||||||
CGRect bounds() const {
|
|
||||||
return _bounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector2D position() const {
|
|
||||||
return _position;
|
|
||||||
}
|
|
||||||
|
|
||||||
CATransform3D transform() const {
|
|
||||||
return _transform;
|
|
||||||
}
|
|
||||||
|
|
||||||
double opacity() const {
|
|
||||||
return _opacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool masksToBounds() const {
|
|
||||||
return _masksToBounds;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isHidden() const {
|
|
||||||
return _isHidden;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
LayerParams layer;
|
|
||||||
CGRect globalRect;
|
|
||||||
CGRect localRect;
|
|
||||||
CATransform3D globalTransform;
|
|
||||||
bool drawsContent;
|
|
||||||
std::shared_ptr<RenderTreeNodeContent> renderContent;
|
|
||||||
int drawContentDescendants;
|
|
||||||
bool isInvertedMatte;
|
|
||||||
std::vector<std::shared_ptr<OutputRenderNode>> subnodes;
|
|
||||||
std::shared_ptr<OutputRenderNode> mask;
|
|
||||||
|
|
||||||
explicit OutputRenderNode(
|
|
||||||
LayerParams const &layer_,
|
|
||||||
CGRect const &globalRect_,
|
|
||||||
CGRect const &localRect_,
|
|
||||||
CATransform3D const &globalTransform_,
|
|
||||||
bool drawsContent_,
|
|
||||||
std::shared_ptr<RenderTreeNodeContent> renderContent_,
|
|
||||||
int drawContentDescendants_,
|
|
||||||
bool isInvertedMatte_,
|
|
||||||
std::vector<std::shared_ptr<OutputRenderNode>> const &subnodes_,
|
|
||||||
std::shared_ptr<OutputRenderNode> const &mask_
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* RenderNode_hpp */
|
|
Loading…
x
Reference in New Issue
Block a user