Browse Source

Added render node concept

flabbet 10 months ago
parent
commit
182bfbb3cd

+ 3 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/SceneObjectRenderContext.cs

@@ -9,10 +9,12 @@ public class SceneObjectRenderContext : RenderContext
 {
     public RectD LocalBounds { get; }
     public bool RenderSurfaceIsScene { get; }
+    public RenderOutputProperty TargetPropertyOutput { get; }
 
-    public SceneObjectRenderContext(DrawingSurface surface, RectD localBounds, KeyFrameTime frameTime,
+    public SceneObjectRenderContext(RenderOutputProperty targetPropertyOutput, DrawingSurface surface, RectD localBounds, KeyFrameTime frameTime,
         ChunkResolution chunkResolution, VecI docSize, bool renderSurfaceIsScene, double opacity) : base(surface, frameTime, chunkResolution, docSize, opacity)
     {
+        TargetPropertyOutput = targetPropertyOutput;
         LocalBounds = localBounds;
         RenderSurfaceIsScene = renderSurfaceIsScene;
     }

+ 24 - 26
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -16,27 +16,22 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 {
     public const string ImageFramesKey = "Frames";
     public const string ImageLayerKey = "LayerImage";
-    public OutputProperty<Texture> RawOutput { get; }
+    //public RenderOutputProperty RawOutput { get; }
 
     public override VecD ScenePosition => layerImage.CommittedSize / 2f;
     public override VecD SceneSize => layerImage.CommittedSize;
-    
+
     public bool LockTransparency { get; set; }
 
     private VecI startSize;
     private ChunkyImage layerImage => keyFrames[0]?.Data as ChunkyImage;
 
-    private static readonly Paint clearPaint = new()
-    {
-        BlendMode = DrawingApi.Core.Surfaces.BlendMode.Src,
-        Color = PixiEditor.DrawingApi.Core.ColorsImpl.Colors.Transparent
-    };
-
-    private Texture fullResrenderedSurface; 
+    private Texture fullResrenderedSurface;
     private int renderedSurfaceFrame = -1;
+
     public ImageLayerNode(VecI size)
     {
-        RawOutput = CreateOutput<Texture>(nameof(RawOutput), "RAW_LAYER_OUTPUT", null);
+        //RawOutput = CreateRenderOutput(nameof(RawOutput), "RAW_LAYER_OUTPUT");
 
         if (keyFrames.Count == 0)
         {
@@ -44,9 +39,8 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         }
 
         this.startSize = size;
-
     }
-    
+
     public override RectD? GetTightBounds(KeyFrameTime frameTime)
     {
         return (RectD?)GetLayerImageAtFrame(frameTime.Frame).FindTightCommittedBounds();
@@ -55,16 +49,21 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     protected override void OnExecute(RenderContext context)
     {
         base.OnExecute(context);
-
-        /*if (RawOutput.Connections.Count > 0)
+        /*var rawOutputTarget = RawOutput.GetFirstRenderTarget(context);
+        if (RawOutput.Connections.Count > 0 && rawOutputTarget != null)
         {
-            var rawWorkingSurface = TryInitWorkingSurface(GetTargetSize(context), context.ChunkResolution, 2);
-            DrawLayer(context, rawWorkingSurface, true, useFilters: false);
-
-            RawOutput.Value = rawWorkingSurface;
+            using SceneObjectRenderContext sceneContext = CreateSceneContext(context, rawOutputTarget, RawOutput);
+            
+            int renderSaved = rawOutputTarget.Canvas.Save();
+            rawOutputTarget.Canvas.ClipRect(new RectD(ScenePosition - (SceneSize / 2f), SceneSize));
+            
+            DrawLayerInScene(sceneContext, rawOutputTarget, false);
+            
+            rawOutputTarget.Canvas.RestoreToCount(renderSaved);
+            RawOutput.Value = rawOutputTarget;
         }*/
     }
-
+    
     protected override VecI GetTargetSize(RenderContext ctx)
     {
         return (GetFrameWithImage(ctx.FrameTime).Data as ChunkyImage).LatestSize;
@@ -76,7 +75,6 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         int scaled = workingSurface.Canvas.Save();
         float multiplier = (float)ctx.ChunkResolution.InvertedMultiplier();
         workingSurface.Canvas.Translate(ScenePosition);
-        //workingSurface.Canvas.Scale(multiplier, multiplier);
         base.DrawLayerInScene(ctx, workingSurface, useFilters);
 
         workingSurface.Canvas.RestoreToCount(scaled);
@@ -85,7 +83,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
         Paint paint)
     {
-        DrawLayer(workingSurface, paint, ctx); 
+        DrawLayer(workingSurface, paint, ctx);
     }
 
     protected override void DrawWithFilters(SceneObjectRenderContext context, DrawingSurface workingSurface,
@@ -99,12 +97,12 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         int saved = workingSurface.Canvas.Save();
 
         VecD topLeft = SceneSize / 2f;
-        if (renderedSurfaceFrame == null || ctx.IsExportRender || ctx.FrameTime.Frame != renderedSurfaceFrame)
+        if (renderedSurfaceFrame == null || ctx.FullRerender || ctx.FrameTime.Frame != renderedSurfaceFrame)
         {
             GetLayerImageAtFrame(ctx.FrameTime.Frame).DrawMostUpToDateRegionOn(
                 new RectI(0, 0, layerImage.LatestSize.X, layerImage.LatestSize.Y),
                 ChunkResolution.Full,
-                workingSurface, -(VecI)topLeft, paint);   
+                workingSurface, -(VecI)topLeft, paint);
         }
         else
         {
@@ -143,7 +141,7 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         }
 
         var img = GetLayerImageAtFrame(frame);
-        
+
         if (Guid.TryParse(elementToRenderName, out Guid guid))
         {
             var keyFrame = keyFrames.FirstOrDefault(x => x.KeyFrameGuid == guid);
@@ -235,13 +233,13 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     public override void RenderChunk(VecI chunkPos, ChunkResolution resolution, KeyFrameTime frameTime)
     {
         base.RenderChunk(chunkPos, resolution, frameTime);
-        
+
         var img = GetLayerImageAtFrame(frameTime.Frame);
 
         RenderChunkyImageChunk(chunkPos, resolution, img, ref fullResrenderedSurface);
         renderedSurfaceFrame = frameTime.Frame;
     }
-    
+
     public void ForEveryFrame(Action<ChunkyImage> action)
     {
         foreach (var frame in keyFrames)

+ 28 - 50
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LayerNode.cs

@@ -29,73 +29,51 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
         blendPaint.Color = new Color(255, 255, 255, 255);
         blendPaint.BlendMode = DrawingApi.Core.Surfaces.BlendMode.SrcOver;
 
-        DrawingSurface target = sceneContext.RenderSurface;
-
         VecI targetSize = GetTargetSize(sceneContext);
 
-        /*if (FilterlessOutput.Connections.Count > 0)
-        {
-            var filterlessWorkingSurface = TryInitWorkingSurface(targetSize, sceneContext.ChunkResolution, 0);
+        RenderContent(targetSize, sceneContext, sceneContext.RenderSurface,
+            sceneContext.TargetPropertyOutput != FilterlessOutput);
+    }
 
-            if (Background.Value != null)
+    private void RenderContent(VecI size, SceneObjectRenderContext context, DrawingSurface renderOnto, bool useFilters)
+    {
+        if (!HasOperations())
+        {
+            if (RenderTarget.Value != null)
             {
-                DrawBackground(filterlessWorkingSurface.DrawingSurface, sceneContext);
                 blendPaint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
             }
 
-            DrawLayer(sceneContext, filterlessWorkingSurface.DrawingSurface, shouldClear, useFilters: false);
-            blendPaint.BlendMode = DrawingApi.Core.Surfaces.BlendMode.Src;
+            DrawLayerInScene(context, renderOnto, useFilters);
+            return;
+        }
 
-            FilterlessOutput.Value = filterlessWorkingSurface;
-        }*/
+        var outputWorkingSurface = TryInitWorkingSurface(size, context.ChunkResolution, 1);
+        outputWorkingSurface.DrawingSurface.Canvas.Clear();
 
-        RenderContent(targetSize, sceneContext, target);
+        DrawLayerOnTexture(context, outputWorkingSurface.DrawingSurface, useFilters);
 
-        Output.Value = target;
-    }
+        ApplyMaskIfPresent(outputWorkingSurface.DrawingSurface, context);
 
-    private void RenderContent(VecI size, SceneObjectRenderContext context, DrawingSurface renderOnto)
-    {
-        if (Output.Connections.Count > 0)
+        if (RenderTarget.Value != null)
         {
-            if (!HasOperations())
+            Texture tempSurface = TryInitWorkingSurface(size, context.ChunkResolution, 4);
+            tempSurface.DrawingSurface.Canvas.Clear();
+            if (RenderTarget.Connection.Node is IClipSource clipSource)
             {
-                if (RenderTarget.Value != null)
-                {
-                    blendPaint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
-                }
-
-                DrawLayerInScene(context, renderOnto, true);
-                return;
+                // TODO: This probably should work with StructureMembers not Layers only
+                DrawClipSource(tempSurface.DrawingSurface, clipSource, context);
             }
 
-            var outputWorkingSurface = TryInitWorkingSurface(size, context.ChunkResolution, 1);
-            outputWorkingSurface.DrawingSurface.Canvas.Clear();
+            ApplyRasterClip(outputWorkingSurface.DrawingSurface, tempSurface.DrawingSurface);
+            blendPaint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
+            tempSurface.DrawingSurface.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0, blendPaint);
 
-            DrawLayerOnTexture(context, outputWorkingSurface.DrawingSurface, true);
-
-            ApplyMaskIfPresent(outputWorkingSurface.DrawingSurface, context);
-
-            if (RenderTarget.Value != null)
-            {
-                Texture tempSurface = TryInitWorkingSurface(size, context.ChunkResolution, 4);
-                tempSurface.DrawingSurface.Canvas.Clear();
-                if (RenderTarget.Connection.Node is IClipSource clipSource)
-                {
-                    // TODO: This probably should work with StructureMembers not Layers only
-                    DrawClipSource(tempSurface.DrawingSurface, clipSource, context);
-                }
-
-                ApplyRasterClip(outputWorkingSurface.DrawingSurface, tempSurface.DrawingSurface);
-                blendPaint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
-                tempSurface.DrawingSurface.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0, blendPaint);
-
-                DrawWithResolution(tempSurface.DrawingSurface, renderOnto, context.ChunkResolution, size);
-                return;
-            }
-
-            DrawWithResolution(outputWorkingSurface.DrawingSurface, renderOnto, context.ChunkResolution, size);
+            DrawWithResolution(tempSurface.DrawingSurface, renderOnto, context.ChunkResolution, size);
+            return;
         }
+
+        DrawWithResolution(outputWorkingSurface.DrawingSurface, renderOnto, context.ChunkResolution, size);
     }
 
     protected internal virtual void DrawLayerOnTexture(SceneObjectRenderContext ctx, DrawingSurface workingSurface,

+ 37 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/OutputNode.cs

@@ -3,15 +3,18 @@ using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
 using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core;
 using PixiEditor.DrawingApi.Core.Surfaces;
+using PixiEditor.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 
 [NodeInfo("Output")]
-public class OutputNode : Node, IRenderInput
+public class OutputNode : Node, IRenderInput, IPreviewRenderable
 {
     public const string InputPropertyName = "Background";
 
     public RenderInputProperty Input { get; } 
+    
+    private VecI? lastDocumentSize;
     public OutputNode()
     {
         Input = new RenderInputProperty(this, InputPropertyName, "BACKGROUND", null, (ctx) => ctx.RenderSurface);
@@ -25,7 +28,40 @@ public class OutputNode : Node, IRenderInput
 
     protected override void OnExecute(RenderContext context)
     {
+        lastDocumentSize = context.DocumentSize;
     }
 
     RenderInputProperty IRenderInput.RenderTarget => Input;
+    public RectD? GetPreviewBounds(int frame, string elementToRenderName = "")
+    {
+        if (lastDocumentSize == null)
+        {
+            return null;
+        }
+        
+        return new RectD(0, 0, lastDocumentSize.Value.X, lastDocumentSize.Value.Y); 
+    }
+
+    public bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame, string elementToRenderName)
+    {
+        var executionQueue = GraphUtils.CalculateExecutionQueue(this);
+        
+        foreach (var node in executionQueue)
+        {
+            if(node == this)
+            {
+                continue;
+            }
+            
+            if (node is IPreviewRenderable previewRenderable)
+            {
+                if (!previewRenderable.RenderPreview(renderOn, resolution, frame, elementToRenderName))
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
+    }
 }

+ 46 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/RenderNode.cs

@@ -0,0 +1,46 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
+using PixiEditor.ChangeableDocument.Rendering;
+using PixiEditor.DrawingApi.Core.Surfaces;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
+
+public abstract class RenderNode : Node, IPreviewRenderable 
+{
+    public RenderOutputProperty Output { get; }
+    
+    public RenderNode()
+    {
+        Output = CreateRenderOutput("Output", "OUTPUT");
+    }
+
+    protected override void OnExecute(RenderContext context)
+    {
+        Output.Value = ExecuteRender(context);
+    }
+    
+    protected abstract DrawingSurface? ExecuteRender(RenderContext context);
+    
+    protected RenderOutputProperty? CreateRenderOutput(string internalName, string displayName)
+    {
+        RenderOutputProperty prop = new RenderOutputProperty(this, internalName, displayName, null);
+        AddOutputProperty(prop);
+
+        return prop;
+    }
+
+    protected RenderInputProperty CreateRenderInput(string internalName, string displayName,
+        Func<RenderContext, DrawingSurface> renderTarget)
+    {
+        RenderInputProperty prop = new RenderInputProperty(this, internalName, displayName, null, renderTarget);
+        AddInputProperty(prop);
+
+        return prop;
+    }
+
+    public abstract RectD? GetPreviewBounds(int frame, string elementToRenderName = "");
+
+    public abstract bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame,
+        string elementToRenderName);
+
+}

+ 22 - 17
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Shapes/RasterizeShapeNode.cs

@@ -9,10 +9,8 @@ using PixiEditor.Numerics;
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Shapes;
 
 [NodeInfo("RasterizeShape")]
-public class RasterizeShapeNode : Node
+public class RasterizeShapeNode : RenderNode
 {
-    public OutputProperty<Texture> Image { get; }
-
     public InputProperty<ShapeVectorData> Data { get; }
 
 
@@ -20,30 +18,37 @@ public class RasterizeShapeNode : Node
 
     public RasterizeShapeNode()
     {
-        Image = CreateOutput<Texture>("Image", "IMAGE", null);
         Data = CreateInput<ShapeVectorData>("Points", "SHAPE", null);
     }
 
-    protected override void OnExecute(RenderContext context)
+    protected override DrawingSurface? ExecuteRender(RenderContext context)
     {
         var shape = Data.Value;
 
         if (shape == null || !shape.IsValid())
-            return;
-
-        var size = context.DocumentSize;
-        var image = RequestTexture(0, size);
-
-        image.DrawingSurface.Canvas.Save();
-
-        shape.RasterizeTransformed(image.DrawingSurface);
-        
-        image.DrawingSurface.Canvas.Restore();
+            return null;
 
-        Image.Value = image;
+        var surface = context.RenderSurface;
         
-        return;
+        shape.RasterizeTransformed(surface);
+        return surface;
     }
 
     public override Node CreateCopy() => new RasterizeShapeNode();
+    public override RectD? GetPreviewBounds(int frame, string elementToRenderName = "")
+    {
+        return Data?.Value?.TransformedAABB;
+    }
+
+    public override bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame, string elementToRenderName)
+    {
+        var shape = Data.Value;
+
+        if (shape == null || !shape.IsValid())
+            return false;
+
+        shape.RasterizeTransformed(renderOn);
+
+        return true;
+    }
 }

+ 50 - 38
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/StructureNode.cs

@@ -13,13 +13,12 @@ using BlendMode = PixiEditor.ChangeableDocument.Enums.BlendMode;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 
-public abstract class StructureNode : Node, IReadOnlyStructureNode, IRenderInput, IPreviewRenderable
+public abstract class StructureNode : RenderNode, IReadOnlyStructureNode, IRenderInput
 {
     public abstract VecD ScenePosition { get; }
     public abstract VecD SceneSize { get; }
 
     public const string DefaultMemberName = "DEFAULT_MEMBER_NAME";
-    public RenderInputProperty RenderTarget { get; }
     public InputProperty<float> Opacity { get; }
     public InputProperty<bool> IsVisible { get; }
     public bool ClipToPreviousMember { get; set; }
@@ -27,9 +26,9 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IRenderInput
     public InputProperty<Texture?> CustomMask { get; }
     public InputProperty<bool> MaskIsVisible { get; }
     public InputProperty<Filter> Filters { get; }
-    public RenderOutputProperty Output { get; }
 
-    public OutputProperty<DrawingSurface?> FilterlessOutput { get; }
+    public RenderInputProperty RenderTarget { get; }
+    public RenderOutputProperty FilterlessOutput { get; }
 
     public ChunkyImage? EmbeddedMask { get; set; }
 
@@ -60,7 +59,6 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IRenderInput
     protected StructureNode()
     {
         RenderTarget = CreateRenderInput("Background", "BACKGROUND", (context => Output.GetFirstRenderTarget(context)));
-        
         Opacity = CreateInput<float>("Opacity", "OPACITY", 1);
         IsVisible = CreateInput<bool>("IsVisible", "IS_VISIBLE", true);
         BlendMode = CreateInput("BlendMode", "BLEND_MODE", Enums.BlendMode.Normal);
@@ -68,51 +66,56 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IRenderInput
         MaskIsVisible = CreateInput<bool>("MaskIsVisible", "MASK_IS_VISIBLE", true);
         Filters = CreateInput<Filter>(nameof(Filters), "FILTERS", null);
 
-        Output = CreateRenderOutput("Output", "OUTPUT");
-        FilterlessOutput = CreateOutput<DrawingSurface?>(nameof(FilterlessOutput), "WITHOUT_FILTERS", null);
+        FilterlessOutput = CreateRenderOutput(nameof(FilterlessOutput), "WITHOUT_FILTERS");
 
         MemberName = DefaultMemberName;
     }
 
-    protected RenderOutputProperty? CreateRenderOutput(string internalName, string displayName)
+    protected override DrawingSurface? ExecuteRender(RenderContext context)
     {
-        RenderOutputProperty prop = new RenderOutputProperty(this, internalName, displayName, null);
-        AddOutputProperty(prop);
-
-        return prop;
-    }
+        DrawingSurface renderTarget = null;
+        if (Output.Connections.Count > 0 || RenderTarget.Value != null)
+        {
+            renderTarget = RenderTarget.Value ?? Output.GetFirstRenderTarget(context);
+            RenderForOutput(context, renderTarget, Output);
+        }
 
-    protected RenderInputProperty CreateRenderInput(string internalName, string displayName,
-        Func<RenderContext, DrawingSurface> renderTarget)
-    {
-        RenderInputProperty prop = new RenderInputProperty(this, internalName, displayName, null, renderTarget);
-        AddInputProperty(prop);
+        if (FilterlessOutput.Connections.Count > 0)
+        {
+            RenderForOutput(context, FilterlessOutput.GetFirstRenderTarget(context), FilterlessOutput);
+        }
 
-        return prop;
+        return renderTarget;
     }
 
-
-    protected override void OnExecute(RenderContext context)
+    private DrawingSurface RenderForOutput(RenderContext context, DrawingSurface renderTarget, RenderOutputProperty output)
     {
-        RectD localBounds = new RectD(0, 0, SceneSize.X, SceneSize.Y);
+        var renderObjectContext = CreateSceneContext(context, renderTarget, output);
 
-        DrawingSurface renderTarget = RenderTarget.Value ?? Output.GetFirstRenderTarget(context);
+        int renderSaved = 0;
+        if (renderTarget != null)
+        {
+            renderSaved = renderTarget.Canvas.Save();
+            renderTarget.Canvas.ClipRect(new RectD(ScenePosition - (SceneSize / 2f), SceneSize));
+        }
+        
+        Render(renderObjectContext);
 
-        int savedNum = renderTarget.Canvas.Save();
+        renderTarget?.Canvas.RestoreToCount(renderSaved);
 
-        renderTarget.Canvas.ClipRect(new RectD(ScenePosition - (SceneSize / 2f), SceneSize));
+        return renderTarget;
+    }
 
-        SceneObjectRenderContext renderObjectContext = new SceneObjectRenderContext(renderTarget, localBounds,
+    protected SceneObjectRenderContext CreateSceneContext(RenderContext context, DrawingSurface renderTarget,
+        RenderOutputProperty output)
+    {
+        RectD localBounds = new RectD(0, 0, SceneSize.X, SceneSize.Y);
+        
+        SceneObjectRenderContext renderObjectContext = new SceneObjectRenderContext(output, renderTarget, localBounds,
             context.FrameTime, context.ChunkResolution, context.DocumentSize, renderTarget == context.RenderSurface,
             context.Opacity);
-        
-        renderObjectContext.IsExportRender = context.IsExportRender;
-
-        Render(renderObjectContext);
-
-        renderTarget.Canvas.RestoreToCount(savedNum);
-
-        Output.Value = renderTarget;
+        renderObjectContext.FullRerender = context.FullRerender;
+        return renderObjectContext;
     }
 
     public abstract void Render(SceneObjectRenderContext sceneContext);
@@ -127,8 +130,17 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IRenderInput
             }
             else if (EmbeddedMask != null)
             {
-                // apply resolution scaling
-                surface.Canvas.DrawSurface(renderedMask.DrawingSurface, 0, 0, maskPaint);
+                if (context.FullRerender)
+                {
+                    EmbeddedMask.DrawMostUpToDateRegionOn(
+                        new RectI(0, 0, EmbeddedMask.LatestSize.X, EmbeddedMask.LatestSize.Y),
+                        ChunkResolution.Full,
+                        surface, VecI.Zero, maskPaint);   
+                }
+                else
+                {
+                    surface.Canvas.DrawSurface(renderedMask.DrawingSurface, 0, 0, maskPaint);
+                }
             }
         }
     }
@@ -233,7 +245,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IRenderInput
         return new None();
     }
 
-    public virtual RectD? GetPreviewBounds(int frame, string elementFor = "")
+    public override RectD? GetPreviewBounds(int frame, string elementFor = "")
     {
         if (elementFor == nameof(EmbeddedMask) && EmbeddedMask != null)
         {
@@ -243,7 +255,7 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IRenderInput
         return null;
     }
 
-    public virtual bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame,
+    public override bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame,
         string elementToRenderName)
     {
         if (elementToRenderName != nameof(EmbeddedMask))

+ 2 - 2
src/PixiEditor.ChangeableDocument/Rendering/DocumentRenderer.cs

@@ -80,7 +80,7 @@ public class DocumentRenderer : IPreviewRenderable
         }
         
         using RenderContext context = new(renderOn, frameTime, resolution, Document.Size);
-        context.IsExportRender = true;
+        context.FullRerender = true;
         
         node.Execute(context);
     }
@@ -136,7 +136,7 @@ public class DocumentRenderer : IPreviewRenderable
 
     public void RenderDocument(DrawingSurface toRenderOn, KeyFrameTime frameTime)
     {
-        using RenderContext context = new(toRenderOn, frameTime, ChunkResolution.Full, Document.Size) { IsExportRender = true };
+        using RenderContext context = new(toRenderOn, frameTime, ChunkResolution.Full, Document.Size) { FullRerender = true };
         Document.NodeGraph.Execute(context);
     }
 }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Rendering/RenderContext.cs

@@ -25,7 +25,7 @@ public class RenderContext : IDisposable
     public VecI DocumentSize { get; set; }
     
     public DrawingSurface RenderSurface { get; set; }
-    public bool IsExportRender { get; set; } = false;
+    public bool FullRerender { get; set; } = false;
 
     public bool IsDisposed { get; private set; }