Add support for gradient strokes. (#181)
* Add support for gradient strokes. * Make IRadialGradient compatible with pre-8.0 C# compiler. WinRT can't use C# 8.0 yet, and the "public" on interface members is a C# 8.0 feature. It was a mistake to have "public" on there anyway. * CR feedback.
This commit is contained in:
Родитель
9928d5ec25
Коммит
d0df8a8187
Двоичные данные
source/Issues/LT0007.md
Двоичные данные
source/Issues/LT0007.md
Двоичный файл не отображается.
|
@ -0,0 +1,20 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
interface IGradient
|
||||
{
|
||||
IAnimatableVector3 StartPoint { get; }
|
||||
|
||||
IAnimatableVector3 EndPoint { get; }
|
||||
|
||||
Animatable<Sequence<ColorGradientStop>> ColorStops { get; }
|
||||
|
||||
Animatable<Sequence<OpacityGradientStop>> OpacityPercentStops { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
interface IRadialGradient : IGradient
|
||||
{
|
||||
Animatable<double> HighlightLength { get; }
|
||||
|
||||
Animatable<double> HighlightDegrees { get; }
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
sealed class LinearGradientFill : ShapeFill
|
||||
sealed class LinearGradientFill : ShapeFill, IGradient
|
||||
{
|
||||
public LinearGradientFill(
|
||||
in ShapeLayerContentArgs args,
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using static Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.SolidColorStroke;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
sealed class LinearGradientStroke : ShapeStroke
|
||||
sealed class LinearGradientStroke : ShapeStroke, IGradient
|
||||
{
|
||||
public LinearGradientStroke(
|
||||
in ShapeLayerContentArgs args,
|
||||
|
@ -22,26 +20,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
IAnimatableVector3 endPoint,
|
||||
Animatable<Sequence<ColorGradientStop>> colorStops,
|
||||
Animatable<Sequence<OpacityGradientStop>> opacityPercentStops)
|
||||
: base(in args, opacityPercent)
|
||||
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
|
||||
{
|
||||
StrokeWidth = strokeWidth;
|
||||
CapType = capType;
|
||||
JoinType = joinType;
|
||||
MiterLimit = miterLimit;
|
||||
StartPoint = startPoint;
|
||||
EndPoint = endPoint;
|
||||
ColorStops = colorStops;
|
||||
OpacityPercentStops = opacityPercentStops;
|
||||
}
|
||||
|
||||
public Animatable<double> StrokeWidth { get; }
|
||||
|
||||
public LineCapType CapType { get; }
|
||||
|
||||
public LineJoinType JoinType { get; }
|
||||
|
||||
public double MiterLimit { get; }
|
||||
|
||||
public IAnimatableVector3 StartPoint { get; }
|
||||
|
||||
public IAnimatableVector3 EndPoint { get; }
|
||||
|
|
|
@ -17,11 +17,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
/// Initializes a new instance of the <see cref="LottieComposition"/> class.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the composition.</param>
|
||||
/// <param name="width">Width of animation canvas as specified in AfterEffects.</param>
|
||||
/// <param name="height">Height of animation canvas as specified in AfterEffects.</param>
|
||||
/// <param name="inPoint">Frame at which animation begins as specified in AfterEffects.</param>
|
||||
/// <param name="outPoint">Frame at which animation ends as specified in AfterEffects.</param>
|
||||
/// <param name="framesPerSecond">FrameRate (frames per second) at which animation data was generated in AfterEffects.</param>
|
||||
/// <param name="width">Width of animation canvas as specified in After Effects.</param>
|
||||
/// <param name="height">Height of animation canvas as specified in After Effects.</param>
|
||||
/// <param name="inPoint">Frame at which animation begins as specified in After Effects.</param>
|
||||
/// <param name="outPoint">Frame at which animation ends as specified in After Effects.</param>
|
||||
/// <param name="framesPerSecond">FrameRate (frames per second) at which animation data was generated in After Effects.</param>
|
||||
/// <param name="is3d">True if the composition is 3d.</param>
|
||||
/// <param name="version">The version of the schema of the composition.</param>
|
||||
/// <param name="assets">Assets that are part of the composition.</param>
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
<SharedGUID>b3db16ee-a821-4474-a188-e64926529bbd</SharedGUID>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="$(MSBuildThisFileDirectory)IGradient.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)IRadialGradient.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\Animatable.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\ExtensionMethods.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\AnimatableVector3.cs" />
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
sealed class RadialGradientFill : ShapeFill
|
||||
sealed class RadialGradientFill : ShapeFill, IRadialGradient
|
||||
{
|
||||
public RadialGradientFill(
|
||||
in ShapeLayerContentArgs args,
|
||||
|
|
|
@ -2,14 +2,12 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using static Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.SolidColorStroke;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
sealed class RadialGradientStroke : ShapeStroke
|
||||
sealed class RadialGradientStroke : ShapeStroke, IRadialGradient
|
||||
{
|
||||
public RadialGradientStroke(
|
||||
in ShapeLayerContentArgs args,
|
||||
|
@ -24,12 +22,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
Animatable<Sequence<OpacityGradientStop>> opacityPercentStops,
|
||||
Animatable<double> highlightLength,
|
||||
Animatable<double> highlightDegrees)
|
||||
: base(in args, opacityPercent)
|
||||
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
|
||||
{
|
||||
StrokeWidth = strokeWidth;
|
||||
CapType = capType;
|
||||
JoinType = joinType;
|
||||
MiterLimit = miterLimit;
|
||||
StartPoint = startPoint;
|
||||
EndPoint = endPoint;
|
||||
ColorStops = colorStops;
|
||||
|
@ -38,14 +32,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
HighlightDegrees = highlightDegrees;
|
||||
}
|
||||
|
||||
public Animatable<double> StrokeWidth { get; }
|
||||
|
||||
public LineCapType CapType { get; }
|
||||
|
||||
public LineJoinType JoinType { get; }
|
||||
|
||||
public double MiterLimit { get; }
|
||||
|
||||
public IAnimatableVector3 StartPoint { get; }
|
||||
|
||||
public IAnimatableVector3 EndPoint { get; }
|
||||
|
|
|
@ -424,7 +424,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
|
||||
yield return FromAnimatable(nameof(content.Color), content.Color);
|
||||
yield return FromAnimatable(nameof(content.OpacityPercent), content.OpacityPercent);
|
||||
yield return FromAnimatable(nameof(content.Thickness), content.Thickness);
|
||||
yield return FromAnimatable(nameof(content.StrokeWidth), content.StrokeWidth);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -346,7 +346,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
var result = superclassContent;
|
||||
result.Add("Color", FromAnimatable(content.Color, FromColor));
|
||||
result.Add("OpacityPercent", FromAnimatable(content.OpacityPercent));
|
||||
result.Add("Thickness", FromAnimatable(content.Thickness));
|
||||
result.Add("Thickness", FromAnimatable(content.StrokeWidth));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,16 +11,46 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
{
|
||||
public ShapeStroke(
|
||||
in ShapeLayerContentArgs args,
|
||||
Animatable<double> opacityPercent)
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<double> strokeWidth,
|
||||
LineCapType capType,
|
||||
LineJoinType joinType,
|
||||
double miterLimit)
|
||||
: base(in args)
|
||||
{
|
||||
OpacityPercent = opacityPercent;
|
||||
StrokeWidth = strokeWidth;
|
||||
CapType = capType;
|
||||
JoinType = joinType;
|
||||
MiterLimit = miterLimit;
|
||||
}
|
||||
|
||||
public Animatable<double> OpacityPercent { get; }
|
||||
|
||||
public Animatable<double> StrokeWidth { get; }
|
||||
|
||||
public LineCapType CapType { get; }
|
||||
|
||||
public LineJoinType JoinType { get; }
|
||||
|
||||
public double MiterLimit { get; }
|
||||
|
||||
public abstract ShapeStrokeKind StrokeKind { get; }
|
||||
|
||||
public enum LineCapType
|
||||
{
|
||||
Butt,
|
||||
Round,
|
||||
Projected,
|
||||
}
|
||||
|
||||
public enum LineJoinType
|
||||
{
|
||||
Miter,
|
||||
Round,
|
||||
Bevel,
|
||||
}
|
||||
|
||||
public enum ShapeStrokeKind
|
||||
{
|
||||
SolidColor,
|
||||
|
|
|
@ -21,35 +21,23 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
IEnumerable<double> dashPattern,
|
||||
Animatable<Color> color,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<double> thickness,
|
||||
Animatable<double> strokeWidth,
|
||||
LineCapType capType,
|
||||
LineJoinType joinType,
|
||||
double miterLimit)
|
||||
: base(in args, opacityPercent)
|
||||
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
|
||||
{
|
||||
DashOffset = dashOffset;
|
||||
_dashPattern = dashPattern.ToArray();
|
||||
Color = color;
|
||||
Thickness = thickness;
|
||||
CapType = capType;
|
||||
JoinType = joinType;
|
||||
MiterLimit = miterLimit;
|
||||
}
|
||||
|
||||
public Animatable<Color> Color { get; }
|
||||
|
||||
public Animatable<double> Thickness { get; }
|
||||
|
||||
public ReadOnlySpan<double> DashPattern => _dashPattern;
|
||||
|
||||
public Animatable<double> DashOffset { get; }
|
||||
|
||||
public LineCapType CapType { get; }
|
||||
|
||||
public LineJoinType JoinType { get; }
|
||||
|
||||
public double MiterLimit { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override ShapeContentType ContentType => ShapeContentType.SolidColorStroke;
|
||||
|
||||
|
@ -57,19 +45,5 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
public override LottieObjectType ObjectType => LottieObjectType.SolidColorStroke;
|
||||
|
||||
public override ShapeStrokeKind StrokeKind => ShapeStrokeKind.SolidColor;
|
||||
|
||||
public enum LineCapType
|
||||
{
|
||||
Butt,
|
||||
Round,
|
||||
Projected,
|
||||
}
|
||||
|
||||
public enum LineJoinType
|
||||
{
|
||||
Miter,
|
||||
Round,
|
||||
Bevel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -964,7 +964,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
|
||||
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
|
||||
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
|
||||
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in AfterEffects is 4
|
||||
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in After Effects is 4
|
||||
|
||||
// Get dash pattern to be set as StrokeDashArray
|
||||
Animatable<double> offset = null;
|
||||
|
@ -1018,8 +1018,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
|
||||
LinearGradientStroke ReadLinearGradientStroke(JObject obj, in ShapeLayerContent.ShapeLayerContentArgs shapeLayerContentArgs)
|
||||
{
|
||||
_issues.GradientStrokes();
|
||||
|
||||
// Not clear whether we need to read these fields.
|
||||
IgnoreFieldThatIsNotYetSupported(obj, "hd");
|
||||
IgnoreFieldThatIsNotYetSupported(obj, "t");
|
||||
|
@ -1029,7 +1027,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
|
||||
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
|
||||
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
|
||||
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in AfterEffects is 4
|
||||
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in After Effects is 4
|
||||
var startPoint = ReadAnimatableVector3(obj.GetNamedObject("s"));
|
||||
var endPoint = ReadAnimatableVector3(obj.GetNamedObject("e"));
|
||||
ReadAnimatableGradientStops(obj.GetNamedObject("g"), out var colorStops, out var opacityPercentStops);
|
||||
|
@ -1050,8 +1048,6 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
|
||||
RadialGradientStroke ReadRadialGradientStroke(JObject obj, in ShapeLayerContent.ShapeLayerContentArgs shapeLayerContentArgs)
|
||||
{
|
||||
_issues.GradientStrokes();
|
||||
|
||||
// Not clear whether we need to read these fields.
|
||||
IgnoreFieldThatIsNotYetSupported(obj, "t");
|
||||
|
||||
|
@ -1077,7 +1073,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
|
||||
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
|
||||
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
|
||||
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in AfterEffects is 4
|
||||
var miterLimit = obj.GetNamedNumber("ml", 4); // Default miter limit in After Effects is 4
|
||||
var startPoint = ReadAnimatableVector3(obj.GetNamedObject("s"));
|
||||
var endPoint = ReadAnimatableVector3(obj.GetNamedObject("e"));
|
||||
ReadAnimatableGradientStops(obj.GetNamedObject("g"), out var colorStops, out var opacityPercentStops);
|
||||
|
|
|
@ -1146,7 +1146,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
readonly LottieToWinCompTranslator _owner;
|
||||
|
||||
internal SolidColorStroke Stroke { get; private set; }
|
||||
internal ShapeStroke Stroke { get; private set; }
|
||||
|
||||
internal ShapeFill Fill { get; private set; }
|
||||
|
||||
|
@ -1176,19 +1176,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
var popped = stack.Peek();
|
||||
switch (popped.ContentType)
|
||||
{
|
||||
case ShapeContentType.LinearGradientStroke:
|
||||
case ShapeContentType.RadialGradientStroke:
|
||||
_owner._issues.GradientStrokeIsNotSupported();
|
||||
break;
|
||||
|
||||
case ShapeContentType.LinearGradientFill:
|
||||
case ShapeContentType.RadialGradientFill:
|
||||
case ShapeContentType.SolidColorFill:
|
||||
Fill = ComposeFills(Fill, (ShapeFill)popped);
|
||||
break;
|
||||
|
||||
case ShapeContentType.LinearGradientStroke:
|
||||
case ShapeContentType.RadialGradientStroke:
|
||||
case ShapeContentType.SolidColorStroke:
|
||||
Stroke = ComposeStrokes(Stroke, (SolidColorStroke)popped);
|
||||
Stroke = ComposeStrokes(Stroke, (ShapeStroke)popped);
|
||||
break;
|
||||
|
||||
case ShapeContentType.RoundedCorner:
|
||||
|
@ -1389,7 +1386,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return b;
|
||||
}
|
||||
|
||||
SolidColorStroke ComposeStrokes(SolidColorStroke a, SolidColorStroke b)
|
||||
ShapeStroke ComposeStrokes(ShapeStroke a, ShapeStroke b)
|
||||
{
|
||||
if (a == null)
|
||||
{
|
||||
|
@ -1400,11 +1397,69 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return a;
|
||||
}
|
||||
|
||||
if (!a.Thickness.IsAnimated && !b.Thickness.IsAnimated &&
|
||||
if (a.StrokeKind != b.StrokeKind)
|
||||
{
|
||||
_owner._issues.MultipleStrokesIsNotSupported();
|
||||
}
|
||||
|
||||
switch (a.StrokeKind)
|
||||
{
|
||||
case ShapeStroke.ShapeStrokeKind.SolidColor:
|
||||
return ComposeSolidColorStrokes((SolidColorStroke)a, (SolidColorStroke)b);
|
||||
case ShapeStroke.ShapeStrokeKind.LinearGradient:
|
||||
return ComposeLinearGradientStrokes((LinearGradientStroke)a, (LinearGradientStroke)b);
|
||||
case ShapeStroke.ShapeStrokeKind.RadialGradient:
|
||||
return ComposeRadialGradientStrokes((RadialGradientStroke)a, (RadialGradientStroke)b);
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
LinearGradientStroke ComposeLinearGradientStrokes(LinearGradientStroke a, LinearGradientStroke b)
|
||||
{
|
||||
Debug.Assert(a != null && b != null, "Precondition");
|
||||
|
||||
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
|
||||
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
|
||||
{
|
||||
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
|
||||
{
|
||||
// a occludes b, so b can be ignored.
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
_owner._issues.MultipleStrokesIsNotSupported();
|
||||
return a;
|
||||
}
|
||||
|
||||
RadialGradientStroke ComposeRadialGradientStrokes(RadialGradientStroke a, RadialGradientStroke b)
|
||||
{
|
||||
Debug.Assert(a != null && b != null, "Precondition");
|
||||
|
||||
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
|
||||
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
|
||||
{
|
||||
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
|
||||
{
|
||||
// a occludes b, so b can be ignored.
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
_owner._issues.MultipleStrokesIsNotSupported();
|
||||
return a;
|
||||
}
|
||||
|
||||
SolidColorStroke ComposeSolidColorStrokes(SolidColorStroke a, SolidColorStroke b)
|
||||
{
|
||||
Debug.Assert(a != null && b != null, "Precondition");
|
||||
|
||||
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
|
||||
!a.DashPattern.Any() && !b.DashPattern.Any() &&
|
||||
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
|
||||
{
|
||||
if (a.Thickness.InitialValue >= b.Thickness.InitialValue)
|
||||
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
|
||||
{
|
||||
// a occludes b, so b can be ignored.
|
||||
return a;
|
||||
|
@ -2581,39 +2636,73 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
void TranslateAndApplyStroke(
|
||||
TranslationContext context,
|
||||
SolidColorStroke shapeStroke,
|
||||
ShapeStroke shapeStroke,
|
||||
CompositionSpriteShape sprite,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
{
|
||||
if (shapeStroke == null || shapeStroke.Thickness.AlwaysEquals(0))
|
||||
if (shapeStroke == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// A ShapeStroke is represented as a CompositionColorBrush and Stroke properties on the relevant SpriteShape.
|
||||
// Map ShapeStroke's color to SpriteShape.StrokeBrush
|
||||
sprite.StrokeBrush = CreateAnimatedColorBrush(
|
||||
if (shapeStroke.StrokeWidth.AlwaysEquals(0))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
switch (shapeStroke.StrokeKind)
|
||||
{
|
||||
case ShapeStroke.ShapeStrokeKind.SolidColor:
|
||||
TranslateAndApplySolidColorStroke(context, (SolidColorStroke)shapeStroke, sprite, contextOpacityPercent);
|
||||
break;
|
||||
case ShapeStroke.ShapeStrokeKind.LinearGradient:
|
||||
TranslateAndApplyLinearGradientStroke(context, (LinearGradientStroke)shapeStroke, sprite, contextOpacityPercent);
|
||||
break;
|
||||
case ShapeStroke.ShapeStrokeKind.RadialGradient:
|
||||
TranslateAndApplyRadialGradientStroke(context, (RadialGradientStroke)shapeStroke, sprite, contextOpacityPercent);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
void TranslateAndApplyLinearGradientStroke(
|
||||
TranslationContext context,
|
||||
LinearGradientStroke shapeStroke,
|
||||
CompositionSpriteShape sprite,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
{
|
||||
ApplyCommonStrokeProperties(
|
||||
context,
|
||||
MultiplyAnimatableColorByAnimatableOpacityPercent(
|
||||
context.TrimAnimatable(shapeStroke.Color),
|
||||
context.TrimAnimatable(shapeStroke.OpacityPercent)),
|
||||
contextOpacityPercent);
|
||||
shapeStroke,
|
||||
TranslateLinearGradientStroke(context, shapeStroke, contextOpacityPercent),
|
||||
sprite);
|
||||
}
|
||||
|
||||
var strokeThickness = context.TrimAnimatable(shapeStroke.Thickness);
|
||||
if (strokeThickness.IsAnimated)
|
||||
{
|
||||
ApplyScalarKeyFrameAnimation(context, strokeThickness, sprite, nameof(sprite.StrokeThickness));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.StrokeThickness = (float)strokeThickness.InitialValue;
|
||||
}
|
||||
void TranslateAndApplyRadialGradientStroke(
|
||||
TranslationContext context,
|
||||
RadialGradientStroke shapeStroke,
|
||||
CompositionSpriteShape sprite,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
{
|
||||
ApplyCommonStrokeProperties(
|
||||
context,
|
||||
shapeStroke,
|
||||
TranslateRadialGradientStroke(context, shapeStroke, contextOpacityPercent),
|
||||
sprite);
|
||||
}
|
||||
|
||||
sprite.StrokeStartCap = sprite.StrokeEndCap = sprite.StrokeDashCap = StrokeCap(shapeStroke.CapType);
|
||||
|
||||
sprite.StrokeLineJoin = StrokeLineJoin(shapeStroke.JoinType);
|
||||
|
||||
sprite.StrokeMiterLimit = (float)shapeStroke.MiterLimit;
|
||||
void TranslateAndApplySolidColorStroke(
|
||||
TranslationContext context,
|
||||
SolidColorStroke shapeStroke,
|
||||
CompositionSpriteShape sprite,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
{
|
||||
ApplyCommonStrokeProperties(
|
||||
context,
|
||||
shapeStroke,
|
||||
TranslateSolidColor(context, shapeStroke.Color, shapeStroke.OpacityPercent, contextOpacityPercent),
|
||||
sprite);
|
||||
|
||||
// NOTE: DashPattern animation (animating dash sizes) are not supported on CompositionSpriteShape.
|
||||
foreach (var dash in shapeStroke.DashPattern)
|
||||
|
@ -2633,6 +2722,32 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
}
|
||||
}
|
||||
|
||||
// Applies the properties that are common to all Lottie ShapeStrokes to a CompositionSpriteShape.
|
||||
void ApplyCommonStrokeProperties(
|
||||
TranslationContext context,
|
||||
ShapeStroke shapeStroke,
|
||||
CompositionBrush brush,
|
||||
CompositionSpriteShape sprite)
|
||||
{
|
||||
var strokeThickness = context.TrimAnimatable(shapeStroke.StrokeWidth);
|
||||
if (strokeThickness.IsAnimated)
|
||||
{
|
||||
ApplyScalarKeyFrameAnimation(context, strokeThickness, sprite, nameof(sprite.StrokeThickness));
|
||||
}
|
||||
else
|
||||
{
|
||||
sprite.StrokeThickness = (float)strokeThickness.InitialValue;
|
||||
}
|
||||
|
||||
sprite.StrokeStartCap = sprite.StrokeEndCap = sprite.StrokeDashCap = StrokeCap(shapeStroke.CapType);
|
||||
|
||||
sprite.StrokeLineJoin = StrokeLineJoin(shapeStroke.JoinType);
|
||||
|
||||
sprite.StrokeMiterLimit = (float)shapeStroke.MiterLimit;
|
||||
|
||||
sprite.StrokeBrush = brush;
|
||||
}
|
||||
|
||||
CompositionBrush TranslateShapeFill(TranslationContext context, ShapeFill shapeFill, TrimmedAnimatable<double> opacityPercent)
|
||||
{
|
||||
if (shapeFill == null)
|
||||
|
@ -2653,30 +2768,26 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
}
|
||||
}
|
||||
|
||||
CompositionColorBrush TranslateSolidColorFill(TranslationContext context, SolidColorFill shapeFill, TrimmedAnimatable<double> opacityPercent)
|
||||
CompositionColorBrush TranslateSolidColor(TranslationContext context, Animatable<Color> color, Animatable<double> opacityPercentA, TrimmedAnimatable<double> opacityPercentB)
|
||||
{
|
||||
return CreateAnimatedColorBrush(
|
||||
context,
|
||||
MultiplyAnimatableColorByAnimatableOpacityPercent(
|
||||
context.TrimAnimatable(shapeFill.Color),
|
||||
context.TrimAnimatable(shapeFill.OpacityPercent)),
|
||||
opacityPercent);
|
||||
context.TrimAnimatable(color),
|
||||
context.TrimAnimatable(opacityPercentA)),
|
||||
opacityPercentB);
|
||||
}
|
||||
|
||||
CompositionColorBrush TranslateSolidColorFill(TranslationContext context, SolidColorFill shapeFill, TrimmedAnimatable<double> opacityPercent)
|
||||
=> TranslateSolidColor(context, shapeFill.Color, shapeFill.OpacityPercent, opacityPercent);
|
||||
|
||||
CompositionLinearGradientBrush TranslateLinearGradientFill(
|
||||
TranslationContext context,
|
||||
LinearGradientFill shapeFill,
|
||||
TrimmedAnimatable<double> opacityPercent)
|
||||
{
|
||||
var colorStops = context.TrimAnimatable(shapeFill.ColorStops);
|
||||
var opacityPercentStops = context.TrimAnimatable(shapeFill.OpacityPercentStops);
|
||||
|
||||
if (colorStops.InitialValue.Items.IsEmpty)
|
||||
{
|
||||
// If there are no color stops then we can't create a brush.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (opacityPercent.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with LinearGradientFill.
|
||||
|
@ -2689,15 +2800,90 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
_issues.GradientFillIsNotSupported("Linear", "opacity stops");
|
||||
}
|
||||
|
||||
var opacityPercentValue = opacityPercent.InitialValue;
|
||||
|
||||
return TranslateLinearGradientFill(context, shapeFill, colorStops, opacityPercentValue);
|
||||
return TranslateLinearGradient(
|
||||
context,
|
||||
shapeFill,
|
||||
opacityPercent.InitialValue);
|
||||
}
|
||||
|
||||
CompositionLinearGradientBrush TranslateLinearGradientFill(
|
||||
CompositionGradientBrush TranslateLinearGradientStroke(
|
||||
TranslationContext context,
|
||||
LinearGradientFill shapeFill,
|
||||
TrimmedAnimatable<Sequence<ColorGradientStop>> colorStops,
|
||||
LinearGradientStroke shapeStroke,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
{
|
||||
var opacityPercentStops = context.TrimAnimatable(shapeStroke.OpacityPercentStops);
|
||||
|
||||
if (contextOpacityPercent.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with LinearGradientFill.
|
||||
_issues.GradientStrokeIsNotSupported("Linear", "animated opacity");
|
||||
}
|
||||
|
||||
if (!opacityPercentStops.InitialValue.Items.IsEmpty)
|
||||
{
|
||||
// We don't yet support opacity stops.
|
||||
_issues.GradientStrokeIsNotSupported("Linear", "opacity stops");
|
||||
}
|
||||
|
||||
return TranslateLinearGradient(
|
||||
context,
|
||||
shapeStroke,
|
||||
contextOpacityPercent.InitialValue);
|
||||
}
|
||||
|
||||
CompositionBrush TranslateRadialGradientFill(
|
||||
TranslationContext context,
|
||||
RadialGradientFill shapeFill,
|
||||
TrimmedAnimatable<double> opacityPercent)
|
||||
{
|
||||
var opacityPercentStops = context.TrimAnimatable(shapeFill.OpacityPercentStops);
|
||||
|
||||
if (opacityPercent.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with RadialGradientFill.
|
||||
_issues.GradientFillIsNotSupported("Radial", "animated opacity");
|
||||
}
|
||||
|
||||
if (!opacityPercentStops.InitialValue.Items.IsEmpty)
|
||||
{
|
||||
// We don't yet support opacity stops.
|
||||
_issues.GradientFillIsNotSupported("Radial", "opacity stops");
|
||||
}
|
||||
|
||||
return TranslateRadialGradient(
|
||||
context,
|
||||
shapeFill,
|
||||
opacityPercent.InitialValue);
|
||||
}
|
||||
|
||||
CompositionGradientBrush TranslateRadialGradientStroke(
|
||||
TranslationContext context,
|
||||
RadialGradientStroke shapeStroke,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
{
|
||||
var opacityPercentStops = context.TrimAnimatable(shapeStroke.OpacityPercentStops);
|
||||
|
||||
if (contextOpacityPercent.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with RadialGradientStroke.
|
||||
_issues.GradientStrokeIsNotSupported("Radial", "animated opacity");
|
||||
}
|
||||
|
||||
if (!opacityPercentStops.InitialValue.Items.IsEmpty)
|
||||
{
|
||||
// We don't yet support opacity stops.
|
||||
_issues.GradientStrokeIsNotSupported("Radial", "opacity stops");
|
||||
}
|
||||
|
||||
return TranslateRadialGradient(
|
||||
context,
|
||||
shapeStroke,
|
||||
contextOpacityPercent.InitialValue);
|
||||
}
|
||||
|
||||
CompositionLinearGradientBrush TranslateLinearGradient(
|
||||
TranslationContext context,
|
||||
IGradient linearGradient,
|
||||
double opacityPercentValue)
|
||||
{
|
||||
var result = _c.CreateLinearGradientBrush();
|
||||
|
@ -2705,8 +2891,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
// BodyMovin specifies start and end points in absolute values.
|
||||
result.MappingMode = CompositionMappingMode.Absolute;
|
||||
|
||||
var startPoint = context.TrimAnimatable(shapeFill.StartPoint);
|
||||
var endPoint = context.TrimAnimatable(shapeFill.EndPoint);
|
||||
var startPoint = context.TrimAnimatable(linearGradient.StartPoint);
|
||||
var endPoint = context.TrimAnimatable(linearGradient.EndPoint);
|
||||
|
||||
if (startPoint.IsAnimated)
|
||||
{
|
||||
|
@ -2728,6 +2914,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
var brushStops = result.ColorStops;
|
||||
|
||||
var colorStops = context.TrimAnimatable(linearGradient.ColorStops);
|
||||
|
||||
if (colorStops.InitialValue.Items.IsEmpty)
|
||||
{
|
||||
// If there are no color stops then we can't create a brush.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (colorStops.IsAnimated)
|
||||
{
|
||||
// Lottie represents animation of stops as a sequence of lists of stops.
|
||||
|
@ -2776,73 +2970,25 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return result;
|
||||
}
|
||||
|
||||
CompositionBrush TranslateRadialGradientFill(
|
||||
CompositionGradientBrush TranslateRadialGradient(
|
||||
TranslationContext context,
|
||||
RadialGradientFill shapeFill,
|
||||
TrimmedAnimatable<double> opacityPercent)
|
||||
{
|
||||
var colorStops = context.TrimAnimatable(shapeFill.ColorStops);
|
||||
var opacityPercentStops = context.TrimAnimatable(shapeFill.OpacityPercentStops);
|
||||
|
||||
if (colorStops.InitialValue.Items.IsEmpty)
|
||||
{
|
||||
// If there are no color stops then we can't create a brush.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (opacityPercent.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with RadialGradientFill.
|
||||
_issues.GradientFillIsNotSupported("Radial", "animated opacity");
|
||||
}
|
||||
|
||||
if (!opacityPercentStops.InitialValue.Items.IsEmpty)
|
||||
{
|
||||
// We don't yet support opacity stops.
|
||||
_issues.GradientFillIsNotSupported("Radial", "opacity stops");
|
||||
}
|
||||
|
||||
var opacityPercentValue = opacityPercent.InitialValue;
|
||||
|
||||
if (IsUapApiAvailable(nameof(CompositionRadialGradientBrush), versionDependentFeatureDescription: "Radial gradient fill"))
|
||||
{
|
||||
return TranslateRadialGradientFillToCompositionRadialGradientBrush(context, shapeFill, colorStops, opacityPercentValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Radial gradient is not available. Convert the RadialGradientFill to a LinearGradientFill as a compromise.
|
||||
var fillArgs = new ShapeLayerContent.ShapeLayerContentArgs()
|
||||
{
|
||||
BlendMode = shapeFill.BlendMode,
|
||||
MatchName = shapeFill.MatchName,
|
||||
Name = shapeFill.Name,
|
||||
};
|
||||
var linearFill = new LinearGradientFill(
|
||||
in fillArgs,
|
||||
shapeFill.FillType,
|
||||
shapeFill.OpacityPercent,
|
||||
shapeFill.StartPoint,
|
||||
shapeFill.EndPoint,
|
||||
shapeFill.ColorStops,
|
||||
shapeFill.OpacityPercentStops);
|
||||
|
||||
return TranslateLinearGradientFill(context, linearFill, opacityPercent);
|
||||
}
|
||||
}
|
||||
|
||||
CompositionRadialGradientBrush TranslateRadialGradientFillToCompositionRadialGradientBrush(
|
||||
TranslationContext context,
|
||||
RadialGradientFill shapeFill,
|
||||
TrimmedAnimatable<Sequence<ColorGradientStop>> colorStops,
|
||||
IRadialGradient gradient,
|
||||
double opacityPercentValue)
|
||||
{
|
||||
if (!IsUapApiAvailable(nameof(CompositionRadialGradientBrush), versionDependentFeatureDescription: "Radial gradient fill"))
|
||||
{
|
||||
// CompositionRadialGradientBrush didn't exist until UAP v8. If the target OS doesn't support
|
||||
// UAP v8 then fall back to linear gradients as a compromise.
|
||||
return TranslateLinearGradient(context, gradient, opacityPercentValue);
|
||||
}
|
||||
|
||||
var result = _c.CreateRadialGradientBrush();
|
||||
|
||||
// BodyMovin specifies start and end points in absolute values.
|
||||
result.MappingMode = CompositionMappingMode.Absolute;
|
||||
|
||||
var startPoint = context.TrimAnimatable(shapeFill.StartPoint);
|
||||
var endPoint = context.TrimAnimatable(shapeFill.EndPoint);
|
||||
var startPoint = context.TrimAnimatable(gradient.StartPoint);
|
||||
var endPoint = context.TrimAnimatable(gradient.EndPoint);
|
||||
|
||||
if (startPoint.IsAnimated)
|
||||
{
|
||||
|
@ -2861,14 +3007,21 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
result.EllipseRadius = new Sn.Vector2(Sn.Vector2.Distance(Vector2(startPoint.InitialValue), Vector2(endPoint.InitialValue)));
|
||||
|
||||
if (shapeFill.HighlightLength != null &&
|
||||
(shapeFill.HighlightLength.InitialValue != 0 || shapeFill.HighlightLength.IsAnimated))
|
||||
if (gradient.HighlightLength != null &&
|
||||
(gradient.HighlightLength.InitialValue != 0 || gradient.HighlightLength.IsAnimated))
|
||||
{
|
||||
// We don't yet support animated HighlightLength.
|
||||
_issues.GradientFillIsNotSupported("Radial", "animated highlight length");
|
||||
}
|
||||
|
||||
var brushStops = result.ColorStops;
|
||||
var colorStops = context.TrimAnimatable(gradient.ColorStops);
|
||||
|
||||
if (colorStops.InitialValue.Items.IsEmpty)
|
||||
{
|
||||
// If there are no color stops then we can't create a brush.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (colorStops.IsAnimated)
|
||||
{
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
internal void GradientFillIsNotSupported(string linearOrRadial, string combination) => Report("LT0006", $"{linearOrRadial} gradient fill with {combination} is not supported.");
|
||||
|
||||
internal void GradientStrokeIsNotSupported() => Report("LT0007", "Gradient stroke is not supported.");
|
||||
internal void GradientStrokeIsNotSupported(string linearOrRadial, string combination) => Report("LT0007", $"{linearOrRadial} gradient stroke with {combination} is not supported.");
|
||||
|
||||
internal void ImageLayerIsNotSupported() => Report("LT0009", "Image layers are not supported.");
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче