mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
Merge branch 'lottie-temp'
This commit is contained in:
commit
c9a651691a
@ -6,30 +6,147 @@
|
||||
|
||||
#include <LottieCpp/RenderTreeNode.h>
|
||||
|
||||
namespace lottie {
|
||||
namespace {
|
||||
|
||||
static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem> const &contentItem, std::optional<CGRect> &effectiveLocalBounds, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
|
||||
for (const auto &shadingVariant : contentItem->shadings) {
|
||||
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, shadingVariant->explicitPath.value());
|
||||
if (shadingVariant->stroke) {
|
||||
shapeBounds = shapeBounds.insetBy(-shadingVariant->stroke->lineWidth / 2.0, -shadingVariant->stroke->lineWidth / 2.0);
|
||||
if (effectiveLocalBounds) {
|
||||
effectiveLocalBounds = effectiveLocalBounds->unionWith(shapeBounds);
|
||||
} else {
|
||||
effectiveLocalBounds = shapeBounds;
|
||||
}
|
||||
} else if (shadingVariant->fill) {
|
||||
if (effectiveLocalBounds) {
|
||||
effectiveLocalBounds = effectiveLocalBounds->unionWith(shapeBounds);
|
||||
} else {
|
||||
effectiveLocalBounds = shapeBounds;
|
||||
}
|
||||
struct TransformedPath {
|
||||
lottie::BezierPath path;
|
||||
lottie::CATransform3D transform;
|
||||
|
||||
TransformedPath(lottie::BezierPath const &path_, lottie::CATransform3D const &transform_) :
|
||||
path(path_),
|
||||
transform(transform_) {
|
||||
}
|
||||
};
|
||||
|
||||
static std::vector<TransformedPath> collectPaths(std::shared_ptr<lottie::RenderTreeNodeContentItem> item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform) {
|
||||
std::vector<TransformedPath> mappedPaths;
|
||||
|
||||
//TODO:remove skipApplyTransform
|
||||
lottie::CATransform3D effectiveTransform = parentTransform;
|
||||
if (!skipApplyTransform && item->isGroup) {
|
||||
effectiveTransform = item->transform * effectiveTransform;
|
||||
}
|
||||
|
||||
size_t maxSubitem = std::min(item->subItems.size(), subItemLimit);
|
||||
|
||||
if (item->path) {
|
||||
mappedPaths.emplace_back(item->path.value(), effectiveTransform);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < maxSubitem; i++) {
|
||||
auto &subItem = item->subItems[i];
|
||||
|
||||
auto subItemPaths = collectPaths(subItem, INT32_MAX, effectiveTransform, false);
|
||||
|
||||
for (auto &path : subItemPaths) {
|
||||
mappedPaths.emplace_back(path.path, path.transform);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &subItem : contentItem->subItems) {
|
||||
processRenderContentItem(subItem, effectiveLocalBounds, bezierPathsBoundingBoxContext);
|
||||
return mappedPaths;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace lottie {
|
||||
|
||||
static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem> const &contentItem, Vector2D const &globalSize, CATransform3D const &parentTransform, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
|
||||
auto currentTransform = parentTransform;
|
||||
|
||||
CATransform3D localTransform = contentItem->transform;
|
||||
currentTransform = localTransform * currentTransform;
|
||||
|
||||
if (!currentTransform.isInvertible()) {
|
||||
contentItem->renderData.isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<CGRect> globalRect;
|
||||
|
||||
int drawContentDescendants = 0;
|
||||
|
||||
for (const auto &shadingVariant : contentItem->shadings) {
|
||||
std::vector<lottie::BezierPath> itemPaths;
|
||||
if (shadingVariant->explicitPath) {
|
||||
itemPaths = shadingVariant->explicitPath.value();
|
||||
} else {
|
||||
auto rawPaths = collectPaths(contentItem, shadingVariant->subItemLimit, lottie::CATransform3D::identity(), true);
|
||||
for (const auto &rawPath : rawPaths) {
|
||||
itemPaths.push_back(rawPath.path.copyUsingTransform(rawPath.transform));
|
||||
}
|
||||
}
|
||||
|
||||
CGRect shapeBounds = bezierPathsBoundingBoxParallel(bezierPathsBoundingBoxContext, itemPaths);
|
||||
if (shadingVariant->stroke) {
|
||||
shapeBounds = shapeBounds.insetBy(-shadingVariant->stroke->lineWidth / 2.0, -shadingVariant->stroke->lineWidth / 2.0);
|
||||
} else if (shadingVariant->fill) {
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
drawContentDescendants += 1;
|
||||
|
||||
CGRect shapeGlobalBounds = shapeBounds.applyingTransform(currentTransform);
|
||||
if (globalRect) {
|
||||
globalRect = globalRect->unionWith(shapeGlobalBounds);
|
||||
} else {
|
||||
globalRect = shapeGlobalBounds;
|
||||
}
|
||||
}
|
||||
|
||||
if (contentItem->isGroup) {
|
||||
for (const auto &subItem : contentItem->subItems) {
|
||||
processRenderContentItem(subItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
|
||||
|
||||
if (subItem->renderData.isValid) {
|
||||
drawContentDescendants += subItem->renderData.drawContentDescendants;
|
||||
if (globalRect) {
|
||||
globalRect = globalRect->unionWith(subItem->renderData.globalRect);
|
||||
} else {
|
||||
globalRect = subItem->renderData.globalRect;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const auto &subItem : contentItem->subItems) {
|
||||
subItem->renderData.isValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!globalRect) {
|
||||
contentItem->renderData.isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
CGRect integralGlobalRect(
|
||||
std::floor(globalRect->x),
|
||||
std::floor(globalRect->y),
|
||||
std::ceil(globalRect->width + globalRect->x - floor(globalRect->x)),
|
||||
std::ceil(globalRect->height + globalRect->y - floor(globalRect->y))
|
||||
);
|
||||
|
||||
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(integralGlobalRect)) {
|
||||
contentItem->renderData.isValid = false;
|
||||
return;
|
||||
}
|
||||
if (integralGlobalRect.width <= 0.0 || integralGlobalRect.height <= 0.0) {
|
||||
contentItem->renderData.isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
contentItem->renderData.isValid = true;
|
||||
|
||||
contentItem->renderData.layer._bounds = CGRect(0.0, 0.0, 0.0, 0.0);
|
||||
contentItem->renderData.layer._position = Vector2D(0.0, 0.0);
|
||||
contentItem->renderData.layer._transform = contentItem->transform;
|
||||
contentItem->renderData.layer._opacity = contentItem->alpha;
|
||||
contentItem->renderData.layer._masksToBounds = false;
|
||||
contentItem->renderData.layer._isHidden = false;
|
||||
|
||||
contentItem->renderData.globalRect = integralGlobalRect;
|
||||
contentItem->renderData.globalTransform = currentTransform;
|
||||
contentItem->renderData.drawContentDescendants = drawContentDescendants;
|
||||
contentItem->renderData.isInvertedMatte = false;
|
||||
}
|
||||
|
||||
static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vector2D const &globalSize, CATransform3D const &parentTransform, bool isInvertedMask, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
|
||||
@ -58,102 +175,59 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
||||
return;
|
||||
}
|
||||
|
||||
std::optional<CGRect> effectiveLocalBounds;
|
||||
|
||||
double alpha = node->alpha();
|
||||
|
||||
int drawContentDescendants = 0;
|
||||
std::optional<CGRect> globalRect;
|
||||
if (node->_contentItem) {
|
||||
processRenderContentItem(node->_contentItem, effectiveLocalBounds, bezierPathsBoundingBoxContext);
|
||||
processRenderContentItem(node->_contentItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
|
||||
if (node->_contentItem->renderData.isValid) {
|
||||
drawContentDescendants += node->_contentItem->renderData.drawContentDescendants;
|
||||
globalRect = node->_contentItem->renderData.globalRect;
|
||||
}
|
||||
}
|
||||
|
||||
bool isInvertedMatte = isInvertedMask;
|
||||
if (isInvertedMatte) {
|
||||
effectiveLocalBounds = node->bounds();
|
||||
CGRect globalBounds = node->bounds().applyingTransform(currentTransform);
|
||||
if (globalRect) {
|
||||
globalRect = globalRect->unionWith(globalBounds);
|
||||
} else {
|
||||
globalRect = globalBounds;
|
||||
}
|
||||
}
|
||||
|
||||
if (effectiveLocalBounds && effectiveLocalBounds->empty()) {
|
||||
effectiveLocalBounds = std::nullopt;
|
||||
}
|
||||
|
||||
std::optional<CGRect> effectiveLocalRect;
|
||||
if (effectiveLocalBounds.has_value()) {
|
||||
effectiveLocalRect = effectiveLocalBounds;
|
||||
}
|
||||
|
||||
std::optional<CGRect> subnodesGlobalRect;
|
||||
bool masksToBounds = node->masksToBounds();
|
||||
|
||||
int drawContentDescendants = 0;
|
||||
|
||||
for (const auto &item : node->subnodes()) {
|
||||
processRenderTree(item, globalSize, currentTransform, false, bezierPathsBoundingBoxContext);
|
||||
if (item->renderData.isValid) {
|
||||
drawContentDescendants += item->renderData.drawContentDescendants;
|
||||
|
||||
if (item->_contentItem) {
|
||||
drawContentDescendants += 1;
|
||||
}
|
||||
|
||||
if (!item->renderData.localRect.empty()) {
|
||||
if (effectiveLocalRect.has_value()) {
|
||||
effectiveLocalRect = effectiveLocalRect->unionWith(item->renderData.localRect);
|
||||
} else {
|
||||
effectiveLocalRect = item->renderData.localRect;
|
||||
}
|
||||
}
|
||||
|
||||
if (subnodesGlobalRect) {
|
||||
subnodesGlobalRect = subnodesGlobalRect->unionWith(item->renderData.globalRect);
|
||||
if (globalRect) {
|
||||
globalRect = globalRect->unionWith(item->renderData.globalRect);
|
||||
} else {
|
||||
subnodesGlobalRect = item->renderData.globalRect;
|
||||
globalRect = item->renderData.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) {
|
||||
if (!globalRect) {
|
||||
node->renderData.isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
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))
|
||||
CGRect integralGlobalRect(
|
||||
std::floor(globalRect->x),
|
||||
std::floor(globalRect->y),
|
||||
std::ceil(globalRect->width + globalRect->x - floor(globalRect->x)),
|
||||
std::ceil(globalRect->height + globalRect->y - floor(globalRect->y))
|
||||
);
|
||||
|
||||
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(globalRect)) {
|
||||
if (!CGRect(0.0, 0.0, globalSize.x, globalSize.y).intersects(integralGlobalRect)) {
|
||||
node->renderData.isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (masksToBounds && effectiveLocalBounds) {
|
||||
CGRect effectiveGlobalBounds = effectiveLocalBounds->applyingTransform(currentTransform);
|
||||
bool masksToBounds = node->masksToBounds();
|
||||
if (masksToBounds) {
|
||||
CGRect effectiveGlobalBounds = node->bounds().applyingTransform(currentTransform);
|
||||
if (effectiveGlobalBounds.contains(CGRect(0.0, 0.0, globalSize.x, globalSize.y))) {
|
||||
masksToBounds = false;
|
||||
}
|
||||
@ -162,7 +236,7 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
||||
if (node->mask()) {
|
||||
processRenderTree(node->mask(), globalSize, currentTransform, node->invertMask(), bezierPathsBoundingBoxContext);
|
||||
if (node->mask()->renderData.isValid) {
|
||||
if (!node->mask()->renderData.globalRect.intersects(globalRect)) {
|
||||
if (!node->mask()->renderData.globalRect.intersects(integralGlobalRect)) {
|
||||
node->renderData.isValid = false;
|
||||
return;
|
||||
}
|
||||
@ -172,21 +246,22 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
||||
}
|
||||
}
|
||||
|
||||
CGRect localRect = effectiveLocalRect.value_or(CGRect(0.0, 0.0, 0.0, 0.0)).applyingTransform(localTransform);
|
||||
if (integralGlobalRect.width <= 0.0 || integralGlobalRect.height <= 0.0) {
|
||||
node->renderData.isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
node->renderData.isValid = true;
|
||||
|
||||
node->renderData.layer._bounds = node->bounds();
|
||||
node->renderData.layer._position = node->position();
|
||||
node->renderData.layer._transform = node->transform();
|
||||
node->renderData.layer._opacity = alpha;
|
||||
node->renderData.layer._opacity = node->alpha();
|
||||
node->renderData.layer._masksToBounds = masksToBounds;
|
||||
node->renderData.layer._isHidden = node->isHidden();
|
||||
|
||||
node->renderData.globalRect = globalRect;
|
||||
node->renderData.localRect = localRect;
|
||||
node->renderData.globalRect = integralGlobalRect;
|
||||
node->renderData.globalTransform = currentTransform;
|
||||
node->renderData.drawsContent = effectiveLocalBounds.has_value();
|
||||
node->renderData.drawContentDescendants = drawContentDescendants;
|
||||
node->renderData.isInvertedMatte = isInvertedMatte;
|
||||
}
|
||||
@ -195,9 +270,62 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
|
||||
|
||||
namespace {
|
||||
|
||||
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> context, std::shared_ptr<lottie::RenderTreeNodeContentItem> item) {
|
||||
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> parentContext, std::shared_ptr<lottie::RenderTreeNodeContentItem> item, double parentAlpha) {
|
||||
if (!item->renderData.isValid) {
|
||||
return;
|
||||
}
|
||||
|
||||
float normalizedOpacity = item->renderData.layer.opacity();
|
||||
double layerAlpha = ((double)normalizedOpacity) * parentAlpha;
|
||||
|
||||
if (item->renderData.layer.isHidden() || normalizedOpacity == 0.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
parentContext->saveState();
|
||||
|
||||
std::shared_ptr<lottieRendering::Canvas> currentContext;
|
||||
std::shared_ptr<lottieRendering::Canvas> tempContext;
|
||||
|
||||
bool needsTempContext = false;
|
||||
needsTempContext = layerAlpha != 1.0 && item->renderData.drawContentDescendants > 1;
|
||||
|
||||
if (needsTempContext) {
|
||||
auto tempContextValue = parentContext->makeLayer((int)(item->renderData.globalRect.width), (int)(item->renderData.globalRect.height));
|
||||
tempContext = tempContextValue;
|
||||
|
||||
currentContext = tempContextValue;
|
||||
currentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-item->renderData.globalRect.x, -item->renderData.globalRect.y)));
|
||||
|
||||
currentContext->saveState();
|
||||
currentContext->concatenate(item->renderData.globalTransform);
|
||||
} else {
|
||||
currentContext = parentContext;
|
||||
}
|
||||
|
||||
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(item->renderData.layer.position().x, item->renderData.layer.position().y)));
|
||||
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-item->renderData.layer.bounds().x, -item->renderData.layer.bounds().y)));
|
||||
parentContext->concatenate(item->renderData.layer.transform());
|
||||
|
||||
double renderAlpha = 1.0;
|
||||
if (tempContext) {
|
||||
renderAlpha = 1.0;
|
||||
} else {
|
||||
renderAlpha = layerAlpha;
|
||||
}
|
||||
|
||||
for (const auto &shading : item->shadings) {
|
||||
if (shading->explicitPath->empty()) {
|
||||
std::vector<lottie::BezierPath> itemPaths;
|
||||
if (shading->explicitPath) {
|
||||
itemPaths = shading->explicitPath.value();
|
||||
} else {
|
||||
auto rawPaths = collectPaths(item, shading->subItemLimit, lottie::CATransform3D::identity(), true);
|
||||
for (const auto &rawPath : rawPaths) {
|
||||
itemPaths.push_back(rawPath.path.copyUsingTransform(rawPath.transform));
|
||||
}
|
||||
}
|
||||
|
||||
if (itemPaths.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -228,7 +356,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
||||
};
|
||||
|
||||
LottiePathItem pathItem;
|
||||
for (const auto &path : shading->explicitPath.value()) {
|
||||
for (const auto &path : itemPaths) {
|
||||
std::optional<lottie::PathElement> previousElement;
|
||||
for (const auto &element : path.elements()) {
|
||||
if (previousElement.has_value()) {
|
||||
@ -304,7 +432,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
||||
dashPattern = shading->stroke->dashPattern;
|
||||
}
|
||||
|
||||
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));
|
||||
currentContext->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 * renderAlpha));
|
||||
} else if (shading->stroke->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Gradient) {
|
||||
//TODO:gradient stroke
|
||||
}
|
||||
@ -328,7 +456,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
||||
if (shading->fill->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Solid) {
|
||||
lottie::RenderTreeNodeContentItem::SolidShading *solidShading = (lottie::RenderTreeNodeContentItem::SolidShading *)shading->fill->shading.get();
|
||||
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));
|
||||
currentContext->fillPath(path, rule, lottieRendering::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity * renderAlpha));
|
||||
}
|
||||
} else if (shading->fill->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Gradient) {
|
||||
lottie::RenderTreeNodeContentItem::GradientShading *gradientShading = (lottie::RenderTreeNodeContentItem::GradientShading *)shading->fill->shading.get();
|
||||
@ -337,7 +465,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
||||
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));
|
||||
colors.push_back(lottieRendering::Color(color.r, color.g, color.b, color.a * gradientShading->opacity * renderAlpha));
|
||||
}
|
||||
locations = gradientShading->locations;
|
||||
|
||||
@ -347,11 +475,11 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
||||
|
||||
switch (gradientShading->gradientType) {
|
||||
case lottie::GradientType::Linear: {
|
||||
context->linearGradientFillPath(path, rule, gradient, start, end);
|
||||
currentContext->linearGradientFillPath(path, rule, gradient, start, end);
|
||||
break;
|
||||
}
|
||||
case lottie::GradientType::Radial: {
|
||||
context->radialGradientFillPath(path, rule, gradient, start, 0.0, start, start.distanceTo(end));
|
||||
currentContext->radialGradientFillPath(path, rule, gradient, start, 0.0, start, start.distanceTo(end));
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -364,8 +492,19 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> conte
|
||||
}
|
||||
|
||||
for (const auto &subItem : item->subItems) {
|
||||
drawLottieContentItem(context, subItem);
|
||||
drawLottieContentItem(currentContext, subItem, renderAlpha);
|
||||
}
|
||||
|
||||
if (tempContext) {
|
||||
tempContext->restoreState();
|
||||
|
||||
parentContext->concatenate(item->renderData.globalTransform.inverted());
|
||||
parentContext->setAlpha(layerAlpha);
|
||||
parentContext->draw(tempContext, item->renderData.globalRect);
|
||||
parentContext->setAlpha(1.0);
|
||||
}
|
||||
|
||||
parentContext->restoreState();
|
||||
}
|
||||
|
||||
static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node, std::shared_ptr<lottieRendering::Canvas> parentContext, lottie::Vector2D const &globalSize, double parentAlpha) {
|
||||
@ -432,10 +571,8 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
|
||||
renderAlpha = layerAlpha;
|
||||
}
|
||||
|
||||
currentContext->setAlpha(renderAlpha);
|
||||
|
||||
if (node->_contentItem) {
|
||||
drawLottieContentItem(currentContext, node->_contentItem);
|
||||
drawLottieContentItem(currentContext, node->_contentItem, renderAlpha);
|
||||
}
|
||||
|
||||
if (node->renderData.isInvertedMatte) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <LottieCpp/CurveVertex.h>
|
||||
#include <LottieCpp/PathElement.h>
|
||||
#include <LottieCpp/CGPath.h>
|
||||
#include <LottieCpp/ShapeAttributes.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
@ -126,7 +127,7 @@ public:
|
||||
public:
|
||||
BezierPath(std::shared_ptr<BezierPathContents> contents);
|
||||
|
||||
private:
|
||||
public:
|
||||
std::shared_ptr<BezierPathContents> _contents;
|
||||
};
|
||||
|
||||
@ -144,6 +145,8 @@ public:
|
||||
CGRect bezierPathsBoundingBox(std::vector<BezierPath> const &paths);
|
||||
CGRect bezierPathsBoundingBoxParallel(BezierPathsBoundingBoxContext &context, std::vector<BezierPath> const &paths);
|
||||
|
||||
std::vector<BezierPath> trimBezierPaths(std::vector<BezierPath> &sourcePaths, double start, double end, double offset, TrimType type);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -13,6 +13,82 @@
|
||||
|
||||
namespace lottie {
|
||||
|
||||
class ProcessedRenderTreeNodeData {
|
||||
public:
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
ProcessedRenderTreeNodeData() :
|
||||
isValid(false),
|
||||
layer(
|
||||
CGRect(0.0, 0.0, 0.0, 0.0),
|
||||
Vector2D(0.0, 0.0),
|
||||
CATransform3D::identity(),
|
||||
1.0,
|
||||
false,
|
||||
false
|
||||
),
|
||||
globalRect(CGRect(0.0, 0.0, 0.0, 0.0)),
|
||||
globalTransform(CATransform3D::identity()),
|
||||
drawContentDescendants(false),
|
||||
isInvertedMatte(false) {
|
||||
|
||||
}
|
||||
|
||||
bool isValid = false;
|
||||
LayerParams layer;
|
||||
CGRect globalRect;
|
||||
CATransform3D globalTransform;
|
||||
int drawContentDescendants;
|
||||
bool isInvertedMatte;
|
||||
};
|
||||
|
||||
class RenderableItem {
|
||||
public:
|
||||
enum class Type {
|
||||
@ -345,8 +421,13 @@ public:
|
||||
public:
|
||||
bool isGroup = false;
|
||||
CATransform3D transform = CATransform3D::identity();
|
||||
double alpha = 0.0;
|
||||
std::optional<TrimParams> trimParams;
|
||||
std::optional<BezierPath> path;
|
||||
std::vector<std::shared_ptr<RenderTreeNodeContentShadingVariant>> shadings;
|
||||
std::vector<std::shared_ptr<RenderTreeNodeContentItem>> subItems;
|
||||
|
||||
ProcessedRenderTreeNodeData renderData;
|
||||
};
|
||||
|
||||
class RenderTreeNodeContentShadingVariant {
|
||||
@ -362,86 +443,6 @@ public:
|
||||
size_t subItemLimit = 0;
|
||||
};
|
||||
|
||||
class ProcessedRenderTreeNodeData {
|
||||
public:
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
ProcessedRenderTreeNodeData() :
|
||||
isValid(false),
|
||||
layer(
|
||||
CGRect(0.0, 0.0, 0.0, 0.0),
|
||||
Vector2D(0.0, 0.0),
|
||||
CATransform3D::identity(),
|
||||
1.0,
|
||||
false,
|
||||
false
|
||||
),
|
||||
globalRect(CGRect(0.0, 0.0, 0.0, 0.0)),
|
||||
localRect(CGRect(0.0, 0.0, 0.0, 0.0)),
|
||||
globalTransform(CATransform3D::identity()),
|
||||
drawsContent(false),
|
||||
drawContentDescendants(false),
|
||||
isInvertedMatte(false) {
|
||||
|
||||
}
|
||||
|
||||
bool isValid = false;
|
||||
LayerParams layer;
|
||||
CGRect globalRect;
|
||||
CGRect localRect;
|
||||
CATransform3D globalTransform;
|
||||
bool drawsContent;
|
||||
int drawContentDescendants;
|
||||
bool isInvertedMatte;
|
||||
};
|
||||
|
||||
class RenderTreeNode {
|
||||
public:
|
||||
RenderTreeNode(
|
||||
|
@ -31,6 +31,25 @@ enum class GradientType: int {
|
||||
Radial = 2
|
||||
};
|
||||
|
||||
enum class TrimType: int {
|
||||
Simultaneously = 1,
|
||||
Individually = 2
|
||||
};
|
||||
|
||||
struct TrimParams {
|
||||
double start = 0.0;
|
||||
double end = 0.0;
|
||||
double offset = 0.0;
|
||||
TrimType type = TrimType::Simultaneously;
|
||||
|
||||
TrimParams(double start_, double end_, double offset_, TrimType type_) :
|
||||
start(start_),
|
||||
end(end_),
|
||||
offset(offset_),
|
||||
type(type_) {
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -437,27 +437,10 @@ public:
|
||||
std::shared_ptr<RenderTreeNodeContentItem::Stroke> _stroke;
|
||||
};
|
||||
|
||||
struct TrimParams {
|
||||
double start = 0.0;
|
||||
double end = 0.0;
|
||||
double offset = 0.0;
|
||||
TrimType type = TrimType::Simultaneously;
|
||||
size_t subItemLimit = 0;
|
||||
|
||||
TrimParams(double start_, double end_, double offset_, TrimType type_, size_t subItemLimit_) :
|
||||
start(start_),
|
||||
end(end_),
|
||||
offset(offset_),
|
||||
type(type_),
|
||||
subItemLimit(subItemLimit_) {
|
||||
}
|
||||
};
|
||||
|
||||
class TrimParamsOutput {
|
||||
public:
|
||||
TrimParamsOutput(Trim const &trim, size_t subItemLimit) :
|
||||
TrimParamsOutput(Trim const &trim) :
|
||||
type(trim.trimType),
|
||||
subItemLimit(subItemLimit),
|
||||
start(trim.start.keyframes),
|
||||
end(trim.end.keyframes),
|
||||
offset(trim.offset.keyframes) {
|
||||
@ -485,12 +468,11 @@ public:
|
||||
|
||||
double resolvedOffset = fmod(offsetValue, 360.0) / 360.0;
|
||||
|
||||
return TrimParams(resolvedStart, resolvedEnd, resolvedOffset, type, subItemLimit);
|
||||
return TrimParams(resolvedStart, resolvedEnd, resolvedOffset, type);
|
||||
}
|
||||
|
||||
private:
|
||||
TrimType type;
|
||||
size_t subItemLimit = 0;
|
||||
|
||||
KeyframeInterpolator<Vector1D> start;
|
||||
double startValue = 0.0;
|
||||
@ -597,7 +579,7 @@ public:
|
||||
}
|
||||
|
||||
if (hasUpdates) {
|
||||
resolvedPath = makeRectangleBezierPath(Vector2D(positionValue.x, positionValue.y), Vector2D(sizeValue.x, sizeValue.y), cornerRadiusValue, direction);
|
||||
ValueInterpolator<BezierPath>::setInplace(makeRectangleBezierPath(Vector2D(positionValue.x, positionValue.y), Vector2D(sizeValue.x, sizeValue.y), cornerRadiusValue, direction), resolvedPath);
|
||||
}
|
||||
|
||||
hasValidData = true;
|
||||
@ -645,7 +627,7 @@ public:
|
||||
}
|
||||
|
||||
if (hasUpdates) {
|
||||
resolvedPath = makeEllipseBezierPath(Vector2D(sizeValue.x, sizeValue.y), Vector2D(positionValue.x, positionValue.y), direction);
|
||||
ValueInterpolator<BezierPath>::setInplace(makeEllipseBezierPath(Vector2D(sizeValue.x, sizeValue.y), Vector2D(positionValue.x, positionValue.y), direction), resolvedPath);
|
||||
}
|
||||
|
||||
hasValidData = true;
|
||||
@ -732,7 +714,7 @@ public:
|
||||
}
|
||||
|
||||
if (hasUpdates) {
|
||||
resolvedPath = makeStarBezierPath(Vector2D(positionValue.x, positionValue.y), outerRadiusValue, innerRadiusValue, outerRoundednessValue, innerRoundednessValue, pointsValue, rotationValue, direction);
|
||||
ValueInterpolator<BezierPath>::setInplace(makeStarBezierPath(Vector2D(positionValue.x, positionValue.y), outerRadiusValue, innerRadiusValue, outerRoundednessValue, innerRoundednessValue, pointsValue, rotationValue, direction), resolvedPath);
|
||||
}
|
||||
|
||||
hasValidData = true;
|
||||
@ -909,10 +891,6 @@ public:
|
||||
transform = std::move(transform_);
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderTreeNode> const &renderTree() const {
|
||||
return _renderTree;
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<PathOutput> path;
|
||||
std::unique_ptr<TransformOutput> transform;
|
||||
@ -920,14 +898,19 @@ public:
|
||||
std::vector<ShadingVariant> shadings;
|
||||
std::vector<std::shared_ptr<TrimParamsOutput>> trims;
|
||||
|
||||
public:
|
||||
std::vector<std::shared_ptr<ContentItem>> subItems;
|
||||
|
||||
std::shared_ptr<RenderTreeNode> _renderTree;
|
||||
std::shared_ptr<RenderTreeNodeContentItem> _contentItem;
|
||||
|
||||
private:
|
||||
std::vector<TransformedPath> collectPaths(size_t subItemLimit, CATransform3D const &parentTransform, bool skipApplyTransform) {
|
||||
bool hasTrims(size_t subItemLimit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
std::vector<TransformedPath> collectPaths(size_t subItemLimit, CATransform3D const &parentTransform, bool skipApplyTransform, bool &hasTrims) {
|
||||
std::vector<TransformedPath> mappedPaths;
|
||||
|
||||
//TODO:remove skipApplyTransform
|
||||
CATransform3D effectiveTransform = parentTransform;
|
||||
if (!skipApplyTransform && isGroup && transform) {
|
||||
effectiveTransform = transform->transform() * effectiveTransform;
|
||||
@ -935,8 +918,8 @@ public:
|
||||
|
||||
size_t maxSubitem = std::min(subItems.size(), subItemLimit);
|
||||
|
||||
if (path) {
|
||||
mappedPaths.emplace_back(*(path->currentPath()), effectiveTransform);
|
||||
if (_contentItem->path) {
|
||||
mappedPaths.emplace_back(_contentItem->path.value(), effectiveTransform);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < maxSubitem; i++) {
|
||||
@ -947,9 +930,10 @@ public:
|
||||
currentTrim = trims[0]->trimParams();
|
||||
}
|
||||
|
||||
auto subItemPaths = subItem->collectPaths(INT32_MAX, effectiveTransform, false);
|
||||
auto subItemPaths = subItem->collectPaths(INT32_MAX, effectiveTransform, false, hasTrims);
|
||||
|
||||
if (currentTrim) {
|
||||
hasTrims = true;
|
||||
CompoundBezierPath tempPath;
|
||||
for (auto &path : subItemPaths) {
|
||||
tempPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||
@ -988,25 +972,17 @@ public:
|
||||
}
|
||||
|
||||
void addTrim(Trim const &trim) {
|
||||
trims.push_back(std::make_shared<TrimParamsOutput>(trim, subItems.size()));
|
||||
trims.push_back(std::make_shared<TrimParamsOutput>(trim));
|
||||
}
|
||||
|
||||
public:
|
||||
void initializeRenderChildren() {
|
||||
_renderTree = std::make_shared<RenderTreeNode>(
|
||||
CGRect(0.0, 0.0, 0.0, 0.0),
|
||||
Vector2D(0.0, 0.0),
|
||||
CATransform3D::identity(),
|
||||
1.0,
|
||||
false,
|
||||
false,
|
||||
std::vector<std::shared_ptr<RenderTreeNode>>(),
|
||||
nullptr,
|
||||
false
|
||||
);
|
||||
_contentItem = std::make_shared<RenderTreeNodeContentItem>();
|
||||
_contentItem->isGroup = isGroup;
|
||||
|
||||
_renderTree->_contentItem = std::make_shared<RenderTreeNodeContentItem>();
|
||||
_renderTree->_contentItem->isGroup = isGroup;
|
||||
if (path) {
|
||||
_contentItem->path = *path->currentPath();
|
||||
}
|
||||
|
||||
if (!shadings.empty()) {
|
||||
for (int i = 0; i < shadings.size(); i++) {
|
||||
@ -1025,7 +1001,7 @@ public:
|
||||
}
|
||||
itemShadingVariant->subItemLimit = shadingVariant.subItemLimit;
|
||||
|
||||
_renderTree->_contentItem->shadings.push_back(itemShadingVariant);
|
||||
_contentItem->shadings.push_back(itemShadingVariant);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1033,22 +1009,7 @@ public:
|
||||
std::vector<std::shared_ptr<RenderTreeNode>> subItemNodes;
|
||||
for (int i = (int)subItems.size() - 1; i >= 0; i--) {
|
||||
subItems[i]->initializeRenderChildren();
|
||||
subItemNodes.push_back(subItems[i]->_renderTree);
|
||||
//_renderTree->_contentItem->subItems.push_back(subItems[i]->_renderTree->_contentItem);
|
||||
}
|
||||
|
||||
if (!subItemNodes.empty()) {
|
||||
_renderTree->_subnodes.push_back(std::make_shared<RenderTreeNode>(
|
||||
CGRect(0.0, 0.0, 0.0, 0.0),
|
||||
Vector2D(0.0, 0.0),
|
||||
CATransform3D::identity(),
|
||||
1.0,
|
||||
false,
|
||||
false,
|
||||
subItemNodes,
|
||||
nullptr,
|
||||
false
|
||||
));
|
||||
_contentItem->subItems.push_back(subItems[i]->_contentItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1061,6 +1022,8 @@ public:
|
||||
|
||||
if (path) {
|
||||
path->update(frameTime);
|
||||
} else {
|
||||
_contentItem->path = std::nullopt;
|
||||
}
|
||||
for (const auto &trim : trims) {
|
||||
trim->update(frameTime);
|
||||
@ -1080,15 +1043,15 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void updateChildren(std::optional<TrimParams> parentTrim) {
|
||||
void updateContents(std::optional<TrimParams> parentTrim) {
|
||||
CATransform3D containerTransform = CATransform3D::identity();
|
||||
double containerOpacity = 1.0;
|
||||
if (transform) {
|
||||
containerTransform = transform->transform();
|
||||
containerOpacity = transform->opacity();
|
||||
}
|
||||
_renderTree->_transform = containerTransform;
|
||||
_renderTree->_alpha = containerOpacity;
|
||||
_contentItem->transform = containerTransform;
|
||||
_contentItem->alpha = containerOpacity;
|
||||
|
||||
for (int i = 0; i < shadings.size(); i++) {
|
||||
const auto &shadingVariant = shadings[i];
|
||||
@ -1097,42 +1060,58 @@ public:
|
||||
continue;
|
||||
}
|
||||
|
||||
CompoundBezierPath compoundPath;
|
||||
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true);
|
||||
for (const auto &path : paths) {
|
||||
compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||
}
|
||||
|
||||
//std::optional<TrimParams> currentTrim = parentTrim;
|
||||
//TODO:investigate
|
||||
/*if (!trims.empty()) {
|
||||
currentTrim = trims[0];
|
||||
}*/
|
||||
|
||||
bool hasTrims = false;
|
||||
if (parentTrim) {
|
||||
CompoundBezierPath compoundPath;
|
||||
hasTrims = true;
|
||||
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true, hasTrims);
|
||||
for (const auto &path : paths) {
|
||||
compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||
}
|
||||
|
||||
compoundPath = trimCompoundPath(compoundPath, parentTrim->start, parentTrim->end, parentTrim->offset, parentTrim->type);
|
||||
|
||||
std::vector<BezierPath> resultPaths;
|
||||
for (const auto &path : compoundPath.paths) {
|
||||
resultPaths.push_back(path);
|
||||
}
|
||||
_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||
} else {
|
||||
CompoundBezierPath compoundPath;
|
||||
auto paths = collectPaths(shadingVariant.subItemLimit, CATransform3D::identity(), true, hasTrims);
|
||||
for (const auto &path : paths) {
|
||||
compoundPath.appendPath(path.path.copyUsingTransform(path.transform));
|
||||
}
|
||||
std::vector<BezierPath> resultPaths;
|
||||
for (const auto &path : compoundPath.paths) {
|
||||
resultPaths.push_back(path);
|
||||
}
|
||||
|
||||
if (hasTrims) {
|
||||
_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||
} else {
|
||||
_contentItem->shadings[i]->explicitPath = std::nullopt;
|
||||
_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<BezierPath> resultPaths;
|
||||
for (const auto &path : compoundPath.paths) {
|
||||
resultPaths.push_back(path);
|
||||
}
|
||||
|
||||
_renderTree->_contentItem->shadings[i]->explicitPath = resultPaths;
|
||||
}
|
||||
|
||||
if (isGroup && !subItems.empty()) {
|
||||
for (int i = (int)subItems.size() - 1; i >= 0; i--) {
|
||||
std::optional<TrimParams> childTrim = parentTrim;
|
||||
for (const auto &trim : trims) {
|
||||
if (i < (int)trim->trimParams().subItemLimit) {
|
||||
//TODO:allow combination
|
||||
//assert(!parentTrim);
|
||||
childTrim = trim->trimParams();
|
||||
}
|
||||
//TODO:allow combination
|
||||
//assert(!parentTrim);
|
||||
childTrim = trim->trimParams();
|
||||
}
|
||||
|
||||
subItems[i]->updateChildren(childTrim);
|
||||
subItems[i]->updateContents(childTrim);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1229,7 +1208,14 @@ private:
|
||||
case ShapeType::Trim: {
|
||||
Trim const &trim = *((Trim *)item.get());
|
||||
|
||||
itemTree->addTrim(trim);
|
||||
auto groupItem = std::make_shared<ContentItem>();
|
||||
groupItem->isGroup = true;
|
||||
for (const auto &subItem : itemTree->subItems) {
|
||||
groupItem->addSubItem(subItem);
|
||||
}
|
||||
groupItem->addTrim(trim);
|
||||
itemTree->subItems.clear();
|
||||
itemTree->addSubItem(groupItem);
|
||||
|
||||
break;
|
||||
}
|
||||
@ -1306,7 +1292,7 @@ void ShapeCompositionLayer::displayContentsWithFrame(double frame, bool forceUpd
|
||||
_frameTime = frame;
|
||||
_frameTimeInitialized = true;
|
||||
_contentTree->itemTree->updateFrame(_frameTime);
|
||||
_contentTree->itemTree->updateChildren(std::nullopt);
|
||||
_contentTree->itemTree->updateContents(std::nullopt);
|
||||
}
|
||||
|
||||
std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
|
||||
@ -1314,12 +1300,26 @@ std::shared_ptr<RenderTreeNode> ShapeCompositionLayer::renderTreeNode() {
|
||||
_frameTime = 0.0;
|
||||
_frameTimeInitialized = true;
|
||||
_contentTree->itemTree->updateFrame(_frameTime);
|
||||
_contentTree->itemTree->updateChildren(std::nullopt);
|
||||
_contentTree->itemTree->updateContents(std::nullopt);
|
||||
}
|
||||
|
||||
if (!_renderTreeNode) {
|
||||
_contentRenderTreeNode = std::make_shared<RenderTreeNode>(
|
||||
CGRect(0.0, 0.0, 0.0, 0.0),
|
||||
Vector2D(0.0, 0.0),
|
||||
CATransform3D::identity(),
|
||||
1.0,
|
||||
false,
|
||||
false,
|
||||
std::vector<std::shared_ptr<RenderTreeNode>>(),
|
||||
nullptr,
|
||||
false
|
||||
);
|
||||
_contentRenderTreeNode->_contentItem = _contentTree->itemTree->_contentItem;
|
||||
|
||||
std::vector<std::shared_ptr<RenderTreeNode>> subnodes;
|
||||
subnodes.push_back(_contentTree->itemTree->renderTree());
|
||||
//subnodes.push_back(_contentTree->itemTree->renderTree());
|
||||
subnodes.push_back(_contentRenderTreeNode);
|
||||
|
||||
std::shared_ptr<RenderTreeNode> maskNode;
|
||||
bool invertMask = false;
|
||||
@ -1351,12 +1351,12 @@ void ShapeCompositionLayer::updateRenderTree() {
|
||||
_matteLayer->updateRenderTree();
|
||||
}
|
||||
|
||||
_contentTree->itemTree->renderTree()->_bounds = _contentsLayer->bounds();
|
||||
_contentTree->itemTree->renderTree()->_position = _contentsLayer->position();
|
||||
_contentTree->itemTree->renderTree()->_transform = _contentsLayer->transform();
|
||||
_contentTree->itemTree->renderTree()->_alpha = _contentsLayer->opacity();
|
||||
_contentTree->itemTree->renderTree()->_masksToBounds = _contentsLayer->masksToBounds();
|
||||
_contentTree->itemTree->renderTree()->_isHidden = _contentsLayer->isHidden();
|
||||
_contentRenderTreeNode->_bounds = _contentsLayer->bounds();
|
||||
_contentRenderTreeNode->_position = _contentsLayer->position();
|
||||
_contentRenderTreeNode->_transform = _contentsLayer->transform();
|
||||
_contentRenderTreeNode->_alpha = _contentsLayer->opacity();
|
||||
_contentRenderTreeNode->_masksToBounds = _contentsLayer->masksToBounds();
|
||||
_contentRenderTreeNode->_isHidden = _contentsLayer->isHidden();
|
||||
|
||||
assert(position() == Vector2D::Zero());
|
||||
assert(transform().isIdentity());
|
||||
|
@ -27,6 +27,7 @@ private:
|
||||
bool _frameTimeInitialized = false;
|
||||
|
||||
std::shared_ptr<RenderTreeNode> _renderTreeNode;
|
||||
std::shared_ptr<RenderTreeNode> _contentRenderTreeNode;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -8,11 +8,6 @@
|
||||
|
||||
namespace lottie {
|
||||
|
||||
enum class TrimType: int {
|
||||
Simultaneously = 1,
|
||||
Individually = 2
|
||||
};
|
||||
|
||||
/// An item that defines trim
|
||||
class Trim: public ShapeItem {
|
||||
public:
|
||||
|
@ -65,9 +65,7 @@
|
||||
result.layer.isHidden = node->renderData.layer._isHidden;
|
||||
|
||||
result.globalRect = CGRectMake(node->renderData.globalRect.x, node->renderData.globalRect.y, node->renderData.globalRect.width, node->renderData.globalRect.height);
|
||||
result.localRect = CGRectMake(node->renderData.localRect.x, node->renderData.localRect.y, node->renderData.localRect.width, node->renderData.localRect.height);
|
||||
result.globalTransform = lottie::nativeTransform(node->renderData.globalTransform);
|
||||
result.drawsContent = node->renderData.drawsContent;
|
||||
result.hasSimpleContents = node->renderData.drawContentDescendants <= 1;
|
||||
result.drawContentDescendants = node->renderData.drawContentDescendants;
|
||||
result.isInvertedMatte = node->renderData.isInvertedMatte;
|
||||
|
Loading…
x
Reference in New Issue
Block a user