Strong type of Lottie Opacity. (#219)
Opacity is special because it's expressed in Lottie as a percent, which is inconvenient for multiplication with alpha. Giving an Opacity a strong type allows us to abstract the percent details, and also make the translator clearer because it's obvious where a value is being used for opacity.
This commit is contained in:
Родитель
f19e3156d0
Коммит
55399f90f6
|
@ -50,8 +50,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
/// Return the color with the given opacity multiplied into the alpha channel.
|
||||
/// </summary>
|
||||
/// <returns>The color with the given opacity multiplied into the alpha channel.</returns>
|
||||
public Color MultipliedByOpacity(double opacity)
|
||||
=> opacity == 1 ? this : new Color(opacity * A, R, G, B);
|
||||
public Color MultipliedByOpacity(Opacity opacity)
|
||||
=> opacity.IsOpaque ? this : new Color(opacity.Value * A, R, G, B);
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override bool Equals(object obj) => obj is Color && Equals((Color)obj);
|
||||
|
|
|
@ -100,5 +100,21 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Opacity Max<TSource>(this ReadOnlySpan<TSource> source, Func<TSource, Opacity> selector)
|
||||
{
|
||||
var result = Opacity.Transparent;
|
||||
|
||||
foreach (var item in source)
|
||||
{
|
||||
var candidate = selector(item);
|
||||
if (candidate > result)
|
||||
{
|
||||
result = candidate;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,11 +12,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
public LinearGradientFill(
|
||||
in ShapeLayerContentArgs args,
|
||||
PathFillType fillType,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<Opacity> opacity,
|
||||
IAnimatableVector3 startPoint,
|
||||
IAnimatableVector3 endPoint,
|
||||
Animatable<Sequence<GradientStop>> gradientStops)
|
||||
: base(in args, fillType, opacityPercent)
|
||||
: base(in args, fillType, opacity)
|
||||
{
|
||||
StartPoint = startPoint;
|
||||
EndPoint = endPoint;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
{
|
||||
public LinearGradientStroke(
|
||||
in ShapeLayerContentArgs args,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<Opacity> opacity,
|
||||
Animatable<double> strokeWidth,
|
||||
LineCapType capType,
|
||||
LineJoinType joinType,
|
||||
|
@ -19,7 +19,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
IAnimatableVector3 startPoint,
|
||||
IAnimatableVector3 endPoint,
|
||||
Animatable<Sequence<GradientStop>> gradientStops)
|
||||
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
|
||||
: base(in args, opacity, strokeWidth, capType, joinType, miterLimit)
|
||||
{
|
||||
StartPoint = startPoint;
|
||||
EndPoint = endPoint;
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
<Compile Include="$(MSBuildThisFileDirectory)\Mask.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\MergePaths.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\NullLayer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\Opacity.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\OpacityGradientStop.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\Optimization\GradientStopOptimizer.cs" />
|
||||
<Compile Include="$(MSBuildThisFileDirectory)\Optimization\Optimizer.cs" />
|
||||
|
|
|
@ -16,14 +16,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
bool inverted,
|
||||
string name,
|
||||
Animatable<Sequence<BezierSegment>> points,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<Opacity> opacity,
|
||||
MaskMode mode
|
||||
)
|
||||
{
|
||||
Inverted = inverted;
|
||||
Name = name;
|
||||
Points = points;
|
||||
OpacityPercent = opacityPercent;
|
||||
Opacity = opacity;
|
||||
Mode = mode;
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
|
||||
public Animatable<Sequence<BezierSegment>> Points { get; }
|
||||
|
||||
public Animatable<double> OpacityPercent { get; }
|
||||
public Animatable<Opacity> Opacity { get; }
|
||||
|
||||
public MaskMode Mode { get; }
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
// 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.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
||||
{
|
||||
/// <summary>
|
||||
/// A percentage value.
|
||||
/// </summary>
|
||||
#if PUBLIC_LottieData
|
||||
public
|
||||
#endif
|
||||
struct Opacity : IEquatable<Opacity>
|
||||
{
|
||||
Opacity(double value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public bool IsOpaque => Value == 1;
|
||||
|
||||
public bool IsTransparent => Value == 0;
|
||||
|
||||
public static Opacity Opaque { get; } = new Opacity(1);
|
||||
|
||||
public double Percent => Value * 100;
|
||||
|
||||
public static Opacity Transparent { get; } = new Opacity(0);
|
||||
|
||||
public double Value { get; }
|
||||
|
||||
public static Opacity FromFloat(double value) => new Opacity(value);
|
||||
|
||||
public static Opacity operator *(Opacity left, Opacity right) => new Opacity(left.Value * right.Value);
|
||||
|
||||
public static Opacity operator *(Opacity opacity, double scale) => new Opacity(opacity.Value * scale);
|
||||
|
||||
public static bool operator >(Opacity left, Opacity right) => left.Value > right.Value;
|
||||
|
||||
public static bool operator <(Opacity left, Opacity right) => left.Value < right.Value;
|
||||
|
||||
public static bool operator ==(Opacity left, Opacity right) => left.Value == right.Value;
|
||||
|
||||
public static bool operator !=(Opacity left, Opacity right) => left.Value != right.Value;
|
||||
|
||||
public bool Equals(Opacity other) => other.Value == Value;
|
||||
|
||||
public override bool Equals(object obj) => obj is Opacity other ? other.Equals(this) : false;
|
||||
|
||||
public override int GetHashCode() => Value.GetHashCode();
|
||||
|
||||
public override string ToString() => $"{Percent}%";
|
||||
}
|
||||
}
|
|
@ -9,18 +9,18 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
#endif
|
||||
sealed class OpacityGradientStop : GradientStop
|
||||
{
|
||||
public OpacityGradientStop(double offset, double opacityPercent)
|
||||
public OpacityGradientStop(double offset, Opacity opacity)
|
||||
: base(offset)
|
||||
{
|
||||
OpacityPercent = opacityPercent;
|
||||
Opacity = opacity;
|
||||
}
|
||||
|
||||
public double OpacityPercent { get; }
|
||||
public Opacity Opacity { get; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override GradientStopKind Kind => GradientStopKind.Opacity;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override string ToString() => $"{OpacityPercent}%@{Offset}";
|
||||
public override string ToString() => $"{Opacity.Percent}%@{Offset}";
|
||||
}
|
||||
}
|
|
@ -63,7 +63,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
|
|||
// The stop is either an OpacityGradientStop or a ColorGradientStop. Convert to a ColorGradientStop
|
||||
// by interpolating the color or opacity as necessary.
|
||||
Color color;
|
||||
double opacityPercent;
|
||||
Opacity opacity;
|
||||
|
||||
if (currentStop.Kind == GradientStop.GradientStopKind.Color)
|
||||
{
|
||||
|
@ -80,7 +80,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
|
|||
orderedStops[i + 1].Offset == currentStop.Offset &&
|
||||
orderedStops[i + 1].Kind == GradientStop.GradientStopKind.Opacity)
|
||||
{
|
||||
opacityPercent = ((OpacityGradientStop)orderedStops[i + 1]).OpacityPercent;
|
||||
opacity = ((OpacityGradientStop)orderedStops[i + 1]).Opacity;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -102,16 +102,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
|
|||
if (previousOpacityStop == null)
|
||||
{
|
||||
// There is no previous opacity stop. Use the next opacity
|
||||
// stop if there is one, or 100% if there are no opacity stops.
|
||||
opacityPercent = nextOpacityStop?.OpacityPercent ?? 100;
|
||||
// stop if there is one, or Opaque if there are no opacity stops.
|
||||
opacity = nextOpacityStop?.Opacity ?? Opacity.Opaque;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If there's a following opacity stop, interpolate between previous
|
||||
// and next, otherwise continue using the previous opacity.
|
||||
opacityPercent = nextOpacityStop == null
|
||||
? previousOpacityStop.OpacityPercent
|
||||
: InterpolateOpacityPercent(previousOpacityStop, nextOpacityStop, currentStop.Offset);
|
||||
opacity = nextOpacityStop == null
|
||||
? previousOpacityStop.Opacity
|
||||
: InterpolateOpacity(previousOpacityStop, nextOpacityStop, currentStop.Offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
|
|||
// The stop is an OpacityGradientStop. Get the opacity value directly from the stop,
|
||||
// and interpolate the color value from the surrounding ColorStops.
|
||||
var currentOpacityStop = previousOpacityStop = (OpacityGradientStop)currentStop;
|
||||
opacityPercent = previousOpacityStop.OpacityPercent;
|
||||
opacity = previousOpacityStop.Opacity;
|
||||
|
||||
// Invalidate nextOpacityStop to force a search for the next opacity stop.
|
||||
nextOpacityStop = null;
|
||||
|
@ -166,7 +166,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
|
|||
}
|
||||
}
|
||||
|
||||
yield return new ColorGradientStop(currentStop.Offset, color.MultipliedByOpacity(opacityPercent / 100.0));
|
||||
yield return new ColorGradientStop(currentStop.Offset, color.MultipliedByOpacity(opacity));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -190,8 +190,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Optimization
|
|||
=> a.y + ((x - a.x) * ((b.y - a.y) / (b.x - a.x)));
|
||||
|
||||
// Returns the opacity percent at the given offset between a and b.
|
||||
static double InterpolateOpacityPercent(OpacityGradientStop a, OpacityGradientStop b, double atOffset)
|
||||
=> Lerp((a.Offset, a.OpacityPercent / 100.0), (b.Offset, b.OpacityPercent / 100.0), atOffset) * 100;
|
||||
static Opacity InterpolateOpacity(OpacityGradientStop a, OpacityGradientStop b, double atOffset)
|
||||
=> Opacity.FromFloat(Lerp((a.Offset, a.Opacity.Value), (b.Offset, b.Opacity.Value), atOffset));
|
||||
|
||||
// Returns the color at the given offset between a and b.
|
||||
static Color InterpolateColor(ColorGradientStop a, ColorGradientStop b, double atOffset)
|
||||
|
|
|
@ -12,13 +12,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
public RadialGradientFill(
|
||||
in ShapeLayerContentArgs args,
|
||||
PathFillType fillType,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<Opacity> opacity,
|
||||
IAnimatableVector3 startPoint,
|
||||
IAnimatableVector3 endPoint,
|
||||
Animatable<Sequence<GradientStop>> gradientStops,
|
||||
Animatable<double> highlightLength,
|
||||
Animatable<double> highlightDegrees)
|
||||
: base(in args, fillType, opacityPercent)
|
||||
: base(in args, fillType, opacity)
|
||||
{
|
||||
StartPoint = startPoint;
|
||||
EndPoint = endPoint;
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
{
|
||||
public RadialGradientStroke(
|
||||
in ShapeLayerContentArgs args,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<Opacity> opacity,
|
||||
Animatable<double> strokeWidth,
|
||||
LineCapType capType,
|
||||
LineJoinType joinType,
|
||||
|
@ -21,7 +21,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
Animatable<Sequence<GradientStop>> gradientStops,
|
||||
Animatable<double> highlightLength,
|
||||
Animatable<double> highlightDegrees)
|
||||
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
|
||||
: base(in args, opacity, strokeWidth, capType, joinType, miterLimit)
|
||||
{
|
||||
StartPoint = startPoint;
|
||||
EndPoint = endPoint;
|
||||
|
|
|
@ -15,23 +15,23 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
IAnimatableVector3 position,
|
||||
IAnimatableVector3 scalePercent,
|
||||
Animatable<double> rotationDegrees,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<double> startOpacityPercent,
|
||||
Animatable<double> endOpacityPercent)
|
||||
: base(in args, anchor, position, scalePercent, rotationDegrees, opacityPercent)
|
||||
Animatable<Opacity> opacity,
|
||||
Animatable<Opacity> startOpacity,
|
||||
Animatable<Opacity> endOpacity)
|
||||
: base(in args, anchor, position, scalePercent, rotationDegrees, opacity)
|
||||
{
|
||||
StartOpacityPercent = startOpacityPercent;
|
||||
EndOpacityPercent = endOpacityPercent;
|
||||
StartOpacity = startOpacity;
|
||||
EndOpacity = endOpacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the opacity of the original shaped. Only used by <see cref="Repeater"/>.
|
||||
/// </summary>
|
||||
public Animatable<double> StartOpacityPercent { get; }
|
||||
public Animatable<Opacity> StartOpacity { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the opacity of the last copy of the original shape. Only used by <see cref="Repeater"/>.
|
||||
/// </summary>
|
||||
public Animatable<double> EndOpacityPercent { get; }
|
||||
public Animatable<Opacity> EndOpacity { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -390,7 +390,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
yield return new XAttribute(nameof(mask.Inverted), mask.Inverted);
|
||||
yield return new XAttribute(nameof(mask.Name), mask.Name);
|
||||
yield return FromAnimatable(nameof(mask.Points), mask.Points);
|
||||
yield return FromAnimatable(nameof(mask.OpacityPercent), mask.OpacityPercent);
|
||||
yield return FromAnimatable(nameof(mask.Opacity), mask.Opacity);
|
||||
yield return new XAttribute(nameof(mask.Mode), mask.Mode);
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +423,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.Opacity), content.Opacity);
|
||||
yield return FromAnimatable(nameof(content.StrokeWidth), content.StrokeWidth);
|
||||
}
|
||||
}
|
||||
|
@ -463,7 +463,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
}
|
||||
|
||||
yield return FromAnimatable("Color", content.Color);
|
||||
yield return FromAnimatable("OpacityPercent", content.OpacityPercent);
|
||||
yield return FromAnimatable("Opacity", content.Opacity);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -506,7 +506,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
yield return FromAnimatable(nameof(content.ScalePercent), content.ScalePercent);
|
||||
yield return FromAnimatable(nameof(content.Position), content.Position);
|
||||
yield return FromAnimatable(nameof(content.Anchor), content.Anchor);
|
||||
yield return FromAnimatable(nameof(content.OpacityPercent), content.OpacityPercent);
|
||||
yield return FromAnimatable(nameof(content.Opacity), content.Opacity);
|
||||
yield return FromAnimatable(nameof(content.RotationDegrees), content.RotationDegrees);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -328,7 +328,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
{ "Name", mask.Name },
|
||||
{ "Inverted", mask.Inverted },
|
||||
{ "Mode", Scalar(mask.Mode) },
|
||||
{ "OpacityPercent", FromAnimatable(mask.OpacityPercent) },
|
||||
{ "OpacityPercent", FromAnimatable(mask.Opacity, FromOpacityPercent) },
|
||||
{ "Points", FromAnimatable(mask.Points, p => FromSequence(p, FromBezierSegment)) },
|
||||
};
|
||||
return result;
|
||||
|
@ -345,7 +345,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("OpacityPercent", FromAnimatable(content.Opacity, FromOpacityPercent));
|
||||
result.Add("Thickness", FromAnimatable(content.StrokeWidth));
|
||||
return result;
|
||||
}
|
||||
|
@ -366,14 +366,14 @@ 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("OpacityPercent", FromAnimatable(content.Opacity, FromOpacityPercent));
|
||||
return result;
|
||||
}
|
||||
|
||||
YamlObject FromLinearGradientFill(LinearGradientFill content, YamlMap superclassContent)
|
||||
{
|
||||
var result = superclassContent;
|
||||
result.Add("OpacityPercent", FromAnimatable(content.OpacityPercent));
|
||||
result.Add("OpacityPercent", FromAnimatable(content.Opacity, FromOpacityPercent));
|
||||
result.Add("GradientStops", FromAnimatable(content.GradientStops, p => FromSequence(p, FromGradientStop)));
|
||||
return result;
|
||||
}
|
||||
|
@ -381,7 +381,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
YamlObject FromRadialGradientFill(RadialGradientFill content, YamlMap superclassContent)
|
||||
{
|
||||
var result = superclassContent;
|
||||
result.Add("OpacityPercent", FromAnimatable(content.OpacityPercent));
|
||||
result.Add("OpacityPercent", FromAnimatable(content.Opacity, FromOpacityPercent));
|
||||
result.Add("GradientStops", FromAnimatable(content.GradientStops, p => FromSequence(p, FromGradientStop)));
|
||||
return result;
|
||||
}
|
||||
|
@ -392,7 +392,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
result.Add("ScalePercent", FromAnimatable(content.ScalePercent));
|
||||
result.Add("Position", FromAnimatable(content.Position));
|
||||
result.Add("Anchor", FromAnimatable(content.Anchor));
|
||||
result.Add("OpacityPercent", FromAnimatable(content.OpacityPercent));
|
||||
result.Add("OpacityPercent", FromAnimatable(content.Opacity, FromOpacityPercent));
|
||||
result.Add("RotationDegrees", FromAnimatable(content.RotationDegrees));
|
||||
return result;
|
||||
}
|
||||
|
@ -440,6 +440,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
|
||||
static YamlObject FromColor(Color value) => (YamlScalar)value?.ToString();
|
||||
|
||||
static YamlObject FromOpacityPercent(Opacity value) => (YamlScalar)value.Percent;
|
||||
|
||||
static YamlObject FromVector3(Vector3 value)
|
||||
{
|
||||
var result = new YamlMap
|
||||
|
@ -500,7 +502,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
{
|
||||
var result = new YamlMap
|
||||
{
|
||||
{ "OpacityPercent", value.OpacityPercent },
|
||||
{ "OpacityPercent", value.Opacity.Percent },
|
||||
{ "Offset", value.Offset },
|
||||
};
|
||||
return result;
|
||||
|
|
|
@ -12,14 +12,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
public ShapeFill(
|
||||
in ShapeLayerContentArgs args,
|
||||
PathFillType fillType,
|
||||
Animatable<double> opacityPercent)
|
||||
Animatable<Opacity> opacity)
|
||||
: base(in args)
|
||||
{
|
||||
OpacityPercent = opacityPercent;
|
||||
Opacity = opacity;
|
||||
FillType = fillType;
|
||||
}
|
||||
|
||||
public Animatable<double> OpacityPercent { get; }
|
||||
public Animatable<Opacity> Opacity { get; }
|
||||
|
||||
public abstract ShapeFillKind FillKind { get; }
|
||||
|
||||
|
|
|
@ -11,21 +11,21 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
{
|
||||
public ShapeStroke(
|
||||
in ShapeLayerContentArgs args,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<Opacity> opacity,
|
||||
Animatable<double> strokeWidth,
|
||||
LineCapType capType,
|
||||
LineJoinType joinType,
|
||||
double miterLimit)
|
||||
: base(in args)
|
||||
{
|
||||
OpacityPercent = opacityPercent;
|
||||
Opacity = opacity;
|
||||
StrokeWidth = strokeWidth;
|
||||
CapType = capType;
|
||||
JoinType = joinType;
|
||||
MiterLimit = miterLimit;
|
||||
}
|
||||
|
||||
public Animatable<double> OpacityPercent { get; }
|
||||
public Animatable<Opacity> Opacity { get; }
|
||||
|
||||
public Animatable<double> StrokeWidth { get; }
|
||||
|
||||
|
|
|
@ -12,9 +12,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
public SolidColorFill(
|
||||
in ShapeLayerContentArgs args,
|
||||
PathFillType fillType,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<Opacity> opacity,
|
||||
Animatable<Color> color)
|
||||
: base(in args, fillType, opacityPercent)
|
||||
: base(in args, fillType, opacity)
|
||||
{
|
||||
Color = color;
|
||||
}
|
||||
|
|
|
@ -20,12 +20,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
Animatable<double> dashOffset,
|
||||
IEnumerable<double> dashPattern,
|
||||
Animatable<Color> color,
|
||||
Animatable<double> opacityPercent,
|
||||
Animatable<Opacity> opacity,
|
||||
Animatable<double> strokeWidth,
|
||||
LineCapType capType,
|
||||
LineJoinType joinType,
|
||||
double miterLimit)
|
||||
: base(in args, opacityPercent, strokeWidth, capType, joinType, miterLimit)
|
||||
: base(in args, opacity, strokeWidth, capType, joinType, miterLimit)
|
||||
{
|
||||
DashOffset = dashOffset;
|
||||
_dashPattern = dashPattern.ToArray();
|
||||
|
|
|
@ -15,14 +15,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
IAnimatableVector3 position,
|
||||
IAnimatableVector3 scalePercent,
|
||||
Animatable<double> rotationDegrees,
|
||||
Animatable<double> opacityPercent)
|
||||
Animatable<Opacity> opacity)
|
||||
: base(in args)
|
||||
{
|
||||
Anchor = anchor;
|
||||
Position = position;
|
||||
ScalePercent = scalePercent;
|
||||
RotationDegrees = rotationDegrees;
|
||||
OpacityPercent = opacityPercent;
|
||||
Opacity = opacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -39,9 +39,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData
|
|||
|
||||
public Animatable<double> RotationDegrees { get; }
|
||||
|
||||
public Animatable<double> OpacityPercent { get; }
|
||||
public Animatable<Opacity> Opacity { get; }
|
||||
|
||||
public bool IsAnimated => Anchor.IsAnimated || Position.IsAnimated || ScalePercent.IsAnimated || RotationDegrees.IsAnimated || OpacityPercent.IsAnimated;
|
||||
public bool IsAnimated => Anchor.IsAnimated || Position.IsAnimated || ScalePercent.IsAnimated || RotationDegrees.IsAnimated || Opacity.IsAnimated;
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override ShapeContentType ContentType => ShapeContentType.Transform;
|
||||
|
|
|
@ -34,6 +34,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
sealed class LottieCompositionReader
|
||||
{
|
||||
static readonly AnimatableFloatParser s_animatableFloatParser = new AnimatableFloatParser();
|
||||
static readonly AnimatableOpacityParser s_animatableOpacityParser = new AnimatableOpacityParser();
|
||||
static readonly AnimatableVector2Parser s_animatableVector2Parser = new AnimatableVector2Parser();
|
||||
static readonly AnimatableVector3Parser s_animatableVector3Parser = new AnimatableVector3Parser();
|
||||
static readonly AnimatableGeometryParser s_animatableGeometryParser = new AnimatableGeometryParser();
|
||||
|
@ -812,7 +813,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
var inverted = obj.GetNamedBoolean("inv");
|
||||
var name = ReadName(obj);
|
||||
var animatedGeometry = ReadAnimatableGeometry(obj.GetNamedObject("pt"));
|
||||
var opacityPercent = ReadAnimatableFloat(obj.GetNamedObject("o"));
|
||||
var opacity = ReadOpacityFromO(obj);
|
||||
var mode = Mask.MaskMode.None;
|
||||
var maskMode = obj.GetNamedString("mode");
|
||||
switch (maskMode)
|
||||
|
@ -848,7 +849,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
inverted,
|
||||
name,
|
||||
animatedGeometry,
|
||||
opacityPercent,
|
||||
opacity,
|
||||
mode
|
||||
);
|
||||
}
|
||||
|
@ -983,8 +984,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
IgnoreFieldThatIsNotYetSupported(obj, "fillEnabled");
|
||||
IgnoreFieldThatIsNotYetSupported(obj, "hd");
|
||||
|
||||
var color = ReadColor(obj);
|
||||
var opacityPercent = ReadOpacityPercent(obj);
|
||||
var color = ReadColorFromC(obj);
|
||||
var opacity = ReadOpacityFromO(obj);
|
||||
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
|
||||
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
|
||||
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
|
||||
|
@ -1019,7 +1020,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
offset ?? s_animatable_0,
|
||||
dashPattern,
|
||||
color,
|
||||
opacityPercent,
|
||||
opacity,
|
||||
strokeWidth,
|
||||
capType,
|
||||
joinType,
|
||||
|
@ -1047,7 +1048,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
IgnoreFieldThatIsNotYetSupported(obj, "t");
|
||||
IgnoreFieldThatIsNotYetSupported(obj, "1");
|
||||
|
||||
var opacityPercent = ReadOpacityPercent(obj);
|
||||
var opacity = ReadOpacityFromO(obj);
|
||||
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
|
||||
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
|
||||
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
|
||||
|
@ -1059,7 +1060,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
AssertAllFieldsRead(obj);
|
||||
return new LinearGradientStroke(
|
||||
in shapeLayerContentArgs,
|
||||
opacityPercent,
|
||||
opacity,
|
||||
strokeWidth,
|
||||
capType,
|
||||
joinType,
|
||||
|
@ -1092,7 +1093,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
highlightDegrees = ReadAnimatableFloat(highlightAngleObject);
|
||||
}
|
||||
|
||||
var opacityPercent = ReadOpacityPercent(obj);
|
||||
var opacity = ReadOpacityFromO(obj);
|
||||
var strokeWidth = ReadAnimatableFloat(obj.GetNamedObject("w"));
|
||||
var capType = LcToLineCapType(obj.GetNamedNumber("lc"));
|
||||
var joinType = LjToLineJoinType(obj.GetNamedNumber("lj"));
|
||||
|
@ -1104,7 +1105,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
AssertAllFieldsRead(obj);
|
||||
return new RadialGradientStroke(
|
||||
in shapeLayerContentArgs,
|
||||
opacityPercent: opacityPercent,
|
||||
opacity: opacity,
|
||||
strokeWidth: strokeWidth,
|
||||
capType: capType,
|
||||
joinType: joinType,
|
||||
|
@ -1125,11 +1126,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
IgnoreFieldThatIsNotYetSupported(obj, "hd");
|
||||
|
||||
var fillType = ReadFillType(obj);
|
||||
var opacityPercent = ReadOpacityPercent(obj);
|
||||
var color = ReadColor(obj);
|
||||
var opacity = ReadOpacityFromO(obj);
|
||||
var color = ReadColorFromC(obj);
|
||||
|
||||
AssertAllFieldsRead(obj);
|
||||
return new SolidColorFill(in shapeLayerContentArgs, fillType, opacityPercent, color);
|
||||
return new SolidColorFill(in shapeLayerContentArgs, fillType, opacity, color);
|
||||
}
|
||||
|
||||
// gf
|
||||
|
@ -1153,7 +1154,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
IgnoreFieldThatIsNotYetSupported(obj, "1");
|
||||
|
||||
var fillType = ReadFillType(obj);
|
||||
var opacityPercent = ReadOpacityPercent(obj);
|
||||
var opacity = ReadOpacityFromO(obj);
|
||||
var startPoint = ReadAnimatableVector3(obj.GetNamedObject("s"));
|
||||
var endPoint = ReadAnimatableVector3(obj.GetNamedObject("e"));
|
||||
ReadAnimatableGradientStops(obj.GetNamedObject("g"), out var gradientStops);
|
||||
|
@ -1176,7 +1177,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
return new RadialGradientFill(
|
||||
in shapeLayerContentArgs,
|
||||
fillType: fillType,
|
||||
opacityPercent: opacityPercent,
|
||||
opacity: opacity,
|
||||
startPoint: startPoint,
|
||||
endPoint: endPoint,
|
||||
gradientStops: gradientStops,
|
||||
|
@ -1190,7 +1191,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
IgnoreFieldThatIsNotYetSupported(obj, "hd");
|
||||
|
||||
var fillType = ReadFillType(obj);
|
||||
var opacityPercent = ReadOpacityPercent(obj);
|
||||
var opacity = ReadOpacityFromO(obj);
|
||||
var startPoint = ReadAnimatableVector3(obj.GetNamedObject("s"));
|
||||
var endPoint = ReadAnimatableVector3(obj.GetNamedObject("e"));
|
||||
ReadAnimatableGradientStops(obj.GetNamedObject("g"), out var gradientStops);
|
||||
|
@ -1199,7 +1200,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
return new LinearGradientFill(
|
||||
in shapeLayerContentArgs,
|
||||
fillType: fillType,
|
||||
opacityPercent: opacityPercent,
|
||||
opacity: opacity,
|
||||
startPoint: startPoint,
|
||||
endPoint: endPoint,
|
||||
gradientStops: gradientStops);
|
||||
|
@ -1386,21 +1387,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
return isWindingFill ? ShapeFill.PathFillType.Winding : ShapeFill.PathFillType.EvenOdd;
|
||||
}
|
||||
|
||||
Animatable<double> ReadOpacityPercent(JObject obj)
|
||||
{
|
||||
var jsonOpacity = obj.GetNamedObject("o", null);
|
||||
return ReadOpacityPercentFromObject(jsonOpacity);
|
||||
}
|
||||
|
||||
Animatable<double> ReadOpacityPercentFromObject(JObject obj)
|
||||
{
|
||||
var result = obj != null
|
||||
? ReadAnimatableFloat(obj)
|
||||
: new Animatable<double>(100, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
Animatable<Color> ReadColor(JObject obj) =>
|
||||
Animatable<Color> ReadColorFromC(JObject obj) =>
|
||||
ReadAnimatableColor(obj.GetNamedObject("c", null));
|
||||
|
||||
Animatable<Color> ReadAnimatableColor(JObject obj)
|
||||
|
@ -1423,8 +1410,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
// except they have an extra couple properties.
|
||||
RepeaterTransform ReadRepeaterTransform(JObject obj, in ShapeLayerContent.ShapeLayerContentArgs shapeLayerContentArgs)
|
||||
{
|
||||
var startOpacityPercent = ReadOpacityPercentFromObject(obj.GetNamedObject("so", null));
|
||||
var endOpacityPercent = ReadOpacityPercentFromObject(obj.GetNamedObject("eo", null));
|
||||
var startOpacity = ReadOpacityFromObject(obj.GetNamedObject("so", null));
|
||||
var endOpacity = ReadOpacityFromObject(obj.GetNamedObject("eo", null));
|
||||
var transform = ReadTransform(obj, in shapeLayerContentArgs);
|
||||
return new RepeaterTransform(
|
||||
in shapeLayerContentArgs,
|
||||
|
@ -1432,9 +1419,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
transform.Position,
|
||||
transform.ScalePercent,
|
||||
transform.RotationDegrees,
|
||||
transform.OpacityPercent,
|
||||
startOpacityPercent,
|
||||
endOpacityPercent);
|
||||
transform.Opacity,
|
||||
startOpacity,
|
||||
endOpacity);
|
||||
}
|
||||
|
||||
Transform ReadTransform(JObject obj, in ShapeLayerContent.ShapeLayerContentArgs shapeLayerContentArgs)
|
||||
|
@ -1467,9 +1454,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
? ReadAnimatableFloat(rotationJson)
|
||||
: new Animatable<double>(0, null);
|
||||
|
||||
var opacityPercent = ReadOpacityPercent(obj);
|
||||
var opacity = ReadOpacityFromO(obj);
|
||||
|
||||
return new Transform(in shapeLayerContentArgs, anchor, position, scalePercent, rotation, opacityPercent);
|
||||
return new Transform(in shapeLayerContentArgs, anchor, position, scalePercent, rotation, opacity);
|
||||
}
|
||||
|
||||
static bool? ReadBool(JObject obj, string name)
|
||||
|
@ -1598,8 +1585,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
if (numberOfColorStops.HasValue)
|
||||
{
|
||||
// There may be opacity stops. Read them.
|
||||
var animatableOpacityPercentStopsParser = new AnimatableOpacityPercentStopsParser(numberOfColorStops.Value);
|
||||
animatableOpacityPercentStopsParser.ParseJson(
|
||||
var animatableOpacityStopsParser = new AnimatableOpacityStopsParser(numberOfColorStops.Value);
|
||||
animatableOpacityStopsParser.ParseJson(
|
||||
this,
|
||||
obj.GetNamedObject("k"),
|
||||
out var opacityKeyFrames,
|
||||
|
@ -1682,6 +1669,30 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
: new Animatable<double>(initialValue, propertyIndex);
|
||||
}
|
||||
|
||||
Animatable<Opacity> ReadOpacityFromO(JObject obj)
|
||||
{
|
||||
var jsonOpacity = obj.GetNamedObject("o", null);
|
||||
return ReadOpacityFromObject(jsonOpacity);
|
||||
}
|
||||
|
||||
Animatable<Opacity> ReadOpacityFromObject(JObject obj)
|
||||
{
|
||||
var result = obj != null
|
||||
? ReadAnimatableOpacity(obj)
|
||||
: new Animatable<Opacity>(Opacity.Opaque, null);
|
||||
return result;
|
||||
}
|
||||
|
||||
Animatable<Opacity> ReadAnimatableOpacity(JObject obj)
|
||||
{
|
||||
s_animatableOpacityParser.ParseJson(this, obj, out IEnumerable<KeyFrame<Opacity>> keyFrames, out Opacity initialValue);
|
||||
var propertyIndex = ReadInt(obj, "ix");
|
||||
|
||||
return keyFrames.Any()
|
||||
? new Animatable<Opacity>(keyFrames, propertyIndex)
|
||||
: new Animatable<Opacity>(initialValue, propertyIndex);
|
||||
}
|
||||
|
||||
static Vector3 ReadVector3FromJsonArray(JArray array)
|
||||
{
|
||||
double x = 0;
|
||||
|
@ -1981,12 +1992,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
}
|
||||
}
|
||||
|
||||
sealed class AnimatableOpacityPercentStopsParser : AnimatableParser<Sequence<GradientStop>>
|
||||
sealed class AnimatableOpacityStopsParser : AnimatableParser<Sequence<GradientStop>>
|
||||
{
|
||||
// The number of color stops. The opacity stops follow this number of color stops.
|
||||
readonly int _colorStopCount;
|
||||
|
||||
internal AnimatableOpacityPercentStopsParser(int colorStopCount)
|
||||
internal AnimatableOpacityStopsParser(int colorStopCount)
|
||||
{
|
||||
_colorStopCount = colorStopCount;
|
||||
}
|
||||
|
@ -2014,7 +2025,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
opacity /= 255;
|
||||
}
|
||||
|
||||
gradientStops[i / 2] = new OpacityGradientStop(offset, opacityPercent: opacity * 100);
|
||||
gradientStops[i / 2] = new OpacityGradientStop(offset, opacity: Opacity.FromFloat(opacity));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2028,6 +2039,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieData.Serialization
|
|||
protected override double ReadValue(JToken obj) => ReadFloat(obj);
|
||||
}
|
||||
|
||||
sealed class AnimatableOpacityParser : AnimatableParser<Opacity>
|
||||
{
|
||||
protected override Opacity ReadValue(JToken obj) => Opacity.FromFloat(ReadFloat(obj) / 100.0);
|
||||
}
|
||||
|
||||
abstract class AnimatableParser<T>
|
||||
where T : IEquatable<T>
|
||||
{
|
||||
|
|
|
@ -395,8 +395,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
continue;
|
||||
}
|
||||
|
||||
if (mask.OpacityPercent.IsAnimated ||
|
||||
mask.OpacityPercent.InitialValue != 100)
|
||||
if (mask.Opacity.IsAnimated ||
|
||||
!mask.Opacity.InitialValue.IsOpaque)
|
||||
{
|
||||
_issues.MaskWithAlphaIsNotSupported();
|
||||
|
||||
|
@ -953,13 +953,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
//
|
||||
|
||||
// Get the opacity of the layer.
|
||||
var layerOpacityPercent = context.TrimAnimatable(context.Layer.Transform.OpacityPercent);
|
||||
var layerOpacity = context.TrimAnimatable(context.Layer.Transform.Opacity);
|
||||
|
||||
// Convert the layer's in point and out point into absolute progress (0..1) values.
|
||||
var inProgress = GetInPointProgress(context);
|
||||
var outProgress = GetOutPointProgress(context);
|
||||
|
||||
if (inProgress > 1 || outProgress <= 0 || inProgress >= outProgress || layerOpacityPercent.AlwaysEquals(0))
|
||||
if (inProgress > 1 || outProgress <= 0 || inProgress >= outProgress || layerOpacity.AlwaysEquals(LottieData.Opacity.Transparent))
|
||||
{
|
||||
// The layer is never visible. Don't create anything.
|
||||
rootNode = null;
|
||||
|
@ -971,7 +971,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
TranslateTransformOnContainerVisualForLayer(context, context.Layer, out rootNode, out contentsNode);
|
||||
|
||||
// Implement opacity for the layer.
|
||||
if (layerOpacityPercent.IsAnimated || layerOpacityPercent.InitialValue < 100)
|
||||
if (layerOpacity.IsAnimated || layerOpacity.InitialValue < LottieData.Opacity.Opaque)
|
||||
{
|
||||
// Insert a new node to control opacity at the top of the chain.
|
||||
var opacityNode = _c.CreateContainerVisual();
|
||||
|
@ -984,13 +984,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
opacityNode.Children.Add(rootNode);
|
||||
rootNode = opacityNode;
|
||||
|
||||
if (layerOpacityPercent.IsAnimated)
|
||||
if (layerOpacity.IsAnimated)
|
||||
{
|
||||
ApplyPercentKeyFrameAnimation(context, layerOpacityPercent, opacityNode, "Opacity", "Layer opacity animation");
|
||||
ApplyOpacityKeyFrameAnimation(context, layerOpacity, opacityNode, "Opacity", "Layer opacity animation");
|
||||
}
|
||||
else
|
||||
{
|
||||
opacityNode.Opacity = PercentF(layerOpacityPercent.InitialValue);
|
||||
opacityNode.Opacity = Opacity(layerOpacity.InitialValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1175,7 +1175,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
sealed class ShapeContentContext
|
||||
{
|
||||
static readonly Animatable<double> s_100Percent = new Animatable<double>(100, null);
|
||||
static readonly Animatable<Opacity> s_100Percent = new Animatable<Opacity>(LottieData.Opacity.Opaque, null);
|
||||
|
||||
readonly LottieToWinCompTranslator _owner;
|
||||
|
||||
|
@ -1192,14 +1192,14 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
// Opacity is not part of the Lottie context for shapes. But because WinComp
|
||||
// doesn't support opacity on shapes, the opacity is inherited from
|
||||
// the Transform and passed through to the brushes here.
|
||||
internal Animatable<double> OpacityPercent { get; private set; }
|
||||
internal Animatable<Opacity> Opacity { get; private set; }
|
||||
|
||||
internal ShapeContentContext(LottieToWinCompTranslator owner)
|
||||
{
|
||||
_owner = owner;
|
||||
|
||||
// Assume opacity is 100% unless otherwise set.
|
||||
OpacityPercent = s_100Percent;
|
||||
Opacity = s_100Percent;
|
||||
}
|
||||
|
||||
internal void UpdateFromStack(Stack<ShapeLayerContent> stack)
|
||||
|
@ -1244,7 +1244,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
Stroke = Stroke,
|
||||
TrimPath = TrimPath,
|
||||
RoundedCorner = RoundedCorner,
|
||||
OpacityPercent = OpacityPercent,
|
||||
Opacity = Opacity,
|
||||
Transform = Transform,
|
||||
};
|
||||
}
|
||||
|
@ -1256,7 +1256,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return;
|
||||
}
|
||||
|
||||
OpacityPercent = ComposeOpacityPercents(OpacityPercent, transform.OpacityPercent);
|
||||
Opacity = ComposeOpacities(Opacity, transform.Opacity);
|
||||
}
|
||||
|
||||
// Only used when translating geometries. Layers use an extra Shape or Visual to
|
||||
|
@ -1267,7 +1267,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
Transform = transform;
|
||||
}
|
||||
|
||||
Animatable<double> ComposeOpacityPercents(Animatable<double> a, Animatable<double> b)
|
||||
Animatable<Opacity> ComposeOpacities(Animatable<Opacity> a, Animatable<Opacity> b)
|
||||
{
|
||||
if (a == null || ReferenceEquals(a, s_100Percent))
|
||||
{
|
||||
|
@ -1282,7 +1282,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
if (!a.IsAnimated && !b.IsAnimated)
|
||||
{
|
||||
// Neither is animated. Just use the initial values.
|
||||
return new Animatable<double>(a.InitialValue * (b.InitialValue / 100.0), null);
|
||||
return new Animatable<Opacity>(a.InitialValue * b.InitialValue, null);
|
||||
}
|
||||
|
||||
if (a.IsAnimated && b.IsAnimated)
|
||||
|
@ -1312,36 +1312,36 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
// Only one is animated.
|
||||
if (a.IsAnimated)
|
||||
{
|
||||
if (b.InitialValue == 100)
|
||||
if (b.InitialValue.IsOpaque)
|
||||
{
|
||||
return a;
|
||||
}
|
||||
else
|
||||
{
|
||||
var bScale = b.InitialValue;
|
||||
return new Animatable<double>(
|
||||
return new Animatable<Opacity>(
|
||||
initialValue: a.InitialValue * bScale,
|
||||
keyFrames: a.KeyFrames.SelectToSpan(kf => ScaleKeyFrame(kf, bScale / 100)),
|
||||
keyFrames: a.KeyFrames.SelectToSpan(kf => ScaleKeyFrame(kf, bScale)),
|
||||
propertyIndex: null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return ComposeOpacityPercents(b, a);
|
||||
return ComposeOpacities(b, a);
|
||||
}
|
||||
}
|
||||
|
||||
// Composes 2 animated percent values where the frames in first come before second.
|
||||
Animatable<double> ComposeNonOverlappingAnimatedPercents(Animatable<double> first, Animatable<double> second)
|
||||
Animatable<Opacity> ComposeNonOverlappingAnimatedPercents(Animatable<Opacity> first, Animatable<Opacity> second)
|
||||
{
|
||||
Debug.Assert(first.IsAnimated, "Precondition");
|
||||
Debug.Assert(second.IsAnimated, "Precondition");
|
||||
Debug.Assert(first.KeyFrames[first.KeyFrames.Length - 1].Frame <= second.KeyFrames[0].Frame, "Precondition");
|
||||
|
||||
var resultFrames = new KeyFrame<double>[first.KeyFrames.Length + second.KeyFrames.Length];
|
||||
var resultFrames = new KeyFrame<Opacity>[first.KeyFrames.Length + second.KeyFrames.Length];
|
||||
var resultCount = 0;
|
||||
var secondInitialScale = second.InitialValue / 100;
|
||||
var firstFinalScale = first.KeyFrames[first.KeyFrames.Length - 1].Value / 100;
|
||||
var secondInitialScale = second.InitialValue;
|
||||
var firstFinalScale = first.KeyFrames[first.KeyFrames.Length - 1].Value;
|
||||
|
||||
foreach (var kf in first.KeyFrames)
|
||||
{
|
||||
|
@ -1355,15 +1355,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
resultCount++;
|
||||
}
|
||||
|
||||
return new Animatable<double>(
|
||||
return new Animatable<Opacity>(
|
||||
first.InitialValue,
|
||||
new ReadOnlySpan<KeyFrame<double>>(resultFrames, 0, resultCount),
|
||||
new ReadOnlySpan<KeyFrame<Opacity>>(resultFrames, 0, resultCount),
|
||||
null);
|
||||
}
|
||||
|
||||
KeyFrame<double> ScaleKeyFrame(KeyFrame<double> keyFrame, double scale)
|
||||
KeyFrame<Opacity> ScaleKeyFrame(KeyFrame<Opacity> keyFrame, Opacity scale)
|
||||
{
|
||||
return new KeyFrame<double>(
|
||||
return new KeyFrame<Opacity>(
|
||||
keyFrame.Frame,
|
||||
keyFrame.Value * scale,
|
||||
keyFrame.SpatialControlPoint1,
|
||||
|
@ -1400,15 +1400,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
SolidColorFill ComposeSolidColorFills(SolidColorFill a, SolidColorFill b)
|
||||
{
|
||||
if (!b.Color.IsAnimated && !b.OpacityPercent.IsAnimated)
|
||||
if (!b.Color.IsAnimated && !b.Opacity.IsAnimated)
|
||||
{
|
||||
if (b.OpacityPercent.InitialValue == 100 &&
|
||||
if (b.Opacity.InitialValue.IsOpaque &&
|
||||
b.Color.InitialValue.A == 1)
|
||||
{
|
||||
// b overrides a.
|
||||
return b;
|
||||
}
|
||||
else if (b.OpacityPercent.InitialValue == 0 || b.Color.InitialValue.A == 0)
|
||||
else if (b.Opacity.InitialValue.IsTransparent || b.Color.InitialValue.A == 0)
|
||||
{
|
||||
// b is transparent, so a wins.
|
||||
return a;
|
||||
|
@ -1454,7 +1454,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
Debug.Assert(a != null && b != null, "Precondition");
|
||||
|
||||
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
|
||||
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
|
||||
a.Opacity.AlwaysEquals(LottieData.Opacity.Opaque) && b.Opacity.AlwaysEquals(LottieData.Opacity.Opaque))
|
||||
{
|
||||
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
|
||||
{
|
||||
|
@ -1472,7 +1472,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
Debug.Assert(a != null && b != null, "Precondition");
|
||||
|
||||
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
|
||||
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
|
||||
a.Opacity.AlwaysEquals(LottieData.Opacity.Opaque) && b.Opacity.AlwaysEquals(LottieData.Opacity.Opaque))
|
||||
{
|
||||
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
|
||||
{
|
||||
|
@ -1491,7 +1491,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
if (!a.StrokeWidth.IsAnimated && !b.StrokeWidth.IsAnimated &&
|
||||
!a.DashPattern.Any() && !b.DashPattern.Any() &&
|
||||
a.OpacityPercent.AlwaysEquals(100) && b.OpacityPercent.AlwaysEquals(100))
|
||||
a.Opacity.AlwaysEquals(LottieData.Opacity.Opaque) && b.Opacity.AlwaysEquals(LottieData.Opacity.Opaque))
|
||||
{
|
||||
if (a.StrokeWidth.InitialValue >= b.StrokeWidth.InitialValue)
|
||||
{
|
||||
|
@ -1703,7 +1703,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
{
|
||||
// Treat each repeated value as a list of items where the repeater is replaced
|
||||
// by n transforms.
|
||||
// TODO - currently ignoring the StartOpacityPercent and EndOpacityPercent - should generate a new transform
|
||||
// TODO - currently ignoring the StartOpacity and EndOpacity - should generate a new transform
|
||||
// that interpolates that.
|
||||
var generatedItems = itemsBeforeRepeater.Concat(Enumerable.Repeat(repeater.Transform, i + 1)).Concat(itemsAfterRepeater).ToArray();
|
||||
|
||||
|
@ -2482,8 +2482,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
void TranslateAndApplyShapeContentContext(TranslationContext context, ShapeContentContext shapeContext, CompositionSpriteShape shape, double trimOffsetDegrees = 0)
|
||||
{
|
||||
shape.FillBrush = TranslateShapeFill(context, shapeContext.Fill, context.TrimAnimatable(shapeContext.OpacityPercent));
|
||||
TranslateAndApplyStroke(context, shapeContext.Stroke, shape, context.TrimAnimatable(shapeContext.OpacityPercent));
|
||||
shape.FillBrush = TranslateShapeFill(context, shapeContext.Fill, context.TrimAnimatable(shapeContext.Opacity));
|
||||
TranslateAndApplyStroke(context, shapeContext.Stroke, shape, context.TrimAnimatable(shapeContext.Opacity));
|
||||
TranslateAndApplyTrimPath(context, shapeContext.TrimPath, shape.Geometry, trimOffsetDegrees);
|
||||
}
|
||||
|
||||
|
@ -2692,7 +2692,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
TranslationContext context,
|
||||
ShapeStroke shapeStroke,
|
||||
CompositionSpriteShape sprite,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
TrimmedAnimatable<Opacity> contextOpacity)
|
||||
{
|
||||
if (shapeStroke == null)
|
||||
{
|
||||
|
@ -2707,13 +2707,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
switch (shapeStroke.StrokeKind)
|
||||
{
|
||||
case ShapeStroke.ShapeStrokeKind.SolidColor:
|
||||
TranslateAndApplySolidColorStroke(context, (SolidColorStroke)shapeStroke, sprite, contextOpacityPercent);
|
||||
TranslateAndApplySolidColorStroke(context, (SolidColorStroke)shapeStroke, sprite, contextOpacity);
|
||||
break;
|
||||
case ShapeStroke.ShapeStrokeKind.LinearGradient:
|
||||
TranslateAndApplyLinearGradientStroke(context, (LinearGradientStroke)shapeStroke, sprite, contextOpacityPercent);
|
||||
TranslateAndApplyLinearGradientStroke(context, (LinearGradientStroke)shapeStroke, sprite, contextOpacity);
|
||||
break;
|
||||
case ShapeStroke.ShapeStrokeKind.RadialGradient:
|
||||
TranslateAndApplyRadialGradientStroke(context, (RadialGradientStroke)shapeStroke, sprite, contextOpacityPercent);
|
||||
TranslateAndApplyRadialGradientStroke(context, (RadialGradientStroke)shapeStroke, sprite, contextOpacity);
|
||||
break;
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
|
@ -2724,12 +2724,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
TranslationContext context,
|
||||
LinearGradientStroke shapeStroke,
|
||||
CompositionSpriteShape sprite,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
TrimmedAnimatable<Opacity> contextOpacity)
|
||||
{
|
||||
ApplyCommonStrokeProperties(
|
||||
context,
|
||||
shapeStroke,
|
||||
TranslateLinearGradientStroke(context, shapeStroke, contextOpacityPercent),
|
||||
TranslateLinearGradientStroke(context, shapeStroke, contextOpacity),
|
||||
sprite);
|
||||
}
|
||||
|
||||
|
@ -2737,12 +2737,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
TranslationContext context,
|
||||
RadialGradientStroke shapeStroke,
|
||||
CompositionSpriteShape sprite,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
TrimmedAnimatable<Opacity> contextOpacity)
|
||||
{
|
||||
ApplyCommonStrokeProperties(
|
||||
context,
|
||||
shapeStroke,
|
||||
TranslateRadialGradientStroke(context, shapeStroke, contextOpacityPercent),
|
||||
TranslateRadialGradientStroke(context, shapeStroke, contextOpacity),
|
||||
sprite);
|
||||
}
|
||||
|
||||
|
@ -2750,12 +2750,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
TranslationContext context,
|
||||
SolidColorStroke shapeStroke,
|
||||
CompositionSpriteShape sprite,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
TrimmedAnimatable<Opacity> contextOpacity)
|
||||
{
|
||||
ApplyCommonStrokeProperties(
|
||||
context,
|
||||
shapeStroke,
|
||||
TranslateSolidColorStrokeColor(context, shapeStroke, contextOpacityPercent),
|
||||
TranslateSolidColorStrokeColor(context, shapeStroke, contextOpacity),
|
||||
sprite);
|
||||
|
||||
// NOTE: DashPattern animation (animating dash sizes) are not supported on CompositionSpriteShape.
|
||||
|
@ -2802,7 +2802,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
sprite.StrokeBrush = brush;
|
||||
}
|
||||
|
||||
CompositionBrush TranslateShapeFill(TranslationContext context, ShapeFill shapeFill, TrimmedAnimatable<double> opacityPercent)
|
||||
CompositionBrush TranslateShapeFill(TranslationContext context, ShapeFill shapeFill, TrimmedAnimatable<Opacity> opacity)
|
||||
{
|
||||
if (shapeFill == null)
|
||||
{
|
||||
|
@ -2812,11 +2812,11 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
switch (shapeFill.FillKind)
|
||||
{
|
||||
case ShapeFill.ShapeFillKind.SolidColor:
|
||||
return TranslateSolidColorFill(context, (SolidColorFill)shapeFill, opacityPercent);
|
||||
return TranslateSolidColorFill(context, (SolidColorFill)shapeFill, opacity);
|
||||
case ShapeFill.ShapeFillKind.LinearGradient:
|
||||
return TranslateLinearGradientFill(context, (LinearGradientFill)shapeFill, opacityPercent);
|
||||
return TranslateLinearGradientFill(context, (LinearGradientFill)shapeFill, opacity);
|
||||
case ShapeFill.ShapeFillKind.RadialGradient:
|
||||
return TranslateRadialGradientFill(context, (RadialGradientFill)shapeFill, opacityPercent);
|
||||
return TranslateRadialGradientFill(context, (RadialGradientFill)shapeFill, opacity);
|
||||
default:
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
@ -2825,15 +2825,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
CompositionColorBrush TranslateSolidColor(
|
||||
TranslationContext context,
|
||||
Animatable<Color> color,
|
||||
Animatable<double> opacityPercentA,
|
||||
TrimmedAnimatable<double> opacityPercentB)
|
||||
Animatable<Opacity> opacityA,
|
||||
TrimmedAnimatable<Opacity> opacityB)
|
||||
{
|
||||
return CreateAnimatedColorBrush(
|
||||
context,
|
||||
MultiplyAnimatableColorByAnimatableOpacityPercent(
|
||||
MultiplyAnimatableColorByAnimatableOpacity(
|
||||
context.TrimAnimatable(color),
|
||||
context.TrimAnimatable(opacityPercentA)),
|
||||
opacityPercentB);
|
||||
context.TrimAnimatable(opacityA)),
|
||||
opacityB);
|
||||
}
|
||||
|
||||
// Parses the given binding string and returns the binding name for the given property, or
|
||||
|
@ -2849,30 +2849,31 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
CompositionColorBrush TranslateSolidColorStrokeColor(
|
||||
TranslationContext context,
|
||||
SolidColorStroke shapeStroke,
|
||||
TrimmedAnimatable<double> inheritedOpacityPercent)
|
||||
TrimmedAnimatable<Opacity> inheritedOpacity)
|
||||
=> TranslateSolidColorWithBindings(
|
||||
context,
|
||||
shapeStroke.Color,
|
||||
shapeStroke.OpacityPercent,
|
||||
inheritedOpacityPercent,
|
||||
shapeStroke.Opacity,
|
||||
inheritedOpacity,
|
||||
bindingSpec: shapeStroke.Name);
|
||||
|
||||
CompositionColorBrush TranslateSolidColorFill(
|
||||
TranslationContext context,
|
||||
SolidColorFill shapeFill,
|
||||
TrimmedAnimatable<double> inheritedOpacityPercent)
|
||||
TrimmedAnimatable<Opacity> inheritedOpacity)
|
||||
=> TranslateSolidColorWithBindings(
|
||||
context,
|
||||
shapeFill.Color,
|
||||
shapeFill.OpacityPercent,
|
||||
inheritedOpacityPercent,
|
||||
shapeFill.Opacity,
|
||||
inheritedOpacity,
|
||||
bindingSpec: shapeFill.Name);
|
||||
|
||||
CompositionColorBrush TranslateSolidColorWithBindings(
|
||||
TranslationContext context,
|
||||
Animatable<Color> color,
|
||||
Animatable<double> colorOpacityPercent,
|
||||
TrimmedAnimatable<double> inheritedOpacityPercent,
|
||||
Animatable<Opacity
|
||||
> colorOpacity,
|
||||
TrimmedAnimatable<Opacity> inheritedOpacity,
|
||||
string bindingSpec)
|
||||
{
|
||||
// Read property bindings embedded into the name of the fill.
|
||||
|
@ -2882,17 +2883,17 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
if (bindingName is string)
|
||||
{
|
||||
// The fill is bound to a property name.
|
||||
return TranslateBoundSolidColor(context, inheritedOpacityPercent, bindingName);
|
||||
return TranslateBoundSolidColor(context, inheritedOpacity, bindingName);
|
||||
}
|
||||
}
|
||||
|
||||
return TranslateSolidColor(context, color, colorOpacityPercent, inheritedOpacityPercent);
|
||||
return TranslateSolidColor(context, color, colorOpacity, inheritedOpacity);
|
||||
}
|
||||
|
||||
// Translates a SolidColorFill that gets its color value from a property set value with the given name.
|
||||
CompositionColorBrush TranslateBoundSolidColor(
|
||||
TranslationContext context,
|
||||
TrimmedAnimatable<double> opacityPercent,
|
||||
TrimmedAnimatable<Opacity> opacity,
|
||||
string bindingName)
|
||||
{
|
||||
// Insert a property set value for the color if one hasn't yet been added.
|
||||
|
@ -2932,12 +2933,12 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
ExpressionAnimation anim;
|
||||
|
||||
if (opacityPercent.IsAnimated)
|
||||
if (opacity.IsAnimated)
|
||||
{
|
||||
// The opacity is animated. Add an animated property for the opacity and use it to multiply
|
||||
// the alpha channel of the color.
|
||||
brush.Properties.InsertScalar("Opacity", PercentF(opacityPercent.InitialValue));
|
||||
ApplyPercentKeyFrameAnimation(context, opacityPercent, brush.Properties, "Opacity", "Opacity", null);
|
||||
brush.Properties.InsertScalar("Opacity", Opacity(opacity.InitialValue));
|
||||
ApplyOpacityKeyFrameAnimation(context, opacity, brush.Properties, "Opacity", "Opacity", null);
|
||||
|
||||
anim = _c.CreateExpressionAnimation(BoundColorWithAnimatedOpacity(bindingName));
|
||||
anim.SetReferenceParameter("my", brush);
|
||||
|
@ -2945,7 +2946,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
else
|
||||
{
|
||||
// Opacity isn't animated. Multiply the alpha channel of the color by the non-animated opacity value.
|
||||
anim = _c.CreateExpressionAnimation(BoundColor(bindingName, opacityPercent.InitialValue / 100));
|
||||
anim = _c.CreateExpressionAnimation(BoundColor(bindingName, opacity.InitialValue.Value));
|
||||
}
|
||||
|
||||
anim.SetReferenceParameter(RootName, _rootVisual);
|
||||
|
@ -2956,9 +2957,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
CompositionLinearGradientBrush TranslateLinearGradientFill(
|
||||
TranslationContext context,
|
||||
LinearGradientFill shapeFill,
|
||||
TrimmedAnimatable<double> opacityPercent)
|
||||
TrimmedAnimatable<Opacity> opacity)
|
||||
{
|
||||
if (opacityPercent.IsAnimated)
|
||||
if (opacity.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with LinearGradientFill.
|
||||
_issues.GradientFillIsNotSupported("Linear", "animated opacity");
|
||||
|
@ -2967,15 +2968,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return TranslateLinearGradient(
|
||||
context,
|
||||
shapeFill,
|
||||
MaxOpacityPercent(in opacityPercent));
|
||||
MaxOpacity(in opacity));
|
||||
}
|
||||
|
||||
CompositionGradientBrush TranslateLinearGradientStroke(
|
||||
TranslationContext context,
|
||||
LinearGradientStroke shapeStroke,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
TrimmedAnimatable<Opacity> contextOpacity)
|
||||
{
|
||||
if (contextOpacityPercent.IsAnimated)
|
||||
if (contextOpacity.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with LinearGradientFill.
|
||||
_issues.GradientStrokeIsNotSupported("Linear", "animated opacity");
|
||||
|
@ -2984,15 +2985,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return TranslateLinearGradient(
|
||||
context,
|
||||
shapeStroke,
|
||||
MaxOpacityPercent(in contextOpacityPercent));
|
||||
MaxOpacity(in contextOpacity));
|
||||
}
|
||||
|
||||
CompositionBrush TranslateRadialGradientFill(
|
||||
TranslationContext context,
|
||||
RadialGradientFill shapeFill,
|
||||
TrimmedAnimatable<double> opacityPercent)
|
||||
TrimmedAnimatable<Opacity> opacity)
|
||||
{
|
||||
if (opacityPercent.IsAnimated)
|
||||
if (opacity.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with RadialGradientFill.
|
||||
_issues.GradientFillIsNotSupported("Radial", "animated opacity");
|
||||
|
@ -3001,15 +3002,15 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return TranslateRadialGradient(
|
||||
context,
|
||||
shapeFill,
|
||||
MaxOpacityPercent(in opacityPercent));
|
||||
MaxOpacity(in opacity));
|
||||
}
|
||||
|
||||
CompositionGradientBrush TranslateRadialGradientStroke(
|
||||
TranslationContext context,
|
||||
RadialGradientStroke shapeStroke,
|
||||
TrimmedAnimatable<double> contextOpacityPercent)
|
||||
TrimmedAnimatable<Opacity> contextOpacity)
|
||||
{
|
||||
if (contextOpacityPercent.IsAnimated)
|
||||
if (contextOpacity.IsAnimated)
|
||||
{
|
||||
// We don't yet support animated opacity with RadialGradientStroke.
|
||||
_issues.GradientStrokeIsNotSupported("Radial", "animated opacity");
|
||||
|
@ -3018,13 +3019,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return TranslateRadialGradient(
|
||||
context,
|
||||
shapeStroke,
|
||||
MaxOpacityPercent(in contextOpacityPercent));
|
||||
MaxOpacity(in contextOpacity));
|
||||
}
|
||||
|
||||
CompositionLinearGradientBrush TranslateLinearGradient(
|
||||
TranslationContext context,
|
||||
IGradient linearGradient,
|
||||
double opacityPercentValue)
|
||||
Opacity opacity)
|
||||
{
|
||||
var result = _c.CreateLinearGradientBrush();
|
||||
|
||||
|
@ -3080,7 +3081,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
var colorKeyFrames = ExtractKeyFramesFromColorStopKeyFrames(
|
||||
colorStopKeyFrames,
|
||||
i,
|
||||
gs => MultiplyColorByOpacityPercent(gs.Color, opacityPercentValue)).ToArray();
|
||||
gs => MultiplyColorByOpacity(gs.Color, opacity)).ToArray();
|
||||
|
||||
ApplyColorKeyFrameAnimation(
|
||||
context,
|
||||
|
@ -3110,7 +3111,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
foreach (var stop in GradientStopOptimizer.Optimize(gradientStops.InitialValue.Items.ToArray()).Distinct())
|
||||
{
|
||||
var offset = stop.Offset;
|
||||
var color = MultiplyColorByOpacityPercent(stop.Color, opacityPercentValue);
|
||||
var color = MultiplyColorByOpacity(stop.Color, opacity);
|
||||
brushStops.Add(_c.CreateColorGradientStop(Float(offset), color));
|
||||
}
|
||||
}
|
||||
|
@ -3121,13 +3122,13 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
CompositionGradientBrush TranslateRadialGradient(
|
||||
TranslationContext context,
|
||||
IRadialGradient gradient,
|
||||
double opacityPercentValue)
|
||||
Opacity opacity)
|
||||
{
|
||||
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);
|
||||
return TranslateLinearGradient(context, gradient, opacity);
|
||||
}
|
||||
|
||||
var result = _c.CreateRadialGradientBrush();
|
||||
|
@ -3191,7 +3192,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
var colorKeyFrames = ExtractKeyFramesFromColorStopKeyFrames(
|
||||
colorStopKeyFrames,
|
||||
i,
|
||||
gs => MultiplyColorByOpacityPercent(gs.Color, opacityPercentValue)).ToArray();
|
||||
gs => MultiplyColorByOpacity(gs.Color, opacity)).ToArray();
|
||||
|
||||
ApplyColorKeyFrameAnimation(
|
||||
context,
|
||||
|
@ -3217,7 +3218,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
foreach (var stop in GradientStopOptimizer.Optimize(gradientStops.InitialValue.Items.ToArray()).Distinct())
|
||||
{
|
||||
var offset = stop.Offset;
|
||||
var color = MultiplyColorByOpacityPercent(stop.Color, opacityPercentValue);
|
||||
var color = MultiplyColorByOpacity(stop.Color, opacity);
|
||||
brushStops.Add(_c.CreateColorGradientStop(Float(offset), color));
|
||||
}
|
||||
}
|
||||
|
@ -3243,7 +3244,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
ShapeOrVisual TranslateSolidLayer(TranslationContext.For<SolidLayer> context)
|
||||
{
|
||||
if (context.Layer.IsHidden || context.Layer.Transform.OpacityPercent.AlwaysEquals(0))
|
||||
if (context.Layer.IsHidden || context.Layer.Transform.Opacity.AlwaysEquals(LottieData.Opacity.Transparent))
|
||||
{
|
||||
// The layer does not render anything. Nothing to translate. This can happen when someone
|
||||
// creates a solid layer to act like a Null layer.
|
||||
|
@ -3291,7 +3292,7 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
// If that layer has no masks, opacity is implemented via the alpha channel on the brush.
|
||||
rectangle.FillBrush = layerHasMasks
|
||||
? _c.CreateNonAnimatedColorBrush(context.Layer.Color)
|
||||
: CreateAnimatedColorBrush(context, context.Layer.Color, context.TrimAnimatable(context.Layer.Transform.OpacityPercent));
|
||||
: CreateAnimatedColorBrush(context, context.Layer.Color, context.TrimAnimatable(context.Layer.Transform.Opacity));
|
||||
|
||||
if (_addDescriptions)
|
||||
{
|
||||
|
@ -3673,6 +3674,37 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
string shortDescription = null)
|
||||
=> ApplyScaledScalarKeyFrameAnimation(context, value, 0.01, targetObject, targetPropertyName, longDescription, shortDescription);
|
||||
|
||||
void ApplyOpacityKeyFrameAnimation(
|
||||
TranslationContext context,
|
||||
in TrimmedAnimatable<Opacity> value,
|
||||
CompositionObject targetObject,
|
||||
string targetPropertyName,
|
||||
string longDescription = null,
|
||||
string shortDescription = null)
|
||||
=> ApplyScaledOpacityKeyFrameAnimation(context, value, 1, targetObject, targetPropertyName, longDescription, shortDescription);
|
||||
|
||||
void ApplyScaledOpacityKeyFrameAnimation(
|
||||
TranslationContext context,
|
||||
in TrimmedAnimatable<Opacity> value,
|
||||
double scale,
|
||||
CompositionObject targetObject,
|
||||
string targetPropertyName,
|
||||
string longDescription,
|
||||
string shortDescription)
|
||||
{
|
||||
Debug.Assert(value.IsAnimated, "Precondition");
|
||||
GenericCreateCompositionKeyFrameAnimation(
|
||||
context,
|
||||
value,
|
||||
_c.CreateScalarKeyFrameAnimation,
|
||||
(ca, progress, val, easing) => ca.InsertKeyFrame(progress, (float)(val.Value * scale), easing),
|
||||
null,
|
||||
targetObject,
|
||||
targetPropertyName,
|
||||
longDescription,
|
||||
shortDescription);
|
||||
}
|
||||
|
||||
void ApplyScaledScalarKeyFrameAnimation(
|
||||
TranslationContext context,
|
||||
in TrimmedAnimatable<double> value,
|
||||
|
@ -4113,85 +4145,85 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
return result;
|
||||
}
|
||||
|
||||
TrimmedAnimatable<Color> MultiplyAnimatableColorByAnimatableOpacityPercent(
|
||||
TrimmedAnimatable<Color> MultiplyAnimatableColorByAnimatableOpacity(
|
||||
in TrimmedAnimatable<Color> color,
|
||||
in TrimmedAnimatable<double> opacityPercent)
|
||||
in TrimmedAnimatable<Opacity> opacity)
|
||||
{
|
||||
if (color.IsAnimated)
|
||||
{
|
||||
var opacityPercentInitialValue = opacityPercent.InitialValue;
|
||||
var opacityInitialValue = opacity.InitialValue;
|
||||
|
||||
if (opacityPercent.IsAnimated)
|
||||
if (opacity.IsAnimated)
|
||||
{
|
||||
// TOOD: multiply animations to produce a new set of key frames for the opacity-multiplied color.
|
||||
_issues.OpacityAndColorAnimatedTogetherIsNotSupported();
|
||||
|
||||
// Multiply the color values by the maximum opacity. This is a heuristic
|
||||
// that can give a better result than just returning the color.
|
||||
opacityPercentInitialValue = MaxOpacityPercent(in opacityPercent);
|
||||
opacityInitialValue = MaxOpacity(in opacity);
|
||||
}
|
||||
|
||||
// Multiply the color animation by the single opacity value.
|
||||
return new TrimmedAnimatable<Color>(
|
||||
color.Context,
|
||||
initialValue: MultiplyColorByOpacityPercent(color.InitialValue, opacityPercent.InitialValue),
|
||||
initialValue: MultiplyColorByOpacity(color.InitialValue, opacity.InitialValue),
|
||||
keyFrames: color.KeyFrames.SelectToSpan(kf =>
|
||||
new KeyFrame<Color>(
|
||||
kf.Frame,
|
||||
MultiplyColorByOpacityPercent(kf.Value, opacityPercentInitialValue),
|
||||
MultiplyColorByOpacity(kf.Value, opacityInitialValue),
|
||||
kf.SpatialControlPoint1,
|
||||
kf.SpatialControlPoint2,
|
||||
kf.Easing)));
|
||||
}
|
||||
else if (opacityPercent.IsAnimated)
|
||||
else if (opacity.IsAnimated)
|
||||
{
|
||||
// Color is not animated.
|
||||
return MultiplyColorByAnimatableOpacityPercent(color.InitialValue, opacityPercent);
|
||||
return MultiplyColorByAnimatableOpacity(color.InitialValue, opacity);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Multiply color by opacity
|
||||
var nonAnimatedMultipliedColor = MultiplyColorByOpacityPercent(color.InitialValue, opacityPercent.InitialValue);
|
||||
var nonAnimatedMultipliedColor = MultiplyColorByOpacity(color.InitialValue, opacity.InitialValue);
|
||||
return new TrimmedAnimatable<Color>(color.Context, nonAnimatedMultipliedColor);
|
||||
}
|
||||
}
|
||||
|
||||
TrimmedAnimatable<Color> MultiplyColorByAnimatableOpacityPercent(
|
||||
TrimmedAnimatable<Color> MultiplyColorByAnimatableOpacity(
|
||||
Color color,
|
||||
in TrimmedAnimatable<double> opacityPercent)
|
||||
in TrimmedAnimatable<Opacity> opacity)
|
||||
{
|
||||
if (!opacityPercent.IsAnimated)
|
||||
if (!opacity.IsAnimated)
|
||||
{
|
||||
return new TrimmedAnimatable<Color>(opacityPercent.Context, MultiplyColorByOpacityPercent(color, opacityPercent.InitialValue));
|
||||
return new TrimmedAnimatable<Color>(opacity.Context, MultiplyColorByOpacity(color, opacity.InitialValue));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Multiply the single color value by the opacity animation.
|
||||
return new TrimmedAnimatable<Color>(
|
||||
opacityPercent.Context,
|
||||
initialValue: MultiplyColorByOpacityPercent(color, opacityPercent.InitialValue),
|
||||
keyFrames: opacityPercent.KeyFrames.SelectToSpan(kf =>
|
||||
opacity.Context,
|
||||
initialValue: MultiplyColorByOpacity(color, opacity.InitialValue),
|
||||
keyFrames: opacity.KeyFrames.SelectToSpan(kf =>
|
||||
new KeyFrame<Color>(
|
||||
kf.Frame,
|
||||
MultiplyColorByOpacityPercent(color, kf.Value),
|
||||
MultiplyColorByOpacity(color, kf.Value),
|
||||
kf.SpatialControlPoint1,
|
||||
kf.SpatialControlPoint2,
|
||||
kf.Easing)));
|
||||
}
|
||||
}
|
||||
|
||||
static Color MultiplyColorByOpacityPercent(Color color, double opacityPercent)
|
||||
=> color?.MultipliedByOpacity(opacityPercent / 100);
|
||||
static Color MultiplyColorByOpacity(Color color, Opacity opacity)
|
||||
=> color?.MultipliedByOpacity(opacity);
|
||||
|
||||
CompositionColorBrush CreateAnimatedColorBrush(TranslationContext context, Color color, in TrimmedAnimatable<double> opacityPercent)
|
||||
CompositionColorBrush CreateAnimatedColorBrush(TranslationContext context, Color color, in TrimmedAnimatable<Opacity> opacity)
|
||||
{
|
||||
var multipliedColor = MultiplyColorByAnimatableOpacityPercent(color, opacityPercent);
|
||||
var multipliedColor = MultiplyColorByAnimatableOpacity(color, opacity);
|
||||
return CreateAnimatedColorBrush(context, multipliedColor);
|
||||
}
|
||||
|
||||
CompositionColorBrush CreateAnimatedColorBrush(TranslationContext context, in TrimmedAnimatable<Color> color, in TrimmedAnimatable<double> opacityPercent)
|
||||
CompositionColorBrush CreateAnimatedColorBrush(TranslationContext context, in TrimmedAnimatable<Color> color, in TrimmedAnimatable<Opacity> opacity)
|
||||
{
|
||||
var multipliedColor = MultiplyAnimatableColorByAnimatableOpacityPercent(color, opacityPercent);
|
||||
var multipliedColor = MultiplyAnimatableColorByAnimatableOpacity(color, opacity);
|
||||
return CreateAnimatedColorBrush(context, multipliedColor);
|
||||
}
|
||||
|
||||
|
@ -4223,9 +4255,9 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
}
|
||||
|
||||
// Returns the maximum opacity value from the given TrimmedAnimatable.
|
||||
// This works for any double value, but we call it MaxOpacityPercent because that
|
||||
// This works for any double value, but we call it MaxOpacity because that
|
||||
// is where it is useful, and the name makes the intention clearer.
|
||||
static double MaxOpacityPercent(in TrimmedAnimatable<double> animatable)
|
||||
static Opacity MaxOpacity(in TrimmedAnimatable<Opacity> animatable)
|
||||
=> animatable.IsAnimated
|
||||
? animatable.KeyFrames.Max(kf => kf.Value)
|
||||
: animatable.InitialValue;
|
||||
|
@ -4307,6 +4339,8 @@ namespace Microsoft.Toolkit.Uwp.UI.Lottie.LottieToWinComp
|
|||
|
||||
static float? FloatDefaultIsOne(double value) => value == 1 ? null : (float?)value;
|
||||
|
||||
static float Opacity(Opacity value) => (float)value.Value;
|
||||
|
||||
static float PercentF(double value) => (float)value / 100F;
|
||||
|
||||
static Sn.Vector2 Vector2(LottieData.Vector3 vector3) => Vector2(vector3.X, vector3.Y);
|
||||
|
|
Загрузка…
Ссылка в новой задаче