diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/Canvas.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/Canvas.h index 25fbffc6da..32a02bfc8a 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/Canvas.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/Canvas.h @@ -81,7 +81,7 @@ public: virtual void setAlpha(float alpha) = 0; - virtual void concatenate(lottie::Transform3D const &transform) = 0; + virtual void concatenate(lottie::Transform2D const &transform) = 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 b7139a8e8f..db8064458a 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.h @@ -40,7 +40,7 @@ public: 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::Transform3D const &transform) override; + virtual void concatenate(lottie::Transform2D const &transform) 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 ef9089971f..38f95beb72 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/CoreGraphicsCanvasImpl.mm @@ -509,7 +509,7 @@ void CanvasImpl::setAlpha(float alpha) { CGContextSetAlpha(_context, alpha); } -void CanvasImpl::concatenate(lottie::Transform3D const &transform) { +void CanvasImpl::concatenate(lottie::Transform2D const &transform) { CGContextConcatCTM(_context, CATransform3DGetAffineTransform(nativeTransform(transform))); } diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.h index faba71da5a..56918703ae 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.h @@ -30,7 +30,7 @@ public: virtual void setAlpha(float alpha) override; - virtual void concatenate(lottie::Transform3D const &transform) override; + virtual void concatenate(lottie::Transform2D const &transform) override; virtual void draw(std::shared_ptr const &other, lottie::CGRect const &rect) override; @@ -39,7 +39,7 @@ public: private: float _width = 0.0f; float _height = 0.0f; - lottie::Transform3D _transform; + lottie::Transform2D _transform; }; } diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.mm index 1b2cb78bfd..6030201180 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/NullCanvasImpl.mm @@ -12,7 +12,7 @@ void addEnumeratedPath(CanvasPathEnumerator const &enumeratePath) { } NullCanvasImpl::NullCanvasImpl(int width, int height) : -_width(width), _height(height), _transform(lottie::Transform3D::identity()) { +_width(width), _height(height), _transform(lottie::Transform2D::identity()) { } NullCanvasImpl::~NullCanvasImpl() { @@ -69,7 +69,7 @@ void NullCanvasImpl::setBlendMode(BlendMode blendMode) { void NullCanvasImpl::setAlpha(float alpha) { } -void NullCanvasImpl::concatenate(lottie::Transform3D const &transform) { +void NullCanvasImpl::concatenate(lottie::Transform2D const &transform) { } void NullCanvasImpl::draw(std::shared_ptr const &other, lottie::CGRect const &rect) { diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm index 25fbb49c66..d53b21787b 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/SoftwareLottieRenderer.mm @@ -15,17 +15,17 @@ static constexpr float minGlobalRectCalculationSize = 200.0f; struct TransformedPath { lottie::BezierPath path; - lottie::Transform3D transform; + lottie::Transform2D transform; - TransformedPath(lottie::BezierPath const &path_, lottie::Transform3D const &transform_) : + TransformedPath(lottie::BezierPath const &path_, lottie::Transform2D const &transform_) : path(path_), transform(transform_) { } }; -static lottie::CGRect collectPathBoundingBoxes(std::shared_ptr item, size_t subItemLimit, lottie::Transform3D const &parentTransform, bool skipApplyTransform, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { +static lottie::CGRect collectPathBoundingBoxes(std::shared_ptr item, size_t subItemLimit, lottie::Transform2D const &parentTransform, bool skipApplyTransform, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { //TODO:remove skipApplyTransform - lottie::Transform3D effectiveTransform = parentTransform; + lottie::Transform2D effectiveTransform = parentTransform; if (!skipApplyTransform && item->isGroup) { effectiveTransform = item->transform * effectiveTransform; } @@ -56,9 +56,9 @@ static lottie::CGRect collectPathBoundingBoxes(std::shared_ptr item, size_t subItemLimit, lottie::Transform3D const &parentTransform, bool skipApplyTransform, std::function const &onPath) { +static void enumeratePaths(std::shared_ptr item, size_t subItemLimit, lottie::Transform2D const &parentTransform, bool skipApplyTransform, std::function const &onPath) { //TODO:remove skipApplyTransform - lottie::Transform3D effectiveTransform = parentTransform; + lottie::Transform2D effectiveTransform = parentTransform; if (!skipApplyTransform && item->isGroup) { effectiveTransform = item->transform * effectiveTransform; } @@ -80,14 +80,14 @@ static void enumeratePaths(std::shared_ptr it namespace lottie { -static std::optional getRenderContentItemGlobalRect(std::shared_ptr const &contentItem, lottie::Vector2D const &globalSize, lottie::Transform3D const &parentTransform, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { +static std::optional getRenderContentItemGlobalRect(std::shared_ptr const &contentItem, lottie::Vector2D const &globalSize, lottie::Transform2D const &parentTransform, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { auto currentTransform = parentTransform; - Transform3D localTransform = contentItem->transform; + Transform2D localTransform = contentItem->transform; currentTransform = localTransform * currentTransform; std::optional globalRect; for (const auto &shadingVariant : contentItem->shadings) { - lottie::CGRect shapeBounds = collectPathBoundingBoxes(contentItem, shadingVariant->subItemLimit, lottie::Transform3D::identity(), true, bezierPathsBoundingBoxContext); + lottie::CGRect shapeBounds = collectPathBoundingBoxes(contentItem, shadingVariant->subItemLimit, lottie::Transform2D::identity(), true, bezierPathsBoundingBoxContext); if (shadingVariant->stroke) { shapeBounds = shapeBounds.insetBy(-shadingVariant->stroke->lineWidth / 2.0, -shadingVariant->stroke->lineWidth / 2.0); @@ -128,13 +128,13 @@ static std::optional getRenderContentItemGlobalRect(std::shared_ptr getRenderNodeGlobalRect(std::shared_ptr const &node, lottie::Vector2D const &globalSize, lottie::Transform3D const &parentTransform, bool isInvertedMatte, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { +static std::optional getRenderNodeGlobalRect(std::shared_ptr const &node, lottie::Vector2D const &globalSize, lottie::Transform2D const &parentTransform, bool isInvertedMatte, BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { if (node->isHidden() || node->alpha() < minVisibleAlpha) { return std::nullopt; } auto currentTransform = parentTransform; - Transform3D localTransform = node->transform(); + Transform2D localTransform = node->transform(); currentTransform = localTransform * currentTransform; std::optional globalRect; @@ -179,9 +179,9 @@ static std::optional getRenderNodeGlobalRect(std::shared_ptr const &parentContext, std::shared_ptr item, float parentAlpha, lottie::Vector2D const &globalSize, lottie::Transform3D const &parentTransform, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { +static void drawLottieContentItem(std::shared_ptr const &parentContext, std::shared_ptr item, float parentAlpha, lottie::Vector2D const &globalSize, lottie::Transform2D const &parentTransform, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { auto currentTransform = parentTransform; - lottie::Transform3D localTransform = item->transform; + lottie::Transform2D localTransform = item->transform; currentTransform = localTransform * currentTransform; float normalizedOpacity = item->alpha; @@ -215,7 +215,7 @@ static void drawLottieContentItem(std::shared_ptr const tempContext = tempContextValue; currentContext = &tempContext; - (*currentContext)->concatenate(lottie::Transform3D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y))); + (*currentContext)->concatenate(lottie::Transform2D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y))); (*currentContext)->saveState(); (*currentContext)->concatenate(currentTransform); @@ -268,7 +268,7 @@ static void drawLottieContentItem(std::shared_ptr const }; } else { iteratePaths = [&](std::function iterate) { - enumeratePaths(item, shading->subItemLimit, lottie::Transform3D::identity(), true, [&](lottie::BezierPath const &sourcePath, lottie::Transform3D const &transform) { + enumeratePaths(item, shading->subItemLimit, lottie::Transform2D::identity(), true, [&](lottie::BezierPath const &sourcePath, lottie::Transform2D const &transform) { auto path = sourcePath.copyUsingTransform(transform); lottieRendering::PathCommand pathCommand; @@ -456,7 +456,7 @@ static void drawLottieContentItem(std::shared_ptr const parentContext->restoreState(); } -static void renderLottieRenderNode(std::shared_ptr node, std::shared_ptr const &parentContext, lottie::Vector2D const &globalSize, lottie::Transform3D 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::Transform2D const &parentTransform, float parentAlpha, bool isInvertedMatte, lottie::BezierPathsBoundingBoxContext &bezierPathsBoundingBoxContext) { float normalizedOpacity = node->alpha(); float layerAlpha = ((float)normalizedOpacity) * parentAlpha; @@ -465,7 +465,7 @@ static void renderLottieRenderNode(std::shared_ptr node, } auto currentTransform = parentTransform; - lottie::Transform3D localTransform = node->transform(); + lottie::Transform2D localTransform = node->transform(); currentTransform = localTransform * currentTransform; std::shared_ptr maskContext; @@ -507,7 +507,7 @@ static void renderLottieRenderNode(std::shared_ptr node, if ((node->mask() && !node->mask()->isHidden() && node->mask()->alpha() >= minVisibleAlpha) || masksToBounds) { auto maskBackingStorage = parentContext->makeLayer((int)(globalRect->width), (int)(globalRect->height)); - maskBackingStorage->concatenate(lottie::Transform3D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y))); + maskBackingStorage->concatenate(lottie::Transform2D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y))); maskBackingStorage->concatenate(currentTransform); if (masksToBounds) { @@ -524,7 +524,7 @@ static void renderLottieRenderNode(std::shared_ptr node, tempContext = tempContextValue; currentContext = tempContextValue; - currentContext->concatenate(lottie::Transform3D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y))); + currentContext->concatenate(lottie::Transform2D::identity().translated(lottie::Vector2D(-globalRect->x, -globalRect->y))); currentContext->saveState(); currentContext->concatenate(currentTransform); @@ -602,13 +602,13 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) { return nil; } - lottie::Transform3D rootTransform = lottie::Transform3D::identity().scaled(lottie::Vector2D(size.width / (float)animation.size.width, size.height / (float)animation.size.height)); + lottie::Transform2D rootTransform = lottie::Transform2D::identity().scaled(lottie::Vector2D(size.width / (float)animation.size.width, size.height / (float)animation.size.height)); if (useReferenceRendering) { 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::Transform3D::makeScale(scale.x, scale.y, 1.0)); + context->concatenate(lottie::Transform2D::makeScale(scale.x, scale.y)); renderLottieRenderNode(renderNode, context, lottie::Vector2D(context->width(), context->height()), rootTransform, 1.0, false, *_bezierPathsBoundingBoxContext.get()); @@ -620,7 +620,7 @@ CGRect getPathNativeBoundingBox(CGPathRef _Nonnull path) { 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::Transform3D::makeScale(scale.x, scale.y, 1.0)); + context->concatenate(lottie::Transform2D::makeScale(scale.x, scale.y)); renderLottieRenderNode(renderNode, context, lottie::Vector2D(context->width(), context->height()), rootTransform, 1.0, false, *_bezierPathsBoundingBoxContext.get()); diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h index b3550f2247..dbd676b5e9 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.h @@ -32,7 +32,7 @@ public: virtual void setAlpha(float alpha) override; - virtual void concatenate(lottie::Transform3D const &transform) override; + virtual void concatenate(lottie::Transform2D const &transform) override; virtual void draw(std::shared_ptr const &other, lottie::CGRect const &rect) override; @@ -52,8 +52,8 @@ private: std::unique_ptr _canvas; float _alpha = 1.0; - lottie::Transform3D _transform; - std::vector _stateStack; + lottie::Transform2D _transform; + std::vector _stateStack; int _bytesPerRow = 0; uint32_t *_backingData = nullptr; int _statsNumStrokes = 0; diff --git a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.mm b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.mm index bd8e3d9b6f..4be6064df2 100644 --- a/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.mm +++ b/Tests/LottieMetalTest/SoftwareLottieRenderer/Sources/ThorVGCanvasImpl.mm @@ -27,7 +27,7 @@ void tvgPath(CanvasPathEnumerator const &enumeratePath, tvg::Shape *shape) { }); } -tvg::Matrix tvgTransform(lottie::Transform3D const &transform) { +tvg::Matrix tvgTransform(lottie::Transform2D const &transform) { CGAffineTransform affineTransform = CATransform3DGetAffineTransform(lottie::nativeTransform(transform)); tvg::Matrix result; result.e11 = affineTransform.a; @@ -45,7 +45,7 @@ tvg::Matrix tvgTransform(lottie::Transform3D const &transform) { } ThorVGCanvasImpl::ThorVGCanvasImpl(int width, int height) : -_width(width), _height(height), _transform(lottie::Transform3D::identity()) { +_width(width), _height(height), _transform(lottie::Transform2D::identity()) { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ tvg::Initializer::init(0); @@ -259,7 +259,7 @@ void ThorVGCanvasImpl::setAlpha(float alpha) { _alpha = alpha; } -void ThorVGCanvasImpl::concatenate(lottie::Transform3D const &transform) { +void ThorVGCanvasImpl::concatenate(lottie::Transform2D const &transform) { _transform = transform * _transform; /*_canvas->concat(SkM44( transform.m11, transform.m21, transform.m31, transform.m41, diff --git a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/BezierPath.h b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/BezierPath.h index 2fd05533e4..b17f942761 100644 --- a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/BezierPath.h +++ b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/BezierPath.h @@ -122,7 +122,7 @@ public: std::optional const &closed() const; void setClosed(std::optional const &closed); std::shared_ptr cgPath() const; - BezierPath copyUsingTransform(Transform3D const &transform) const; + BezierPath copyUsingTransform(Transform2D const &transform) const; public: BezierPath(std::shared_ptr contents); diff --git a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CGPath.h b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CGPath.h index 4288688ab8..1ddeeb81ed 100644 --- a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CGPath.h +++ b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CGPath.h @@ -57,7 +57,7 @@ public: virtual bool empty() const = 0; - virtual std::shared_ptr copyUsingTransform(Transform3D const &transform) const = 0; + virtual std::shared_ptr copyUsingTransform(Transform2D const &transform) const = 0; virtual void addLineTo(Vector2D const &point) = 0; virtual void addCurveTo(Vector2D const &point, Vector2D const &control1, Vector2D const &control2) = 0; @@ -71,7 +71,7 @@ public: virtual bool isEqual(CGPath *other) const = 0; }; -Vector2D transformVector(Vector2D const &v, Transform3D const &m); +Vector2D transformVector(Vector2D const &v, Transform2D const &m); } diff --git a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CGPathCocoa.h b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CGPathCocoa.h index 5626825a62..af32f20bb5 100644 --- a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CGPathCocoa.h +++ b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CGPathCocoa.h @@ -22,7 +22,7 @@ public: virtual bool empty() const override; - virtual std::shared_ptr copyUsingTransform(Transform3D const &transform) const override; + virtual std::shared_ptr copyUsingTransform(Transform2D const &transform) const override; virtual void addLineTo(Vector2D const &point) override; virtual void addCurveTo(Vector2D const &point, Vector2D const &control1, Vector2D const &control2) override; diff --git a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CurveVertex.h b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CurveVertex.h index 4f5a8a28d5..90e3ccf305 100644 --- a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CurveVertex.h +++ b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/CurveVertex.h @@ -64,7 +64,7 @@ public: return CurveVertex(point + translation, inTangent + translation, outTangent + translation, false); } - CurveVertex transformed(Transform3D const &transform) const { + CurveVertex transformed(Transform2D const &transform) const { return CurveVertex(transformVector(point, transform), transformVector(inTangent, transform), transformVector(outTangent, transform), false); } diff --git a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/RenderTreeNode.h b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/RenderTreeNode.h index 9d08581009..09616bdf0a 100644 --- a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/RenderTreeNode.h +++ b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/RenderTreeNode.h @@ -364,7 +364,7 @@ public: public: bool isGroup = false; - Transform3D transform = Transform3D::identity(); + Transform2D transform = Transform2D::identity(); float alpha = 0.0; std::optional trimParams; std::shared_ptr path; @@ -392,7 +392,7 @@ class RenderTreeNode { public: RenderTreeNode( Vector2D size_, - Transform3D transform_, + Transform2D transform_, float alpha_, bool masksToBounds_, bool isHidden_, @@ -421,7 +421,7 @@ public: return _size; } - Transform3D const &transform() const { + Transform2D const &transform() const { return _transform; } @@ -451,7 +451,7 @@ public: public: Vector2D _size; - Transform3D _transform = Transform3D::identity(); + Transform2D _transform = Transform2D::identity(); float _alpha = 1.0f; bool _masksToBounds = false; bool _isHidden = false; diff --git a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/Vectors.h b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/Vectors.h index 14029225d0..ffe5596872 100644 --- a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/Vectors.h +++ b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/Vectors.h @@ -8,6 +8,8 @@ #include +#import + namespace lottie { struct Vector1D { @@ -148,167 +150,64 @@ inline float radiansToDegrees(float value) { return value * 180.0f / M_PI; } -struct Transform3D { - float m11, m12, m13, m14; - float m21, m22, m23, m24; - float m31, m32, m33, m34; - float m41, m42, m43, m44; - - Transform3D( - float m11_, float m12_, float m13_, float m14_, - float m21_, float m22_, float m23_, float m24_, - float m31_, float m32_, float m33_, float m34_, - float m41_, float m42_, float m43_, float m44_ - ) : - m11(m11_), m12(m12_), m13(m13_), m14(m14_), - m21(m21_), m22(m22_), m23(m23_), m24(m24_), - m31(m31_), m32(m32_), m33(m33_), m34(m34_), - m41(m41_), m42(m42_), m43(m43_), m44(m44_) { +struct Transform2D { + static Transform2D const &identity() { + return _identity; } - bool operator==(Transform3D const &rhs) const { - return m11 == rhs.m11 && m12 == rhs.m12 && m13 == rhs.m13 && m14 == rhs.m14 && - m21 == rhs.m21 && m22 == rhs.m22 && m23 == rhs.m23 && m24 == rhs.m24 && - m31 == rhs.m31 && m32 == rhs.m32 && m33 == rhs.m33 && m34 == rhs.m34 && - m41 == rhs.m41 && m42 == rhs.m42 && m43 == rhs.m43 && m44 == rhs.m44; + explicit Transform2D(simd_float3x3 const &rows_) : + _rows(rows_) { } - bool operator!=(Transform3D const &rhs) const { - return !(*this == rhs); + Transform2D operator*(Transform2D const &other) const { + return Transform2D(simd_mul(other._rows, _rows)); } - inline bool isIdentity() const { - return m11 == 1.0 && m12 == 0.0 && m13 == 0.0 && m14 == 0.0 && - m21 == 0.0 && m22 == 1.0 && m23 == 0.0 && m24 == 0.0 && - m31 == 0.0 && m32 == 0.0 && m33 == 1.0 && m34 == 0.0 && - m41 == 0.0 && m42 == 0.0 && m43 == 0.0 && m44 == 1.0; + bool isInvertible() const { + return simd_determinant(_rows) > 0.00000001; } - static Transform3D makeTranslation(float tx, float ty, float tz) { - return Transform3D( - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - tx, ty, tz, 1 - ); + Transform2D inverted() const { + return Transform2D(simd_inverse(_rows)); } - static Transform3D makeScale(float sx, float sy, float sz) { - return Transform3D( - sx, 0, 0, 0, - 0, sy, 0, 0, - 0, 0, sz, 0, - 0, 0, 0, 1 - ); + bool isIdentity() const { + return (*this) == identity(); } - static Transform3D makeRotation(float radians, float x, float y, float z); - - static Transform3D makeSkew(float skew, float skewAxis) { - float mCos = cos(degreesToRadians(skewAxis)); - float mSin = sin(degreesToRadians(skewAxis)); - float aTan = tan(degreesToRadians(skew)); - - Transform3D transform1( - mCos, - mSin, - 0.0, - 0.0, - -mSin, - mCos, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - - Transform3D transform2( - 1.0, - 0.0, - 0.0, - 0.0, - aTan, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - - Transform3D transform3( - mCos, - -mSin, - 0.0, - 0.0, - mSin, - mCos, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0, - 0.0, - 0.0, - 0.0, - 0.0, - 1.0 - ); - - return transform3 * transform2 * transform1; - } - - static Transform3D makeTransform( + static Transform2D makeTranslation(float tx, float ty); + static Transform2D makeScale(float sx, float sy); + static Transform2D makeRotation(float radians); + static Transform2D makeSkew(float skew, float skewAxis); + static Transform2D makeTransform( Vector2D const &anchor, Vector2D const &position, Vector2D const &scale, float rotation, std::optional skew, std::optional skewAxis - ) { - Transform3D result = Transform3D::identity(); - if (skew.has_value() && skewAxis.has_value()) { - result = Transform3D::identity().translated(position).rotated(rotation).skewed(-skew.value(), skewAxis.value()).scaled(Vector2D(scale.x * 0.01, scale.y * 0.01)).translated(Vector2D(-anchor.x, -anchor.y)); - } else { - result = Transform3D::identity().translated(position).rotated(rotation).scaled(Vector2D(scale.x * 0.01, scale.y * 0.01)).translated(Vector2D(-anchor.x, -anchor.y)); - } - - return result; + ); + + Transform2D rotated(float degrees) const; + Transform2D translated(Vector2D const &translation) const; + Transform2D scaled(Vector2D const &scale) const; + Transform2D skewed(float skew, float skewAxis) const; + + bool operator==(Transform2D const &rhs) const { + return simd_equal(_rows, rhs._rows); } - Transform3D rotated(float degrees) const; - - Transform3D translated(Vector2D const &translation) const; - - Transform3D scaled(Vector2D const &scale) const; - - Transform3D skewed(float skew, float skewAxis) const { - return Transform3D::makeSkew(skew, skewAxis) * (*this); + bool operator!=(Transform2D const &rhs) const { + return !((*this) == rhs); } - static Transform3D const &identity() { - return _identity; + simd_float3x3 const &rows() const { + return _rows; } - - Transform3D operator*(Transform3D const &b) const; - - bool isInvertible() const; - - Transform3D inverted() const; - private: - static Transform3D _identity; + static Transform2D _identity; + + simd_float3x3 _rows; }; struct CGRect { @@ -359,7 +258,7 @@ struct CGRect { CGRect intersection(CGRect const &other) const; CGRect unionWith(CGRect const &other) const; - CGRect applyingTransform(Transform3D const &transform) const; + CGRect applyingTransform(Transform2D const &transform) const; }; inline bool isInRangeOrEqual(float value, float from, float to) { diff --git a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/VectorsCocoa.h b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/VectorsCocoa.h index bf8083f45b..ef77ad9966 100644 --- a/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/VectorsCocoa.h +++ b/submodules/TelegramUI/Components/LottieCpp/PublicHeaders/LottieCpp/VectorsCocoa.h @@ -7,8 +7,8 @@ namespace lottie { -::CATransform3D nativeTransform(Transform3D const &value); -Transform3D fromNativeTransform(::CATransform3D const &value); +::CATransform3D nativeTransform(Transform2D const &value); +Transform2D fromNativeTransform(::CATransform3D const &value); } diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.hpp b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.hpp index af69491fa3..c170f21a58 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.hpp +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/CompLayers/PreCompositionLayer.hpp @@ -122,7 +122,7 @@ public: std::vector> renderTreeValue; auto renderTreeContentItem = std::make_shared( Vector2D(0.0, 0.0), - Transform3D::identity(), + Transform2D::identity(), 1.0, false, false, @@ -136,7 +136,7 @@ public: _contentsTreeNode = std::make_shared( Vector2D(0.0, 0.0), - Transform3D::identity(), + Transform2D::identity(), 1.0, false, false, @@ -159,7 +159,7 @@ public: _renderTreeNode = std::make_shared( Vector2D(0.0, 0.0), - Transform3D::identity(), + Transform2D::identity(), 1.0, false, false, diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/CompLayers/ShapeCompositionLayer.cpp b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/CompLayers/ShapeCompositionLayer.cpp index 19f244e0ee..e7ad955e0f 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/CompLayers/ShapeCompositionLayer.cpp +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/CompLayers/ShapeCompositionLayer.cpp @@ -492,9 +492,9 @@ public: struct TransformedPath { BezierPath path; - Transform3D transform; + Transform2D transform; - TransformedPath(BezierPath const &path_, Transform3D const &transform_) : + TransformedPath(BezierPath const &path_, Transform2D const &transform_) : path(path_), transform(transform_) { } @@ -853,13 +853,13 @@ public: _opacityValue = 1.0; } - _transformValue = Transform3D::identity().translated(Vector2D(positionValue.x, positionValue.y)).rotated(rotationValue).skewed(-skewValue, skewAxisValue).scaled(Vector2D(scaleValue.x * 0.01, scaleValue.y * 0.01)).translated(Vector2D(-anchorValue.x, -anchorValue.y)); + _transformValue = Transform2D::identity().translated(Vector2D(positionValue.x, positionValue.y)).rotated(rotationValue).skewed(-skewValue, skewAxisValue).scaled(Vector2D(scaleValue.x * 0.01, scaleValue.y * 0.01)).translated(Vector2D(-anchorValue.x, -anchorValue.y)); hasValidData = true; } } - Transform3D const &transform() { + Transform2D const &transform() { return _transformValue; } @@ -878,7 +878,7 @@ public: std::unique_ptr> _skewAxis; std::unique_ptr> _opacity; - Transform3D _transformValue = Transform3D::identity(); + Transform2D _transformValue = Transform2D::identity(); float _opacityValue = 1.0; }; @@ -910,11 +910,11 @@ public: std::shared_ptr _contentItem; private: - std::vector collectPaths(size_t subItemLimit, Transform3D const &parentTransform, bool skipApplyTransform) { + std::vector collectPaths(size_t subItemLimit, Transform2D const &parentTransform, bool skipApplyTransform) { std::vector mappedPaths; //TODO:remove skipApplyTransform - Transform3D effectiveTransform = parentTransform; + Transform2D effectiveTransform = parentTransform; if (!skipApplyTransform && isGroup && transform) { effectiveTransform = transform->transform() * effectiveTransform; } @@ -942,7 +942,7 @@ public: } CompoundBezierPath trimmedPath = trimCompoundPath(tempPath, currentTrim->start, currentTrim->end, currentTrim->offset, currentTrim->type); for (auto &path : trimmedPath.paths) { - mappedPaths.emplace_back(path, Transform3D::identity()); + mappedPaths.emplace_back(path, Transform2D::identity()); } } else { for (auto &path : subItemPaths) { @@ -1061,7 +1061,7 @@ public: } void updateContents(std::optional parentTrim) { - Transform3D containerTransform = Transform3D::identity(); + Transform2D containerTransform = Transform2D::identity(); float containerOpacity = 1.0; if (transform) { containerTransform = transform->transform(); @@ -1089,7 +1089,7 @@ public: if (parentTrim) { CompoundBezierPath compoundPath; - auto paths = collectPaths(shadingVariant.subItemLimit, Transform3D::identity(), true); + auto paths = collectPaths(shadingVariant.subItemLimit, Transform2D::identity(), true); for (const auto &path : paths) { compoundPath.appendPath(path.path.copyUsingTransform(path.transform)); } @@ -1104,7 +1104,7 @@ public: } else { if (hasTrims()) { CompoundBezierPath compoundPath; - auto paths = collectPaths(shadingVariant.subItemLimit, Transform3D::identity(), true); + auto paths = collectPaths(shadingVariant.subItemLimit, Transform2D::identity(), true); for (const auto &path : paths) { compoundPath.appendPath(path.path.copyUsingTransform(path.transform)); } @@ -1324,7 +1324,7 @@ std::shared_ptr ShapeCompositionLayer::renderTreeNode(BezierPath if (!_renderTreeNode) { _contentRenderTreeNode = std::make_shared( Vector2D(0.0, 0.0), - Transform3D::identity(), + Transform2D::identity(), 1.0, false, false, @@ -1349,7 +1349,7 @@ std::shared_ptr ShapeCompositionLayer::renderTreeNode(BezierPath _renderTreeNode = std::make_shared( Vector2D(0.0, 0.0), - Transform3D::identity(), + Transform2D::identity(), 1.0, false, false, diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/MainThreadAnimationLayer.hpp b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/MainThreadAnimationLayer.hpp index b8b288307f..b9e47a7a60 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/MainThreadAnimationLayer.hpp +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/MainThreadAnimationLayer.hpp @@ -238,7 +238,7 @@ public: } _renderTreeNode = std::make_shared( size(), - Transform3D::identity(), + Transform2D::identity(), 1.0, false, false, diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/Utility/LayerTransformNode.hpp b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/Utility/LayerTransformNode.hpp index 79c9950b2a..459558a2bd 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/Utility/LayerTransformNode.hpp +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/LayerContainers/Utility/LayerTransformNode.hpp @@ -157,7 +157,7 @@ public: Vector3D anchor = _transformProperties->anchor()->value(); Vector3D scale = _transformProperties->scale()->value(); - _localTransform = Transform3D::makeTransform( + _localTransform = Transform2D::makeTransform( Vector2D(anchor.x, anchor.y), position, Vector2D(scale.x, scale.y), @@ -181,7 +181,7 @@ public: return _opacity; } - Transform3D const &globalTransform() { + Transform2D const &globalTransform() { return _globalTransform; } @@ -191,8 +191,8 @@ private: std::shared_ptr _transformProperties; float _opacity = 1.0; - Transform3D _localTransform = Transform3D::identity(); - Transform3D _globalTransform = Transform3D::identity(); + Transform2D _localTransform = Transform2D::identity(); + Transform2D _globalTransform = Transform2D::identity(); public: virtual LayerTransformNode *asLayerTransformNode() override { diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.hpp b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.hpp index dc252f6102..6e8b534b48 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.hpp +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/MainThread/NodeRenderSystem/Nodes/Text/TextAnimatorNode.hpp @@ -93,7 +93,7 @@ public: return _childKeypaths; } - Transform3D caTransform() { + Transform2D caTransform() { Vector2D anchor = Vector2D::Zero(); if (_anchor) { auto anchor3d = _anchor->value(); @@ -126,7 +126,7 @@ public: skewAxis = _skewAxis->value().value; } - return Transform3D::makeTransform( + return Transform2D::makeTransform( anchor, position, scale, @@ -212,16 +212,16 @@ public: return _parentTextNode; } - Transform3D xform() { + Transform2D xform() { if (_xform.has_value()) { return _xform.value(); } else if (_parentTextNode) { return _parentTextNode->xform(); } else { - return Transform3D::identity(); + return Transform2D::identity(); } } - void setXform(Transform3D const &xform) { + void setXform(Transform2D const &xform) { _xform = xform; } @@ -312,7 +312,7 @@ private: std::shared_ptr _outputPath; - std::optional _xform; + std::optional _xform; std::optional _opacity; std::optional _strokeColor; std::optional _fillColor; diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/Utility/Primitives/BezierPath.cpp b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/Utility/Primitives/BezierPath.cpp index 2ab088e42a..85c50dba1e 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/Utility/Primitives/BezierPath.cpp +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Private/Utility/Primitives/BezierPath.cpp @@ -486,8 +486,8 @@ std::shared_ptr BezierPath::cgPath() const { return _contents->cgPath(); } -BezierPath BezierPath::copyUsingTransform(Transform3D const &transform) const { - if (transform == Transform3D::identity()) { +BezierPath BezierPath::copyUsingTransform(Transform2D const &transform) const { + if (transform == Transform2D::identity()) { return (*this); } BezierPath result; diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CALayer.hpp b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CALayer.hpp index 2c40c5667e..c0c0a61006 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CALayer.hpp +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CALayer.hpp @@ -64,10 +64,10 @@ public: _size = size; } - Transform3D const &transform() const { + Transform2D const &transform() const { return _transform; } - void setTransform(Transform3D const &transform) { + void setTransform(Transform2D const &transform) { _transform = transform; } @@ -117,7 +117,7 @@ private: bool _isHidden = false; float _opacity = 1.0; Vector2D _size = Vector2D(0.0, 0.0); - Transform3D _transform = Transform3D::identity(); + Transform2D _transform = Transform2D::identity(); std::shared_ptr _mask; bool _masksToBounds = false; std::optional _compositingFilter; diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CGPath.cpp b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CGPath.cpp index d1cf338111..e985e18392 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CGPath.cpp +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CGPath.cpp @@ -35,11 +35,10 @@ void addPointToBoundingRect(bool *isFirst, CGRect *rect, Vector2D const *point) } -Vector2D transformVector(Vector2D const &v, Transform3D const &m) { - return Vector2D( - m.m11 * v.x + m.m21 * v.y + m.m41 * 1.0, - m.m12 * v.x + m.m22 * v.y + m.m42 * 1.0 - ); +Vector2D transformVector(Vector2D const &v, Transform2D const &m) { + float transformedX = m.rows().columns[0][0] * v.x + m.rows().columns[1][0] * v.y + m.rows().columns[2][0] * 1.0f; + float transformedY = m.rows().columns[0][1] * v.x + m.rows().columns[1][1] * v.y + m.rows().columns[2][1] * 1.0f; + return Vector2D(transformedX, transformedY); } class CGPathImpl: public CGPath { @@ -51,7 +50,7 @@ public: virtual bool empty() const override; - virtual std::shared_ptr copyUsingTransform(Transform3D const &transform) const override; + virtual std::shared_ptr copyUsingTransform(Transform2D const &transform) const override; virtual void addLineTo(Vector2D const &point) override; virtual void addCurveTo(Vector2D const &point, Vector2D const &control1, Vector2D const &control2) override; @@ -108,10 +107,10 @@ bool CGPathImpl::empty() const { return _items.empty(); } -std::shared_ptr CGPathImpl::copyUsingTransform(Transform3D const &transform) const { +std::shared_ptr CGPathImpl::copyUsingTransform(Transform2D const &transform) const { auto result = std::make_shared(); - if (transform == Transform3D::identity()) { + if (transform == Transform2D::identity()) { result->_items = _items; return result; } diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CGPath.mm b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CGPath.mm index ab13e06922..93a5e242a1 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CGPath.mm +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/CGPath.mm @@ -92,29 +92,12 @@ bool CGPathCocoaImpl::empty() const { return CGPathIsEmpty(_path); } -std::shared_ptr CGPathCocoaImpl::copyUsingTransform(Transform3D const &transform) const { - ::CATransform3D nativeTransform; - nativeTransform.m11 = transform.m11; - nativeTransform.m12 = transform.m12; - nativeTransform.m13 = transform.m13; - nativeTransform.m14 = transform.m14; - - nativeTransform.m21 = transform.m21; - nativeTransform.m22 = transform.m22; - nativeTransform.m23 = transform.m23; - nativeTransform.m24 = transform.m24; - - nativeTransform.m31 = transform.m31; - nativeTransform.m32 = transform.m32; - nativeTransform.m33 = transform.m33; - nativeTransform.m34 = transform.m34; - - nativeTransform.m41 = transform.m41; - nativeTransform.m42 = transform.m42; - nativeTransform.m43 = transform.m43; - nativeTransform.m44 = transform.m44; - - auto affineTransform = CATransform3DGetAffineTransform(nativeTransform); +std::shared_ptr CGPathCocoaImpl::copyUsingTransform(Transform2D const &transform) const { + CGAffineTransform affineTransform = CGAffineTransformMake( + transform.rows().columns[0][0], transform.rows().columns[0][1], + transform.rows().columns[1][0], transform.rows().columns[1][1], + transform.rows().columns[2][0], transform.rows().columns[2][1] + ); CGPathRef resultPath = CGPathCreateCopyByTransformingPath(_path, &affineTransform); if (resultPath == nil) { diff --git a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/Vectors.mm b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/Vectors.mm index 9618e9e289..3695d35aa0 100644 --- a/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/Vectors.mm +++ b/submodules/TelegramUI/Components/LottieCpp/Sources/Lottie/Public/Primitives/Vectors.mm @@ -8,10 +8,261 @@ #import -#import - namespace lottie { +/*explicit Transform2D(Transform3D const &t) { + CGAffineTransform at = CATransform3DGetAffineTransform(nativeTransform(t)); + _rows.columns[0] = simd_make_float3(at.a, at.b, 0.0); + _rows.columns[1] = simd_make_float3(at.c, at.d, 0.0); + _rows.columns[2] = simd_make_float3(at.tx, at.ty, 1.0); +} + + Transform3D transform3D() { + CGAffineTransform at = CGAffineTransformMake( + _rows.columns[0][0], _rows.columns[0][1], + _rows.columns[1][0], _rows.columns[1][1], + _rows.columns[2][0], _rows.columns[2][1] + ); + return fromNativeTransform(CATransform3DMakeAffineTransform(at)); + }*/ + +/*struct Transform3D { + float m11, m12, m13, m14; + float m21, m22, m23, m24; + float m31, m32, m33, m34; + float m41, m42, m43, m44; + + Transform3D( + float m11_, float m12_, float m13_, float m14_, + float m21_, float m22_, float m23_, float m24_, + float m31_, float m32_, float m33_, float m34_, + float m41_, float m42_, float m43_, float m44_ + ) : + m11(m11_), m12(m12_), m13(m13_), m14(m14_), + m21(m21_), m22(m22_), m23(m23_), m24(m24_), + m31(m31_), m32(m32_), m33(m33_), m34(m34_), + m41(m41_), m42(m42_), m43(m43_), m44(m44_) { + } + + bool operator==(Transform3D const &rhs) const { + return m11 == rhs.m11 && m12 == rhs.m12 && m13 == rhs.m13 && m14 == rhs.m14 && + m21 == rhs.m21 && m22 == rhs.m22 && m23 == rhs.m23 && m24 == rhs.m24 && + m31 == rhs.m31 && m32 == rhs.m32 && m33 == rhs.m33 && m34 == rhs.m34 && + m41 == rhs.m41 && m42 == rhs.m42 && m43 == rhs.m43 && m44 == rhs.m44; + } + + bool operator!=(Transform3D const &rhs) const { + return !(*this == rhs); + } + + inline bool isIdentity() const { + return m11 == 1.0 && m12 == 0.0 && m13 == 0.0 && m14 == 0.0 && + m21 == 0.0 && m22 == 1.0 && m23 == 0.0 && m24 == 0.0 && + m31 == 0.0 && m32 == 0.0 && m33 == 1.0 && m34 == 0.0 && + m41 == 0.0 && m42 == 0.0 && m43 == 0.0 && m44 == 1.0; + } + + static Transform3D makeTranslation(float tx, float ty, float tz) { + return Transform3D( + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + tx, ty, tz, 1 + ); + } + + static Transform3D makeScale(float sx, float sy, float sz) { + return Transform3D( + sx, 0, 0, 0, + 0, sy, 0, 0, + 0, 0, sz, 0, + 0, 0, 0, 1 + ); + } + + static Transform3D makeRotation(float radians); + + static Transform3D makeSkew(float skew, float skewAxis) { + float mCos = cos(degreesToRadians(skewAxis)); + float mSin = sin(degreesToRadians(skewAxis)); + float aTan = tan(degreesToRadians(skew)); + + Transform3D transform1( + mCos, + mSin, + 0.0, + 0.0, + -mSin, + mCos, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ); + + Transform3D transform2( + 1.0, + 0.0, + 0.0, + 0.0, + aTan, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ); + + Transform3D transform3( + mCos, + -mSin, + 0.0, + 0.0, + mSin, + mCos, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0, + 0.0, + 0.0, + 0.0, + 0.0, + 1.0 + ); + + return transform3 * transform2 * transform1; + } + + static Transform3D makeTransform( + Vector2D const &anchor, + Vector2D const &position, + Vector2D const &scale, + float rotation, + std::optional skew, + std::optional skewAxis + ) { + Transform3D result = Transform3D::identity(); + if (skew.has_value() && skewAxis.has_value()) { + result = Transform3D::identity().translated(position).rotated(rotation).skewed(-skew.value(), skewAxis.value()).scaled(Vector2D(scale.x * 0.01, scale.y * 0.01)).translated(Vector2D(-anchor.x, -anchor.y)); + } else { + result = Transform3D::identity().translated(position).rotated(rotation).scaled(Vector2D(scale.x * 0.01, scale.y * 0.01)).translated(Vector2D(-anchor.x, -anchor.y)); + } + + return result; + } + + Transform3D rotated(float degrees) const; + + Transform3D translated(Vector2D const &translation) const; + + Transform3D scaled(Vector2D const &scale) const; + + Transform3D skewed(float skew, float skewAxis) const { + return Transform3D::makeSkew(skew, skewAxis) * (*this); + } + + static Transform3D identity() { + return Transform3D( + 1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f + ); + } + + Transform3D operator*(Transform3D const &b) const; +};*/ + +/*Transform2D t2d(Transform3D const &testMatrix) { + ::CATransform3D nativeTest; + + nativeTest.m11 = testMatrix.m11; + nativeTest.m12 = testMatrix.m12; + nativeTest.m13 = testMatrix.m13; + nativeTest.m14 = testMatrix.m14; + + nativeTest.m21 = testMatrix.m21; + nativeTest.m22 = testMatrix.m22; + nativeTest.m23 = testMatrix.m23; + nativeTest.m24 = testMatrix.m24; + + nativeTest.m31 = testMatrix.m31; + nativeTest.m32 = testMatrix.m32; + nativeTest.m33 = testMatrix.m33; + nativeTest.m34 = testMatrix.m34; + + nativeTest.m41 = testMatrix.m41; + nativeTest.m42 = testMatrix.m42; + nativeTest.m43 = testMatrix.m43; + nativeTest.m44 = testMatrix.m44; + + CGAffineTransform at = CATransform3DGetAffineTransform(nativeTest); + Transform2D result = Transform2D::identity(); + simd_float3x3 *rows = (simd_float3x3 *)&result.rows(); + rows->columns[0] = simd_make_float3(at.a, at.b, 0.0); + rows->columns[1] = simd_make_float3(at.c, at.d, 0.0); + rows->columns[2] = simd_make_float3(at.tx, at.ty, 1.0); + + return result; +} + +Transform3D t3d(Transform2D const &t) { + CGAffineTransform at = CGAffineTransformMake( + t.rows().columns[0][0], t.rows().columns[0][1], + t.rows().columns[1][0], t.rows().columns[1][1], + t.rows().columns[2][0], t.rows().columns[2][1] + ); + ::CATransform3D value = CATransform3DMakeAffineTransform(at); + + Transform3D result = Transform3D::identity(); + result.m11 = value.m11; + result.m12 = value.m12; + result.m13 = value.m13; + result.m14 = value.m14; + + result.m21 = value.m21; + result.m22 = value.m22; + result.m23 = value.m23; + result.m24 = value.m24; + + result.m31 = value.m31; + result.m32 = value.m32; + result.m33 = value.m33; + result.m34 = value.m34; + + result.m41 = value.m41; + result.m42 = value.m42; + result.m43 = value.m43; + result.m44 = value.m44; + + return result; +} + +Transform3D Transform3D::operator*(Transform3D const &b) const { + if (isIdentity()) { + return b; + } + if (b.isIdentity()) { + return *this; + } + + return t3d((t2d(*this) * t2d(b))); +}*/ + Vector1D::Vector1D(lottiejson11::Json const &json) noexcept(false) { if (json.is_number()) { value = json.number_value(); @@ -140,13 +391,108 @@ lottiejson11::Json Vector3D::toJson() const { return lottiejson11::Json(result); } -Transform3D Transform3D::_identity = Transform3D( - 1.0, 0.0, 0.0, 0.0, - 0.0, 1.0, 0.0, 0.0, - 0.0, 0.0, 1.0, 0.0, - 0.0, 0.0, 0.0, 1.0 +Transform2D Transform2D::_identity = Transform2D( + simd_float3x3({ + simd_make_float3(1.0f, 0.0f, 0.0f), + simd_make_float3(0.0f, 1.0f, 0.0f), + simd_make_float3(0.0f, 0.0f, 1.0f) + }) ); +Transform2D Transform2D::makeTranslation(float tx, float ty) { + return Transform2D(simd_float3x3({ + simd_make_float3(1.0f, 0.0f, 0.0f), + simd_make_float3(0.0f, 1.0f, 0.0f), + simd_make_float3(tx, ty, 1.0f) + })); +} + +Transform2D Transform2D::makeScale(float sx, float sy) { + return Transform2D(simd_float3x3({ + simd_make_float3(sx, 0.0f, 0.0f), + simd_make_float3(0.0f, sy, 0.0f), + simd_make_float3(0.0f, 0.0f, 1.0f) + })); +} + +Transform2D Transform2D::makeRotation(float radians) { + float c = cos(radians); + float s = sin(radians); + + return Transform2D(simd_float3x3({ + simd_make_float3(c, s, 0.0f), + simd_make_float3(-s, c, 0.0f), + simd_make_float3(0.0f, 0.0f, 1.0f) + })); +} + +Transform2D Transform2D::makeSkew(float skew, float skewAxis) { + if (std::abs(skew) <= FLT_EPSILON && std::abs(skewAxis) <= FLT_EPSILON) { + return Transform2D::identity(); + } + + float mCos = cos(degreesToRadians(skewAxis)); + float mSin = sin(degreesToRadians(skewAxis)); + float aTan = tan(degreesToRadians(skew)); + + simd_float3x3 simd1 = simd_float3x3({ + simd_make_float3(mCos, -mSin, 0.0), + simd_make_float3(mSin, mCos, 0.0), + simd_make_float3(0.0, 0.0, 1.0) + }); + + simd_float3x3 simd2 = simd_float3x3({ + simd_make_float3(1.0, 0.0, 0.0), + simd_make_float3(aTan, 1.0, 0.0), + simd_make_float3(0.0, 0.0, 1.0) + }); + + simd_float3x3 simd3 = simd_float3x3({ + simd_make_float3(mCos, mSin, 0.0), + simd_make_float3(-mSin, mCos, 0.0), + simd_make_float3(0.0, 0.0, 1.0) + }); + + simd_float3x3 result = simd_mul(simd_mul(simd3, simd2), simd1); + Transform2D resultTransform(result); + + return resultTransform; +} + +Transform2D Transform2D::makeTransform( + Vector2D const &anchor, + Vector2D const &position, + Vector2D const &scale, + float rotation, + std::optional skew, + std::optional skewAxis +) { + Transform2D result = Transform2D::identity(); + if (skew.has_value() && skewAxis.has_value()) { + result = Transform2D::identity().translated(position).rotated(rotation).skewed(-skew.value(), skewAxis.value()).scaled(Vector2D(scale.x * 0.01, scale.y * 0.01)).translated(Vector2D(-anchor.x, -anchor.y)); + } else { + result = Transform2D::identity().translated(position).rotated(rotation).scaled(Vector2D(scale.x * 0.01, scale.y * 0.01)).translated(Vector2D(-anchor.x, -anchor.y)); + } + + return result; +} + +Transform2D Transform2D::rotated(float degrees) const { + return Transform2D::makeRotation(degreesToRadians(degrees)) * (*this); +} + +Transform2D Transform2D::translated(Vector2D const &translation) const { + return Transform2D::makeTranslation(translation.x, translation.y) * (*this); +} + +Transform2D Transform2D::scaled(Vector2D const &scale) const { + return Transform2D::makeScale(scale.x, scale.y) * (*this); +} + +Transform2D Transform2D::skewed(float skew, float skewAxis) const { + return Transform2D::makeSkew(skew, skewAxis) * (*this); +} + float interpolate(float value, float to, float amount) { return value + ((to - value) * amount); } @@ -415,8 +761,15 @@ Vector2D Vector2D::interpolate( return point.point; } -::CATransform3D nativeTransform(Transform3D const &value) { - ::CATransform3D result; +::CATransform3D nativeTransform(Transform2D const &value) { + CGAffineTransform at = CGAffineTransformMake( + value.rows().columns[0][0], value.rows().columns[0][1], + value.rows().columns[1][0], value.rows().columns[1][1], + value.rows().columns[2][0], value.rows().columns[2][1] + ); + return CATransform3DMakeAffineTransform(at); + + /*::CATransform3D result; result.m11 = value.m11; result.m12 = value.m12; @@ -438,11 +791,20 @@ Vector2D Vector2D::interpolate( result.m43 = value.m43; result.m44 = value.m44; - return result; + return result;*/ } -Transform3D fromNativeTransform(::CATransform3D const &value) { - Transform3D result = Transform3D::identity(); +Transform2D fromNativeTransform(::CATransform3D const &value) { + CGAffineTransform at = CATransform3DGetAffineTransform(value); + return Transform2D( + simd_float3x3({ + simd_make_float3(at.a, at.b, 0.0), + simd_make_float3(at.c, at.d, 0.0), + simd_make_float3(at.tx, at.ty, 1.0) + }) + ); + + /*Transform2D result = Transform2D::identity(); result.m11 = value.m11; result.m12 = value.m12; @@ -464,47 +826,23 @@ Transform3D fromNativeTransform(::CATransform3D const &value) { result.m43 = value.m43; result.m44 = value.m44; - return result; + return result;*/ } -Transform3D Transform3D::makeRotation(float radians, float x, float y, float z) { - if (std::abs(radians) <= FLT_EPSILON || (x == 0.0 && y == 0.0 && z == 0.0)) { +/*Transform3D Transform3D::makeRotation(float radians) { + if (std::abs(radians) <= FLT_EPSILON) { return Transform3D::identity(); } float s = sin(radians); float c = cos(radians); - float len = sqrt(x*x + y*y + z*z); - x /= len; y /= len; z /= len; - - Transform3D returnValue = Transform3D::identity(); - - returnValue.m11 = c + (1.0f - c) * x * x; - returnValue.m12 = (1.0f - c) * x*y + s * z; - returnValue.m13 = (1.0f - c) * x*z - s * y; - returnValue.m14 = 0.0f; - - returnValue.m21 = (1.0f - c) * y * x - s * z; - returnValue.m22 = c + (1.0f - c) * y * y; - returnValue.m23 = (1.0f - c) * y * z + s * x; - returnValue.m24 = 0.0f; - - returnValue.m31 = (1.0f - c) * z * x + s * y; - returnValue.m32 = (1.0f - c) * y * z - s * x; - returnValue.m33 = c + (1.0f - c) * z * z; - returnValue.m34 = 0.0f; - - returnValue.m41 = 0.0f; - returnValue.m42 = 0.0f; - returnValue.m43 = 0.0f; - returnValue.m44 = 1.0f; - - return returnValue; + ::CGAffineTransform t = CGAffineTransformMake(c, s, -s, c, 0.0f, 0.0f); + return fromNativeTransform(CATransform3DMakeAffineTransform(t)); } Transform3D Transform3D::rotated(float degrees) const { - return Transform3D::makeRotation(degreesToRadians(degrees), 0.0, 0.0, 1.0) * (*this); + return Transform3D::makeRotation(degreesToRadians(degrees)) * (*this); } Transform3D Transform3D::translated(Vector2D const &translation) const { @@ -515,57 +853,14 @@ Transform3D Transform3D::scaled(Vector2D const &scale) const { return Transform3D::makeScale(scale.x, scale.y, 1.0) * (*this); } -Transform3D Transform3D::operator*(Transform3D const &b) const { - if (isIdentity()) { - return b; - } - if (b.isIdentity()) { - return *this; - } - - simd_float4x4 simdLhs = { - simd_make_float4(b.m11, b.m21, b.m31, b.m41), - simd_make_float4(b.m12, b.m22, b.m32, b.m42), - simd_make_float4(b.m13, b.m23, b.m33, b.m43), - simd_make_float4(b.m14, b.m24, b.m34, b.m44) - }; - simd_float4x4 simdRhs = { - simd_make_float4(m11, m21, m31, m41), - simd_make_float4(m12, m22, m32, m42), - simd_make_float4(m13, m23, m33, m43), - simd_make_float4(m14, m24, m34, m44) - }; - - simd_float4x4 simdResult = simd_mul(simdRhs, simdLhs); - return Transform3D( - simdResult.columns[0][0], simdResult.columns[1][0], simdResult.columns[2][0], simdResult.columns[3][0], - simdResult.columns[0][1], simdResult.columns[1][1], simdResult.columns[2][1], simdResult.columns[3][1], - simdResult.columns[0][2], simdResult.columns[1][2], simdResult.columns[2][2], simdResult.columns[3][2], - simdResult.columns[0][3], simdResult.columns[1][3], simdResult.columns[2][3], simdResult.columns[3][3] - ); -} - bool Transform3D::isInvertible() const { - return std::abs(m11 * m22 - m12 * m21) >= 0.00000001; + return Transform2D(*this).isInvertible(); + //return std::abs(m11 * m22 - m12 * m21) >= 0.00000001; } Transform3D Transform3D::inverted() const { - simd_float4x4 matrix = { - simd_make_float4(m11, m21, m31, m41), - simd_make_float4(m12, m22, m32, m42), - simd_make_float4(m13, m23, m33, m43), - simd_make_float4(m14, m24, m34, m44) - }; - simd_float4x4 result = simd_inverse(matrix); - Transform3D nativeResult = Transform3D( - result.columns[0][0], result.columns[1][0], result.columns[2][0], result.columns[3][0], - result.columns[0][1], result.columns[1][1], result.columns[2][1], result.columns[3][1], - result.columns[0][2], result.columns[1][2], result.columns[2][2], result.columns[3][2], - result.columns[0][3], result.columns[1][3], result.columns[2][3], result.columns[3][3] - ); - - return nativeResult; -} + return Transform2D(*this).inverted().transform3D(); +}*/ bool CGRect::intersects(CGRect const &other) const { return CGRectIntersectsRect(CGRectMake(x, y, width, height), CGRectMake(other.x, other.y, other.width, other.height)); @@ -585,29 +880,26 @@ CGRect CGRect::unionWith(CGRect const &other) const { return CGRect(result.origin.x, result.origin.y, result.size.width, result.size.height); } -CGRect CGRect::applyingTransform(Transform3D const &transform) const { +CGRect CGRect::applyingTransform(Transform2D const &transform) const { if (transform.isIdentity()) { return *this; } - simd_float3 simdRow1 = simd_make_float3(transform.m11, transform.m12, transform.m14); - simd_float3 simdRow2 = simd_make_float3(transform.m21, transform.m22, transform.m24); - simd_float3 simdRow3 = simd_make_float3(transform.m41, transform.m42, transform.m44); - Vector2D sourceTopLeft = Vector2D(x, y); Vector2D sourceTopRight = Vector2D(x + width, y); Vector2D sourceBottomLeft = Vector2D(x, y + height); Vector2D sourceBottomRight = Vector2D(x + width, y + height); - simd_float3 simdTopLeft = sourceTopLeft.x * simdRow1 + sourceTopLeft.y * simdRow2 + simdRow3; - simd_float3 simdTopRight = sourceTopRight.x * simdRow1 + sourceTopRight.y * simdRow2 + simdRow3; - simd_float3 simdBottomLeft = sourceBottomLeft.x * simdRow1 + sourceBottomLeft.y * simdRow2 + simdRow3; - simd_float3 simdBottomRight = sourceBottomRight.x * simdRow1 + sourceBottomRight.y * simdRow2 + simdRow3; + simd_float4 xs = simd_make_float4(sourceTopLeft.x, sourceTopRight.x, sourceBottomLeft.x, sourceBottomRight.x); + simd_float4 ys = simd_make_float4(sourceTopLeft.y, sourceTopRight.y, sourceBottomLeft.y, sourceBottomRight.y); - Vector2D topLeft = Vector2D(simdTopLeft[0] / simdTopLeft[2], simdTopLeft[1] / simdTopLeft[2]); - Vector2D topRight = Vector2D(simdTopRight[0] / simdTopRight[2], simdTopRight[1] / simdTopRight[2]); - Vector2D bottomLeft = Vector2D(simdBottomLeft[0] / simdBottomLeft[2], simdBottomLeft[1] / simdBottomLeft[2]); - Vector2D bottomRight = Vector2D(simdBottomRight[0] / simdBottomRight[2], simdBottomRight[1] / simdBottomRight[2]); + simd_float4 rx = xs * transform.rows().columns[0][0] + ys * transform.rows().columns[1][0] + transform.rows().columns[2][0]; + simd_float4 ry = xs * transform.rows().columns[0][1] + ys * transform.rows().columns[1][1] + transform.rows().columns[2][1]; + + Vector2D topLeft = Vector2D(rx[0], ry[0]); + Vector2D topRight = Vector2D(rx[1], ry[1]); + Vector2D bottomLeft = Vector2D(rx[2], ry[2]); + Vector2D bottomRight = Vector2D(rx[3], ry[3]); float minX = simd_reduce_min(simd_make_float4(topLeft.x, topRight.x, bottomLeft.x, bottomRight.x)); float minY = simd_reduce_min(simd_make_float4(topLeft.y, topRight.y, bottomLeft.y, bottomRight.y));