Skip to content

Commit 8678643

Browse files
author
Isaac
committed
Lottie
1 parent aee7844 commit 8678643

4 files changed

Lines changed: 61 additions & 113 deletions

File tree

‎Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm‎

Lines changed: 56 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -84,12 +84,14 @@
8484

8585
namespace lottie {
8686

87-
static std::optional<CGRect> getRenderContentItemGlobalRect(std::shared_ptr<RenderTreeNodeContentItem> const &contentItem, lottie::Vector2D const &globalSize, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
87+
static std::optional<CGRect> getRenderContentItemGlobalRect(std::shared_ptr<RenderTreeNodeContentItem> const &contentItem, lottie::Vector2D const &globalSize, lottie::CATransform3D const &parentTransform, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
8888
if (!contentItem->renderData.isValid) {
8989
return std::nullopt;
9090
}
9191

92-
auto currentTransform = contentItem->renderData.globalTransform;
92+
auto currentTransform = parentTransform;
93+
CATransform3D localTransform = contentItem->transform;
94+
currentTransform = localTransform * currentTransform;
9395

9496
std::optional<CGRect> globalRect;
9597
for (const auto &shadingVariant : contentItem->shadings) {
@@ -111,7 +113,7 @@
111113
}
112114

113115
for (const auto &subItem : contentItem->subItems) {
114-
auto subGlobalRect = getRenderContentItemGlobalRect(subItem, globalSize, bezierPathsBoundingBoxContext);
116+
auto subGlobalRect = getRenderContentItemGlobalRect(subItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
115117
if (subGlobalRect) {
116118
if (globalRect) {
117119
globalRect = globalRect->unionWith(subGlobalRect.value());
@@ -134,15 +136,20 @@ CGRect integralGlobalRect(
134136
}
135137
}
136138

137-
static std::optional<CGRect> getRenderNodeGlobalRect(std::shared_ptr<RenderTreeNode> const &node, lottie::Vector2D const &globalSize, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
139+
static std::optional<CGRect> getRenderNodeGlobalRect(std::shared_ptr<RenderTreeNode> const &node, lottie::Vector2D const &globalSize, lottie::CATransform3D const &parentTransform, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
138140
if (!node->renderData.isValid) {
139141
return std::nullopt;
140142
}
141-
auto currentTransform = node->renderData.globalTransform;
143+
144+
auto currentTransform = parentTransform;
145+
Vector2D localTranslation(node->position().x + -node->bounds().x, node->position().y + -node->bounds().y);
146+
CATransform3D localTransform = node->transform();
147+
localTransform = localTransform.translated(localTranslation);
148+
currentTransform = localTransform * currentTransform;
142149

143150
std::optional<CGRect> globalRect;
144151
if (node->_contentItem) {
145-
globalRect = getRenderContentItemGlobalRect(node->_contentItem, globalSize, bezierPathsBoundingBoxContext);
152+
globalRect = getRenderContentItemGlobalRect(node->_contentItem, globalSize, currentTransform, bezierPathsBoundingBoxContext);
146153
}
147154

148155
if (node->renderData.isInvertedMatte) {
@@ -155,7 +162,7 @@ CGRect integralGlobalRect(
155162
}
156163

157164
for (const auto &subNode : node->subnodes()) {
158-
auto subGlobalRect = getRenderNodeGlobalRect(subNode, globalSize, bezierPathsBoundingBoxContext);
165+
auto subGlobalRect = getRenderNodeGlobalRect(subNode, globalSize, currentTransform, bezierPathsBoundingBoxContext);
159166
if (subGlobalRect) {
160167
if (globalRect) {
161168
globalRect = globalRect->unionWith(subGlobalRect.value());
@@ -180,7 +187,6 @@ CGRect integralGlobalRect(
180187

181188
static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem> const &contentItem, Vector2D const &globalSize, CATransform3D const &parentTransform, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
182189
auto currentTransform = parentTransform;
183-
184190
CATransform3D localTransform = contentItem->transform;
185191
currentTransform = localTransform * currentTransform;
186192

@@ -217,14 +223,8 @@ static void processRenderContentItem(std::shared_ptr<RenderTreeNodeContentItem>
217223

218224
contentItem->renderData.isValid = true;
219225

220-
contentItem->renderData.layer._bounds = CGRect(0.0, 0.0, 0.0, 0.0);
221-
contentItem->renderData.layer._position = Vector2D(0.0, 0.0);
222-
contentItem->renderData.layer._transform = contentItem->transform;
223-
contentItem->renderData.layer._opacity = contentItem->alpha;
224-
contentItem->renderData.layer._masksToBounds = false;
225-
contentItem->renderData.layer._isHidden = false;
226+
contentItem->renderData.layer.masksToBounds = false;
226227

227-
contentItem->renderData.globalTransform = currentTransform;
228228
contentItem->renderData.drawContentDescendants = drawContentDescendants;
229229
contentItem->renderData.isInvertedMatte = false;
230230
}
@@ -243,11 +243,9 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
243243
}
244244

245245
auto currentTransform = parentTransform;
246-
247246
Vector2D localTranslation(node->position().x + -node->bounds().x, node->position().y + -node->bounds().y);
248247
CATransform3D localTransform = node->transform();
249248
localTransform = localTransform.translated(localTranslation);
250-
251249
currentTransform = localTransform * currentTransform;
252250

253251
if (!currentTransform.isInvertible()) {
@@ -290,14 +288,8 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
290288

291289
node->renderData.isValid = true;
292290

293-
node->renderData.layer._bounds = node->bounds();
294-
node->renderData.layer._position = node->position();
295-
node->renderData.layer._transform = node->transform();
296-
node->renderData.layer._opacity = node->alpha();
297-
node->renderData.layer._masksToBounds = masksToBounds;
298-
node->renderData.layer._isHidden = node->isHidden();
291+
node->renderData.layer.masksToBounds = masksToBounds;
299292

300-
node->renderData.globalTransform = currentTransform;
301293
node->renderData.drawContentDescendants = drawContentDescendants;
302294
node->renderData.isInvertedMatte = isInvertedMatte;
303295
}
@@ -306,15 +298,19 @@ static void processRenderTree(std::shared_ptr<RenderTreeNode> const &node, Vecto
306298

307299
namespace {
308300

309-
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> parentContext, std::shared_ptr<lottie::RenderTreeNodeContentItem> item, float parentAlpha, lottie::Vector2D const &globalSize, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
301+
static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> parentContext, std::shared_ptr<lottie::RenderTreeNodeContentItem> item, float parentAlpha, lottie::Vector2D const &globalSize, lottie::CATransform3D const &parentTransform, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
310302
if (!item->renderData.isValid) {
311303
return;
312304
}
313305

314-
float normalizedOpacity = item->renderData.layer.opacity();
306+
auto currentTransform = parentTransform;
307+
lottie::CATransform3D localTransform = item->transform;
308+
currentTransform = localTransform * currentTransform;
309+
310+
float normalizedOpacity = item->alpha;
315311
float layerAlpha = ((float)normalizedOpacity) * parentAlpha;
316312

317-
if (item->renderData.layer.isHidden() || normalizedOpacity == 0.0f) {
313+
if (normalizedOpacity == 0.0f) {
318314
return;
319315
}
320316

@@ -328,7 +324,7 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
328324

329325
std::optional<lottie::CGRect> globalRect;
330326
if (needsTempContext) {
331-
globalRect = lottie::getRenderContentItemGlobalRect(item, globalSize, bezierPathsBoundingBoxContext);
327+
globalRect = lottie::getRenderContentItemGlobalRect(item, globalSize, parentTransform, bezierPathsBoundingBoxContext);
332328
if (!globalRect || globalRect->width <= 0.0f || globalRect->height <= 0.0f) {
333329
parentContext->restoreState();
334330
return;
@@ -341,14 +337,12 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
341337
currentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y)));
342338

343339
currentContext->saveState();
344-
currentContext->concatenate(item->renderData.globalTransform);
340+
currentContext->concatenate(currentTransform);
345341
} else {
346342
currentContext = parentContext;
347343
}
348344

349-
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(item->renderData.layer.position().x, item->renderData.layer.position().y)));
350-
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-item->renderData.layer.bounds().x, -item->renderData.layer.bounds().y)));
351-
parentContext->concatenate(item->renderData.layer.transform());
345+
parentContext->concatenate(item->transform);
352346

353347
float renderAlpha = 1.0;
354348
if (tempContext) {
@@ -536,13 +530,13 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
536530

537531
for (auto it = item->subItems.rbegin(); it != item->subItems.rend(); it++) {
538532
const auto &subItem = *it;
539-
drawLottieContentItem(currentContext, subItem, renderAlpha, globalSize, bezierPathsBoundingBoxContext);
533+
drawLottieContentItem(currentContext, subItem, renderAlpha, globalSize, currentTransform, bezierPathsBoundingBoxContext);
540534
}
541535

542536
if (tempContext) {
543537
tempContext->restoreState();
544538

545-
parentContext->concatenate(item->renderData.globalTransform.inverted());
539+
parentContext->concatenate(currentTransform.inverted());
546540
parentContext->setAlpha(layerAlpha);
547541
parentContext->draw(tempContext, globalRect.value());
548542
parentContext->setAlpha(1.0);
@@ -551,17 +545,23 @@ static void drawLottieContentItem(std::shared_ptr<lottieRendering::Canvas> paren
551545
parentContext->restoreState();
552546
}
553547

554-
static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node, std::shared_ptr<lottieRendering::Canvas> parentContext, lottie::Vector2D const &globalSize, float parentAlpha, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
548+
static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node, std::shared_ptr<lottieRendering::Canvas> parentContext, lottie::Vector2D const &globalSize, lottie::CATransform3D const &parentTransform, float parentAlpha, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) {
555549
if (!node->renderData.isValid) {
556550
return;
557551
}
558-
float normalizedOpacity = node->renderData.layer.opacity();
552+
float normalizedOpacity = node->alpha();
559553
float layerAlpha = ((float)normalizedOpacity) * parentAlpha;
560554

561-
if (node->renderData.layer.isHidden() || normalizedOpacity == 0.0f) {
555+
if (node->isHidden() || normalizedOpacity == 0.0f) {
562556
return;
563557
}
564558

559+
auto currentTransform = parentTransform;
560+
lottie::Vector2D localTranslation(node->position().x + -node->bounds().x, node->position().y + -node->bounds().y);
561+
lottie::CATransform3D localTransform = node->transform();
562+
localTransform = localTransform.translated(localTranslation);
563+
currentTransform = localTransform * currentTransform;
564+
565565
parentContext->saveState();
566566

567567
std::shared_ptr<lottieRendering::Canvas> maskContext;
@@ -572,28 +572,28 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
572572
if (node->mask() && node->mask()->renderData.isValid) {
573573
needsTempContext = true;
574574
} else {
575-
needsTempContext = layerAlpha != 1.0 || node->renderData.layer.masksToBounds();
575+
needsTempContext = layerAlpha != 1.0 || node->renderData.layer.masksToBounds;
576576
}
577577

578578
std::optional<lottie::CGRect> globalRect;
579579
if (needsTempContext) {
580-
globalRect = lottie::getRenderNodeGlobalRect(node, globalSize, bezierPathsBoundingBoxContext);
580+
globalRect = lottie::getRenderNodeGlobalRect(node, globalSize, parentTransform, bezierPathsBoundingBoxContext);
581581
if (!globalRect || globalRect->width <= 0.0f || globalRect->height <= 0.0f) {
582582
parentContext->restoreState();
583583
return;
584584
}
585585

586-
if ((node->mask() && node->mask()->renderData.isValid) || node->renderData.layer.masksToBounds()) {
586+
if ((node->mask() && node->mask()->renderData.isValid) || node->renderData.layer.masksToBounds) {
587587
auto maskBackingStorage = parentContext->makeLayer((int)(globalRect->width), (int)(globalRect->height));
588588

589589
maskBackingStorage->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y)));
590-
maskBackingStorage->concatenate(node->renderData.globalTransform);
590+
maskBackingStorage->concatenate(currentTransform);
591591

592-
if (node->renderData.layer.masksToBounds()) {
593-
maskBackingStorage->fill(lottie::CGRect(node->renderData.layer.bounds().x, node->renderData.layer.bounds().y, node->renderData.layer.bounds().width, node->renderData.layer.bounds().height), lottie::Color(1.0, 1.0, 1.0, 1.0));
592+
if (node->renderData.layer.masksToBounds) {
593+
maskBackingStorage->fill(lottie::CGRect(node->bounds().x, node->bounds().y, node->bounds().width, node->bounds().height), lottie::Color(1.0, 1.0, 1.0, 1.0));
594594
}
595595
if (node->mask() && node->mask()->renderData.isValid) {
596-
renderLottieRenderNode(node->mask(), maskBackingStorage, globalSize, 1.0, bezierPathsBoundingBoxContext);
596+
renderLottieRenderNode(node->mask(), maskBackingStorage, globalSize, currentTransform, 1.0, bezierPathsBoundingBoxContext);
597597
}
598598

599599
maskContext = maskBackingStorage;
@@ -606,14 +606,14 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
606606
currentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y)));
607607

608608
currentContext->saveState();
609-
currentContext->concatenate(node->renderData.globalTransform);
609+
currentContext->concatenate(currentTransform);
610610
} else {
611611
currentContext = parentContext;
612612
}
613613

614-
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(node->renderData.layer.position().x, node->renderData.layer.position().y)));
615-
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-node->renderData.layer.bounds().x, -node->renderData.layer.bounds().y)));
616-
parentContext->concatenate(node->renderData.layer.transform());
614+
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(node->position().x, node->position().y)));
615+
parentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-node->bounds().x, -node->bounds().y)));
616+
parentContext->concatenate(node->transform());
617617

618618
float renderAlpha = 1.0;
619619
if (tempContext) {
@@ -623,17 +623,17 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
623623
}
624624

625625
if (node->_contentItem) {
626-
drawLottieContentItem(currentContext, node->_contentItem, renderAlpha, globalSize, bezierPathsBoundingBoxContext);
626+
drawLottieContentItem(currentContext, node->_contentItem, renderAlpha, globalSize, currentTransform, bezierPathsBoundingBoxContext);
627627
}
628628

629629
if (node->renderData.isInvertedMatte) {
630-
currentContext->fill(lottie::CGRect(node->renderData.layer.bounds().x, node->renderData.layer.bounds().y, node->renderData.layer.bounds().width, node->renderData.layer.bounds().height), lottie::Color(0.0, 0.0, 0.0, 1.0));
630+
currentContext->fill(lottie::CGRect(node->bounds().x, node->bounds().y, node->bounds().width, node->bounds().height), lottie::Color(0.0, 0.0, 0.0, 1.0));
631631
currentContext->setBlendMode(lottieRendering::BlendMode::DestinationOut);
632632
}
633633

634634
for (const auto &subnode : node->subnodes()) {
635635
if (subnode->renderData.isValid) {
636-
renderLottieRenderNode(subnode, currentContext, globalSize, renderAlpha, bezierPathsBoundingBoxContext);
636+
renderLottieRenderNode(subnode, currentContext, globalSize, currentTransform, renderAlpha, bezierPathsBoundingBoxContext);
637637
}
638638
}
639639

@@ -645,7 +645,7 @@ static void renderLottieRenderNode(std::shared_ptr<lottie::RenderTreeNode> node,
645645
tempContext->draw(maskContext, lottie::CGRect(globalRect->x, globalRect->y, globalRect->width, globalRect->height));
646646
}
647647

648-
parentContext->concatenate(node->renderData.globalTransform.inverted());
648+
parentContext->concatenate(currentTransform.inverted());
649649
parentContext->setAlpha(layerAlpha);
650650
parentContext->draw(tempContext, globalRect.value());
651651
}
@@ -689,15 +689,17 @@ - (UIImage * _Nullable)renderForSize:(CGSize)size useReferenceRendering:(bool)us
689689
return nil;
690690
}
691691

692-
processRenderTree(renderNode, lottie::Vector2D((int)size.width, (int)size.height), lottie::CATransform3D::identity().scaled(lottie::Vector2D(size.width / (float)animation.size.width, size.height / (float)animation.size.height)), false, *_bezierPathsBoundingBoxContext.get());
692+
lottie::CATransform3D rootTransform = lottie::CATransform3D::identity().scaled(lottie::Vector2D(size.width / (float)animation.size.width, size.height / (float)animation.size.height));
693+
694+
processRenderTree(renderNode, lottie::Vector2D((int)size.width, (int)size.height), rootTransform, false, *_bezierPathsBoundingBoxContext.get());
693695

694696
if (useReferenceRendering) {
695697
auto context = std::make_shared<lottieRendering::CanvasImpl>((int)size.width, (int)size.height);
696698

697699
CGPoint scale = CGPointMake(size.width / (CGFloat)animation.size.width, size.height / (CGFloat)animation.size.height);
698700
context->concatenate(lottie::CATransform3D::makeScale(scale.x, scale.y, 1.0));
699701

700-
renderLottieRenderNode(renderNode, context, lottie::Vector2D(context->width(), context->height()), 1.0, *_bezierPathsBoundingBoxContext.get());
702+
renderLottieRenderNode(renderNode, context, lottie::Vector2D(context->width(), context->height()), rootTransform, 1.0, *_bezierPathsBoundingBoxContext.get());
701703

702704
auto image = context->makeImage();
703705

‎Tests/LottieMetalTest/Sources/ViewController.swift‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ private final class ReferenceCompareTest {
7878
}
7979

8080
var continueFromName: String?
81-
//continueFromName = "1471004892762996754.json"
81+
//continueFromName = "1137162165791228042.json"
8282

8383
let _ = await processAnimationFolderAsync(basePath: bundlePath, path: "", stopOnFailure: true, process: { path, name, alwaysDraw in
8484
if let continueFromNameValue = continueFromName {

0 commit comments

Comments
 (0)