Browse Source

parser wip

flabbet 1 year ago
parent
commit
3764a924bb

+ 75 - 291
src/PixiEditor.AvaloniaUI/Helpers/DocumentViewModelBuilder.cs

@@ -1,22 +1,16 @@
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Runtime.InteropServices;
-using ChunkyImageLib;
+using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
 using PixiEditor.AvaloniaUI.Helpers.Extensions;
-using PixiEditor.AvaloniaUI.Views.Animations;
-using PixiEditor.DrawingApi.Core.Numerics;
-using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.AvaloniaUI.ViewModels.Document;
 using PixiEditor.Extensions.CommonApi.Palettes;
 using PixiEditor.Numerics;
 using PixiEditor.Parser;
-using PixiEditor.Parser.Helpers;
-using BlendMode = PixiEditor.ChangeableDocument.Enums.BlendMode;
+using PixiEditor.Parser.Graph;
+using PixiEditor.Parser.Skia;
 
 namespace PixiEditor.AvaloniaUI.Helpers;
 
-internal class DocumentViewModelBuilder : ChildrenBuilder
+internal class DocumentViewModelBuilder : PixiParserV3DocumentEx.ChildrenBuilder
 {
     public int Width { get; set; }
     public int Height { get; set; }
@@ -26,6 +20,8 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
 
     public ReferenceLayerBuilder ReferenceLayer { get; set; }
     public List<KeyFrameBuilder> AnimationData { get; set; } = new List<KeyFrameBuilder>();
+    
+    public NodeGraphBuilder Graph { get; set; }
 
     public DocumentViewModelBuilder WithSize(int width, int height)
     {
@@ -55,11 +51,12 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
     public DocumentViewModelBuilder WithPalette<T>(IEnumerable<T> pallet, Func<T, PaletteColor> toColor) =>
         WithPalette(pallet.Select(toColor));
 
-    public DocumentViewModelBuilder WithReferenceLayer<T>(T reference, Action<T, ReferenceLayerBuilder> builder)
+    public DocumentViewModelBuilder WithReferenceLayer<T>(T reference, Action<T, ReferenceLayerBuilder, ImageEncoder?> builder,
+        ImageEncoder? encoder)
     {
         if (reference != null)
         {
-            WithReferenceLayer(x => builder(reference, x));
+            WithReferenceLayer(x => builder(reference, x, encoder));
         }
 
         return this;
@@ -76,19 +73,38 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
         return this;
     }
     
-    public DocumentViewModelBuilder WithAnimationData(AnimationData? animationData, Folder documentRootFolder)
+    public DocumentViewModelBuilder WithAnimationData(AnimationData? animationData)
     {
         AnimationData = new List<KeyFrameBuilder>();
 
         if (animationData != null && animationData.KeyFrameGroups.Count > 0)
         {
-            BuildKeyFrames(animationData.KeyFrameGroups.Cast<IKeyFrame>().ToList(), AnimationData, documentRootFolder);
+            BuildKeyFrames(animationData.KeyFrameGroups.Cast<IKeyFrame>().ToList(), AnimationData);
         }
 
         return this;
     }
+    
+    public DocumentViewModelBuilder WithGraph(NodeGraph graph)
+    {
+        Graph = new NodeGraphBuilder();
+        
+        if (graph.AllNodes != null)
+        {
+            foreach (var node in graph.AllNodes)
+            {
+                Graph.WithNode(new NodeBuilder()
+                    .WithId(node.Id)
+                    .WithPosition(node.Position)
+                    .WithName(node.Name)
+                    .WithUniqueNodeName(node.UniqueNodeName));
+            }
+        }
+        
+        return this;
+    }
 
-    private static void BuildKeyFrames(List<IKeyFrame> root, List<KeyFrameBuilder> data, Folder documentRootFolder)
+    private static void BuildKeyFrames(List<IKeyFrame> root, List<KeyFrameBuilder> data)
     {
         foreach (var keyFrame in root)
         {
@@ -123,251 +139,6 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
         }
     }
 
-    public abstract class StructureMemberBuilder
-    {
-        private MaskBuilder maskBuilder;
-
-        public int OrderInStructure { get; set; }
-
-        public string Name { get; set; }
-
-        public bool IsVisible { get; set; }
-
-        public float Opacity { get; set; }
-
-        public BlendMode BlendMode { get; set; }
-
-        public bool ClipToMemberBelow { get; set; }
-
-        public bool HasMask => maskBuilder is not null;
-
-        [NotNull] public MaskBuilder Mask => maskBuilder ??= new MaskBuilder();
-
-        public Guid Id { get; set; }
-
-        public StructureMemberBuilder()
-        {
-            IsVisible = true;
-            Opacity = 1;
-        }
-
-        public StructureMemberBuilder WithOrderInStructure(int order)
-        {
-            OrderInStructure = order;
-            return this;
-        }
-
-        public StructureMemberBuilder WithName(string name)
-        {
-            Name = name;
-            return this;
-        }
-
-        public StructureMemberBuilder WithVisibility(bool visibility)
-        {
-            IsVisible = visibility;
-            return this;
-        }
-
-        public StructureMemberBuilder WithOpacity(float opacity)
-        {
-            Opacity = opacity;
-            return this;
-        }
-
-        public StructureMemberBuilder WithBlendMode(BlendMode blendMode)
-        {
-            BlendMode = blendMode;
-            return this;
-        }
-
-        public StructureMemberBuilder WithMask(Action<MaskBuilder> mask)
-        {
-            mask(Mask);
-            return this;
-        }
-
-        public StructureMemberBuilder WithMask<T>(T reference, Action<MaskBuilder, T> mask)
-        {
-            return reference != null ? WithMask(x => mask(x, reference)) : this;
-        }
-
-        public StructureMemberBuilder WithGuid(Guid guid)
-        {
-            Id = guid;
-            return this;
-        }
-
-        public StructureMemberBuilder WithClipToBelow(bool value)
-        {
-            ClipToMemberBelow = value;
-            return this;
-        }
-    }
-
-    public class LayerBuilder : StructureMemberBuilder
-    {
-        private int? width;
-        private int? height;
-
-        public SurfaceBuilder? Surface { get; set; }
-
-        public int Width
-        {
-            get => width ?? default;
-            set => width = value;
-        }
-
-        public int Height
-        {
-            get => height ?? default;
-            set => height = value;
-        }
-
-        public int OffsetX { get; set; }
-
-        public int OffsetY { get; set; }
-
-        public bool LockAlpha { get; set; }
-
-        public new LayerBuilder WithName(string name) => base.WithName(name) as LayerBuilder;
-
-        public new LayerBuilder WithVisibility(bool visibility) => base.WithVisibility(visibility) as LayerBuilder;
-
-        public new LayerBuilder WithOpacity(float opacity) => base.WithOpacity(opacity) as LayerBuilder;
-
-        public new LayerBuilder WithBlendMode(BlendMode blendMode) => base.WithBlendMode(blendMode) as LayerBuilder;
-
-        public new LayerBuilder WithClipToBelow(bool value) => base.WithClipToBelow(value) as LayerBuilder;
-
-        public LayerBuilder WithLockAlpha(bool layerLockAlpha)
-        {
-            LockAlpha = layerLockAlpha;
-            return this;
-        }
-
-        public new LayerBuilder WithMask(Action<MaskBuilder> mask) => base.WithMask(mask) as LayerBuilder;
-
-        public new LayerBuilder WithGuid(Guid guid) => base.WithGuid(guid) as LayerBuilder;
-
-        public LayerBuilder WithSurface(Surface surface)
-        {
-            Surface = new(surface);
-            return this;
-        }
-
-        public LayerBuilder WithSize(int width, int height)
-        {
-            Width = width;
-            Height = height;
-            return this;
-        }
-
-        public LayerBuilder WithSize(VecI size) => WithSize(size.X, size.Y);
-
-        public LayerBuilder WithRect(int width, int height, int offsetX, int offsetY)
-        {
-            Width = width;
-            Height = height;
-            OffsetX = offsetX;
-            OffsetY = offsetY;
-            return this;
-        }
-
-        public LayerBuilder WithSurface(Action<SurfaceBuilder> surface)
-        {
-            if (width is null || height is null)
-            {
-                throw new InvalidOperationException(
-                    "You must first set the width and height of the layer. You can do this by calling WithRect() or setting the Width and Height properties.");
-            }
-
-            var surfaceBuilder = new SurfaceBuilder(new Surface(new VecI(Width, Height)));
-            surface(surfaceBuilder);
-            Surface = surfaceBuilder;
-            return this;
-        }
-    }
-
-    public class FolderBuilder : StructureMemberBuilder
-    {
-        public List<StructureMemberBuilder> Children { get; set; } = new List<StructureMemberBuilder>();
-
-        public new FolderBuilder WithName(string name) => base.WithName(name) as FolderBuilder;
-
-        public new FolderBuilder WithVisibility(bool visibility) => base.WithVisibility(visibility) as FolderBuilder;
-
-        public new FolderBuilder WithOpacity(float opacity) => base.WithOpacity(opacity) as FolderBuilder;
-
-        public new FolderBuilder WithBlendMode(BlendMode blendMode) => base.WithBlendMode(blendMode) as FolderBuilder;
-
-        public new FolderBuilder WithMask(Action<MaskBuilder> mask) => base.WithMask(mask) as FolderBuilder;
-
-        public new FolderBuilder WithGuid(Guid guid) => base.WithGuid(guid) as FolderBuilder;
-
-        public FolderBuilder WithClipToBelow(bool value) => base.WithClipToBelow(value) as FolderBuilder;
-
-        public FolderBuilder WithChildren(Action<ChildrenBuilder> children)
-        {
-            ChildrenBuilder childrenBuilder = new();
-            children(childrenBuilder);
-            Children = childrenBuilder.Children;
-            return this;
-        }
-    }
-
-    public class SurfaceBuilder
-    {
-        public Surface Surface { get; set; }
-
-        public SurfaceBuilder(Surface surface)
-        {
-            Surface = surface;
-        }
-
-        public SurfaceBuilder WithImage(ReadOnlySpan<byte> buffer) => WithImage(buffer, 0, 0);
-
-        public SurfaceBuilder WithImage(ReadOnlySpan<byte> buffer, int x, int y)
-        {
-            if (buffer.IsEmpty) return this;
-
-            Surface.DrawingSurface.Canvas.DrawBitmap(Bitmap.Decode(buffer), x, y);
-            return this;
-        }
-    }
-
-    public class MaskBuilder
-    {
-        public bool IsVisible { get; set; }
-
-        public SurfaceBuilder Surface { get; set; }
-
-        public MaskBuilder()
-        {
-            IsVisible = true;
-        }
-
-        public MaskBuilder WithVisibility(bool isVisible)
-        {
-            IsVisible = isVisible;
-            return this;
-        }
-
-        public MaskBuilder WithSurface(Surface surface)
-        {
-            Surface = new SurfaceBuilder(surface);
-            return this;
-        }
-
-        public MaskBuilder WithSurface(int width, int height, Action<SurfaceBuilder> surface)
-        {
-            var surfaceBuilder = new SurfaceBuilder(new Surface(new VecI(Math.Max(width, 1), Math.Max(height, 1))));
-            surface(surfaceBuilder);
-            Surface = surfaceBuilder;
-            return this;
-        }
-    }
-
     public class ReferenceLayerBuilder
     {
         public bool IsVisible { get; set; }
@@ -422,28 +193,6 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
     }
 }
 
-internal class ChildrenBuilder
-{
-    public List<DocumentViewModelBuilder.StructureMemberBuilder> Children { get; set; } =
-        new List<DocumentViewModelBuilder.StructureMemberBuilder>();
-
-    public ChildrenBuilder WithLayer(Action<DocumentViewModelBuilder.LayerBuilder> layer)
-    {
-        var layerBuilder = new DocumentViewModelBuilder.LayerBuilder();
-        layer(layerBuilder);
-        Children.Add(layerBuilder);
-        return this;
-    }
-
-    public ChildrenBuilder WithFolder(Action<DocumentViewModelBuilder.FolderBuilder> folder)
-    {
-        var folderBuilder = new DocumentViewModelBuilder.FolderBuilder();
-        folder(folderBuilder);
-        Children.Add(folderBuilder);
-        return this;
-    }
-}
-
 internal class KeyFrameBuilder()
 {
     public int StartFrame { get; set; }
@@ -504,17 +253,52 @@ internal class GroupKeyFrameBuilder : KeyFrameBuilder
 
 internal class RasterKeyFrameBuilder : KeyFrameBuilder
 {
-    public DocumentViewModelBuilder.SurfaceBuilder Surface { get; set; }
-
-    public RasterKeyFrameBuilder WithSurface(Surface surface)
-    {
-        Surface = new DocumentViewModelBuilder.SurfaceBuilder(new Surface(surface));
-        return this;
-    }
-
     public new RasterKeyFrameBuilder WithVisibility(bool isVisible) => base.WithVisibility(isVisible) as RasterKeyFrameBuilder;
     public new RasterKeyFrameBuilder WithLayerGuid(Guid layerGuid) => base.WithLayerGuid(layerGuid) as RasterKeyFrameBuilder;
     public new RasterKeyFrameBuilder WithId(Guid id) => base.WithId(id) as RasterKeyFrameBuilder;
     public new RasterKeyFrameBuilder WithStartFrame(int startFrame) => base.WithStartFrame(startFrame) as RasterKeyFrameBuilder;
     public new RasterKeyFrameBuilder WithDuration(int duration) => base.WithDuration(duration) as RasterKeyFrameBuilder;
 }
+
+internal class NodeGraphBuilder
+{
+    public List<NodeBuilder> AllNodes { get; set; } = new List<NodeBuilder>();
+
+    public NodeGraphBuilder WithNode(NodeBuilder node)
+    {
+        AllNodes.Add(node);
+        return this;
+    }
+}
+
+internal class NodeBuilder
+{
+    public int Id { get; set; }
+    public Vector2 Position { get; set; }
+    public string Name { get; set; }
+    public string UniqueNodeName { get; set; }
+
+    public NodeBuilder WithId(int id)
+    {
+        Id = id;
+        return this;
+    }
+
+    public NodeBuilder WithPosition(Vector2 position)
+    {
+        Position = position;
+        return this;
+    }
+
+    public NodeBuilder WithName(string name)
+    {
+        Name = name;
+        return this;
+    }
+
+    public NodeBuilder WithUniqueNodeName(string uniqueNodeName)
+    {
+        UniqueNodeName = uniqueNodeName;
+        return this;
+    }
+}

+ 10 - 0
src/PixiEditor.AvaloniaUI/Helpers/Extensions/PixelFormatHelper.cs

@@ -14,6 +14,16 @@ internal static class PixelFormatHelper
 
         throw new NotImplementedException($"Skia does not support the '{format}' format");
     }
+    
+    public static ColorType ToColorType(this SKColorType colorType)
+    { 
+        return (ColorType)colorType;
+    }
+    
+    public static AlphaType ToAlphaType(this SKAlphaType alphaType)
+    {
+        return (AlphaType)alphaType;
+    }
 
     public static bool TryConvertToColorType(this PixelFormat format, out ColorType colorType, out AlphaType alphaType)
     {

+ 33 - 109
src/PixiEditor.AvaloniaUI/Helpers/Extensions/PixiParserDocumentEx.cs

@@ -1,130 +1,54 @@
-using System.Collections.Generic;
-using ChunkyImageLib;
+using ChunkyImageLib;
 using PixiEditor.AvaloniaUI.ViewModels.Document;
-using PixiEditor.DrawingApi.Core.Numerics;
-using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.Extensions.CommonApi.Palettes;
 using PixiEditor.Numerics;
 using PixiEditor.Parser;
-using PixiEditor.Parser.Deprecated;
+using PixiEditor.Parser.Graph;
+using PixiEditor.Parser.Skia;
 
 namespace PixiEditor.AvaloniaUI.Helpers.Extensions;
 
 internal static class PixiParserDocumentEx
 {
-    public static VecD ToVecD(this Vector2 vec)
-    {
-        return new VecD(vec.X, vec.Y);
-    }
-    
     public static DocumentViewModel ToDocument(this Document document)
     {
-        return DocumentViewModel.Build(b =>
-        {
-            b.WithSize(document.Width, document.Height)
-                .WithPalette(document.Palette, x => new PaletteColor(x.R, x.G, x.B))
-                .WithSwatches(document.Swatches, x => new(x.R, x.G, x.B))
-                .WithReferenceLayer(document.ReferenceLayer, (r, builder) => builder
-                    .WithIsVisible(r.Enabled)
-                    .WithShape(r.Corners)
-                    .WithIsTopmost(r.Topmost)
-                    .WithSurface(Surface.Load(r.ImageBytes)))
-                .WithAnimationData(document.AnimationData, document.RootFolder);
-
-            BuildChildren(b, document.RootFolder.Children);
-        });
-
-        void BuildChildren(ChildrenBuilder builder, IEnumerable<IStructureMember> members)
+        ImageEncoder? encoder = document.GetEncoder();
+        if (encoder == null)
         {
-            foreach (var member in members)
-            {
-                if (member is Folder folder)
-                {
-                    builder.WithFolder(x => BuildFolder(x, folder));
-                }
-                else if (member is ImageLayer layer)
-                {
-                    builder.WithLayer(x => BuildLayer(x, layer));
-                }
-                else
-                {
-                    throw new NotImplementedException($"StructureMember of type '{member.GetType().FullName}' has not been implemented");
-                }
-            }
+            throw new ArgumentException("Document does not have a valid encoder");
         }
 
-        void BuildFolder(DocumentViewModelBuilder.FolderBuilder builder, Folder folder) => builder
-            .WithName(folder.Name)
-            .WithVisibility(folder.Enabled)
-            .WithOpacity(folder.Opacity)
-            .WithBlendMode((PixiEditor.ChangeableDocument.Enums.BlendMode)(int)folder.BlendMode)
-            .WithChildren(x => BuildChildren(x, folder.Children))
-            .WithClipToBelow(folder.ClipToMemberBelow)
-            .WithMask(folder.Mask, (x, m) => x.WithVisibility(m.Enabled).WithSurface(m.Width, m.Height, x => x.WithImage(m.ImageBytes, m.OffsetX, m.OffsetY)));
-
-        void BuildLayer(DocumentViewModelBuilder.LayerBuilder builder, ImageLayer layer)
-        {
-            builder
-                .WithName(layer.Name)
-                .WithGuid(layer.Guid)
-                .WithVisibility(layer.Enabled)
-                .WithOpacity(layer.Opacity)
-                .WithBlendMode((PixiEditor.ChangeableDocument.Enums.BlendMode)(int)layer.BlendMode)
-                .WithRect(layer.Width, layer.Height, layer.OffsetX, layer.OffsetY)
-                .WithClipToBelow(layer.ClipToMemberBelow)
-                .WithLockAlpha(layer.LockAlpha)
-                .WithMask(layer.Mask,
-                    (x, m) => x.WithVisibility(m.Enabled).WithSurface(m.Width, m.Height,
-                        x => x.WithImage(m.ImageBytes, m.OffsetX, m.OffsetY)));
-
-            if (layer is { Width: > 0, Height: > 0 })
-            {
-                builder.WithSurface(x => x.WithImage(layer.ImageBytes, 0, 0));
-            }
-        }
-        
+        return DocumentViewModel.Build(b => b
+            .WithSize(document.Width, document.Height)
+            .WithPalette(document.Palette, color => new PaletteColor(color.R, color.G, color.B))
+            .WithSwatches(document.Swatches, x => new(x.R, x.G, x.B))
+            .WithReferenceLayer(document.ReferenceLayer, BuildReferenceLayer, document.GetEncoder())
+            .WithGraph(document.Graph)
+            .WithAnimationData(document.AnimationData));
     }
-    
-    public static SKBitmap RenderOldDocument(this SerializableDocument document)
-    {
-        SKImageInfo info = new(document.Width, document.Height, SKColorType.RgbaF32, SKAlphaType.Unpremul, SKColorSpace.CreateSrgb());
-        using SKSurface surface = SKSurface.Create(info);
-        SKCanvas canvas = surface.Canvas;
-        using SKPaint paint = new();
 
-        foreach (var layer in document)
-        {
-            if (layer.PngBytes == null || layer.PngBytes.Length == 0)
-            {
-                continue;
-            }
-
-            bool visible = document.Layers.GetFinalLayerVisibilty(layer);
-
-            if (!visible)
-            {
-                continue;
-            }
-
-            double opacity = document.Layers.GetFinalLayerOpacity(layer);
-
-            if (opacity == 0)
-            {
-                continue;
-            }
-
-            using SKColorFilter filter = SKColorFilter.CreateBlendMode(SKColors.White.WithAlpha((byte)(opacity * 255)), SKBlendMode.DstIn);
-            paint.ColorFilter = filter;
-
-            using var image = SKImage.FromEncodedData(layer.PngBytes);
-            
-            canvas.DrawImage(image, layer.OffsetX, layer.OffsetY, paint);
-        }
+    private static void BuildReferenceLayer(
+        ReferenceLayer referenceLayer,
+        DocumentViewModelBuilder.ReferenceLayerBuilder layerBuilder,
+        ImageEncoder encoder)
+    {
+        DecodeSurface(referenceLayer.ImageBytes, (int)referenceLayer.Width, (int)referenceLayer.Height, encoder);
 
-        SKBitmap bitmap = new(info);
+        layerBuilder
+            .WithIsVisible(referenceLayer.Enabled)
+            .WithShape(referenceLayer.Corners)
+            .WithIsTopmost(referenceLayer.Topmost)
+            .WithSurface(Surface.Load(referenceLayer.ImageBytes));
+    }
 
-        surface.ReadPixels(info, bitmap.GetPixels(), info.RowBytes, 0, 0);
+    private static Surface DecodeSurface(byte[] imgBytes, int width, int height, ImageEncoder encoder)
+    {
+        Surface surface = new Surface(new VecI(width, height));
 
-        return bitmap;
+        byte[] decoded =
+            encoder.Decode(imgBytes, out SKColorType colorType, out SKAlphaType alphaType);
+        surface.DrawBytes(surface.Size, decoded, colorType.ToColorType(), alphaType.ToAlphaType());
+        
+        return surface;
     }
 }

+ 357 - 0
src/PixiEditor.AvaloniaUI/Helpers/Extensions/PixiParserV3DocumentEx.cs

@@ -0,0 +1,357 @@
+using System.Diagnostics.CodeAnalysis;
+using ChunkyImageLib;
+using PixiEditor.AvaloniaUI.ViewModels.Document;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.Extensions.CommonApi.Palettes;
+using PixiEditor.Numerics;
+using PixiEditor.Parser;
+using PixiEditor.Parser.Deprecated;
+using BlendMode = PixiEditor.Parser.BlendMode;
+
+namespace PixiEditor.AvaloniaUI.Helpers.Extensions;
+
+internal static class PixiParserV3DocumentEx
+{
+    public static VecD ToVecD(this Vector2 vec)
+    {
+        return new VecD(vec.X, vec.Y);
+    }
+
+    public static DocumentViewModel ToDocument(this DeprecatedDocument document)
+    {
+        return DocumentViewModel.Build(b =>
+        {
+            b.WithSize(document.Width, document.Height)
+                .WithPalette(document.Palette, x => new PaletteColor(x.R, x.G, x.B))
+                .WithSwatches(document.Swatches, x => new(x.R, x.G, x.B))
+                .WithReferenceLayer(document.ReferenceLayer, (r, builder) => builder
+                    .WithIsVisible(r.Enabled)
+                    .WithShape(r.Corners)
+                    .WithIsTopmost(r.Topmost)
+                    .WithSurface(Surface.Load(r.ImageBytes)));
+
+            BuildChildren(b, document.RootFolder.Children);
+        });
+
+        void BuildChildren(ChildrenBuilder builder, IEnumerable<IStructureMember> members)
+        {
+            foreach (var member in members)
+            {
+                if (member is Folder folder)
+                {
+                    builder.WithFolder(x => BuildFolder(x, folder));
+                }
+                else if (member is ImageLayer layer)
+                {
+                    builder.WithLayer(x => BuildLayer(x, layer));
+                }
+                else
+                {
+                    throw new NotImplementedException(
+                        $"StructureMember of type '{member.GetType().FullName}' has not been implemented");
+                }
+            }
+        }
+
+        void BuildFolder(FolderBuilder builder, Folder folder) => builder
+            .WithName(folder.Name)
+            .WithVisibility(folder.Enabled)
+            .WithOpacity(folder.Opacity)
+            .WithBlendMode(folder.BlendMode)
+            .WithChildren(x => BuildChildren(x, folder.Children))
+            .WithClipToBelow(folder.ClipToMemberBelow)
+            .WithMask(folder.Mask,
+                (x, m) => x.WithVisibility(m.Enabled).WithSurface(m.Width, m.Height,
+                    x => x.WithImage(m.ImageBytes, m.OffsetX, m.OffsetY)));
+
+        void BuildLayer(LayerBuilder builder, ImageLayer layer)
+        {
+            builder
+                .WithName(layer.Name)
+                .WithGuid(layer.Guid)
+                .WithVisibility(layer.Enabled)
+                .WithOpacity(layer.Opacity)
+                .WithBlendMode(layer.BlendMode)
+                .WithRect(layer.Width, layer.Height, layer.OffsetX, layer.OffsetY)
+                .WithClipToBelow(layer.ClipToMemberBelow)
+                .WithLockAlpha(layer.LockAlpha)
+                .WithMask(layer.Mask,
+                    (x, m) => x.WithVisibility(m.Enabled).WithSurface(m.Width, m.Height,
+                        x => x.WithImage(m.ImageBytes, m.OffsetX, m.OffsetY)));
+
+            if (layer is { Width: > 0, Height: > 0 })
+            {
+                builder.WithSurface(x => x.WithImage(layer.ImageBytes, 0, 0));
+            }
+        }
+    }
+
+
+    internal class ChildrenBuilder
+    {
+        public List<StructureMemberBuilder> Children { get; set; } =
+            new List<StructureMemberBuilder>();
+
+        public ChildrenBuilder WithLayer(Action<LayerBuilder> layer)
+        {
+            var layerBuilder = new LayerBuilder();
+            layer(layerBuilder);
+            Children.Add(layerBuilder);
+            return this;
+        }
+
+        public ChildrenBuilder WithFolder(Action<FolderBuilder> folder)
+        {
+            var folderBuilder = new FolderBuilder();
+            folder(folderBuilder);
+            Children.Add(folderBuilder);
+            return this;
+        }
+    }
+
+
+    public abstract class StructureMemberBuilder
+    {
+        private MaskBuilder maskBuilder;
+
+        public int OrderInStructure { get; set; }
+
+        public string Name { get; set; }
+
+        public bool IsVisible { get; set; }
+
+        public float Opacity { get; set; }
+
+        public BlendMode BlendMode { get; set; }
+
+        public bool ClipToMemberBelow { get; set; }
+
+        public bool HasMask => maskBuilder is not null;
+
+        [NotNull] public MaskBuilder Mask => maskBuilder ??= new MaskBuilder();
+
+        public Guid Id { get; set; }
+
+        public StructureMemberBuilder()
+        {
+            IsVisible = true;
+            Opacity = 1;
+        }
+
+        public StructureMemberBuilder WithOrderInStructure(int order)
+        {
+            OrderInStructure = order;
+            return this;
+        }
+
+        public StructureMemberBuilder WithName(string name)
+        {
+            Name = name;
+            return this;
+        }
+
+        public StructureMemberBuilder WithVisibility(bool visibility)
+        {
+            IsVisible = visibility;
+            return this;
+        }
+
+        public StructureMemberBuilder WithOpacity(float opacity)
+        {
+            Opacity = opacity;
+            return this;
+        }
+
+        public StructureMemberBuilder WithBlendMode(BlendMode blendMode)
+        {
+            BlendMode = blendMode;
+            return this;
+        }
+
+        public StructureMemberBuilder WithMask(Action<MaskBuilder> mask)
+        {
+            mask(Mask);
+            return this;
+        }
+
+        public StructureMemberBuilder WithMask<T>(T reference, Action<MaskBuilder, T> mask)
+        {
+            return reference != null ? WithMask(x => mask(x, reference)) : this;
+        }
+
+        public StructureMemberBuilder WithGuid(Guid guid)
+        {
+            Id = guid;
+            return this;
+        }
+
+        public StructureMemberBuilder WithClipToBelow(bool value)
+        {
+            ClipToMemberBelow = value;
+            return this;
+        }
+    }
+
+    public class LayerBuilder : StructureMemberBuilder
+    {
+        private int? width;
+        private int? height;
+
+        public SurfaceBuilder? Surface { get; set; }
+
+        public int Width
+        {
+            get => width ?? default;
+            set => width = value;
+        }
+
+        public int Height
+        {
+            get => height ?? default;
+            set => height = value;
+        }
+
+        public int OffsetX { get; set; }
+
+        public int OffsetY { get; set; }
+
+        public bool LockAlpha { get; set; }
+
+        public new LayerBuilder WithName(string name) => base.WithName(name) as LayerBuilder;
+
+        public new LayerBuilder WithVisibility(bool visibility) => base.WithVisibility(visibility) as LayerBuilder;
+
+        public new LayerBuilder WithOpacity(float opacity) => base.WithOpacity(opacity) as LayerBuilder;
+
+        public new LayerBuilder WithBlendMode(BlendMode blendMode) => base.WithBlendMode(blendMode) as LayerBuilder;
+
+        public new LayerBuilder WithClipToBelow(bool value) => base.WithClipToBelow(value) as LayerBuilder;
+
+        public LayerBuilder WithLockAlpha(bool layerLockAlpha)
+        {
+            LockAlpha = layerLockAlpha;
+            return this;
+        }
+
+        public new LayerBuilder WithMask(Action<MaskBuilder> mask) => base.WithMask(mask) as LayerBuilder;
+
+        public new LayerBuilder WithGuid(Guid guid) => base.WithGuid(guid) as LayerBuilder;
+
+        public LayerBuilder WithSurface(Surface surface)
+        {
+            Surface = new(surface);
+            return this;
+        }
+
+        public LayerBuilder WithSize(int width, int height)
+        {
+            Width = width;
+            Height = height;
+            return this;
+        }
+
+        public LayerBuilder WithSize(VecI size) => WithSize(size.X, size.Y);
+
+        public LayerBuilder WithRect(int width, int height, int offsetX, int offsetY)
+        {
+            Width = width;
+            Height = height;
+            OffsetX = offsetX;
+            OffsetY = offsetY;
+            return this;
+        }
+
+        public LayerBuilder WithSurface(Action<SurfaceBuilder> surface)
+        {
+            if (width is null || height is null)
+            {
+                throw new InvalidOperationException(
+                    "You must first set the width and height of the layer. You can do this by calling WithRect() or setting the Width and Height properties.");
+            }
+
+            var surfaceBuilder = new SurfaceBuilder(new Surface(new VecI(Width, Height)));
+            surface(surfaceBuilder);
+            Surface = surfaceBuilder;
+            return this;
+        }
+    }
+
+    public class FolderBuilder : StructureMemberBuilder
+    {
+        public List<StructureMemberBuilder> Children { get; set; } = new List<StructureMemberBuilder>();
+
+        public new FolderBuilder WithName(string name) => base.WithName(name) as FolderBuilder;
+
+        public new FolderBuilder WithVisibility(bool visibility) => base.WithVisibility(visibility) as FolderBuilder;
+
+        public new FolderBuilder WithOpacity(float opacity) => base.WithOpacity(opacity) as FolderBuilder;
+
+        public new FolderBuilder WithBlendMode(BlendMode blendMode) => base.WithBlendMode(blendMode) as FolderBuilder;
+
+        public new FolderBuilder WithMask(Action<MaskBuilder> mask) => base.WithMask(mask) as FolderBuilder;
+
+        public new FolderBuilder WithGuid(Guid guid) => base.WithGuid(guid) as FolderBuilder;
+
+        public FolderBuilder WithClipToBelow(bool value) => base.WithClipToBelow(value) as FolderBuilder;
+
+        public FolderBuilder WithChildren(Action<ChildrenBuilder> children)
+        {
+            ChildrenBuilder childrenBuilder = new();
+            children(childrenBuilder);
+            Children = childrenBuilder.Children;
+            return this;
+        }
+    }
+
+    public class SurfaceBuilder
+    {
+        public Surface Surface { get; set; }
+
+        public SurfaceBuilder(Surface surface)
+        {
+            Surface = surface;
+        }
+
+        public SurfaceBuilder WithImage(ReadOnlySpan<byte> buffer) => WithImage(buffer, 0, 0);
+
+        public SurfaceBuilder WithImage(ReadOnlySpan<byte> buffer, int x, int y)
+        {
+            if (buffer.IsEmpty) return this;
+
+            Surface.DrawingSurface.Canvas.DrawBitmap(Bitmap.Decode(buffer), x, y);
+            return this;
+        }
+    }
+
+    public class MaskBuilder
+    {
+        public bool IsVisible { get; set; }
+
+        public SurfaceBuilder Surface { get; set; }
+
+        public MaskBuilder()
+        {
+            IsVisible = true;
+        }
+
+        public MaskBuilder WithVisibility(bool isVisible)
+        {
+            IsVisible = isVisible;
+            return this;
+        }
+
+        public MaskBuilder WithSurface(Surface surface)
+        {
+            Surface = new SurfaceBuilder(surface);
+            return this;
+        }
+
+        public MaskBuilder WithSurface(int width, int height, Action<SurfaceBuilder> surface)
+        {
+            var surfaceBuilder = new SurfaceBuilder(new Surface(new VecI(Math.Max(width, 1), Math.Max(height, 1))));
+            surface(surfaceBuilder);
+            Surface = surfaceBuilder;
+            return this;
+        }
+    }
+}

+ 0 - 176
src/PixiEditor.AvaloniaUI/Helpers/SerializableDocumentEx.cs

@@ -1,176 +0,0 @@
-using System.Collections.Generic;
-using System.Linq;
-using ChunkyImageLib;
-using PixiEditor.AvaloniaUI.ViewModels.Document;
-using PixiEditor.DrawingApi.Core.Numerics;
-using PixiEditor.DrawingApi.Core.Surface.ImageData;
-using PixiEditor.Extensions.CommonApi.Palettes;
-using PixiEditor.Numerics;
-using PixiEditor.Parser;
-using PixiEditor.Parser.Collections.Deprecated;
-using PixiEditor.Parser.Deprecated;
-
-namespace PixiEditor.AvaloniaUI.Helpers;
-
-internal static class SerializableDocumentEx
-{
-    public static Vector2 ToVector2(this VecD serializableVector2)
-    {
-        return new Vector2 { X = serializableVector2.X, Y = serializableVector2.Y };
-    }
-    public static Image ToImage(this SerializableLayer serializableLayer)
-    {
-        if (serializableLayer.PngBytes == null)
-        {
-            return null;
-        }
-
-        return Image.FromEncodedData(serializableLayer.PngBytes);
-    }
-
-    public static DocumentViewModel ToDocument(this SerializableDocument serializableDocument)
-    {
-        List<SerializableLayer> builtLayers = new List<SerializableLayer>();
-        DocumentViewModel vm = DocumentViewModel.Build(builder =>
-        {
-            builder
-                .WithSize(serializableDocument.Width, serializableDocument.Height)
-                .WithPalette(serializableDocument.Palette.Select(x => new PaletteColor(x.R, x.G, x.B)).ToList())
-                .WithSwatches(serializableDocument.Swatches.Select(x => new PaletteColor(x.R, x.G, x.B)).ToList());
-
-            if (serializableDocument.Groups != null)
-            {
-                foreach (var group in serializableDocument.Groups)
-                {
-                    builder.WithFolder(folderBuilder =>
-                    {
-                        builtLayers.AddRange(BuildFolder(
-                            folderBuilder,
-                            group,
-                            GatherFolderLayers(group, serializableDocument.Layers),
-                            serializableDocument));
-                    });
-                }
-            }
-
-            BuildLayers(serializableDocument.Layers.Where(x => !builtLayers.Contains(x)), builder, serializableDocument);
-            SortMembersRecursively(builder.Children);
-        });
-
-        return vm;
-    }
-
-    /// <summary>
-    ///     Builds folder and its children.
-    /// </summary>
-    /// <param name="folderBuilder">Folder to build.</param>
-    /// <param name="group">Serialized folder (group), which will be used to build.</param>
-    /// <param name="layers">Layers only in this folder.</param>
-    /// <param name="doc">Document which contains all the serialized data.</param>
-    /// <returns>List of layers which were built.</returns>
-    private static List<SerializableLayer> BuildFolder(DocumentViewModelBuilder.FolderBuilder folderBuilder, SerializableGroup group, List<SerializableLayer> layers, SerializableDocument doc)
-    {
-        List<SerializableLayer> builtLayers = new List<SerializableLayer>(layers);
-        folderBuilder
-            .WithName(group.Name)
-            .WithOpacity(group.Opacity)
-            .WithVisibility(group.IsVisible)
-            .WithOrderInStructure(group.StartLayer);
-
-        folderBuilder.WithChildren(childrenBuilder =>
-            {
-                if (group.Subgroups != null)
-                {
-                    foreach (var subGroup in group.Subgroups)
-                    {
-                        childrenBuilder.WithFolder(subFolderBuilder =>
-                        {
-                            builtLayers.AddRange(BuildFolder(
-                                subFolderBuilder,
-                                subGroup,
-                                GatherFolderLayers(subGroup, doc.Layers),
-                                doc));
-                        });
-                    }
-                }
-
-                BuildLayers(layers, childrenBuilder, doc);
-            });
-
-        return builtLayers;
-    }
-
-    private static void BuildLayers(IEnumerable<SerializableLayer> layers, ChildrenBuilder builder, SerializableDocument document)
-    {
-        if (layers != null)
-        {
-            foreach (var layer in layers)
-            {
-                builder.WithLayer((layerBuilder) =>
-                {
-                    layerBuilder
-                        .WithSize(layer.Width, layer.Height)
-                        .WithName(layer.Name)
-                        .WithOpacity(layer.Opacity)
-                        .WithVisibility(layer.IsVisible)
-                        .WithRect(layer.Width, layer.Height, layer.OffsetX, layer.OffsetY)
-                        .WithSurface((surfaceBuilder) =>
-                        {
-                            if (layer.PngBytes is { Length: > 0 })
-                            {
-                                surfaceBuilder.WithImage(layer.PngBytes);
-                            }
-                            else
-                            {
-                                surfaceBuilder.Surface = new Surface(new VecI(1, 1));
-                            }
-                        })
-                        .WithOrderInStructure(document.Layers.IndexOf(layer));
-                });
-            }
-        }
-    }
-
-    /// <summary>
-    ///     Gathers all layers which are in the folder. Excludes layers which are in subfolders.
-    /// </summary>
-    /// <param name="group">Group which contains folder data.</param>
-    /// <param name="serializableDocumentLayers">All layers in document.</param>
-    /// <returns>List of layers in folder, excluding layers in nested folders.</returns>
-    private static List<SerializableLayer> GatherFolderLayers(SerializableGroup group, LayerCollection serializableDocumentLayers)
-    {
-        List<SerializableLayer> layers = new List<SerializableLayer>();
-
-        for (int i = group.StartLayer; i <= group.EndLayer; i++)
-        {
-            layers.Add(serializableDocumentLayers[i]);
-        }
-
-        if (group.Subgroups is { Count: > 0 })
-        {
-            foreach (var subGroup in group.Subgroups)
-            {
-                var nestedGroupLayers = GatherFolderLayers(subGroup, serializableDocumentLayers);
-                layers.RemoveAll(x => nestedGroupLayers.Contains(x));
-            }
-        }
-
-        return layers;
-    }
-
-    /// <summary>
-    /// Sorts StructureMemberBuilder by its OrderInStructure property.
-    /// </summary>
-    /// <param name="builderChildren">Structure to sort</param>
-    private static void SortMembersRecursively(List<DocumentViewModelBuilder.StructureMemberBuilder> builderChildren)
-    {
-        builderChildren.Sort(Comparer<DocumentViewModelBuilder.StructureMemberBuilder>.Create((a, b) => a.OrderInStructure - b.OrderInStructure));
-        
-        foreach (var child in builderChildren)
-        {
-            if (child is not DocumentViewModelBuilder.FolderBuilder folderBuilder)
-                continue;
-            SortMembersRecursively(folderBuilder.Children);
-        }
-    }
-}

+ 2 - 5
src/PixiEditor.AvaloniaUI/Models/Controllers/ClipboardController.cs

@@ -220,12 +220,9 @@ internal static class ClipboardController
                         }
 
                         stream.Position = 0;
-                        using var bitmap = DepractedPixiParser.Deserialize(stream).RenderOldDocument();
-                        var size = new VecI(bitmap.Width, bitmap.Height);
-                        imported = new Surface(size);
-                        imported.DrawBytes(size, bitmap.Bytes, ColorType.RgbaF32, AlphaType.Premul);
+                        var document = DeprecatedPixiParser.Deserialize(stream);
 
-                        System.Diagnostics.Debug.Write(imported.ToString());
+                        imported = Surface.Load(document.PreviewImage);
                     }
                 }
                 else

+ 2 - 2
src/PixiEditor.AvaloniaUI/Models/IO/Importer.cs

@@ -102,7 +102,7 @@ internal class Importer : ObservableObject
         {
             try
             {
-                var doc = DepractedPixiParser.Deserialize(path).ToDocument();
+                var doc = DeprecatedPixiParser.Deserialize(path).ToDocument();
                 
                 if (associatePath)
                 {
@@ -130,7 +130,7 @@ internal class Importer : ObservableObject
         {
             try
             {
-                var doc = DepractedPixiParser.Deserialize(file).ToDocument();
+                var doc = DeprecatedPixiParser.Deserialize(file).ToDocument();
                 doc.FullFilePath = originalFilePath;
                 return doc;
             }

+ 2 - 2
src/PixiEditor.AvaloniaUI/PixiEditor.AvaloniaUI.csproj

@@ -72,13 +72,13 @@
     <PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="4.9.2"/>
     <PackageReference Include="Newtonsoft.Json" Version="13.0.3"/>
     <PackageReference Include="PixiEditor.ColorPicker.Models" Version="1.0.5"/>
-    <PackageReference Include="PixiEditor.Parser" Version="3.4.0"/>
-    <PackageReference Include="PixiEditor.Parser.Skia" Version="3.0.1"/>
     <PackageReference Include="PixiEditor.ColorPicker.AvaloniaUI" Version="1.0.5"/>
   </ItemGroup>
 
   <ItemGroup>
     <ProjectReference Include="..\..\..\PixiDocks\src\PixiDocks.Avalonia\PixiDocks.Avalonia.csproj"/>
+    <ProjectReference Include="..\..\..\PixiParser\src\PixiParser.Skia\PixiParser.Skia.csproj" />
+    <ProjectReference Include="..\..\..\PixiParser\src\PixiParser\PixiParser.csproj" />
     <ProjectReference Include="..\ChunkyImageLib\ChunkyImageLib.csproj"/>
     <ProjectReference Include="..\PixiEditor.AnimationRenderer.Core\PixiEditor.AnimationRenderer.Core.csproj" />
     <ProjectReference Include="..\PixiEditor.AnimationRenderer.FFmpeg\PixiEditor.AnimationRenderer.FFmpeg.csproj" />

+ 60 - 0
src/PixiEditor.sln

@@ -102,6 +102,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiEditor.AnimationRendere
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AnimationRendering", "AnimationRendering", "{2BA72059-FFD7-4887-AE88-269017198933}"
 EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiParser", "..\..\PixiParser\src\PixiParser\PixiParser.csproj", "{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PixiParser.Skia", "..\..\PixiParser\src\PixiParser.Skia\PixiParser.Skia.csproj", "{F355C56A-3E47-40C0-8204-002233CEFE23}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|x64 = Debug|x64
@@ -1500,6 +1504,62 @@ Global
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|x64.Build.0 = Debug|Any CPU
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|ARM64.ActiveCfg = Debug|Any CPU
 		{CD863C88-72E3-40F4-9AAE-5696BBB4460C}.Steam|ARM64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Debug|x64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Debug|ARM64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.DevRelease|x64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.DevRelease|x64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.DevRelease|ARM64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.DevRelease|ARM64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.DevSteam|x64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.DevSteam|x64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.DevSteam|ARM64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.DevSteam|ARM64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.MSIX Debug|x64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.MSIX Debug|x64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.MSIX Debug|ARM64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.MSIX Debug|ARM64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.MSIX|x64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.MSIX|x64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.MSIX|ARM64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.MSIX|ARM64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Release|x64.ActiveCfg = Release|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Release|x64.Build.0 = Release|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Release|ARM64.ActiveCfg = Release|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Release|ARM64.Build.0 = Release|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Steam|x64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Steam|x64.Build.0 = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Steam|ARM64.ActiveCfg = Debug|Any CPU
+		{2ABF7BD3-08C8-4A08-8F0B-08FE1403DDC3}.Steam|ARM64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Debug|x64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Debug|ARM64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Debug|ARM64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.DevRelease|x64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.DevRelease|x64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.DevRelease|ARM64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.DevRelease|ARM64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.DevSteam|x64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.DevSteam|x64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.DevSteam|ARM64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.DevSteam|ARM64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.MSIX Debug|x64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.MSIX Debug|x64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.MSIX Debug|ARM64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.MSIX Debug|ARM64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.MSIX|x64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.MSIX|x64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.MSIX|ARM64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.MSIX|ARM64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Release|x64.ActiveCfg = Release|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Release|x64.Build.0 = Release|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Release|ARM64.ActiveCfg = Release|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Release|ARM64.Build.0 = Release|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Steam|x64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Steam|x64.Build.0 = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Steam|ARM64.ActiveCfg = Debug|Any CPU
+		{F355C56A-3E47-40C0-8204-002233CEFE23}.Steam|ARM64.Build.0 = Debug|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE