From 814852d902f577f2739c2e00b8ddeba3ed9a52ef Mon Sep 17 00:00:00 2001 From: Isaac <> Date: Sun, 19 May 2024 02:04:45 +0400 Subject: [PATCH] Lottie --- .../SoftwareLottieRenderer/Sources/Canvas.h | 28 ++- .../Sources/CoreGraphicsCanvasImpl.h | 13 +- .../Sources/CoreGraphicsCanvasImpl.mm | 110 ++++++--- .../Sources/NullCanvasImpl.h | 47 ++++ .../Sources/NullCanvasImpl.mm | 81 +++++++ .../Sources/SoftwareLottieRenderer.mm | 223 ++++++++++-------- .../Sources/ThorVGCanvasImpl.h | 13 +- .../Sources/ThorVGCanvasImpl.mm | 46 ++-- .../Sources/ViewController.swift | 4 +- 9 files changed, 385 insertions(+), 180 deletions(-) create mode 100644 Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.h create mode 100644 Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.mm diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/Canvas.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/Canvas.h index 1aa1c930bb..9eb9bc90d6 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/Canvas.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/Canvas.h @@ -6,6 +6,7 @@ #include #include #include +#include namespace lottieRendering { @@ -41,6 +42,20 @@ enum class BlendMode { DestinationOut }; +enum class PathCommandType { + MoveTo, + LineTo, + CurveTo, + Close +}; + +typedef struct { + PathCommandType type; + CGPoint points[4]; +} PathCommand; + +typedef std::function)> CanvasPathEnumerator; + class Canvas { public: virtual ~Canvas() = default; @@ -53,13 +68,13 @@ public: virtual void saveState() = 0; virtual void restoreState() = 0; - virtual void fillPath(std::shared_ptr const &path, lottie::FillRule fillRule, lottie::Color const &color) = 0; - virtual void linearGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) = 0; - virtual void radialGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) = 0; + virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) = 0; + virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) = 0; + virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) = 0; - virtual void strokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) = 0; - virtual void linearGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) = 0; - virtual void radialGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) = 0; + virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) = 0; + virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) = 0; + virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) = 0; virtual void fill(lottie::CGRect const &rect, lottie::Color const &fillColor) = 0; virtual void setBlendMode(BlendMode blendMode) = 0; @@ -67,7 +82,6 @@ public: virtual void setAlpha(float alpha) = 0; virtual void concatenate(lottie::CATransform3D const &transform) = 0; - virtual lottie::CATransform3D currentTransform() = 0; virtual void draw(std::shared_ptr const &other, lottie::CGRect const &rect) = 0; }; diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h index de7c1f39dd..3a4176ba0d 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h @@ -29,19 +29,18 @@ public: virtual void saveState() override; virtual void restoreState() override; - virtual void fillPath(std::shared_ptr const &path, lottie::FillRule fillRule, lottie::Color const &color) override; - virtual void linearGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; - virtual void radialGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; + virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) override; + virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; + virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; - virtual void strokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) override; - virtual void linearGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; - virtual void radialGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; + virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) override; + virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; + virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; virtual void fill(lottie::CGRect const &rect, lottie::Color const &fillColor) override; virtual void setBlendMode(BlendMode blendMode) override; virtual void setAlpha(float alpha) override; virtual void concatenate(lottie::CATransform3D const &transform) override; - virtual lottie::CATransform3D currentTransform() override; virtual std::shared_ptr makeImage() const; virtual void draw(std::shared_ptr const &other, lottie::CGRect const &rect) override; diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm index db48fd2f4b..d9fd69f65c 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm @@ -11,6 +11,52 @@ int alignUp(int size, int align) { return (size + alignmentMask) & ~alignmentMask; } +bool addEnumeratedPath(CGContextRef context, CanvasPathEnumerator const &enumeratePath) { + bool isEmpty = true; + + enumeratePath([&](PathCommand const &command) { + switch (command.type) { + case PathCommandType::MoveTo: { + if (isEmpty) { + isEmpty = false; + CGContextBeginPath(context); + } + CGContextMoveToPoint(context, command.points[0].x, command.points[0].y); + break; + } + case PathCommandType::LineTo: { + if (isEmpty) { + isEmpty = false; + CGContextBeginPath(context); + } + CGContextAddLineToPoint(context, command.points[0].x, command.points[0].y); + break; + } + case PathCommandType::CurveTo: { + if (isEmpty) { + isEmpty = false; + CGContextBeginPath(context); + } + CGContextAddCurveToPoint(context, command.points[0].x, command.points[0].y, command.points[1].x, command.points[1].y, command.points[2].x, command.points[2].y); + break; + } + case PathCommandType::Close: { + if (isEmpty) { + isEmpty = false; + CGContextBeginPath(context); + } + CGContextClosePath(context); + break; + } + default: { + break; + } + } + }); + + return !isEmpty; +} + } ImageImpl::ImageImpl(::CGImageRef image) { @@ -87,11 +133,10 @@ void CanvasImpl::restoreState() { CGContextRestoreGState(_context); } -void CanvasImpl::fillPath(std::shared_ptr const &path, lottie::FillRule fillRule, lottie::Color const &color) { - CGContextBeginPath(_context); - lottie::CGPathCocoaImpl::withNativePath(path, [context = _context](CGPathRef nativePath) { - CGContextAddPath(context, nativePath); - }); +void CanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) { + if (!addEnumeratedPath(_context, enumeratePath)) { + return; + } CGFloat components[4] = { color.r, color.g, color.b, color.a }; CGColorRef nativeColor = CGColorCreate(CGBitmapContextGetColorSpace(_topContext), components); @@ -110,12 +155,13 @@ void CanvasImpl::fillPath(std::shared_ptr const &path, lottie::F } } -void CanvasImpl::linearGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { +void CanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { CGContextSaveGState(_context); - CGContextBeginPath(_context); - lottie::CGPathCocoaImpl::withNativePath(path, [context = _context](CGPathRef nativePath) { - CGContextAddPath(context, nativePath); - }); + + if (!addEnumeratedPath(_context, enumeratePath)) { + CGContextRestoreGState(_context); + return; + } switch (fillRule) { case lottie::FillRule::EvenOdd: { @@ -155,12 +201,13 @@ void CanvasImpl::linearGradientFillPath(std::shared_ptr const &p CGContextRestoreGState(_context); } -void CanvasImpl::radialGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { +void CanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { CGContextSaveGState(_context); - CGContextBeginPath(_context); - lottie::CGPathCocoaImpl::withNativePath(path, [context = _context](CGPathRef nativePath) { - CGContextAddPath(context, nativePath); - }); + + if (!addEnumeratedPath(_context, enumeratePath)) { + CGContextRestoreGState(_context); + return; + } switch (fillRule) { case lottie::FillRule::EvenOdd: { @@ -200,11 +247,10 @@ void CanvasImpl::radialGradientFillPath(std::shared_ptr const &p CGContextRestoreGState(_context); } -void CanvasImpl::strokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) { - CGContextBeginPath(_context); - lottie::CGPathCocoaImpl::withNativePath(path, [context = _context](CGPathRef nativePath) { - CGContextAddPath(context, nativePath); - }); +void CanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) { + if (!addEnumeratedPath(_context, enumeratePath)) { + return; + } CGFloat components[4] = { color.r, color.g, color.b, color.a }; CGColorRef nativeColor = CGColorCreate(CGBitmapContextGetColorSpace(_topContext), components); @@ -261,12 +307,12 @@ void CanvasImpl::strokePath(std::shared_ptr const &path, float l CGContextStrokePath(_context); } -void CanvasImpl::linearGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { +void CanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { CGContextSaveGState(_context); - CGContextBeginPath(_context); - lottie::CGPathCocoaImpl::withNativePath(path, [context = _context](CGPathRef nativePath) { - CGContextAddPath(context, nativePath); - }); + if (!addEnumeratedPath(_context, enumeratePath)) { + CGContextRestoreGState(_context); + return; + } CGContextSetLineWidth(_context, lineWidth); @@ -346,12 +392,12 @@ void CanvasImpl::linearGradientStrokePath(std::shared_ptr const CGContextRestoreGState(_context); } -void CanvasImpl::radialGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { +void CanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { CGContextSaveGState(_context); - CGContextBeginPath(_context); - lottie::CGPathCocoaImpl::withNativePath(path, [context = _context](CGPathRef nativePath) { - CGContextAddPath(context, nativePath); - }); + if (!addEnumeratedPath(_context, enumeratePath)) { + CGContextRestoreGState(_context); + return; + } CGContextSetLineWidth(_context, lineWidth); @@ -467,10 +513,6 @@ void CanvasImpl::concatenate(lottie::CATransform3D const &transform) { CGContextConcatCTM(_context, CATransform3DGetAffineTransform(nativeTransform(transform))); } -lottie::CATransform3D CanvasImpl::currentTransform() { - return lottie::fromNativeTransform(CATransform3DMakeAffineTransform(CGContextGetCTM(_context))); -} - std::shared_ptr CanvasImpl::makeImage() const { ::CGImageRef nativeImage = CGBitmapContextCreateImage(_context); if (nativeImage) { diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.h new file mode 100644 index 0000000000..92e930e316 --- /dev/null +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.h @@ -0,0 +1,47 @@ +#ifndef NullCanvasImpl_h +#define NullCanvasImpl_h + +#include "Canvas.h" + +namespace lottieRendering { + +class NullCanvasImpl: public Canvas { +public: + NullCanvasImpl(int width, int height); + virtual ~NullCanvasImpl(); + + virtual int width() const override; + virtual int height() const override; + + virtual std::shared_ptr makeLayer(int width, int height) override; + + virtual void saveState() override; + virtual void restoreState() override; + + virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) override; + virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottieRendering::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; + virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottieRendering::Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; + virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) override; + virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; + virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; + virtual void fill(lottie::CGRect const &rect, lottie::Color const &fillColor) override; + + virtual void setBlendMode(BlendMode blendMode) override; + + virtual void setAlpha(float alpha) override; + + virtual void concatenate(lottie::CATransform3D const &transform) override; + + virtual void draw(std::shared_ptr const &other, lottie::CGRect const &rect) override; + + void flush(); + +private: + float _width = 0.0f; + float _height = 0.0f; + lottie::CATransform3D _transform; +}; + +} + +#endif diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.mm new file mode 100644 index 0000000000..29d14e03ed --- /dev/null +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.mm @@ -0,0 +1,81 @@ +#include "NullCanvasImpl.h" + +namespace lottieRendering { + +namespace { + +void addEnumeratedPath(CanvasPathEnumerator const &enumeratePath) { + enumeratePath([&](PathCommand const &command) { + }); +} + +} + +NullCanvasImpl::NullCanvasImpl(int width, int height) : +_width(width), _height(height), _transform(lottie::CATransform3D::identity()) { +} + +NullCanvasImpl::~NullCanvasImpl() { +} + +int NullCanvasImpl::width() const { + return _width; +} + +int NullCanvasImpl::height() const { + return _height; +} + +std::shared_ptr NullCanvasImpl::makeLayer(int width, int height) { + return std::make_shared(width, height); +} + +void NullCanvasImpl::saveState() { +} + +void NullCanvasImpl::restoreState() { +} + +void NullCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) { + addEnumeratedPath(enumeratePath); +} + +void NullCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { + addEnumeratedPath(enumeratePath); +} + +void NullCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { + addEnumeratedPath(enumeratePath); +} + +void NullCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) { + addEnumeratedPath(enumeratePath); +} + +void NullCanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { + addEnumeratedPath(enumeratePath); +} + +void NullCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { + addEnumeratedPath(enumeratePath); +} + +void NullCanvasImpl::fill(lottie::CGRect const &rect, lottie::Color const &fillColor) { +} + +void NullCanvasImpl::setBlendMode(BlendMode blendMode) { +} + +void NullCanvasImpl::setAlpha(float alpha) { +} + +void NullCanvasImpl::concatenate(lottie::CATransform3D const &transform) { +} + +void NullCanvasImpl::draw(std::shared_ptr const &other, lottie::CGRect const &rect) { +} + +void NullCanvasImpl::flush() { +} + +} diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm index 39433d22d5..aa4005b252 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm @@ -3,6 +3,7 @@ #import "Canvas.h" #import "CoreGraphicsCanvasImpl.h" #import "ThorVGCanvasImpl.h" +#import "NullCanvasImpl.h" #include @@ -10,6 +11,8 @@ namespace { static constexpr float minVisibleAlpha = 0.5f / 255.0f; +static constexpr float minGlobalRectCalculationSize = 200.0f; + struct TransformedPath { lottie::BezierPath path; lottie::CATransform3D transform; @@ -53,9 +56,7 @@ static lottie::CGRect collectPathBoundingBoxes(std::shared_ptr collectPaths(std::shared_ptr item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform) { - std::vector mappedPaths; - +static void enumeratePaths(std::shared_ptr item, size_t subItemLimit, lottie::CATransform3D const &parentTransform, bool skipApplyTransform, std::function const &onPath) { //TODO:remove skipApplyTransform lottie::CATransform3D effectiveTransform = parentTransform; if (!skipApplyTransform && item->isGroup) { @@ -65,21 +66,14 @@ static std::vector collectPaths(std::shared_ptrsubItems.size(), subItemLimit); if (item->path) { - mappedPaths.emplace_back(item->path->path, effectiveTransform); + onPath(item->path->path, effectiveTransform); } - assert(!item->trimParams); 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); - } + enumeratePaths(subItem, INT32_MAX, effectiveTransform, false, onPath); } - - return mappedPaths; } } @@ -187,7 +181,7 @@ static std::optional getRenderNodeGlobalRect(std::shared_ptr parentContext, std::shared_ptr item, float parentAlpha, lottie::Vector2D const &globalSize, lottie::CATransform3D const &parentTransform, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { +static void drawLottieContentItem(std::shared_ptr const &parentContext, std::shared_ptr item, float parentAlpha, lottie::Vector2D const &globalSize, lottie::CATransform3D const &parentTransform, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { auto currentTransform = parentTransform; lottie::CATransform3D localTransform = item->transform; currentTransform = localTransform * currentTransform; @@ -201,7 +195,7 @@ static void drawLottieContentItem(std::shared_ptr paren parentContext->saveState(); - std::shared_ptr currentContext; + std::shared_ptr const *currentContext; std::shared_ptr tempContext; bool needsTempContext = false; @@ -209,7 +203,11 @@ static void drawLottieContentItem(std::shared_ptr paren std::optional globalRect; if (needsTempContext) { - globalRect = lottie::getRenderContentItemGlobalRect(item, globalSize, parentTransform, bezierPathsBoundingBoxContext); + if (globalSize.x <= minGlobalRectCalculationSize && globalSize.y <= minGlobalRectCalculationSize) { + globalRect = lottie::CGRect(0.0, 0.0, globalSize.x, globalSize.y); + } else { + globalRect = lottie::getRenderContentItemGlobalRect(item, globalSize, parentTransform, bezierPathsBoundingBoxContext); + } if (!globalRect || globalRect->width <= 0.0f || globalRect->height <= 0.0f) { parentContext->restoreState(); return; @@ -218,13 +216,13 @@ static void drawLottieContentItem(std::shared_ptr paren auto tempContextValue = parentContext->makeLayer((int)(globalRect->width), (int)(globalRect->height)); tempContext = tempContextValue; - currentContext = tempContextValue; - currentContext->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y))); + currentContext = &tempContext; + (*currentContext)->concatenate(lottie::CATransform3D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y))); - currentContext->saveState(); - currentContext->concatenate(currentTransform); + (*currentContext)->saveState(); + (*currentContext)->concatenate(currentTransform); } else { - currentContext = parentContext; + currentContext = &parentContext; } parentContext->concatenate(item->transform); @@ -237,75 +235,105 @@ static void drawLottieContentItem(std::shared_ptr paren } for (const auto &shading : item->shadings) { - std::vector itemPaths; + lottieRendering::CanvasPathEnumerator iteratePaths; 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; - } - - std::shared_ptr 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 : itemPaths) { - std::optional 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); + auto itemPaths = shading->explicitPath.value(); + iteratePaths = [itemPaths = itemPaths](std::function iterate) -> void { + lottieRendering::PathCommand pathCommand; + for (const auto &path : itemPaths) { + std::optional previousElement; + for (const auto &element : path.elements()) { + if (previousElement.has_value()) { + if (previousElement->vertex.outTangentRelative().isZero() && element.vertex.inTangentRelative().isZero()) { + pathCommand.type = lottieRendering::PathCommandType::LineTo; + pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + iterate(pathCommand); + } else { + pathCommand.type = lottieRendering::PathCommandType::CurveTo; + pathCommand.points[2] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + pathCommand.points[1] = CGPointMake(element.vertex.inTangent.x, element.vertex.inTangent.y); + pathCommand.points[0] = CGPointMake(previousElement->vertex.outTangent.x, previousElement->vertex.outTangent.y); + iterate(pathCommand); + } + } else { + pathCommand.type = lottieRendering::PathCommandType::MoveTo; + pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + iterate(pathCommand); + } + previousElement = element; + } + if (path.closed().value_or(true)) { + pathCommand.type = lottieRendering::PathCommandType::Close; + iterate(pathCommand); } - } 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); - } + }; + } else { + iteratePaths = [&](std::function iterate) { + enumeratePaths(item, shading->subItemLimit, lottie::CATransform3D::identity(), true, [&](lottie::BezierPath const &sourcePath, lottie::CATransform3D const &transform) { + auto path = sourcePath.copyUsingTransform(transform); + + lottieRendering::PathCommand pathCommand; + std::optional previousElement; + for (const auto &element : path.elements()) { + if (previousElement.has_value()) { + if (previousElement->vertex.outTangentRelative().isZero() && element.vertex.inTangentRelative().isZero()) { + pathCommand.type = lottieRendering::PathCommandType::LineTo; + pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + iterate(pathCommand); + } else { + pathCommand.type = lottieRendering::PathCommandType::CurveTo; + pathCommand.points[2] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + pathCommand.points[1] = CGPointMake(element.vertex.inTangent.x, element.vertex.inTangent.y); + pathCommand.points[0] = CGPointMake(previousElement->vertex.outTangent.x, previousElement->vertex.outTangent.y); + iterate(pathCommand); + } + } else { + pathCommand.type = lottieRendering::PathCommandType::MoveTo; + pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + iterate(pathCommand); + } + previousElement = element; + } + if (path.closed().value_or(true)) { + pathCommand.type = lottieRendering::PathCommandType::Close; + iterate(pathCommand); + } + }); + }; } + /*auto iteratePaths = [&](std::function iterate) -> void { + lottieRendering::PathCommand pathCommand; + for (const auto &path : itemPaths) { + std::optional previousElement; + for (const auto &element : path.elements()) { + if (previousElement.has_value()) { + if (previousElement->vertex.outTangentRelative().isZero() && element.vertex.inTangentRelative().isZero()) { + pathCommand.type = lottieRendering::PathCommandType::LineTo; + pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + iterate(pathCommand); + } else { + pathCommand.type = lottieRendering::PathCommandType::CurveTo; + pathCommand.points[2] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + pathCommand.points[1] = CGPointMake(element.vertex.inTangent.x, element.vertex.inTangent.y); + pathCommand.points[0] = CGPointMake(previousElement->vertex.outTangent.x, previousElement->vertex.outTangent.y); + iterate(pathCommand); + } + } else { + pathCommand.type = lottieRendering::PathCommandType::MoveTo; + pathCommand.points[0] = CGPointMake(element.vertex.point.x, element.vertex.point.y); + iterate(pathCommand); + } + previousElement = element; + } + if (path.closed().value_or(true)) { + pathCommand.type = lottieRendering::PathCommandType::Close; + iterate(pathCommand); + } + } + };*/ + if (shading->stroke) { if (shading->stroke->shading->type() == lottie::RenderTreeNodeContentItem::ShadingType::Solid) { lottie::RenderTreeNodeContentItem::SolidShading *solidShading = (lottie::RenderTreeNodeContentItem::SolidShading *)shading->stroke->shading.get(); @@ -354,7 +382,7 @@ static void drawLottieContentItem(std::shared_ptr paren dashPattern = shading->stroke->dashPattern; } - currentContext->strokePath(path, shading->stroke->lineWidth, lineJoin, lineCap, shading->stroke->dashPhase, dashPattern, lottie::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity * renderAlpha)); + (*currentContext)->strokePath(iteratePaths, shading->stroke->lineWidth, lineJoin, lineCap, shading->stroke->dashPhase, dashPattern, lottie::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 } @@ -378,7 +406,7 @@ static void drawLottieContentItem(std::shared_ptr paren 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) { - currentContext->fillPath(path, rule, lottie::Color(solidShading->color.r, solidShading->color.g, solidShading->color.b, solidShading->color.a * solidShading->opacity * renderAlpha)); + (*currentContext)->fillPath(iteratePaths, rule, lottie::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(); @@ -397,11 +425,11 @@ static void drawLottieContentItem(std::shared_ptr paren switch (gradientShading->gradientType) { case lottie::GradientType::Linear: { - currentContext->linearGradientFillPath(path, rule, gradient, start, end); + (*currentContext)->linearGradientFillPath(iteratePaths, rule, gradient, start, end); break; } case lottie::GradientType::Radial: { - currentContext->radialGradientFillPath(path, rule, gradient, start, 0.0, start, start.distanceTo(end)); + (*currentContext)->radialGradientFillPath(iteratePaths, rule, gradient, start, 0.0, start, start.distanceTo(end)); break; } default: { @@ -415,7 +443,7 @@ static void drawLottieContentItem(std::shared_ptr paren for (auto it = item->subItems.rbegin(); it != item->subItems.rend(); it++) { const auto &subItem = *it; - drawLottieContentItem(currentContext, subItem, renderAlpha, globalSize, currentTransform, bezierPathsBoundingBoxContext); + drawLottieContentItem(*currentContext, subItem, renderAlpha, globalSize, currentTransform, bezierPathsBoundingBoxContext); } if (tempContext) { @@ -430,7 +458,7 @@ static void drawLottieContentItem(std::shared_ptr paren parentContext->restoreState(); } -static void renderLottieRenderNode(std::shared_ptr node, std::shared_ptr parentContext, lottie::Vector2D const &globalSize, lottie::CATransform3D const &parentTransform, float parentAlpha, bool isInvertedMatte, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { +static void renderLottieRenderNode(std::shared_ptr node, std::shared_ptr const &parentContext, lottie::Vector2D const &globalSize, lottie::CATransform3D const &parentTransform, float parentAlpha, bool isInvertedMatte, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { float normalizedOpacity = node->alpha(); float layerAlpha = ((float)normalizedOpacity) * parentAlpha; @@ -470,7 +498,11 @@ static void renderLottieRenderNode(std::shared_ptr node, std::optional globalRect; if (needsTempContext) { - globalRect = lottie::getRenderNodeGlobalRect(node, globalSize, parentTransform, false, bezierPathsBoundingBoxContext); + if (globalSize.x <= minGlobalRectCalculationSize && globalSize.y <= minGlobalRectCalculationSize) { + globalRect = lottie::CGRect(0.0, 0.0, globalSize.x, globalSize.y); + } else { + globalRect = lottie::getRenderNodeGlobalRect(node, globalSize, parentTransform, false, bezierPathsBoundingBoxContext); + } if (!globalRect || globalRect->width <= 0.0f || globalRect->height <= 0.0f) { parentContext->restoreState(); return; @@ -578,10 +610,6 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) { lottie::CATransform3D rootTransform = lottie::CATransform3D::identity().scaled(lottie::Vector2D(size.width / (float)animation.size.width, size.height / (float)animation.size.height)); - if (!useReferenceRendering) { - return nil; - } - if (useReferenceRendering) { auto context = std::make_shared((int)size.width, (int)size.height); @@ -594,12 +622,13 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) { return [[UIImage alloc] initWithCGImage:std::static_pointer_cast(image)->nativeImage()]; } else { - /*auto context = std::make_shared((int)size.width, (int)size.height); + //auto context = std::make_shared((int)size.width, (int)size.height); + auto context = std::make_shared((int)size.width, (int)size.height); CGPoint scale = CGPointMake(size.width / (CGFloat)animation.size.width, size.height / (CGFloat)animation.size.height); context->concatenate(lottie::CATransform3D::makeScale(scale.x, scale.y, 1.0)); - renderLottieRenderNode(renderNode, context, lottie::Vector2D(context->width(), context->height()), 1.0);*/ + renderLottieRenderNode(renderNode, context, lottie::Vector2D(context->width(), context->height()), rootTransform, 1.0, false, *_bezierPathsBoundingBoxContext.get()); return nil; } diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h index 39126f6036..2e822f7ffc 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h @@ -20,12 +20,12 @@ public: virtual void saveState() override; virtual void restoreState() override; - virtual void fillPath(std::shared_ptr const &path, lottie::FillRule fillRule, lottie::Color const &color) override; - virtual void linearGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, lottieRendering::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; - virtual void radialGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, lottieRendering::Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; - virtual void strokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) override; - virtual void linearGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; - virtual void radialGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; + virtual void fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) override; + virtual void linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottieRendering::Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; + virtual void radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottieRendering::Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; + virtual void strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) override; + virtual void linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) override; + virtual void radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) override; virtual void fill(lottie::CGRect const &rect, lottie::Color const &fillColor) override; virtual void setBlendMode(BlendMode blendMode) override; @@ -33,7 +33,6 @@ public: virtual void setAlpha(float alpha) override; virtual void concatenate(lottie::CATransform3D const &transform) override; - virtual lottie::CATransform3D currentTransform() override; virtual void draw(std::shared_ptr const &other, lottie::CGRect const &rect) override; diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.mm index a6561c587a..4573881392 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.mm @@ -4,22 +4,22 @@ namespace lottieRendering { namespace { -void tvgPath(std::shared_ptr const &path, tvg::Shape *shape) { - path->enumerate([shape](lottie::CGPathItem const &item) { - switch (item.type) { - case lottie::CGPathItem::Type::MoveTo: { - shape->moveTo(item.points[0].x, item.points[0].y); +void tvgPath(CanvasPathEnumerator const &enumeratePath, tvg::Shape *shape) { + enumeratePath([&](PathCommand const &command) { + switch (command.type) { + case PathCommandType::MoveTo: { + shape->moveTo(command.points[0].x, command.points[0].y); break; } - case lottie::CGPathItem::Type::LineTo: { - shape->lineTo(item.points[0].x, item.points[0].y); + case PathCommandType::LineTo: { + shape->lineTo(command.points[0].x, command.points[0].y); break; } - case lottie::CGPathItem::Type::CurveTo: { - shape->cubicTo(item.points[0].x, item.points[0].y, item.points[1].x, item.points[1].y, item.points[2].x, item.points[2].y); + case PathCommandType::CurveTo: { + shape->cubicTo(command.points[0].x, command.points[0].y, command.points[1].x, command.points[1].y, command.points[2].x, command.points[2].y); break; } - case lottie::CGPathItem::Type::Close: { + case PathCommandType::Close: { shape->close(); break; } @@ -89,9 +89,9 @@ void ThorVGCanvasImpl::restoreState() { _stateStack.pop_back(); } -void ThorVGCanvasImpl::fillPath(std::shared_ptr const &path, lottie::FillRule fillRule, lottie::Color const &color) { +void ThorVGCanvasImpl::fillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, lottie::Color const &color) { auto shape = tvg::Shape::gen(); - tvgPath(path, shape.get()); + tvgPath(enumeratePath, shape.get()); shape->transform(tvgTransform(_transform)); @@ -101,9 +101,9 @@ void ThorVGCanvasImpl::fillPath(std::shared_ptr const &path, lot _canvas->push(std::move(shape)); } -void ThorVGCanvasImpl::linearGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { +void ThorVGCanvasImpl::linearGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { auto shape = tvg::Shape::gen(); - tvgPath(path, shape.get()); + tvgPath(enumeratePath, shape.get()); shape->transform(tvgTransform(_transform)); @@ -129,9 +129,9 @@ void ThorVGCanvasImpl::linearGradientFillPath(std::shared_ptr co _canvas->push(std::move(shape)); } -void ThorVGCanvasImpl::radialGradientFillPath(std::shared_ptr const &path, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { +void ThorVGCanvasImpl::radialGradientFillPath(CanvasPathEnumerator const &enumeratePath, lottie::FillRule fillRule, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { auto shape = tvg::Shape::gen(); - tvgPath(path, shape.get()); + tvgPath(enumeratePath, shape.get()); shape->transform(tvgTransform(_transform)); @@ -157,9 +157,9 @@ void ThorVGCanvasImpl::radialGradientFillPath(std::shared_ptr co _canvas->push(std::move(shape)); } -void ThorVGCanvasImpl::strokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) { +void ThorVGCanvasImpl::strokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, lottie::Color const &color) { auto shape = tvg::Shape::gen(); - tvgPath(path, shape.get()); + tvgPath(enumeratePath, shape.get()); shape->transform(tvgTransform(_transform)); @@ -217,12 +217,10 @@ void ThorVGCanvasImpl::strokePath(std::shared_ptr const &path, f _canvas->push(std::move(shape)); } -void ThorVGCanvasImpl::linearGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { - assert(false); +void ThorVGCanvasImpl::linearGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &start, lottie::Vector2D const &end) { } -void ThorVGCanvasImpl::radialGradientStrokePath(std::shared_ptr const &path, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { - assert(false); +void ThorVGCanvasImpl::radialGradientStrokePath(CanvasPathEnumerator const &enumeratePath, float lineWidth, lottie::LineJoin lineJoin, lottie::LineCap lineCap, float dashPhase, std::vector const &dashPattern, Gradient const &gradient, lottie::Vector2D const &startCenter, float startRadius, lottie::Vector2D const &endCenter, float endRadius) { } void ThorVGCanvasImpl::fill(lottie::CGRect const &rect, lottie::Color const &fillColor) { @@ -271,10 +269,6 @@ void ThorVGCanvasImpl::concatenate(lottie::CATransform3D const &transform) { ));*/ } -lottie::CATransform3D ThorVGCanvasImpl::currentTransform() { - return _transform; -} - void ThorVGCanvasImpl::draw(std::shared_ptr const &other, lottie::CGRect const &rect) { /*ThorVGCanvasImpl *impl = (ThorVGCanvasImpl *)other.get(); auto image = impl->surface()->makeImageSnapshot(); diff --git a/Tests/LottieMetalTest/Sources/ViewController.swift b/Tests/LottieMetalTest/Sources/ViewController.swift index 47603b86ca..2efe5e5fbf 100644 --- a/Tests/LottieMetalTest/Sources/ViewController.swift +++ b/Tests/LottieMetalTest/Sources/ViewController.swift @@ -78,7 +78,7 @@ private final class ReferenceCompareTest { } var continueFromName: String? - //continueFromName = "4986037051573928320.json" + //continueFromName = "35707580709863498.json" let _ = await processAnimationFolderAsync(basePath: bundlePath, path: "", stopOnFailure: true, process: { path, name, alwaysDraw in if let continueFromNameValue = continueFromName { @@ -119,7 +119,7 @@ public final class ViewController: UIViewController { self.view.layer.addSublayer(MetalEngine.shared.rootLayer) - if "".isEmpty { + if !"".isEmpty { if #available(iOS 13.0, *) { self.test = ReferenceCompareTest(view: self.view) }