Browse Source

Folder and layer gpu wip

flabbet 11 months ago
parent
commit
4984e4f07d

+ 14 - 7
src/PixiEditor.DrawingApi.Core/Texture.cs

@@ -13,6 +13,8 @@ public class Texture : IDisposable
     public VecI Size { get; }
     public DrawingSurface Surface { get; }
 
+    public bool IsDisposed { get; private set; }
+
     public Texture(VecI size)
     {
         Size = size;
@@ -24,10 +26,6 @@ public class Texture : IDisposable
                 });
     }
 
-    public void Dispose()
-    {
-        Surface.Dispose();
-    }
 
     public static Texture Load(string path)
     {
@@ -39,7 +37,7 @@ public class Texture : IDisposable
 
         Texture texture = new Texture(image.Size);
         texture.Surface.Canvas.DrawImage(image, 0, 0);
-        
+
         return texture;
     }
 
@@ -48,7 +46,7 @@ public class Texture : IDisposable
         using Image image = Image.FromEncodedData(data);
         Texture texture = new Texture(image.Size);
         texture.Surface.Canvas.DrawImage(image, 0, 0);
-        
+
         return texture;
     }
 
@@ -81,7 +79,7 @@ public class Texture : IDisposable
         paint.FilterQuality = filterQuality;
 
         newTexture.Surface.Canvas.DrawImage(image, new RectD(0, 0, newSize.X, newSize.Y), paint);
-        
+
         return newTexture;
     }
 
@@ -93,4 +91,13 @@ public class Texture : IDisposable
         //TODO:
         return Color.Empty;
     }
+
+    public void Dispose()
+    {
+        if (IsDisposed)
+            return;
+        
+        IsDisposed = true;
+        Surface.Dispose();
+    }
 }

+ 4 - 3
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -147,7 +147,8 @@ internal class ActionAccumulator
                         var bitmap = document.StructureHelper.Find(info.GuidValue)?.PreviewSurface;
                         if (bitmap is null)
                             continue;
-                        bitmap.AddDirtyRect(new RectI(0, 0, bitmap.Size.X, bitmap.Size.Y));
+                        //TODO: Implement dirty rects
+                        // bitmap.AddDirtyRect(new RectI(0, 0, bitmap.Size.X, bitmap.Size.Y));
                     }
                     break;
                 case MaskPreviewDirty_RenderInfo info:
@@ -155,7 +156,7 @@ internal class ActionAccumulator
                         var bitmap = document.StructureHelper.Find(info.GuidValue)?.MaskPreviewSurface;
                         if (bitmap is null)
                             continue;
-                        bitmap.AddDirtyRect(new RectI(0, 0, bitmap.Size.X, bitmap.Size.Y));
+                        //bitmap.AddDirtyRect(new RectI(0, 0, bitmap.Size.X, bitmap.Size.Y));
                     }
                     break;
                 case CanvasPreviewDirty_RenderInfo:
@@ -168,7 +169,7 @@ internal class ActionAccumulator
                         var node = document.StructureHelper.Find(info.NodeId);
                         if (node is null || node.PreviewSurface is null)
                             continue;
-                        node.PreviewSurface.AddDirtyRect(new RectI(0, 0, node.PreviewSurface.Size.X, node.PreviewSurface.Size.Y));
+                        //node.PreviewSurface.AddDirtyRect(new RectI(0, 0, node.PreviewSurface.Size.X, node.PreviewSurface.Size.Y));
                     }
                     break;
             }

+ 1 - 1
src/PixiEditor/Models/Handlers/IKeyFrameHandler.cs

@@ -5,7 +5,7 @@ namespace PixiEditor.Models.Handlers;
 
 internal interface IKeyFrameHandler
 {
-    public Surface? PreviewSurface { get; set; }
+    public Texture? PreviewSurface { get; set; }
     public int StartFrameBindable { get; }
     public int DurationBindable { get; }
     public bool IsSelected { get; set; }

+ 1 - 1
src/PixiEditor/Models/Handlers/INodeHandler.cs

@@ -15,7 +15,7 @@ public interface INodeHandler : INotifyPropertyChanged
     public string InternalName { get; }
     public ObservableRangeCollection<INodePropertyHandler> Inputs { get; }
     public ObservableRangeCollection<INodePropertyHandler> Outputs { get; }
-    public Surface ResultPreview { get; set; }
+    public Texture? ResultPreview { get; set; }
     public VecD PositionBindable { get; set; }
     public bool IsSelected { get; set; }
     public void TraverseBackwards(Func<INodeHandler, bool> func);

+ 2 - 2
src/PixiEditor/Models/Handlers/IStructureMemberHandler.cs

@@ -12,8 +12,8 @@ namespace PixiEditor.Models.Handlers;
 internal interface IStructureMemberHandler : INodeHandler
 {
     public bool HasMaskBindable { get; }
-    public Surface? MaskPreviewSurface { get; set; }
-    public Surface? PreviewSurface { get; set; }
+    public Texture? MaskPreviewSurface { get; set; }
+    public Texture? PreviewSurface { get; set; }
     public bool MaskIsVisibleBindable { get; set; }
     public StructureMemberSelectionType Selection { get; set; }
     public float OpacityBindable { get; set; }

+ 41 - 46
src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs

@@ -191,7 +191,7 @@ internal class MemberPreviewUpdater
             if (member is null)
                 continue;
 
-            if (forMasks && member.Mask.Value is null)
+            if (forMasks && member.Mask.NonOverridenValue is null)
             {
                 newPreviewBitmapSizes.Add(guid, null);
                 continue;
@@ -237,17 +237,14 @@ internal class MemberPreviewUpdater
                 if (member.PreviewSurface is not null && member.PreviewSurface.Size.X == newSize.Value.previewSize.X &&
                     member.PreviewSurface.Size.Y == newSize.Value.previewSize.Y)
                 {
-                    member.PreviewSurface!.DrawingSurface.Canvas.Clear();
+                    member.PreviewSurface!.Surface.Canvas.Clear();
                 }
                 else
                 {
                     member.PreviewSurface?.Dispose();
-                    member.PreviewSurface = new Surface(newSize.Value.previewSize);
+                    member.PreviewSurface = new Texture(newSize.Value.previewSize);
                 }
             }
-
-            //TODO: Make sure PreviewBitmap implementation raises PropertyChanged
-            //member.OnPropertyChanged(nameof(member.PreviewBitmap));
         }
 
         // update masks
@@ -262,11 +259,8 @@ internal class MemberPreviewUpdater
             }
             else
             {
-                member.MaskPreviewSurface = new Surface(newSize.Value.previewSize); // TODO: premul bgra8888 was here
+                member.MaskPreviewSurface = new Texture(newSize.Value.previewSize); // TODO: premul bgra8888 was here
             }
-
-            //TODO: Make sure MaskPreviewBitmap implementation raises PropertyChanged
-            //member.OnPropertyChanged(nameof(member.MaskPreviewBitmap));
         }
     }
 
@@ -278,7 +272,7 @@ internal class MemberPreviewUpdater
     private RectI? GetOrFindMemberTightBounds(IReadOnlyStructureNode member, int atFrame,
         AffectedArea currentlyAffectedArea, bool forMask)
     {
-        if (forMask && member.Mask.Value is null)
+        if (forMask && member.Mask.NonOverridenValue is null)
             throw new InvalidOperationException();
 
         RectI? prevTightBounds = null;
@@ -308,10 +302,10 @@ internal class MemberPreviewUpdater
     /// </summary>
     private RectI? FindLayerTightBounds(IReadOnlyLayerNode layer, int frame, bool forMask)
     {
-        if (layer.Mask.Value is null && forMask)
+        if (layer.Mask.NonOverridenValue is null && forMask)
             throw new InvalidOperationException();
 
-        if (layer.Mask.Value is not null && forMask)
+        if (layer.Mask.NonOverridenValue is not null && forMask)
             return FindImageTightBoundsFast(layer.Mask.Value);
 
         if (layer is IReadOnlyImageNode raster)
@@ -550,7 +544,7 @@ internal class MemberPreviewUpdater
             keyFrame.PreviewSurface.Size != memberVM.PreviewSurface.Size)
         {
             keyFrame.PreviewSurface?.Dispose();
-            keyFrame.PreviewSurface = new Surface(memberVM.PreviewSurface.Size);
+            keyFrame.PreviewSurface = new Texture(memberVM.PreviewSurface.Size);
         }
 
         RenderLayerMainPreview((IReadOnlyLayerNode)member, keyFrame.PreviewSurface, affArea.Value,
@@ -564,10 +558,10 @@ internal class MemberPreviewUpdater
         AffectedArea area,
         VecI position, float scaling)
     {
-        memberVM.PreviewSurface.DrawingSurface.Canvas.Save();
-        memberVM.PreviewSurface.DrawingSurface.Canvas.Scale(scaling);
-        memberVM.PreviewSurface.DrawingSurface.Canvas.Translate(-position);
-        memberVM.PreviewSurface.DrawingSurface.Canvas.ClipRect((RectD)area.GlobalArea);
+        memberVM.PreviewSurface.Surface.Canvas.Save();
+        memberVM.PreviewSurface.Surface.Canvas.Scale(scaling);
+        memberVM.PreviewSurface.Surface.Canvas.Translate(-position);
+        memberVM.PreviewSurface.Surface.Canvas.ClipRect((RectD)area.GlobalArea);
         foreach (var chunk in area.Chunks)
         {
             var pos = chunk * ChunkResolution.Full.PixelSize();
@@ -589,30 +583,30 @@ internal class MemberPreviewUpdater
 
             if (rendered.IsT0)
             {
-                memberVM.PreviewSurface.DrawingSurface.Canvas.DrawSurface(rendered.AsT0.Surface.DrawingSurface, pos,
+                memberVM.PreviewSurface.Surface.Canvas.DrawSurface(rendered.AsT0.Surface.DrawingSurface, pos,
                     scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint);
                 rendered.AsT0.Dispose();
             }
             else
             {
-                memberVM.PreviewSurface.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, ChunkResolution.Full.PixelSize(),
+                memberVM.PreviewSurface.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkResolution.Full.PixelSize(),
                     ChunkResolution.Full.PixelSize(), ClearPaint);
             }
         }
 
-        memberVM.PreviewSurface.DrawingSurface.Canvas.Restore();
+        memberVM.PreviewSurface.Surface.Canvas.Restore();
     }
 
     /// <summary>
     /// Re-render the <paramref name="area"/> of the main preview of the <paramref name="memberVM"/> layer
     /// </summary>
-    private void RenderLayerMainPreview(IReadOnlyLayerNode layer, Surface surface, AffectedArea area,
+    private void RenderLayerMainPreview(IReadOnlyLayerNode layer, Texture surface, AffectedArea area,
         VecI position, float scaling, int frame)
     {
-        surface.DrawingSurface.Canvas.Save();
-        surface.DrawingSurface.Canvas.Scale(scaling);
-        surface.DrawingSurface.Canvas.Translate(-position);
-        surface.DrawingSurface.Canvas.ClipRect((RectD)area.GlobalArea);
+        surface.Surface.Canvas.Save();
+        surface.Surface.Canvas.Scale(scaling);
+        surface.Surface.Canvas.Translate(-position);
+        surface.Surface.Canvas.ClipRect((RectD)area.GlobalArea);
 
         foreach (var chunk in area.Chunks)
         {
@@ -622,15 +616,16 @@ internal class MemberPreviewUpdater
 
             if (!result.DrawCommittedChunkOn(
                     chunk,
-                    ChunkResolution.Full, surface.DrawingSurface, pos,
+                    ChunkResolution.Full, surface.Surface, pos,
                     scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint))
             {
-                surface.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
+                surface.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
                     ChunkyImage.FullChunkSize, ClearPaint);
             }
         }
 
-        surface.DrawingSurface.Canvas.Restore();
+        surface.Surface.Canvas.Restore();
+        surface.Surface.Flush();
     }
 
     private void RenderAnimationFramePreview(IReadOnlyImageNode node, IKeyFrameHandler keyFrameVM, AffectedArea area)
@@ -638,24 +633,24 @@ internal class MemberPreviewUpdater
         if (keyFrameVM.PreviewSurface is null)
         {
             keyFrameVM.PreviewSurface =
-                new Surface(StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size));
+                new Texture(StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size));
         }
 
-        keyFrameVM.PreviewSurface!.DrawingSurface.Canvas.Save();
+        keyFrameVM.PreviewSurface!.Surface.Canvas.Save();
         float scaling = (float)keyFrameVM.PreviewSurface.Size.X / internals.Tracker.Document.Size.X;
-        keyFrameVM.PreviewSurface.DrawingSurface.Canvas.Scale(scaling);
+        keyFrameVM.PreviewSurface.Surface.Canvas.Scale(scaling);
         foreach (var chunk in area.Chunks)
         {
             var pos = chunk * ChunkResolution.Full.PixelSize();
             if (!node.GetLayerImageByKeyFrameGuid(keyFrameVM.Id).DrawCommittedChunkOn(chunk, ChunkResolution.Full,
-                    keyFrameVM.PreviewSurface!.DrawingSurface, pos, ReplacingPaint))
+                    keyFrameVM.PreviewSurface!.Surface, pos, ReplacingPaint))
             {
-                keyFrameVM.PreviewSurface!.DrawingSurface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
+                keyFrameVM.PreviewSurface!.Surface.Canvas.DrawRect(pos.X, pos.Y, ChunkyImage.FullChunkSize,
                     ChunkyImage.FullChunkSize, ClearPaint);
             }
         }
 
-        keyFrameVM.PreviewSurface!.DrawingSurface.Canvas.Restore();
+        keyFrameVM.PreviewSurface!.Surface.Canvas.Restore();
     }
 
     private void RenderMaskPreviews(
@@ -701,19 +696,19 @@ internal class MemberPreviewUpdater
 
             var member = internals.Tracker.Document.FindMemberOrThrow(guid);
 
-            memberVM.MaskPreviewSurface!.DrawingSurface.Canvas.Save();
-            memberVM.MaskPreviewSurface.DrawingSurface.Canvas.Scale(scaling);
-            memberVM.MaskPreviewSurface.DrawingSurface.Canvas.Translate(-position);
-            memberVM.MaskPreviewSurface.DrawingSurface.Canvas.ClipRect((RectD)affArea.Value.GlobalArea);
+            memberVM.MaskPreviewSurface!.Surface.Canvas.Save();
+            memberVM.MaskPreviewSurface.Surface.Canvas.Scale(scaling);
+            memberVM.MaskPreviewSurface.Surface.Canvas.Translate(-position);
+            memberVM.MaskPreviewSurface.Surface.Canvas.ClipRect((RectD)affArea.Value.GlobalArea);
             foreach (var chunk in affArea.Value.Chunks)
             {
                 var pos = chunk * ChunkResolution.Full.PixelSize();
                 member.Mask!.Value.DrawMostUpToDateChunkOn
-                (chunk, ChunkResolution.Full, memberVM.MaskPreviewSurface.DrawingSurface, pos,
+                (chunk, ChunkResolution.Full, memberVM.MaskPreviewSurface.Surface, pos,
                     scaling < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint);
             }
 
-            memberVM.MaskPreviewSurface.DrawingSurface.Canvas.Restore();
+            memberVM.MaskPreviewSurface.Surface.Canvas.Restore();
             infos.Add(new MaskPreviewDirty_RenderInfo(guid));
         }
     }
@@ -739,21 +734,21 @@ internal class MemberPreviewUpdater
             if (nodeVm.ResultPreview == null)
             {
                 nodeVm.ResultPreview =
-                    new Surface(StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size, 150));
+                    new Texture(StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size, 150));
             }
 
             float scalingX = (float)nodeVm.ResultPreview.Size.X / node.CachedResult.Size.X;
             float scalingY = (float)nodeVm.ResultPreview.Size.Y / node.CachedResult.Size.Y;
 
-            nodeVm.ResultPreview.DrawingSurface.Canvas.Save();
-            nodeVm.ResultPreview.DrawingSurface.Canvas.Scale(scalingX, scalingY);
+            nodeVm.ResultPreview.Surface.Canvas.Save();
+            nodeVm.ResultPreview.Surface.Canvas.Scale(scalingX, scalingY);
 
             RectI region = new RectI(0, 0, node.CachedResult.Size.X, node.CachedResult.Size.Y);
 
-            nodeVm.ResultPreview.DrawingSurface.Canvas.DrawSurface(node.CachedResult.DrawingSurface, 0, 0,
+            nodeVm.ResultPreview.Surface.Canvas.DrawSurface(node.CachedResult.DrawingSurface, 0, 0,
                 ReplacingPaint);
 
-            nodeVm.ResultPreview.DrawingSurface.Canvas.Restore();
+            nodeVm.ResultPreview.Surface.Canvas.Restore();
             infos.Add(new NodePreviewDirty_RenderInfo(node.Id));
         }
     }

+ 2 - 2
src/PixiEditor/ViewModels/Document/KeyFrameViewModel.cs

@@ -9,7 +9,7 @@ namespace PixiEditor.ViewModels.Document;
 
 internal abstract class KeyFrameViewModel : ObservableObject, IKeyFrameHandler
 {
-    private Surface? previewSurface;
+    private Texture? previewSurface;
     private int startFrameBindable;
     private int durationBindable;
     private bool isVisibleBindable = true;
@@ -27,7 +27,7 @@ internal abstract class KeyFrameViewModel : ObservableObject, IKeyFrameHandler
 
     IDocument IKeyFrameHandler.Document => Document;
 
-    public Surface? PreviewSurface
+    public Texture? PreviewSurface
     {
         get => previewSurface;
         set => SetProperty(ref previewSurface, value);

+ 5 - 4
src/PixiEditor/ViewModels/Document/StructureMemberViewModel.cs

@@ -6,6 +6,7 @@ using PixiEditor.Views.Nodes;
 using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core.Numerics;
+using PixiEditor.Extensions.FlyUI.Elements;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.Handlers;
@@ -143,16 +144,16 @@ internal abstract class StructureMemberViewModel : NodeViewModel, IStructureMemb
         set => SetProperty(ref selection, value);
     }
 
-    private Surface? previewSurface;
-    private Surface? maskPreviewSurface;
+    private Texture? previewSurface;
+    private Texture? maskPreviewSurface;
 
-    public Surface? PreviewSurface
+    public Texture? PreviewSurface
     {
         get => previewSurface;
         set => SetProperty(ref previewSurface, value);
     }
 
-    public Surface? MaskPreviewSurface
+    public Texture? MaskPreviewSurface
     {
         get => maskPreviewSurface;
         set => SetProperty(ref maskPreviewSurface, value);

+ 2 - 2
src/PixiEditor/ViewModels/Nodes/NodeViewModel.cs

@@ -19,7 +19,7 @@ internal class NodeViewModel : ObservableObject, INodeHandler
     private VecD position;
     private ObservableRangeCollection<INodePropertyHandler> inputs = new();
     private ObservableRangeCollection<INodePropertyHandler> outputs = new();
-    private Surface resultPreview;
+    private Texture resultPreview;
     private bool isSelected;
 
     protected Guid id;
@@ -71,7 +71,7 @@ internal class NodeViewModel : ObservableObject, INodeHandler
         set => SetProperty(ref outputs, value);
     }
 
-    public Surface ResultPreview
+    public Texture ResultPreview
     {
         get => resultPreview;
         set => SetProperty(ref resultPreview, value);

+ 4 - 3
src/PixiEditor/Views/Layers/FolderControl.axaml

@@ -65,14 +65,15 @@
                                     </ImageBrush.Transform>
                                 </ImageBrush>
                             </Border.Background>
-                            <visuals:SurfaceControl Surface="{Binding Folder.PreviewSurface, ElementName=folderControl}" Stretch="Uniform" Width="30" Height="30">
+                            <visuals:TextureControl Texture="{Binding Folder.PreviewSurface, ElementName=folderControl}" 
+                                                    Stretch="Uniform" Width="30" Height="30">
                                 <ui:RenderOptionsBindable.BitmapInterpolationMode>
                                     <MultiBinding Converter="{converters:WidthToBitmapScalingModeConverter}">
                                         <Binding Path="Folder.PreviewSurface.Size.X" ElementName="folderControl"/>
                                         <Binding RelativeSource="{RelativeSource Mode=Self}" Path="Bounds.Width"/>
                                     </MultiBinding>
                                 </ui:RenderOptionsBindable.BitmapInterpolationMode>
-                            </visuals:SurfaceControl>
+                            </visuals:TextureControl>
                         </Border>
                         <Border 
                             Width="32" Height="32" 
@@ -89,7 +90,7 @@
                                 </ImageBrush>
                             </Border.Background>
                             <Grid IsHitTestVisible="False">
-                                <visuals:SurfaceControl Surface="{Binding Folder.MaskPreviewSurface, ElementName=folderControl}" Stretch="Uniform" Width="30" Height="30"
+                                <visuals:TextureControl Texture="{Binding Folder.MaskPreviewSurface, ElementName=folderControl}" Stretch="Uniform" Width="30" Height="30"
                                     RenderOptions.BitmapInterpolationMode="None" IsHitTestVisible="False"/>
                                 <Path 
                                 Data="M 2 0 L 10 8 L 18 0 L 20 2 L 12 10 L 20 18 L 18 20 L 10 12 L 2 20 L 0 18 L 8 10 L 0 2 Z" 

+ 2 - 2
src/PixiEditor/Views/Layers/LayerControl.axaml

@@ -75,7 +75,7 @@
                                 <Binding ElementName="uc" Path="Layer.HasMaskBindable"/>
                             </MultiBinding>
                         </Border.BorderBrush>
-                        <visuals:SurfaceControl Surface="{Binding Layer.PreviewSurface, ElementName=uc}"
+                        <visuals:TextureControl Texture="{Binding Layer.PreviewSurface, ElementName=uc}"
                                                 Stretch="Uniform" Width="30"
                                                 Height="30"
                            RenderOptions.BitmapInterpolationMode="None" IsHitTestVisible="False"/>
@@ -100,7 +100,7 @@
                             </MultiBinding>
                         </Border.BorderBrush>
                         <Grid IsHitTestVisible="False">
-                            <visuals:SurfaceControl Surface="{Binding Layer.MaskPreviewSurface,ElementName=uc}" Stretch="Uniform" Width="30" Height="30"
+                            <visuals:TextureControl Texture="{Binding Layer.MaskPreviewSurface,ElementName=uc}" Stretch="Uniform" Width="30" Height="30"
                            RenderOptions.BitmapInterpolationMode="None" IsHitTestVisible="False"/>
                             <Path
                                 Data="M 2 0 L 10 8 L 18 0 L 20 2 L 12 10 L 20 18 L 18 20 L 10 12 L 2 20 L 0 18 L 8 10 L 0 2 Z"