Browse Source

.pixi 4.0

CPKreuz 2 years ago
parent
commit
99ed6f0ff6

+ 15 - 4
src/PixiEditor/Helpers/DocumentViewModelBuilder.cs

@@ -24,18 +24,24 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
         return this;
     }
     
-    public DocumentViewModelBuilder WithSwatches(List<Color> swatches)
+    public DocumentViewModelBuilder WithSwatches(IEnumerable<Color> swatches)
     {
-        Swatches = swatches;
+        Swatches = new (swatches);
         return this;
     }
+
+    public DocumentViewModelBuilder WithSwatches<T>(IEnumerable<T> swatches, Func<T, Color> toColor) =>
+        WithSwatches(swatches.Select(toColor));
     
-    public DocumentViewModelBuilder WithPalette(List<Color> palette)
+    public DocumentViewModelBuilder WithPalette(IEnumerable<Color> palette)
     {
-        Palette = palette;
+        Palette = new(palette);
         return this;
     }
 
+    public DocumentViewModelBuilder WithPalette<T>(IEnumerable<T> pallet, Func<T, Color> toColor) =>
+        WithPalette(pallet.Select(toColor));
+
     public abstract class StructureMemberBuilder
     {
         private MaskBuilder maskBuilder;
@@ -98,6 +104,11 @@ internal class DocumentViewModelBuilder : ChildrenBuilder
             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)
         {

+ 52 - 1
src/PixiEditor/Helpers/Extensions/ParserHelpers.cs

@@ -7,7 +7,8 @@ using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.Parser;
-using PixiEditor.Parser.Collections;
+using PixiEditor.Parser.Deprecated;
+using PixiEditor.Parser.Collections.Deprecated;
 using PixiEditor.Parser.Skia;
 using PixiEditor.ViewModels.SubViewModels.Document;
 
@@ -55,6 +56,56 @@ internal static class ParserHelpers
         return vm;
     }
 
+    public static DocumentViewModel ToDocument(this Document document)
+    {
+        return DocumentViewModel.Build(b =>
+        {
+            b
+                .WithSize(document.Width, document.Height)
+                .WithPalette(document.Palette, x => new Color(x.R, x.G, x.B, x.A))
+                .WithSwatches(document.Swatches, x => new(x.R, x.G, x.B, x.A));
+
+            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(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))
+            .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)
+            .WithVisibility(layer.Enabled)
+            .WithOpacity(layer.Opacity)
+            .WithBlendMode((PixiEditor.ChangeableDocument.Enums.BlendMode)(int)layer.BlendMode)
+            .WithSize(layer.Width, layer.Height)
+            .WithSurface(x => x.WithImage(layer.ImageBytes, layer.OffsetX, layer.OffsetY))
+            .WithMask(layer.Mask, (x, m) => x.WithVisibility(m.Enabled).WithSurface(m.Width, m.Height, x => x.WithImage(m.ImageBytes, m.OffsetX, m.OffsetY)));
+    }
+
     /// <summary>
     ///     Builds folder and its children.
     /// </summary>

+ 2 - 1
src/PixiEditor/Models/DataHolders/RecentlyOpenedDocument.cs

@@ -3,6 +3,7 @@ using System.IO;
 using System.Windows.Media.Imaging;
 using ChunkyImageLib;
 using ChunkyImageLib.DataHolders;
+using PixiEditor.Parser.Deprecated;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.Helpers;
 using PixiEditor.Models.IO;
@@ -77,7 +78,7 @@ internal class RecentlyOpenedDocument : NotifyableObject
 
             try
             {
-                serializableDocument = PixiParser.Deserialize(filePath);
+                serializableDocument = DepractedPixiParser.Deserialize(filePath);
             }
             catch
             {

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

@@ -12,7 +12,9 @@ using PixiEditor.Exceptions;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DataHolders;
 using PixiEditor.Parser;
+using PixiEditor.Parser.Deprecated;
 using PixiEditor.ViewModels.SubViewModels.Document;
+using BlendMode = PixiEditor.DrawingApi.Core.Surface.BlendMode;
 
 namespace PixiEditor.Models.IO;
 
@@ -63,13 +65,22 @@ internal class Importer : NotifyableObject
     {
         try
         {
-            DocumentViewModel doc = PixiParser.Deserialize(path).ToDocument();
+            var doc = PixiParser.Deserialize(path).ToDocument();
             doc.FullFilePath = path;
             return doc;
         }
         catch (InvalidFileException)
         {
-            throw new CorruptedFileException();
+            try
+            {
+                var doc = DepractedPixiParser.Deserialize(path).ToDocument();
+                doc.FullFilePath = path;
+                return doc;
+            }
+            catch (InvalidFileException)
+            {
+                throw new CorruptedFileException();
+            }
         }
     }
 

+ 3 - 3
src/PixiEditor/PixiEditor.csproj

@@ -216,8 +216,8 @@
 		<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
 		<PackageReference Include="OneOf" Version="3.0.216" />
 		<PackageReference Include="PixiEditor.ColorPicker" Version="3.3.1" />
-		<PackageReference Include="PixiEditor.Parser" Version="2.1.0.3" />
-		<PackageReference Include="PixiEditor.Parser.Skia" Version="2.1.0" />
+		<PackageReference Include="PixiEditor.Parser" Version="3.0.0" />
+		<PackageReference Include="PixiEditor.Parser.Skia" Version="3.0.0" />
 		<PackageReference Include="System.Drawing.Common" Version="6.0.0" />
 		<PackageReference Include="WpfAnimatedGif" Version="2.0.2" />
 		<PackageReference Include="WriteableBitmapEx">
@@ -349,7 +349,7 @@
 		<ProjectReference Include="..\PixiEditor.DrawingApi.Skia\PixiEditor.DrawingApi.Skia.csproj" />
 		<ProjectReference Include="..\PixiEditor.UpdateModule\PixiEditor.UpdateModule.csproj" />
 		<ProjectReference Include="..\PixiEditor.Zoombox\PixiEditor.Zoombox.csproj" />
-		<ProjectReference Include="..\PixiEditorGen\PixiEditorGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false"  />
+		<ProjectReference Include="..\PixiEditorGen\PixiEditorGen.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
 	</ItemGroup>
 	<ItemGroup>
 		<Reference Include="PixiParser">

+ 79 - 77
src/PixiEditor/ViewModels/SubViewModels/Document/DocumentViewModel.Serialization.cs

@@ -1,112 +1,114 @@
-using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using System.Drawing;
+using ChunkyImageLib;
+using ChunkyImageLib.DataHolders;
+using PixiEditor.ChangeableDocument.Changeables.Interfaces;
+using PixiEditor.DrawingApi.Core.Bridge;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.DrawingApi.Core.Surface;
+using PixiEditor.DrawingApi.Core.Surface.ImageData;
+using PixiEditor.Models.DataHolders;
 using PixiEditor.Parser;
-using TerraFX.Interop.Windows;
+using PixiEditor.Parser.Collections;
+using BlendMode = PixiEditor.Parser.BlendMode;
+using PixiDocument = PixiEditor.Parser.Document;
+using PixiColor = PixiEditor.DrawingApi.Core.ColorsImpl.Color;
 
 namespace PixiEditor.ViewModels.SubViewModels.Document;
 
 internal partial class DocumentViewModel
 {
-    public SerializableDocument ToSerializable()
+    public PixiDocument ToSerializable()
     {
+        var root = new Folder();
+        
         IReadOnlyDocument doc = Internals.Tracker.Document;
 
-        SerializableDocument document = new SerializableDocument(Width, Height,
-            ToSerializableGroups(doc.StructureRoot, doc),
-            ToSerializableLayers(doc))
-            .AddSwatches(Swatches)
-            .AddPalette(Palette);
+        AddMembers(doc.StructureRoot.Children, doc, root);
+        
+        var document = new PixiDocument
+        {
+            Width = Width, Height = Height,
+            Swatches = ToCollection(Swatches), Palette = ToCollection(Palette),
+            RootFolder = root
+        };
 
         return document;
     }
 
-    private static List<SerializableLayer> ToSerializableLayers(IReadOnlyDocument document)
+    private static void AddMembers(IEnumerable<IReadOnlyStructureMember> members, IReadOnlyDocument document, Folder parent)
     {
-        List<SerializableLayer> layers = new List<SerializableLayer>();
-        
-        document.ForEveryReadonlyMember(member =>
+        foreach (var member in members)
         {
-            if (member is IReadOnlyLayer layer)
+            if (member is IReadOnlyFolder readOnlyFolder)
+            {
+                var folder = ToSerializable(readOnlyFolder);
+
+                AddMembers(readOnlyFolder.Children, document, folder);
+
+                parent.Children.Add(folder);
+            }
+            else if (member is IReadOnlyLayer readOnlyLayer)
             {
-                SerializableLayer serializable = ToSerializable(layer, document);
-                if (serializable != null)
-                {
-                    layers.Add(serializable);
-                }
+                parent.Children.Add(ToSerializable(readOnlyLayer, document));
             }
-        });
-        
-        return layers;
+        }
     }
-
-    private static SerializableLayer ToSerializable(IReadOnlyLayer layer, IReadOnlyDocument document)
+    
+    private static Folder ToSerializable(IReadOnlyFolder folder)
+    {
+        return new Folder
+        {
+            Name = folder.Name,
+            BlendMode = (BlendMode)(int)folder.BlendMode,
+            Enabled = folder.IsVisible,
+            Opacity = folder.Opacity,
+            Mask = GetMask(folder.Mask, folder.MaskIsVisible)
+        };
+    }
+    
+    private static ImageLayer ToSerializable(IReadOnlyLayer layer, IReadOnlyDocument document)
     {
         var result = document.GetLayerImage(layer.GuidValue);
 
-        if (result != null)
+        var tightBounds = document.GetLayerTightBounds(layer.GuidValue);
+        using var data = result?.DrawingSurface.Snapshot().Encode();
+        byte[] bytes = data?.AsSpan().ToArray();
+        var serializable = new ImageLayer
         {
-            RectI tightBounds = document.GetLayerTightBounds(layer.GuidValue).Value;
-            var serializable = new SerializableLayer(result.Size.X, result.Size.Y, tightBounds.X, tightBounds.Y)
-                { IsVisible = layer.IsVisible, Name = layer.Name, Opacity = layer.Opacity };
-            using var data = result.DrawingSurface.Snapshot().Encode();
-            byte[] bytes = data.AsSpan().ToArray();
-            serializable.PngBytes = bytes;
-            
-            return serializable;
-        }
+            Width = result?.Size.X ?? 0, Height = result?.Size.Y ?? 0, OffsetX = tightBounds?.X ?? 0, OffsetY = tightBounds?.Y ?? 0,
+            Enabled = layer.IsVisible, BlendMode = (BlendMode)(int)layer.BlendMode, ImageBytes = bytes,
+            Name = layer.Name, Opacity = layer.Opacity, Mask = GetMask(layer.Mask, layer.MaskIsVisible)
+        };
 
-        return new SerializableLayer(1, 1) { Name = layer.Name, IsVisible = layer.IsVisible, Opacity = layer.Opacity };
+        return serializable;
     }
 
-    private static List<SerializableGroup> ToSerializableGroups(IReadOnlyFolder documentStructureRoot, IReadOnlyDocument document, int passIndex = 0)
+    private static Mask GetMask(IReadOnlyChunkyImage mask, bool maskVisible)
     {
-        List<SerializableGroup> group = new List<SerializableGroup>();
+        if (mask == null) 
+            return null;
         
-        int currentLayerIndex = passIndex;
-        foreach (var memberViewModel in documentStructureRoot.Children)
+        var maskBound = mask.FindLatestBounds();
+
+        if (maskBound == null)
         {
-            if (memberViewModel is IReadOnlyFolder folder && folder != document.StructureRoot)
-            {
-                int startIndex = currentLayerIndex;
-                int endIndex = GetEndIndex(folder, startIndex);
-                group.Add(new SerializableGroup(folder.Name, startIndex, endIndex, ToSerializableGroups(folder, document, startIndex)));        
-            }
-            else if(memberViewModel is IReadOnlyLayer)
-            {
-                currentLayerIndex++;
-            }
+            return new Mask();
         }
         
-        return group;
-    }
+        var surface = DrawingBackendApi.Current.SurfaceImplementation.Create(new ImageInfo(
+            maskBound.Value.Width,
+            maskBound.Value.Height));
+                
+        mask.DrawMostUpToDateRegionOn(new RectI(0, 0, maskBound.Value.Width, maskBound.Value.Height), ChunkResolution.Full, surface, new VecI(0, 0));
 
-    private static int GetEndIndex(IReadOnlyFolder folder, int startIndex)
-    {
-        int endIndex = startIndex - 1;
-        Traverse(folder, member =>
-        {
-            if (member is IReadOnlyLayer)
-            {
-                endIndex++;
-            }
-        });
-        
-        return endIndex;
-    }
-    
-    private static void Traverse(IReadOnlyFolder folder, Action<IReadOnlyStructureMember> action)
-    {
-        action(folder);
-        foreach (var member in folder.Children)
+        return new Mask
         {
-            if (member is IReadOnlyLayer)
-            {
-                action(member);
-            }
-            if (member is IReadOnlyFolder subFolder)
-            {
-                Traverse(subFolder, action);
-            }
-        }
+            Width = maskBound.Value.Width, Height = maskBound.Value.Height,
+            OffsetX = maskBound.Value.X, OffsetY = maskBound.Value.Y,
+            Enabled = maskVisible, ImageBytes = surface.Snapshot().Encode().AsSpan().ToArray()
+        };
     }
+
+    private ColorCollection ToCollection(WpfObservableRangeCollection<PixiColor> collection) =>
+        new(collection.Select(x => Color.FromArgb(x.A, x.R, x.G, x.B)));
 }