This commit is contained in:
Andrii Borziak 2022-09-15 11:07:29 -07:00
Родитель 1f51334d7a
Коммит f44baca6d0
14 изменённых файлов: 815 добавлений и 33 удалений

Просмотреть файл

@ -19,7 +19,23 @@
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Margin" Value="0,10,0,10"/>
</Style>
<Style x:Key="StatsBorder" TargetType="Border">
<Setter Property="BorderBrush" Value="DarkGray"/>
<Setter Property="BorderThickness" Value="1.0"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Margin" Value="0,2,0,2"/>
<Setter Property="Padding" Value="6"/>
<Setter Property="CornerRadius" Value="8"/>
</Style>
<Style x:Key="StatsSeparator" TargetType="Border">
<Setter Property="BorderBrush" Value="DarkGray"/>
<Setter Property="BorderThickness" Value="0,1,0,0"/>
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Margin" Value="0,2,0,2"/>
</Style>
<Color x:Key="LottieBasic">#FF00D1C1</Color>
<Color x:Key="DisabledColor">#FF888888</Color>
<Color x:Key="ForegroundColor">#FFEBEBEB</Color>

Просмотреть файл

@ -85,7 +85,6 @@
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x64' ">
</PropertyGroup>
<ItemGroup>
<Compile Include="Anim.cs" />
<Compile Include="AnimatedVisuals\LottieViewer_04_Playback.cs" />
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
@ -93,6 +92,9 @@
<Compile Include="AnimatedVisuals\UiFeedbackAnimations.cs" />
<Compile Include="AnimatedVisuals\LottieLogo.cs" />
<Compile Include="ColorPaletteEntry.cs" />
<Compile Include="PerfStats.xaml.cs">
<DependentUpon>PerfStats.xaml</DependentUpon>
</Compile>
<Compile Include="PixelViewElement.cs" />
<Compile Include="FeedbackLottie.xaml.cs">
<DependentUpon>FeedbackLottie.xaml</DependentUpon>
@ -119,6 +121,7 @@
<Compile Include="ViewModel\Marker.cs" />
<Compile Include="ViewModel\MarkerWithDuration.cs" />
<Compile Include="ViewModel\PairOfStrings.cs" />
<Compile Include="ViewModel\StatsEntry.cs" />
<Compile Include="VisibilityConverter.cs" />
</ItemGroup>
<ItemGroup>
@ -200,6 +203,10 @@
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="PerfStats.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="PlayStopButton.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>

Просмотреть файл

@ -83,12 +83,7 @@
AutomationProperties.Name="View perf stats"
ToolTipService.ToolTip="Animation perf stats"
Style="{StaticResource ControlsToggleButtonStyle}">
<Grid>
<!-- Switch icon based on whether or not the Lottie file has any issues. -->
<TextBlock Text="&#xEC4A;" Visibility="{x:Bind _stage.DiagnosticsViewModel.HasIssues, Converter={StaticResource VisibilityConverter}, ConverterParameter=not, Mode=OneWay}" AutomationProperties.AccessibilityView="Raw"/>
<!-- Different color if there are issues. -->
<TextBlock Text="&#xEC4A;" Visibility="{x:Bind _stage.DiagnosticsViewModel.HasIssues, Converter={StaticResource VisibilityConverter}, Mode=OneWay}" Foreground="Orange" AutomationProperties.AccessibilityView="Raw"/>
</Grid>
&#xEC4A;
</ToggleButton>
</StackPanel>
</Grid>
@ -342,13 +337,12 @@
</StackPanel>
</ScrollViewer>
<!-- Info panel -->
<!-- Perf panel -->
<ScrollViewer
x:Name="PerfPanel"
Width="{StaticResource ControlPanelWidth}">
<StackPanel Padding="20,10,20,0">
</StackPanel>
<local:PerfStats x:Name="_perfStats"></local:PerfStats>
</ScrollViewer>
</Grid>

Просмотреть файл

@ -104,21 +104,18 @@ namespace LottieViewer
void DiagnosticsViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
var list = PropertiesList;
var viewModel = _stage.DiagnosticsViewModel;
if (viewModel is null)
_perfStats.Update(viewModel);
PropertiesList.Clear();
MarkersList.Clear();
if (viewModel is not null)
{
list.Clear();
MarkersList.Clear();
}
else if (e.PropertyName == nameof(viewModel.FileName))
{
list.Clear();
MarkersList.Clear();
if (!string.IsNullOrWhiteSpace(viewModel.FileName))
{
list.Add(new PairOfStrings("File", viewModel.FileName));
PropertiesList.Add(new PairOfStrings("File", viewModel.FileName));
}
// If the Lottie has 0 duration then it isn't valid, so don't show properties
@ -128,12 +125,12 @@ namespace LottieViewer
// Not all Lotties have a name, so only add the name if it exists.
if (!string.IsNullOrWhiteSpace(viewModel.Name))
{
list.Add(new PairOfStrings("Name", viewModel.Name));
PropertiesList.Add(new PairOfStrings("Name", viewModel.Name));
}
list.Add(new PairOfStrings("Size", viewModel.SizeText));
list.Add(new PairOfStrings("Duration", viewModel.DurationText));
list.Add(new PairOfStrings("Frames", $"{viewModel.FrameCountText} @ {viewModel.FramesPerSecond:0.#}fps"));
PropertiesList.Add(new PairOfStrings("Size", viewModel.SizeText));
PropertiesList.Add(new PairOfStrings("Duration", viewModel.DurationText));
PropertiesList.Add(new PairOfStrings("Frames", $"{viewModel.FrameCountText} @ {viewModel.FramesPerSecond:0.#}fps"));
if (viewModel.Markers.Count > 0)
{

Просмотреть файл

@ -239,11 +239,6 @@
<TextBlock FontWeight="Bold">Colors</TextBlock>
<CheckBox x:Name="_showSolidBackground">Show solid background</CheckBox>
<muxc2:AnimatedVisualPlayer AutoPlay="True"
Stretch="None">
<av:Anim/>
</muxc2:AnimatedVisualPlayer>
</StackPanel>
</StackPanel>
</Grid>

122
LottieViewer/PerfStats.xaml Normal file
Просмотреть файл

@ -0,0 +1,122 @@
<UserControl
x:Class="LottieViewer.PerfStats"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:LottieViewer"
xmlns:viewmodel="using:LottieViewer.ViewModel"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="900"
d:DesignWidth="400">
<StackPanel Grid.Row="2" Orientation="Vertical" Padding="20,10,20,0">
<TextBlock Text="Total animation complexity score" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Center" FontSize="18"/>
<TextBlock Text="0.0" x:Name="ScoreValue" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Center" FontSize="40"/>
<!--
<TextBlock FontWeight="Bold">Input (lottie objects):</TextBlock>
<Border Style="{StaticResource StatsBorder}">
<StackPanel>
<ItemsControl ItemsSource="{x:Bind InputLayers, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="viewmodel:StatsEntry">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind Name}" Grid.Column="0" TextWrapping="Wrap" Foreground="LightGray"/>
<TextBlock Text="{x:Bind Count}" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border Style="{StaticResource StatsSeparator}" Padding="0"/>
<ItemsControl ItemsSource="{x:Bind InputMasks, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="viewmodel:StatsEntry">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind Name}" Grid.Column="0" TextWrapping="Wrap" Foreground="LightGray"/>
<TextBlock Text="{x:Bind Count}" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<Border Style="{StaticResource StatsSeparator}" Padding="0"/>
<ItemsControl ItemsSource="{x:Bind InputEffects, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="viewmodel:StatsEntry">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind Name}" Grid.Column="0" TextWrapping="Wrap" Foreground="LightGray"/>
<TextBlock Text="{x:Bind Count}" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Border>-->
<TextBlock FontWeight="Bold">Details:</TextBlock>
<Border Style="{StaticResource StatsBorder}">
<StackPanel>
<ItemsControl ItemsSource="{x:Bind OutputTotal, Mode=OneWay}">
<ItemsControl.ItemTemplate>
<DataTemplate x:DataType="viewmodel:StatsEntry">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Text="{x:Bind Name}" Grid.Column="0" TextWrapping="Wrap" Foreground="LightGray"/>
<TextBlock Text="{x:Bind Count}" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Separator -->
<Border Style="{StaticResource StatsSeparator}" Padding="0"/>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" TextWrapping="Wrap" Foreground="LightGray" Text="Animations complexity"/>
<TextBlock Grid.Row="0" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right" Text="0.0" x:Name="AnimationsComplexity"/>
<TextBlock Grid.Row="1" Grid.Column="0" TextWrapping="Wrap" Foreground="LightGray" Text="Geometry complexity"/>
<TextBlock Grid.Row="1" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right" Text="0.0" x:Name="GeometryComplexity"/>
<TextBlock Grid.Row="2" Grid.Column="0" TextWrapping="Wrap" Foreground="LightGray" Text="Effects complexity"/>
<TextBlock Grid.Row="2" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right" Text="0.0" x:Name="EffectsComplexity"/>
<TextBlock Grid.Row="3" Grid.Column="0" TextWrapping="Wrap" Foreground="LightGray" Text="Visual tree complexity"/>
<TextBlock Grid.Row="3" Grid.Column="1" TextWrapping="Wrap" Foreground="White" HorizontalAlignment="Right" Text="0.0" x:Name="TreeComplexity"/>
</Grid>
</StackPanel>
</Border>
</StackPanel>
</UserControl>

Просмотреть файл

@ -0,0 +1,89 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices.WindowsRuntime;
using LottieViewer.ViewModel;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
namespace LottieViewer
{
/// <summary>
/// Displays perf stats.
/// </summary>
internal sealed partial class PerfStats : UserControl
{
public PerfStats()
{
this.InitializeComponent();
}
public ObservableCollection<object> InputLayers { get; } = new ObservableCollection<object>();
public ObservableCollection<object> InputMasks { get; } = new ObservableCollection<object>();
public ObservableCollection<object> InputEffects { get; } = new ObservableCollection<object>();
public ObservableCollection<object> OutputTotal { get; } = new ObservableCollection<object>();
public ObservableCollection<object> OutputVisuals { get; } = new ObservableCollection<object>();
public ObservableCollection<object> OutputAnimations { get; } = new ObservableCollection<object>();
public ObservableCollection<object> OutputEffects { get; } = new ObservableCollection<object>();
public void Update(LottieVisualDiagnosticsViewModel diagnostics)
{
InputLayers.Clear();
InputMasks.Clear();
InputEffects.Clear();
OutputTotal.Clear();
OutputVisuals.Clear();
OutputAnimations.Clear();
OutputEffects.Clear();
foreach (var statsEntry in diagnostics.Stats)
{
if ((statsEntry.Tags & ~(StatsEntry.LOTTIE_COMPOSITION_TAG | StatsEntry.LAYER_TAG)) == 0)
{
InputLayers.Add(statsEntry);
}
if ((statsEntry.Tags & ~(StatsEntry.LOTTIE_COMPOSITION_TAG | StatsEntry.MASK_TAG)) == 0)
{
InputMasks.Add(statsEntry);
}
if ((statsEntry.Tags & ~(StatsEntry.LOTTIE_COMPOSITION_TAG | StatsEntry.EFFECT_TAG)) == 0)
{
InputEffects.Add(statsEntry);
}
if ((statsEntry.Tags & ~StatsEntry.WINDOWS_COMPOSITION_TAG) == 0)
{
OutputTotal.Add(statsEntry);
}
}
if (diagnostics.LottieVisualDiagnostics is not null && diagnostics.LottieVisualDiagnostics.WinCompStats is not null)
{
ScoreValue.Text = string.Format("{0:0.00}", diagnostics.LottieVisualDiagnostics!.WinCompStats!.CalculateApproximateComplexity());
AnimationsComplexity.Text = string.Format("{0:0.00}", diagnostics.LottieVisualDiagnostics!.WinCompStats!.CalculateApproximateAnimationsComplexity());
GeometryComplexity.Text = string.Format("{0:0.00}", diagnostics.LottieVisualDiagnostics!.WinCompStats!.CalculateApproximateGeometryComplexity());
EffectsComplexity.Text = string.Format("{0:0.00}", diagnostics.LottieVisualDiagnostics!.WinCompStats!.CalculateApproximateEffectsComplexity());
TreeComplexity.Text = string.Format("{0:0.00}", diagnostics.LottieVisualDiagnostics!.WinCompStats!.CalculateApproximateTreeComplexity());
}
}
}
}

Просмотреть файл

@ -37,6 +37,7 @@ namespace LottieViewer.ViewModel
LottieVisualDiagnostics = (LottieVisualDiagnostics?)value;
Issues.Clear();
Markers.Clear();
Stats.Clear();
ThemePropertyBindings.Clear();
ThemingPropertySet = null;
@ -52,6 +53,37 @@ namespace LottieViewer.ViewModel
Issues.Add(issue);
}
if (LottieVisualDiagnostics.LottieCompositionStats is not null)
{
uint tags = StatsEntry.LOTTIE_COMPOSITION_TAG | StatsEntry.LAYER_TAG;
Stats.Add(new StatsEntry("Solid layers", LottieVisualDiagnostics.LottieCompositionStats.SolidLayerCount, tags));
Stats.Add(new StatsEntry("Shape layers", LottieVisualDiagnostics.LottieCompositionStats.ShapeLayerCount, tags));
Stats.Add(new StatsEntry("PreComp layers", LottieVisualDiagnostics.LottieCompositionStats.PreCompLayerCount, tags));
Stats.Add(new StatsEntry("Image layers", LottieVisualDiagnostics.LottieCompositionStats.ImageLayerCount, tags));
tags = StatsEntry.LOTTIE_COMPOSITION_TAG | StatsEntry.MASK_TAG;
Stats.Add(new StatsEntry("Masks", LottieVisualDiagnostics.LottieCompositionStats.MaskCount, tags));
Stats.Add(new StatsEntry("Matte layers", LottieVisualDiagnostics.LottieCompositionStats.MatteLayerCount, tags));
tags = StatsEntry.LOTTIE_COMPOSITION_TAG | StatsEntry.EFFECT_TAG;
Stats.Add(new StatsEntry("Drop shadow", LottieVisualDiagnostics.LottieCompositionStats.DropShadowEffectCount, tags));
Stats.Add(new StatsEntry("Gaussian blur", LottieVisualDiagnostics.LottieCompositionStats.GaussianBlurEffectCount, tags));
}
if (LottieVisualDiagnostics.WinCompStats is not null)
{
uint tags = StatsEntry.WINDOWS_COMPOSITION_TAG;
Stats.Add(new StatsEntry("Keyframe animators", LottieVisualDiagnostics.WinCompStats.KeyframeAnimatorCount, tags));
Stats.Add(new StatsEntry("Expression animators", LottieVisualDiagnostics.WinCompStats.ExpressionAnimatorCount, tags));
Stats.Add(new StatsEntry("Keyframe count", LottieVisualDiagnostics.WinCompStats.KeyframeCount, tags));
Stats.Add(new StatsEntry("Geometries count", LottieVisualDiagnostics.WinCompStats.GeometriesCount, tags));
Stats.Add(new StatsEntry("Path commands count", LottieVisualDiagnostics.WinCompStats.PathCommandsCount, tags));
Stats.Add(new StatsEntry("Effect brush", LottieVisualDiagnostics.WinCompStats.EffectBrushCount, tags));
Stats.Add(new StatsEntry("Effect factory", LottieVisualDiagnostics.WinCompStats.EffectFactoryCount, tags));
Stats.Add(new StatsEntry("Composition objects", LottieVisualDiagnostics.WinCompStats.CompositionObjectCount, tags));
}
// Populate the marker info.
var composition = LottieVisualDiagnostics.LottieComposition;
if (composition is not null)
@ -160,6 +192,8 @@ namespace LottieViewer.ViewModel
public ObservableCollection<Issue> Issues { get; } = new ObservableCollection<Issue>();
public ObservableCollection<StatsEntry> Stats { get; } = new ObservableCollection<StatsEntry>();
public string SizeText
{
get

Просмотреть файл

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace LottieViewer.ViewModel
{
public class StatsEntry
{
public const uint LOTTIE_COMPOSITION_TAG = 1 << 0;
public const uint WINDOWS_COMPOSITION_TAG = 1 << 1;
public const uint LAYER_TAG = 1 << 2;
public const uint MASK_TAG = 1 << 3;
public const uint EFFECT_TAG = 1 << 4;
internal StatsEntry(string name, int count, uint tags)
{
Name = name;
Count = count;
Tags = tags;
}
public string Name { get; }
public int Count { get; }
public uint Tags { get; }
}
}

Просмотреть файл

@ -92,7 +92,15 @@ namespace CommunityToolkit.WinUI.Lottie
if (lottieComposition is not null)
{
lottieComposition = LottieMergeOptimizer.Optimize(lottieComposition);
if (diagnostics is not null)
{
diagnostics.LottieCompositionStats = new LottieData.Tools.Stats(lottieComposition);
}
if (options.HasFlag(LottieVisualOptions.Optimize))
{
lottieComposition = LottieMergeOptimizer.Optimize(lottieComposition);
}
}
if (diagnostics is not null)
@ -177,6 +185,11 @@ namespace CommunityToolkit.WinUI.Lottie
diagnostics.OptimizationTime = timeMeasurer.GetElapsedAndRestart();
}
}
if (diagnostics is not null)
{
diagnostics.WinCompStats = new UIData.Tools.Stats(wincompDataRootVisual);
}
});
if (wincompDataRootVisual is null)

Просмотреть файл

@ -72,6 +72,10 @@ namespace CommunityToolkit.WinUI.Lottie
// Describes the property bindings in the ThemingPropertySet.
internal IReadOnlyList<PropertyBinding>? ThemePropertyBindings { get; set; }
internal LottieData.Tools.Stats? LottieCompositionStats { get; set; }
internal UIData.Tools.Stats? WinCompStats { get; set; }
internal LottieVisualDiagnostics Clone() =>
new LottieVisualDiagnostics
{
@ -90,6 +94,8 @@ namespace CommunityToolkit.WinUI.Lottie
TranslationIssues = TranslationIssues,
TranslationTime = TranslationTime,
ValidationTime = ValidationTime,
LottieCompositionStats = LottieCompositionStats,
WinCompStats = WinCompStats,
};
#pragma warning restore CS1591 // Missing XML comment for publicly visible type or member
}

Просмотреть файл

@ -85,7 +85,23 @@ namespace CommunityToolkit.WinUI.Lottie.LottieData.Tools
}
}
MaskCount += layer.Masks.Count;
foreach (var effect in layer.Effects)
{
switch (effect.Type)
{
case Effect.EffectType.DropShadow:
DropShadowEffectCount++;
break;
case Effect.EffectType.GaussianBlur:
GaussianBlurEffectCount++;
break;
}
}
if (layer.LayerMatteType != Layer.MatteType.None)
{
MatteLayerCount++;
}
}
}
@ -101,6 +117,8 @@ namespace CommunityToolkit.WinUI.Lottie.LottieData.Tools
public int MaskCount { get; }
public int MatteLayerCount { get; }
public int MaskAddCount { get; }
public int MaskDarkenCount { get; }
@ -123,6 +141,10 @@ namespace CommunityToolkit.WinUI.Lottie.LottieData.Tools
public int TextLayerCount { get; }
public int GaussianBlurEffectCount { get; }
public int DropShadowEffectCount { get; }
public double Width { get; }
public double Height { get; }

Просмотреть файл

@ -0,0 +1,268 @@
// 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.
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using CommunityToolkit.WinUI.Lottie.WinCompData;
namespace CommunityToolkit.WinUI.Lottie.UIData.Tools
{
/// <summary>
/// Calculates stats for a WinCompData tree. Used to report the size of data
/// and the effectiveness of optimization.
/// </summary>
#if PUBLIC_UIData
public
#endif
sealed class Stats
{
public Stats(CompositionObject? root)
{
if (root is null)
{
return;
}
var objectGraph = Graph.FromCompositionObject(root, includeVertices: false);
CompositionPathCount = objectGraph.CompositionPathNodes.Count();
CanvasGeometryCount = objectGraph.CanvasGeometryNodes.Count();
var v = new HashSet<CompositionObject>();
foreach (var (_, obj) in objectGraph.CompositionObjectNodes)
{
AnimatorCount += obj.Animators.Count;
var expressionAnimatorCount = obj.Animators.Where(a => a.Animation.Type == CompositionObjectType.ExpressionAnimation).Count();
ExpressionAnimatorCount += expressionAnimatorCount;
KeyframeAnimatorCount += obj.Animators.Count - expressionAnimatorCount;
foreach (var animator in obj.Animators)
{
AnimatorCountByPropertyName[animator.AnimatedProperty] = AnimatorCountByPropertyName.GetValueOrDefault(animator.AnimatedProperty) + 1;
}
AnimatorCountByPropertyName[obj.Type.ToString()] = AnimatorCountByPropertyName.GetValueOrDefault(obj.Type.ToString()) + 1;
CompositionObjectCount++;
switch (obj.Type)
{
case CompositionObjectType.AnimationController:
AnimationControllerCount++;
break;
case CompositionObjectType.BooleanKeyFrameAnimation:
BooleanKeyFrameAnimationCount++;
break;
case CompositionObjectType.ColorKeyFrameAnimation:
ColorKeyFrameAnimationCount++;
break;
case CompositionObjectType.CompositionColorBrush:
ColorBrushCount++;
break;
case CompositionObjectType.CompositionColorGradientStop:
ColorGradientStopCount++;
break;
case CompositionObjectType.CompositionContainerShape:
ContainerShapeCount++;
break;
case CompositionObjectType.CompositionEffectBrush:
EffectBrushCount++;
break;
case CompositionObjectType.CompositionEllipseGeometry:
EllipseGeometryCount++;
break;
case CompositionObjectType.CompositionGeometricClip:
GeometricClipCount++;
break;
case CompositionObjectType.CompositionLinearGradientBrush:
LinearGradientBrushCount++;
break;
case CompositionObjectType.CompositionMaskBrush:
MaskBrushCount++;
break;
case CompositionObjectType.CompositionPathGeometry:
PathGeometryCount++;
break;
case CompositionObjectType.CompositionPropertySet:
{
var propertyCount = ((CompositionPropertySet)obj).Names.Count();
if (propertyCount > 0)
{
PropertySetCount++;
PropertySetPropertyCount += propertyCount;
}
}
break;
case CompositionObjectType.CompositionRadialGradientBrush:
RadialGradientBrushCount++;
break;
case CompositionObjectType.CompositionRectangleGeometry:
RectangleGeometryCount++;
break;
case CompositionObjectType.CompositionRoundedRectangleGeometry:
RoundedRectangleGeometryCount++;
break;
case CompositionObjectType.CompositionSpriteShape:
SpriteShapeCount++;
break;
case CompositionObjectType.CompositionSurfaceBrush:
SurfaceBrushCount++;
break;
case CompositionObjectType.CompositionViewBox:
ViewBoxCount++;
break;
case CompositionObjectType.CompositionVisualSurface:
VisualSurfaceCount++;
break;
case CompositionObjectType.ContainerVisual:
ContainerVisualCount++;
break;
case CompositionObjectType.CubicBezierEasingFunction:
CubicBezierEasingFunctionCount++;
break;
case CompositionObjectType.DropShadow:
DropShadowCount++;
break;
case CompositionObjectType.ExpressionAnimation:
ExpressionAnimationCount++;
break;
case CompositionObjectType.InsetClip:
InsetClipCount++;
break;
case CompositionObjectType.LayerVisual:
LayerVisualCount++;
break;
case CompositionObjectType.LinearEasingFunction:
LinearEasingFunctionCount++;
break;
case CompositionObjectType.PathKeyFrameAnimation:
PathKeyFrameAnimationCount++;
break;
case CompositionObjectType.ScalarKeyFrameAnimation:
ScalarKeyFrameAnimationCount++;
break;
case CompositionObjectType.ShapeVisual:
ShapeVisualCount++;
break;
case CompositionObjectType.SpriteVisual:
SpriteVisualCount++;
break;
case CompositionObjectType.StepEasingFunction:
StepEasingFunctionCount++;
break;
case CompositionObjectType.Vector2KeyFrameAnimation:
Vector2KeyFrameAnimationCount++;
break;
case CompositionObjectType.Vector3KeyFrameAnimation:
Vector3KeyFrameAnimationCount++;
break;
case CompositionObjectType.Vector4KeyFrameAnimation:
Vector4KeyFrameAnimationCount++;
break;
case CompositionObjectType.CompositionEffectFactory:
EffectFactoryCount++;
break;
default:
throw new InvalidOperationException();
}
}
}
public int AnimationControllerCount { get; }
public int AnimatorCount { get; }
public int ExpressionAnimatorCount { get; }
public int KeyframeAnimatorCount { get; }
public Dictionary<string, int> AnimatorCountByPropertyName { get; } = new Dictionary<string, int>();
public int BooleanKeyframeAnimatorCount { get; }
public int BooleanKeyFrameAnimationCount { get; }
public int CanvasGeometryCount { get; }
public int ColorKeyFrameAnimationCount { get; }
public int ColorBrushCount { get; }
public int ColorGradientStopCount { get; }
public int CompositionObjectCount { get; }
public int CompositionPathCount { get; }
public int ContainerShapeCount { get; }
public int DropShadowCount { get; }
public int EffectBrushCount { get; }
public int EffectFactoryCount { get; }
public int EllipseGeometryCount { get; }
public int GeometricClipCount { get; }
public int LinearGradientBrushCount { get; }
public int MaskBrushCount { get; }
public int PathGeometryCount { get; }
public int PropertySetPropertyCount { get; }
public int PropertySetCount { get; }
public int RadialGradientBrushCount { get; }
public int RectangleGeometryCount { get; }
public int RoundedRectangleGeometryCount { get; }
public int SpriteShapeCount { get; }
public int SurfaceBrushCount { get; }
public int ViewBoxCount { get; }
public int VisualSurfaceCount { get; }
public int ContainerVisualCount { get; }
public int CubicBezierEasingFunctionCount { get; }
public int ExpressionAnimationCount { get; }
public int InsetClipCount { get; }
public int LayerVisualCount { get; }
public int LinearEasingFunctionCount { get; }
public int PathKeyFrameAnimationCount { get; }
public int ScalarKeyFrameAnimationCount { get; }
public int ShapeVisualCount { get; }
public int SpriteVisualCount { get; }
public int StepEasingFunctionCount { get; }
public int Vector2KeyFrameAnimationCount { get; }
public int Vector3KeyFrameAnimationCount { get; }
public int Vector4KeyFrameAnimationCount { get; }
}
}

Просмотреть файл

@ -5,8 +5,10 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using CommunityToolkit.WinUI.Lottie.WinCompData;
using CommunityToolkit.WinUI.Lottie.WinCompData.Mgcg;
namespace CommunityToolkit.WinUI.Lottie.UIData.Tools
{
@ -19,6 +21,63 @@ namespace CommunityToolkit.WinUI.Lottie.UIData.Tools
#endif
sealed class Stats
{
private int CountNumberOfPathCommands(CanvasGeometry geometry)
{
if (geometry is CanvasGeometry.Path path)
{
return path.Commands.Length;
}
if (geometry is CanvasGeometry.Combination combination)
{
return CountNumberOfPathCommands(combination.A) + CountNumberOfPathCommands(combination.B);
}
if (geometry is CanvasGeometry.TransformedGeometry transformed)
{
return CountNumberOfPathCommands(transformed.SourceGeometry);
}
if (geometry is CanvasGeometry.Group group)
{
int res = 0;
foreach (var g in group.Geometries)
{
res += CountNumberOfPathCommands(g);
}
return res;
}
return 0;
}
private int CountNumberOfGeometries(CanvasGeometry geometry)
{
if (geometry is CanvasGeometry.Combination combination)
{
return CountNumberOfGeometries(combination.A) + CountNumberOfGeometries(combination.B);
}
if (geometry is CanvasGeometry.TransformedGeometry transformed)
{
return CountNumberOfGeometries(transformed.SourceGeometry);
}
if (geometry is CanvasGeometry.Group group)
{
int res = 0;
foreach (var g in group.Geometries)
{
res += CountNumberOfGeometries(g);
}
return res;
}
return 1;
}
public Stats(CompositionObject? root)
{
if (root is null)
@ -31,10 +90,58 @@ namespace CommunityToolkit.WinUI.Lottie.UIData.Tools
CompositionPathCount = objectGraph.CompositionPathNodes.Count();
CanvasGeometryCount = objectGraph.CanvasGeometryNodes.Count();
var v = new HashSet<CompositionObject>();
foreach (var (_, obj) in objectGraph.CompositionObjectNodes)
{
AnimatorCount += obj.Animators.Count;
var expressionAnimatorCount = obj.Animators.Where(a => a.Animation.Type == CompositionObjectType.ExpressionAnimation).Count();
ExpressionAnimatorCount += expressionAnimatorCount;
KeyframeAnimatorCount += obj.Animators.Count - expressionAnimatorCount;
foreach (var animator in obj.Animators)
{
// AnimatorCountByPropertyName[animator.AnimatedProperty] = AnimatorCountByPropertyName.GetValueOrDefault(animator.AnimatedProperty) + 1;
if (animator.Animation is KeyFrameAnimation_ animation)
{
KeyframeCount += animation.KeyFrameCount;
}
}
if (obj is CompositionSpriteShape spriteShape)
{
if (spriteShape.Geometry is CompositionPathGeometry geometry)
{
if (geometry.Path?.Source is CanvasGeometry canvasGeometry)
{
PathCommandsCount += CountNumberOfPathCommands(canvasGeometry);
GeometriesCount += CountNumberOfGeometries(canvasGeometry);
}
}
else
{
GeometriesCount += 1;
}
}
if (obj is PathKeyFrameAnimation pathAnimation)
{
foreach (var keyframe in pathAnimation.KeyFrames)
{
if (keyframe is PathKeyFrameAnimation.ValueKeyFrame valueKeyframe)
{
if (valueKeyframe.Value.Source is CanvasGeometry geometry)
{
PathCommandsCount += CountNumberOfPathCommands(geometry);
GeometriesCount += CountNumberOfGeometries(geometry);
}
}
}
}
// AnimatorCountByPropertyName[obj.Type.ToString()] = AnimatorCountByPropertyName.GetValueOrDefault(obj.Type.ToString()) + 1;
CompositionObjectCount++;
switch (obj.Type)
{
@ -160,12 +267,94 @@ namespace CommunityToolkit.WinUI.Lottie.UIData.Tools
}
}
public int AnimationControllerListCount { get; }
public float CalculateApproximateAnimationsComplexity()
{
var complexity = 0.0f;
var otherKeyframeAnimators = KeyframeAnimatorCount;
complexity += ExpressionAnimatorCount * 15;
otherKeyframeAnimators -= AnimatorCountByPropertyName.GetValueOrDefault("IsVisible");
complexity += AnimatorCountByPropertyName.GetValueOrDefault("IsVisible") * 5;
otherKeyframeAnimators -= AnimatorCountByPropertyName.GetValueOrDefault("Opacity");
complexity += AnimatorCountByPropertyName.GetValueOrDefault("Opacity") * 30;
otherKeyframeAnimators -= AnimatorCountByPropertyName.GetValueOrDefault("Color");
complexity += AnimatorCountByPropertyName.GetValueOrDefault("Color") * 30;
complexity += otherKeyframeAnimators * 10;
complexity += KeyframeCount * 5;
return complexity / 1000.0f;
}
public float CalculateApproximateGeometryComplexity()
{
var complexity = 0.0f;
complexity += PathCommandsCount * 4;
complexity += GeometriesCount * 20;
return complexity / 1000.0f;
}
public float CalculateApproximateEffectsComplexity()
{
var complexity = 0.0f;
complexity += EffectBrushCount * 500;
complexity += EffectFactoryCount * 1000;
return complexity / 1000.0f;
}
public float CalculateApproximateTreeComplexity()
{
var complexity = 0.0f;
complexity += ContainerVisualCount * 5;
complexity += LayerVisualCount * 5;
complexity += ShapeVisualCount * 5;
complexity += SpriteVisualCount * 20;
complexity += ContainerShapeCount * 5;
complexity += CompositionObjectCount;
return complexity / 1000.0f;
}
public float CalculateApproximateComplexity()
{
var complexity = 0.0f;
complexity += CalculateApproximateAnimationsComplexity();
complexity += CalculateApproximateGeometryComplexity();
complexity += CalculateApproximateEffectsComplexity();
complexity += CalculateApproximateTreeComplexity();
return complexity;
}
public int AnimationControllerCount { get; }
public int AnimatorCount { get; }
public int ExpressionAnimatorCount { get; }
public int KeyframeAnimatorCount { get; }
public int KeyframeCount { get; }
public int PathCommandsCount { get; }
public int GeometriesCount { get; }
public Dictionary<string, int> AnimatorCountByPropertyName { get; } = new Dictionary<string, int>();
public int BooleanKeyframeAnimatorCount { get; }
public int BooleanKeyFrameAnimationCount { get; }
public int CanvasGeometryCount { get; }