Browse Source

Improved layer rendering

flabbet 10 months ago
parent
commit
50bcd6a33b

+ 9 - 7
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -5,6 +5,7 @@ using PixiEditor.ChangeableDocument.Helpers;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surfaces;
 using PixiEditor.DrawingApi.Core.Surfaces.PaintImpl;
 using PixiEditor.Numerics;
 
@@ -78,24 +79,25 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         return (GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage).LatestSize;
     }
 
-    protected override void DrawWithoutFilters(RenderContext ctx, Texture workingSurface, bool shouldClear,
+    protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
         Paint paint)
     {
         var frameImage = GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage;
         if (!frameImage.DrawMostUpToDateChunkOn(
                 ctx.ChunkToUpdate,
                 ctx.ChunkResolution,
-                workingSurface.DrawingSurface,
+                workingSurface,
                 ctx.ChunkToUpdate * ctx.ChunkResolution.PixelSize(),
                 blendPaint) && shouldClear)
         {
-            workingSurface.DrawingSurface.Canvas.DrawRect((RectD)CalculateDestinationRect(ctx), clearPaint);
+            // TODO: Is it necessary to clear the surface?
+            //workingSurface.Canvas.DrawRect((RectD)CalculateDestinationRect(ctx), clearPaint);
         }
     }
 
     // Draw with filters is a bit tricky since some filters sample data from chunks surrounding the chunk being drawn,
     // this is why we need to do intermediate drawing to a temporary surface and then apply filters to that surface
-    protected override void DrawWithFilters(RenderContext context, Texture workingSurface,
+    protected override void DrawWithFilters(SceneObjectRenderContext context, DrawingSurface workingSurface,
         bool shouldClear, Paint paint)
     {
         var frameImage = GetFrameWithImage(context.FrameTime).Data as ChunkyImage;
@@ -133,11 +135,11 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         }
 
         VecI tempSize = tempSizeInChunks * context.ChunkResolution.PixelSize();
-        tempSize = new VecI(Math.Min(tempSize.X, workingSurface.Size.X), Math.Min(tempSize.Y, workingSurface.Size.Y));
+        tempSize = new VecI(Math.Min(tempSize.X, (int)context.LocalBounds.Size.X), Math.Min(tempSize.Y, (int)context.LocalBounds.Size.Y));
 
         if (shouldClear)
         {
-            workingSurface.DrawingSurface.Canvas.DrawRect(
+            workingSurface.Canvas.DrawRect(
                 new RectD(
                     VecI.Zero,
                     tempSize),
@@ -188,7 +190,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
         DrawChunk(frameImage, context, tempSurface, new VecI(0, 0), paint);
 
-        workingSurface.DrawingSurface.Canvas.DrawSurface(tempSurface.DrawingSurface, VecI.Zero, paint);
+        workingSurface.Canvas.DrawSurface(tempSurface.DrawingSurface, VecI.Zero, paint);
     }
 
     public override bool RenderPreview(Texture renderOn, VecI chunk, ChunkResolution resolution, int frame)

+ 26 - 33
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LayerNode.cs

@@ -4,6 +4,7 @@ using PixiEditor.ChangeableDocument.Helpers;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
+using PixiEditor.DrawingApi.Core.Surfaces;
 using PixiEditor.DrawingApi.Core.Surfaces.PaintImpl;
 using PixiEditor.Numerics;
 
@@ -14,21 +15,18 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
     protected Dictionary<(ChunkResolution, int), Texture> workingSurfaces =
         new Dictionary<(ChunkResolution, int), Texture>();
 
-    protected override void OnExecute(RenderContext context)
-    {
-        base.OnExecute(context);
-    }
-
     public override void Render(SceneObjectRenderContext sceneContext)
     {
         if (!IsVisible.Value || Opacity.Value <= 0 || IsEmptyMask())
         {
-            Output.Value = Background.Value;
+            Output.Value = sceneContext.TargetSurface;
             return;
         }
 
         blendPaint.Color = new Color(255, 255, 255, 255);
-        blendPaint.BlendMode = DrawingApi.Core.Surfaces.BlendMode.Src;
+        blendPaint.BlendMode = DrawingApi.Core.Surfaces.BlendMode.SrcOver;
+
+        DrawingSurface target = sceneContext.TargetSurface;
 
         VecI targetSize = GetTargetSize(sceneContext);
         bool shouldClear = Background.Value == null;
@@ -49,59 +47,54 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
             FilterlessOutput.Value = filterlessWorkingSurface;
         }*/
 
-        var rendered = RenderImage(targetSize, sceneContext, shouldClear);
-        //TODO: optimize
-        sceneContext.TargetSurface.Canvas.DrawSurface(rendered.DrawingSurface, 0, 0);
-        
-        Output.Value = sceneContext.TargetSurface;
+        RenderImage(targetSize, sceneContext, target, shouldClear);
 
+        Output.Value = target;
     }
 
-    private Texture RenderImage(VecI size, RenderContext context, bool shouldClear)
+    private void RenderImage(VecI size, SceneObjectRenderContext context, DrawingSurface renderOnto, bool shouldClear)
     {
         if (Output.Connections.Count > 0)
         {
-            var outputWorkingSurface = TryInitWorkingSurface(size, context.ChunkResolution, 1);
-
             if (!HasOperations())
             {
+                /*
                 if (Background.Value != null)
                 {
                     DrawBackground(outputWorkingSurface.DrawingSurface, context);
                     blendPaint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
                 }
+                */
 
-                DrawLayer(context, outputWorkingSurface, shouldClear);
+                DrawLayer(context, renderOnto, shouldClear);
 
-                return outputWorkingSurface;
+                return;
             }
 
-            DrawLayer(context, outputWorkingSurface, true);
+            //var outputWorkingSurface = TryInitWorkingSurface(size, context.ChunkResolution, 1);
+            
+            DrawLayer(context, renderOnto, true);
 
             // shit gets downhill with mask on big canvases, TODO: optimize
-            ApplyMaskIfPresent(outputWorkingSurface, context);
+            ApplyMaskIfPresent(renderOnto, context);
 
             if (Background.Value != null)
             {
-                Texture tempSurface = RequestTexture(4, outputWorkingSurface.Size, true);
+                Texture tempSurface = RequestTexture(4, size);
                 DrawBackground(tempSurface.DrawingSurface, context);
-                ApplyRasterClip(outputWorkingSurface, tempSurface);
+                ApplyRasterClip(renderOnto, tempSurface.DrawingSurface);
                 blendPaint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
-                tempSurface.DrawingSurface.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0,
+                tempSurface.DrawingSurface.Canvas.DrawSurface(renderOnto, 0, 0,
                     blendPaint);
 
-                return tempSurface;
+                renderOnto.Canvas.DrawSurface(tempSurface.DrawingSurface, VecI.Zero, blendPaint);
             }
-
-            return outputWorkingSurface;
         }
-
-        return null;
     }
 
     protected abstract VecI GetTargetSize(RenderContext ctx);
 
-    protected virtual void DrawLayer(RenderContext ctx, Texture workingSurface, bool shouldClear,
+    protected virtual void DrawLayer(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
         bool useFilters = true)
     {
         blendPaint.Color = blendPaint.Color.WithAlpha((byte)Math.Round(Opacity.Value * 255));
@@ -117,11 +110,11 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
             DrawWithoutFilters(ctx, workingSurface, shouldClear, blendPaint);
         }
     }
-    
-    protected abstract void DrawWithoutFilters(RenderContext ctx, Texture workingSurface, bool shouldClear,
+
+    protected abstract void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
         Paint paint);
-    
-    protected abstract void DrawWithFilters(RenderContext ctx, Texture workingSurface, bool shouldClear,
+
+    protected abstract void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
         Paint paint);
 
     protected Texture TryInitWorkingSurface(VecI imageSize, ChunkResolution resolution, int id)
@@ -129,7 +122,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
         ChunkResolution targetResolution = resolution;
         bool hasSurface = workingSurfaces.TryGetValue((targetResolution, id), out Texture workingSurface);
         VecI targetSize = (VecI)(imageSize * targetResolution.Multiplier());
-        
+
         targetSize = new VecI(Math.Max(1, targetSize.X), Math.Max(1, targetSize.Y));
 
         if (!hasSurface || workingSurface.Size != targetSize || workingSurface.IsDisposed)

+ 9 - 7
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/StructureNode.cs

@@ -45,7 +45,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
     }
 
     private Paint maskPaint = new Paint() { BlendMode = DrawingApi.Core.Surfaces.BlendMode.DstIn };
-    protected Paint blendPaint = new Paint();
+    protected Paint blendPaint = new Paint() { BlendMode = DrawingApi.Core.Surfaces.BlendMode.SrcOver};
 
     private int maskCacheHash = 0;
 
@@ -72,7 +72,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
     {
         RectD localBounds = new RectD(0, 0, SceneSize.X, SceneSize.Y);
 
-        DrawingSurface sceneSurface = context.TargetSurface;
+        DrawingSurface sceneSurface = Background.Value ?? context.TargetSurface;
         
         int savedNum = sceneSurface.Canvas.Save();
         sceneSurface.Canvas.ClipRect(RectD.Create((VecI)ScenePosition.Floor(), (VecI)SceneSize.Ceiling()));
@@ -84,24 +84,26 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         Render(renderObjectContext);
         
         sceneSurface.Canvas.RestoreToCount(savedNum);
+        
+        Output.Value = sceneSurface;
     }
 
     public abstract void Render(SceneObjectRenderContext sceneContext);
 
-    protected void ApplyMaskIfPresent(Texture surface, RenderContext context)
+    protected void ApplyMaskIfPresent(DrawingSurface surface, RenderContext context)
     {
         if (MaskIsVisible.Value)
         {
             if (CustomMask.Value != null)
             {
-                surface.DrawingSurface.Canvas.DrawSurface(CustomMask.Value.DrawingSurface, 0, 0, maskPaint);
+                surface.Canvas.DrawSurface(CustomMask.Value.DrawingSurface, 0, 0, maskPaint);
             }
             else if (EmbeddedMask != null)
             {
                 EmbeddedMask.DrawMostUpToDateChunkOn(
                     context.ChunkToUpdate,
                     context.ChunkResolution,
-                    surface.DrawingSurface,
+                    surface,
                     context.ChunkToUpdate * context.ChunkResolution.PixelSize(),
                     maskPaint);
             }
@@ -120,11 +122,11 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IBackgroundI
         maskCacheHash = EmbeddedMask?.GetCacheHash() ?? 0;
     }
 
-    protected void ApplyRasterClip(Texture toClip, Texture clipSource)
+    protected void ApplyRasterClip(DrawingSurface toClip, DrawingSurface clipSource)
     {
         if (ClipToPreviousMember && Background.Value != null)
         {
-            toClip.DrawingSurface.Canvas.DrawSurface(clipSource.DrawingSurface, 0, 0, maskPaint);
+            toClip.Canvas.DrawSurface(clipSource, 0, 0, maskPaint);
         }
     }
 

+ 6 - 6
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/VectorLayerNode.cs

@@ -57,7 +57,7 @@ public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorN
         return ctx.DocumentSize;
     }
 
-    protected override void DrawWithoutFilters(RenderContext ctx, Texture workingSurface, bool shouldClear,
+    protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear,
         Paint paint)
     {
         if (ShapeData == null)
@@ -67,13 +67,13 @@ public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorN
 
         if (shouldClear)
         {
-            workingSurface.DrawingSurface.Canvas.Clear();
+            workingSurface.Canvas.Clear();
         }
 
-        Rasterize(workingSurface.DrawingSurface, ctx.ChunkResolution, paint);
+        Rasterize(workingSurface, ctx.ChunkResolution, paint);
     }
 
-    protected override void DrawWithFilters(RenderContext ctx, Texture workingSurface, bool shouldClear, Paint paint)
+    protected override void DrawWithFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface, bool shouldClear, Paint paint)
     {
         if (ShapeData == null)
         {
@@ -82,10 +82,10 @@ public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorN
 
         if (shouldClear)
         {
-            workingSurface.DrawingSurface.Canvas.Clear();
+            workingSurface.Canvas.Clear();
         }
 
-        Rasterize(workingSurface.DrawingSurface, ctx.ChunkResolution, paint);
+        Rasterize(workingSurface, ctx.ChunkResolution, paint);
     }
 
     public override bool RenderPreview(Texture renderOn, VecI chunk, ChunkResolution resolution, int frame)

+ 4 - 4
src/PixiEditor/Views/Rendering/UniversalScene.cs

@@ -26,7 +26,7 @@ public class UniversalScene : Zoombox.Zoombox, ICustomHitTest
         get => GetValue(SceneRendererProperty);
         set => SetValue(SceneRendererProperty, value);
     }
-
+    
     public override void Render(DrawingContext context)
     {
         // TODO: Do bounds pass, that will be used to calculate dirty bounds
@@ -36,7 +36,7 @@ public class UniversalScene : Zoombox.Zoombox, ICustomHitTest
             return;
         }
         
-        var drawOperation = new DrawUniversalSceneOperation(SceneRenderer.RenderScene, Bounds, CalculateTransformMatrix());
+        using var drawOperation = new DrawUniversalSceneOperation(SceneRenderer.RenderScene, Bounds, CalculateTransformMatrix());
         context.Custom(drawOperation);
 
         Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Render);
@@ -60,13 +60,13 @@ public class UniversalScene : Zoombox.Zoombox, ICustomHitTest
 
 class DrawUniversalSceneOperation : SkiaDrawOperation
 {
-    public event Action<DrawingSurface> RenderScene;
+    public Action<DrawingSurface> RenderScene;
     public Matrix TransformMatrix { get; set; }
 
     public DrawUniversalSceneOperation(Action<DrawingSurface> renderAction, Rect dirtyBounds,
         Matrix calculateTransformMatrix) : base(dirtyBounds)
     {
-        RenderScene += renderAction;
+        RenderScene = renderAction;
         TransformMatrix = calculateTransformMatrix;
     }
 

+ 1 - 2
src/PixiEditor/Views/Visuals/SkiaDrawOperation.cs

@@ -8,8 +8,7 @@ namespace PixiEditor.Views.Visuals;
 
 internal abstract class SkiaDrawOperation : ICustomDrawOperation
 {
-    public Rect Bounds { get; }
-
+    public Rect Bounds { get; set; }
 
     public SkiaDrawOperation(Rect dirtyBounds)
     {