Browse Source

Improved blur and filter applying

Krzysztof Krysiński 3 days ago
parent
commit
9c213593eb

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit ecaab29256ad9ebbcf8ba3a0c19d763f64e9d0e1
+Subproject commit 7c3a89098ddf9c239c709658d9096bda268326ab

+ 17 - 10
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/BlurNode.cs

@@ -10,11 +10,13 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.FilterNodes;
 public class BlurNode : FilterNode
 public class BlurNode : FilterNode
 {
 {
     public InputProperty<bool> PreserveAlpha { get; }
     public InputProperty<bool> PreserveAlpha { get; }
-    
+
     public InputProperty<VecD> Radius { get; }
     public InputProperty<VecD> Radius { get; }
 
 
     protected override bool ExecuteOnlyOnCacheChange => true;
     protected override bool ExecuteOnlyOnCacheChange => true;
 
 
+    protected override CacheTriggerFlags CacheTrigger => CacheTriggerFlags.Inputs | CacheTriggerFlags.RenderSize;
+
     public BlurNode()
     public BlurNode()
     {
     {
         PreserveAlpha = CreateInput("PreserveAlpha", "PRESERVE_ALPHA", true);
         PreserveAlpha = CreateInput("PreserveAlpha", "PRESERVE_ALPHA", true);
@@ -26,11 +28,15 @@ public class BlurNode : FilterNode
         var sigma = (VecF)(Radius.Value * context.ChunkResolution.Multiplier());
         var sigma = (VecF)(Radius.Value * context.ChunkResolution.Multiplier());
         var preserveAlpha = PreserveAlpha.Value;
         var preserveAlpha = PreserveAlpha.Value;
 
 
-        var xFilter = GetGaussianFilter(sigma.X, true, preserveAlpha, null, out float[] xKernel);
-        
+        if (preserveAlpha)
+        {
+            return ImageFilter.CreateBlur(sigma.X, sigma.Y, TileMode.Mirror);
+        }
+
+        var xFilter = GetGaussianFilter(sigma.X, true, null, out float[] xKernel);
         // Reuse xKernel if x == y
         // Reuse xKernel if x == y
         var yKernel = Math.Abs(sigma.Y - sigma.X) < 0.0001f ? xKernel : null;
         var yKernel = Math.Abs(sigma.Y - sigma.X) < 0.0001f ? xKernel : null;
-        var yFilter = GetGaussianFilter(sigma.Y, false, preserveAlpha, yKernel, out _);
+        var yFilter = GetGaussianFilter(sigma.Y, false, yKernel, out _);
 
 
         return (xFilter, yFilter) switch
         return (xFilter, yFilter) switch
         {
         {
@@ -40,20 +46,21 @@ public class BlurNode : FilterNode
         };
         };
     }
     }
 
 
-    private static ImageFilter? GetGaussianFilter(float sigma, bool isX, bool preserveAlpha, float[]? kernel, out float[] usedKernel)
+    private static ImageFilter? GetGaussianFilter(float sigma, bool isX, float[]? kernel,
+        out float[] usedKernel)
     {
     {
         usedKernel = null;
         usedKernel = null;
         if (sigma < 0.0001f) return null;
         if (sigma < 0.0001f) return null;
-        
+
         kernel ??= GenerateGaussianKernel(sigma);
         kernel ??= GenerateGaussianKernel(sigma);
         usedKernel = kernel;
         usedKernel = kernel;
-        
+
         var size = isX ? new VecI(kernel.Length, 1) : new VecI(1, kernel.Length);
         var size = isX ? new VecI(kernel.Length, 1) : new VecI(1, kernel.Length);
         var offset = isX ? new VecI(kernel.Length / 2, 0) : new VecI(0, kernel.Length / 2);
         var offset = isX ? new VecI(kernel.Length / 2, 0) : new VecI(0, kernel.Length / 2);
-        
-        return ImageFilter.CreateMatrixConvolution(size, kernel, 1, 0, offset, TileMode.Repeat, !preserveAlpha);
+
+        return ImageFilter.CreateMatrixConvolution(size, kernel, 1, 0, offset, TileMode.Repeat, true);
     }
     }
-    
+
     public static float[] GenerateGaussianKernel(float sigma)
     public static float[] GenerateGaussianKernel(float sigma)
     {
     {
         int radius = (int)Math.Ceiling(3 * sigma);
         int radius = (int)Math.Ceiling(3 * sigma);

+ 25 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -158,9 +158,21 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         workingSurface.Scale((float)ctx.ChunkResolution.InvertedMultiplier());
         workingSurface.Scale((float)ctx.ChunkResolution.InvertedMultiplier());
         var img = GetLayerImageAtFrame(ctx.FrameTime.Frame);
         var img = GetLayerImageAtFrame(ctx.FrameTime.Frame);
 
 
+        Texture? intermediate = null;
+        VecD finalDrawPos = topLeft;
         if (saveLayer)
         if (saveLayer)
         {
         {
-            workingSurface.SaveLayer(paint);
+            var visibleRegion = ctx.VisibleDocumentRegion ?? latestSize;
+            var multiplier = visibleRegion != latestSize ? 1 : ctx.ChunkResolution.Multiplier();
+            var intersection = visibleRegion.Intersect(latestSize);
+            region = intersection;
+            VecI chunkAwareSize = (VecI)(new VecI(region.Width, region.Height) * multiplier);
+            intermediate = RequestTexture(1336, chunkAwareSize, ColorSpace.CreateSrgb());
+            finalDrawPos = VecD.Zero;
+            if (visibleRegion != latestSize)
+            {
+                topLeft = region.TopLeft - sceneSize / 2;
+            }
         }
         }
 
 
         if (!ctx.FullRerender)
         if (!ctx.FullRerender)
@@ -168,14 +180,24 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
             img.DrawMostUpToDateRegionOnWithAffected(
             img.DrawMostUpToDateRegionOnWithAffected(
                 region,
                 region,
                 ctx.ChunkResolution,
                 ctx.ChunkResolution,
-                workingSurface, ctx.AffectedArea, topLeft, saveLayer ? null : paint, ctx.DesiredSamplingOptions);
+                saveLayer ? intermediate.DrawingSurface.Canvas : workingSurface, ctx.AffectedArea, finalDrawPos, saveLayer ? null : paint, ctx.DesiredSamplingOptions);
         }
         }
         else
         else
         {
         {
             img.DrawMostUpToDateRegionOn(
             img.DrawMostUpToDateRegionOn(
                 region,
                 region,
                 ctx.ChunkResolution,
                 ctx.ChunkResolution,
-                workingSurface, topLeft, saveLayer ? null : paint, ctx.DesiredSamplingOptions);
+                saveLayer ? intermediate.DrawingSurface.Canvas : workingSurface, finalDrawPos, saveLayer ? null : paint, ctx.DesiredSamplingOptions);
+        }
+
+        if (saveLayer && intermediate != null)
+        {
+            int intermediateSaved = workingSurface.Save();
+            workingSurface.Translate(topLeft);
+
+            workingSurface.DrawSurface(intermediate.DrawingSurface, 0, 0, paint);
+
+            workingSurface.RestoreToCount(intermediateSaved);
         }
         }
 
 
         workingSurface.RestoreToCount(saved);
         workingSurface.RestoreToCount(saved);