From 0443b1e789fa3b28c57e7b539d902a79db89c5a3 Mon Sep 17 00:00:00 2001 From: aborziak-ms <83784664+aborziak-ms@users.noreply.github.com> Date: Wed, 28 Feb 2024 12:14:20 -0800 Subject: [PATCH] Fix codegen to generate IAnimatedVisual2 and IAnimatedVisualSource2 interfaces for WinUI3 (#551) * Unify animation controller initialization code for remapped time scales * Fixed CreateSpriteShape helper codegen * Allow IAV2 and IAVS2 to be implemented for WinUI3 --- source/LottieToWinComp/Animate.cs | 28 ++++++++++++++----- source/LottieToWinComp/TranslationContext.cs | 15 ---------- .../CSharp/CSharpInstantiatorGenerator.cs | 14 ++++++---- .../CodeGen/CodegenConfiguration.cs | 2 +- .../Cppwinrt/CppwinrtInstantiatorGenerator.cs | 8 +++--- .../CodeGen/Cx/CxInstantiatorGenerator.cs | 7 ++--- .../CodeGen/InstantiatorGeneratorBase.cs | 4 +-- 7 files changed, 39 insertions(+), 39 deletions(-) diff --git a/source/LottieToWinComp/Animate.cs b/source/LottieToWinComp/Animate.cs index 590c7b21..79b9a7eb 100644 --- a/source/LottieToWinComp/Animate.cs +++ b/source/LottieToWinComp/Animate.cs @@ -43,15 +43,27 @@ public static void WithKeyFrame( Debug.Assert(scale <= 1, "Precondition"); Debug.Assert(animation.KeyFrameCount > 0, "Precondition"); - if (scale == 1.0 && offset == 0.0 && context.ObjectFactory.IsUapApiAvailable(nameof(AnimationController)) && context.RootProgressController is not null) + var key = new ScaleAndOffset(scale, offset); + var state = context.GetStateCache(); + + if (context.ObjectFactory.IsUapApiAvailable(nameof(AnimationController))) { - // Special case when we can use root AnimationController (no time stretch, no time offset) - compObject.StartAnimation(target, animation, context.RootProgressController!); + if (!state.ProgressControllers.TryGetValue(key, out var controllerCached)) + { + controllerCached = context.ObjectFactory.CreateAnimationControllerList(); + controllerCached.Pause(); + + var rootProgressAnimation = context.ObjectFactory.CreateExpressionAnimation(scale == 1.0 && offset == 0.0 ? ExpressionFactory.RootProgress : ExpressionFactory.ScaledAndOffsetRootProgress(scale, offset)); + rootProgressAnimation.SetReferenceParameter(ExpressionFactory.RootName, context.RootVisual!); + controllerCached.StartAnimation("Progress", rootProgressAnimation); + + state.ProgressControllers.Add(key, controllerCached); + } + + compObject.StartAnimation(target, animation, controllerCached); return; } - var state = context.GetStateCache(); - // Start the animation ... compObject.StartAnimation(target, animation); @@ -61,7 +73,6 @@ public static void WithKeyFrame( controller!.Pause(); // Bind it to the root visual's Progress property, scaling and offsetting if necessary. - var key = new ScaleAndOffset(scale, offset); if (!state.ProgressBindingAnimations.TryGetValue(key, out var bindingAnimation)) { bindingAnimation = context.ObjectFactory.CreateExpressionAnimation(ExpressionFactory.ScaledAndOffsetRootProgress(scale, offset)); @@ -853,7 +864,7 @@ void InsertExpressionKeyFrame(TCA animation, float progress, CubicBezierFunction } // A pair of doubles used as a key in a dictionary. - sealed class ScaleAndOffset + public sealed class ScaleAndOffset { internal ScaleAndOffset(double scale, double offset) { @@ -877,6 +888,9 @@ sealed class StateCache { public Dictionary ProgressBindingAnimations { get; } = new Dictionary(); + + public Dictionary ProgressControllers { get; } + = new Dictionary(); } } } diff --git a/source/LottieToWinComp/TranslationContext.cs b/source/LottieToWinComp/TranslationContext.cs index 1b751a02..634289d3 100644 --- a/source/LottieToWinComp/TranslationContext.cs +++ b/source/LottieToWinComp/TranslationContext.cs @@ -150,11 +150,6 @@ internal static TranslationResult TryTranslateLottieComposition( /// public ContainerVisual? RootVisual { get; private set; } - /// - /// AnimationController that has Progress property bound to RootVisual.Progress property. - /// - public AnimationController? RootProgressController { get; private set; } - /// /// True iff theme property bindings are enabled. /// @@ -228,16 +223,6 @@ void Translate() // Add the master progress property to the visual. RootVisual.Properties.InsertScalar(ProgressPropertyName, 0); - // AnimationController that has Progress value bound to RootVisual.Progress - if (ObjectFactory.IsUapApiAvailable(nameof(AnimationController))) - { - RootProgressController = ObjectFactory.CreateAnimationControllerList(); - var rootProgressAnimation = context.ObjectFactory.CreateExpressionAnimation(ExpressionFactory.RootProgress); - rootProgressAnimation.SetReferenceParameter(ExpressionFactory.RootName, RootVisual); - RootProgressController.Pause(); - RootProgressController.StartAnimation("Progress", rootProgressAnimation); - } - // Add the translations of each layer to the root visual. This will recursively // add the tranlation of the layers in precomps. var contentsChildren = RootVisual.Children; diff --git a/source/UIDataCodeGen/CodeGen/CSharp/CSharpInstantiatorGenerator.cs b/source/UIDataCodeGen/CodeGen/CSharp/CSharpInstantiatorGenerator.cs index 5ca4d2e4..49fce3b1 100644 --- a/source/UIDataCodeGen/CodeGen/CSharp/CSharpInstantiatorGenerator.cs +++ b/source/UIDataCodeGen/CodeGen/CSharp/CSharpInstantiatorGenerator.cs @@ -273,7 +273,7 @@ void WriteIAnimatedVisualSource(CodeBuilder builder, bool implementDynamicAVS) builder.WriteLine($": {Interface_IAnimatedVisualSource.GetQualifiedName(_s)}"); } - if (SourceInfo.WinUIVersion >= new Version(2, 6) && SourceInfo.WinUIVersion.Major < 3) + if (SourceInfo.WinUIVersion >= new Version(2, 6)) { builder.WriteLine($", {Interface_IAnimatedVisualSource2.GetQualifiedName(_s)}"); } @@ -685,15 +685,17 @@ void WriteSetPropertyImpl( protected override void WriteAnimatedVisualStart(CodeBuilder builder, IAnimatedVisualInfo info) { // Start the instantiator class. + builder.WriteLine($"sealed class {info.ClassName}"); + builder.Indent(); + builder.WriteLine($": {Interface_IAnimatedVisual.GetQualifiedName(_s)}"); + if (info.ImplementCreateAndDestroyMethods) { - builder.WriteLine($"sealed class {info.ClassName} : {Interface_IAnimatedVisual2.GetQualifiedName(_s)}"); - } - else - { - builder.WriteLine($"sealed class {info.ClassName} : {Interface_IAnimatedVisual.GetQualifiedName(_s)}"); + builder.WriteLine($", {Interface_IAnimatedVisual2.GetQualifiedName(_s)}"); } + builder.UnIndent(); + builder.OpenScope(); } diff --git a/source/UIDataCodeGen/CodeGen/CodegenConfiguration.cs b/source/UIDataCodeGen/CodeGen/CodegenConfiguration.cs index 45de7a2a..44a7840b 100644 --- a/source/UIDataCodeGen/CodeGen/CodegenConfiguration.cs +++ b/source/UIDataCodeGen/CodeGen/CodegenConfiguration.cs @@ -114,6 +114,6 @@ Version winUIVersion /// public Version WinUIVersion { get; set; } - public bool ImplementCreateAndDestroyMethods => WinUIVersion >= Version.Parse("2.8") && WinUIVersion < Version.Parse("3.0"); + public bool ImplementCreateAndDestroyMethods => WinUIVersion >= Version.Parse("2.8"); } } diff --git a/source/UIDataCodeGen/CodeGen/Cppwinrt/CppwinrtInstantiatorGenerator.cs b/source/UIDataCodeGen/CodeGen/Cppwinrt/CppwinrtInstantiatorGenerator.cs index 638afc8b..53e7c158 100644 --- a/source/UIDataCodeGen/CodeGen/Cppwinrt/CppwinrtInstantiatorGenerator.cs +++ b/source/UIDataCodeGen/CodeGen/Cppwinrt/CppwinrtInstantiatorGenerator.cs @@ -145,11 +145,11 @@ string GenerateIdlText() else { builder.WriteLine($": [default] {Interface_IAnimatedVisualSource.NormalizedQualifiedName}"); + } - if (SourceInfo.WinUIVersion >= new Version(2, 6) && SourceInfo.WinUIVersion.Major < 3) - { - builder.WriteLine($", {Interface_IAnimatedVisualSource2.NormalizedQualifiedName}"); - } + if (SourceInfo.WinUIVersion >= new Version(2, 6)) + { + builder.WriteLine($", {Interface_IAnimatedVisualSource2.NormalizedQualifiedName}"); } if (_isIDynamic) diff --git a/source/UIDataCodeGen/CodeGen/Cx/CxInstantiatorGenerator.cs b/source/UIDataCodeGen/CodeGen/Cx/CxInstantiatorGenerator.cs index 15bc559f..b6cfd945 100644 --- a/source/UIDataCodeGen/CodeGen/Cx/CxInstantiatorGenerator.cs +++ b/source/UIDataCodeGen/CodeGen/Cx/CxInstantiatorGenerator.cs @@ -71,8 +71,7 @@ public static CxCodegenResult CreateFactoryCode(CodegenConfiguration configurati _animatedVisualTypeName = Interface_IAnimatedVisual.GetQualifiedName(_s); _animatedVisualTypeName2 = Interface_IAnimatedVisual2.GetQualifiedName(_s); - // Temporary until IAnimatedVisualSource2 makes it into WinUI3. - _isAnimatedIcon = SourceInfo.WinUIVersion >= new Version(2, 6) && SourceInfo.WinUIVersion.Major < 3; + _isAnimatedIcon = SourceInfo.WinUIVersion >= new Version(2, 6); } static string FieldAssignment(string fieldName) => fieldName is not null ? $"{fieldName} = " : string.Empty; @@ -134,7 +133,7 @@ void WriteIAnimatedVisualSourceHeaderText(HeaderBuilder builder) inherits.Add(Interface_IAnimatedVisualSource.GetQualifiedName(_s)); - if (SourceInfo.WinUIVersion >= new Version(2, 6) && SourceInfo.WinUIVersion.Major < 3) + if (SourceInfo.WinUIVersion >= new Version(2, 6)) { inherits.Add(Interface_IAnimatedVisualSource2.GetQualifiedName(_s)); } @@ -372,7 +371,7 @@ void WriteIDynamicAnimatedVisualSourceHeaderText(HeaderBuilder builder) inherits.Add("Microsoft::UI::Xaml::Controls::IDynamicAnimatedVisualSource"); - if (SourceInfo.WinUIVersion >= new Version(2, 6) && SourceInfo.WinUIVersion.Major < 3) + if (SourceInfo.WinUIVersion >= new Version(2, 6)) { inherits.Add(Interface_IAnimatedVisualSource2.GetQualifiedName(_s)); } diff --git a/source/UIDataCodeGen/CodeGen/InstantiatorGeneratorBase.cs b/source/UIDataCodeGen/CodeGen/InstantiatorGeneratorBase.cs index aed75338..d9e81774 100644 --- a/source/UIDataCodeGen/CodeGen/InstantiatorGeneratorBase.cs +++ b/source/UIDataCodeGen/CodeGen/InstantiatorGeneratorBase.cs @@ -2212,7 +2212,7 @@ void WriteCallHelperCreateSpriteShape( { b.WriteLine($"{ReferenceTypeName("CompositionSpriteShape")} CreateSpriteShape({ReferenceTypeName("CompositionGeometry")} geometry, {_s.TypeMatrix3x2} transformMatrix)"); b.OpenScope(); - WriteCreateAssignment(b, node, $"_c{Deref}CreateSpriteShape(geometry)"); + b.WriteLine($"{ConstVar} result = _c{Deref}CreateSpriteShape(geometry);"); WriteSetPropertyStatement(b, "TransformMatrix", "transformMatrix"); b.WriteLine("return result;"); b.CloseScope(); @@ -2244,7 +2244,7 @@ void WriteCallHelperCreateSpriteShapeWithFillBrush( { b.WriteLine($"{ReferenceTypeName("CompositionSpriteShape")} CreateSpriteShape({ReferenceTypeName("CompositionGeometry")} geometry, {_s.TypeMatrix3x2} transformMatrix, {ReferenceTypeName("CompositionBrush")} fillBrush)"); b.OpenScope(); - WriteCreateAssignment(b, node, $"_c{Deref}CreateSpriteShape(geometry)"); + b.WriteLine($"{ConstVar} result = _c{Deref}CreateSpriteShape(geometry);"); WriteSetPropertyStatement(b, "TransformMatrix", "transformMatrix"); WriteSetPropertyStatement(b, "FillBrush", "fillBrush"); b.WriteLine("return result;");