Selaa lähdekoodia

Added mask previews and fixed masks

Krzysztof Krysiński 2 viikkoa sitten
vanhempi
commit
1e163caa32

+ 32 - 17
src/ChunkyImageLib/ChunkyImageEx.cs

@@ -22,9 +22,9 @@ public static class IReadOnlyChunkyImageEx
     /// <param name="paint">Paint to use for drawing</param>
     /// <param name="paint">Paint to use for drawing</param>
     public static void DrawMostUpToDateRegionOn
     public static void DrawMostUpToDateRegionOn
     (this IReadOnlyChunkyImage image, RectI fullResRegion, ChunkResolution resolution, DrawingSurface surface,
     (this IReadOnlyChunkyImage image, RectI fullResRegion, ChunkResolution resolution, DrawingSurface surface,
-        VecD pos, Paint? paint = null, SamplingOptions? sampling = null)
+        VecD pos, Paint? paint = null, SamplingOptions? sampling = null, bool drawPaintOnEmpty = false)
     {
     {
-        DrawRegionOn(fullResRegion, resolution, surface, pos, image.DrawMostUpToDateChunkOn, paint, sampling);
+        DrawRegionOn(fullResRegion, resolution, surface, pos, image.DrawMostUpToDateChunkOn, paint, sampling, drawPaintOnEmpty);
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -39,10 +39,10 @@ public static class IReadOnlyChunkyImageEx
     /// <param name="paint">Paint to use for drawing</param>
     /// <param name="paint">Paint to use for drawing</param>
     public static void DrawMostUpToDateRegionOnWithAffected
     public static void DrawMostUpToDateRegionOnWithAffected
     (this IReadOnlyChunkyImage image, RectI fullResRegion, ChunkResolution resolution, DrawingSurface surface,
     (this IReadOnlyChunkyImage image, RectI fullResRegion, ChunkResolution resolution, DrawingSurface surface,
-        AffectedArea affectedArea, VecD pos, Paint? paint = null, SamplingOptions? sampling = null)
+        AffectedArea affectedArea, VecD pos, Paint? paint = null, SamplingOptions? sampling = null, bool drawPaintOnEmpty = false)
     {
     {
         DrawRegionOn(fullResRegion, resolution, surface, pos, image.DrawMostUpToDateChunkOn,
         DrawRegionOn(fullResRegion, resolution, surface, pos, image.DrawMostUpToDateChunkOn,
-            image.DrawCachedMostUpToDateChunkOn, affectedArea, paint, sampling);
+            image.DrawCachedMostUpToDateChunkOn, affectedArea, paint, sampling, drawPaintOnEmpty);
     }
     }
 
 
     /// <summary>
     /// <summary>
@@ -57,9 +57,9 @@ public static class IReadOnlyChunkyImageEx
     /// <param name="paint">Paint to use for drawing</param>
     /// <param name="paint">Paint to use for drawing</param>
     public static void DrawCommittedRegionOn
     public static void DrawCommittedRegionOn
     (this IReadOnlyChunkyImage image, RectI fullResRegion, ChunkResolution resolution, DrawingSurface surface,
     (this IReadOnlyChunkyImage image, RectI fullResRegion, ChunkResolution resolution, DrawingSurface surface,
-        VecI pos, Paint? paint = null, SamplingOptions? samplingOptions = null)
+        VecI pos, Paint? paint = null, SamplingOptions? samplingOptions = null, bool drawPaintOnEmpty = false)
     {
     {
-        DrawRegionOn(fullResRegion, resolution, surface, pos, image.DrawCommittedChunkOn, paint, samplingOptions);
+        DrawRegionOn(fullResRegion, resolution, surface, pos, image.DrawCommittedChunkOn, paint, samplingOptions, drawPaintOnEmpty);
     }
     }
 
 
     private static void DrawRegionOn(
     private static void DrawRegionOn(
@@ -68,7 +68,7 @@ public static class IReadOnlyChunkyImageEx
         DrawingSurface surface,
         DrawingSurface surface,
         VecD pos,
         VecD pos,
         Func<VecI, ChunkResolution, DrawingSurface, VecD, Paint?, SamplingOptions?, bool> drawingFunc,
         Func<VecI, ChunkResolution, DrawingSurface, VecD, Paint?, SamplingOptions?, bool> drawingFunc,
-        Paint? paint = null, SamplingOptions? samplingOptions = null)
+        Paint? paint = null, SamplingOptions? samplingOptions = null, bool drawPaintOnEmpty = false)
     {
     {
         int count = surface.Canvas.Save();
         int count = surface.Canvas.Save();
         surface.Canvas.ClipRect(new RectD(pos, fullResRegion.Size));
         surface.Canvas.ClipRect(new RectD(pos, fullResRegion.Size));
@@ -83,9 +83,14 @@ public static class IReadOnlyChunkyImageEx
             for (int i = chunkTopLeft.X; i <= chunkBotRight.X; i++)
             for (int i = chunkTopLeft.X; i <= chunkBotRight.X; i++)
             {
             {
                 var chunkPos = new VecI(i, j);
                 var chunkPos = new VecI(i, j);
-                drawingFunc(chunkPos, resolution, surface,
-                    offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos, paint,
-                    samplingOptions);
+                if (!drawingFunc(chunkPos, resolution, surface,
+                        offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos, paint,
+                        samplingOptions) && paint != null && drawPaintOnEmpty)
+                {
+                    surface.Canvas.DrawRect(new RectD(
+                        offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos,
+                        new VecD(resolution.PixelSize())), paint);
+                }
             }
             }
         }
         }
 
 
@@ -100,7 +105,7 @@ public static class IReadOnlyChunkyImageEx
         Func<VecI, ChunkResolution, DrawingSurface, VecD, Paint?, SamplingOptions?, bool> drawingFunc,
         Func<VecI, ChunkResolution, DrawingSurface, VecD, Paint?, SamplingOptions?, bool> drawingFunc,
         Func<VecI, ChunkResolution, DrawingSurface, VecD, Paint?, SamplingOptions?, bool> quickDrawingFunc,
         Func<VecI, ChunkResolution, DrawingSurface, VecD, Paint?, SamplingOptions?, bool> quickDrawingFunc,
         AffectedArea area,
         AffectedArea area,
-        Paint? paint = null, SamplingOptions? samplingOptions = null)
+        Paint? paint = null, SamplingOptions? samplingOptions = null, bool drawPaintOnEmpty = false)
     {
     {
         int count = surface.Canvas.Save();
         int count = surface.Canvas.Save();
         surface.Canvas.ClipRect(new RectD(pos, fullResRegion.Size));
         surface.Canvas.ClipRect(new RectD(pos, fullResRegion.Size));
@@ -117,15 +122,25 @@ public static class IReadOnlyChunkyImageEx
                 var chunkPos = new VecI(i, j);
                 var chunkPos = new VecI(i, j);
                 if (area.Chunks != null && area.Chunks.Contains(chunkPos))
                 if (area.Chunks != null && area.Chunks.Contains(chunkPos))
                 {
                 {
-                    drawingFunc(chunkPos, resolution, surface,
-                        offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos, paint,
-                        samplingOptions);
+                    if (!drawingFunc(chunkPos, resolution, surface,
+                            offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos, paint,
+                            samplingOptions) && paint != null && drawPaintOnEmpty)
+                    {
+                        surface.Canvas.DrawRect(new RectD(
+                            offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos,
+                            new VecD(resolution.PixelSize())), paint);
+                    }
                 }
                 }
                 else
                 else
                 {
                 {
-                    quickDrawingFunc(chunkPos, resolution, surface,
-                        offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos, paint,
-                        samplingOptions);
+                    if (!quickDrawingFunc(chunkPos, resolution, surface,
+                            offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos, paint,
+                            samplingOptions) && paint != null && drawPaintOnEmpty)
+                    {
+                        surface.Canvas.DrawRect(new RectD(
+                            offsetTargetRes + (chunkPos - chunkTopLeft) * resolution.PixelSize() + pos,
+                            new VecD(resolution.PixelSize())), paint);
+                    }
                 }
                 }
             }
             }
         }
         }

+ 17 - 31
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -29,6 +29,8 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
 
     private VecI startSize;
     private VecI startSize;
     private ColorSpace colorSpace;
     private ColorSpace colorSpace;
+
+
     private ChunkyImage layerImage => keyFrames[0]?.Data as ChunkyImage;
     private ChunkyImage layerImage => keyFrames[0]?.Data as ChunkyImage;
 
 
     public ImageLayerNode(VecI size, ColorSpace colorSpace)
     public ImageLayerNode(VecI size, ColorSpace colorSpace)
@@ -131,40 +133,24 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         var region = ctx.VisibleDocumentRegion ?? new RectI(0, 0, layerImage.LatestSize.X, layerImage.LatestSize.Y);
         var region = ctx.VisibleDocumentRegion ?? new RectI(0, 0, layerImage.LatestSize.X, layerImage.LatestSize.Y);
         VecD topLeft = region.TopLeft - sceneSize / 2;
         VecD topLeft = region.TopLeft - sceneSize / 2;
 
 
-        //if (renderedSurfaceFrame == null || ctx.FullRerender || ctx.FrameTime.Frame != renderedSurfaceFrame)
+        topLeft *= ctx.ChunkResolution.Multiplier();
+        workingSurface.Canvas.Scale((float)ctx.ChunkResolution.InvertedMultiplier());
+        var img = GetLayerImageAtFrame(ctx.FrameTime.Frame);
+
+        if (!ctx.FullRerender)
         {
         {
-            topLeft *= ctx.ChunkResolution.Multiplier();
-            workingSurface.Canvas.Scale((float)ctx.ChunkResolution.InvertedMultiplier());
-            if (!ctx.FullRerender)
-            {
-                GetLayerImageAtFrame(ctx.FrameTime.Frame).DrawMostUpToDateRegionOnWithAffected(
-                    region,
-                    ctx.ChunkResolution,
-                    workingSurface, ctx.AffectedArea, topLeft, paint, ctx.DesiredSamplingOptions);
-            }
-            else
-            {
-                GetLayerImageAtFrame(ctx.FrameTime.Frame).DrawMostUpToDateRegionOn(
-                    region,
-                    ctx.ChunkResolution,
-                    workingSurface, topLeft, paint, ctx.DesiredSamplingOptions);
-            }
+            img.DrawMostUpToDateRegionOnWithAffected(
+                region,
+                ctx.ChunkResolution,
+                workingSurface, ctx.AffectedArea, topLeft, paint, ctx.DesiredSamplingOptions);
         }
         }
-        /*else
+        else
         {
         {
-            if (ctx.DesiredSamplingOptions == SamplingOptions.Default)
-            {
-                workingSurface.Canvas.DrawSurface(
-                    fullResrenderedSurface.DrawingSurface, -(float)topLeft.X, -(float)topLeft.Y, paint);
-            }
-            else
-            {
-                using var snapshot = fullResrenderedSurface.DrawingSurface.Snapshot();
-                workingSurface.Canvas.DrawImage(snapshot, -(float)topLeft.X, -(float)topLeft.Y,
-                    ctx.DesiredSamplingOptions,
-                    paint);
-            }
-        }*/
+            img.DrawMostUpToDateRegionOn(
+                region,
+                ctx.ChunkResolution,
+                workingSurface, topLeft, paint, ctx.DesiredSamplingOptions);
+        }
 
 
         workingSurface.Canvas.RestoreToCount(saved);
         workingSurface.Canvas.RestoreToCount(saved);
     }
     }

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

@@ -22,6 +22,7 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
 
 
     public override void Render(SceneObjectRenderContext sceneContext)
     public override void Render(SceneObjectRenderContext sceneContext)
     {
     {
+        RenderPreviews(sceneContext);
         if (!IsVisible.Value || Opacity.Value <= 0 || IsEmptyMask())
         if (!IsVisible.Value || Opacity.Value <= 0 || IsEmptyMask())
         {
         {
             Output.Value = Background.Value;
             Output.Value = Background.Value;
@@ -34,7 +35,6 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
         RenderContent(sceneContext, sceneContext.RenderSurface,
         RenderContent(sceneContext, sceneContext.RenderSurface,
             sceneContext.TargetPropertyOutput == Output);
             sceneContext.TargetPropertyOutput == Output);
 
 
-        RenderPreviews(sceneContext);
     }
     }
 
 
     private void RenderContent(SceneObjectRenderContext context, DrawingSurface renderOnto, bool useFilters)
     private void RenderContent(SceneObjectRenderContext context, DrawingSurface renderOnto, bool useFilters)
@@ -62,7 +62,8 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
                 var tempSurface = TryInitWorkingSurface(context.RenderOutputSize, context.ChunkResolution,
                 var tempSurface = TryInitWorkingSurface(context.RenderOutputSize, context.ChunkResolution,
                     context.ProcessingColorSpace, 22);
                     context.ProcessingColorSpace, 22);
 
 
-                DrawLayerOnTexture(context, tempSurface.DrawingSurface, context.ChunkResolution, useFilters, targetPaint);
+                DrawLayerOnTexture(context, tempSurface.DrawingSurface, context.ChunkResolution, useFilters,
+                    targetPaint);
 
 
                 blendPaint.SetFilters(null);
                 blendPaint.SetFilters(null);
                 DrawWithResolution(tempSurface.DrawingSurface, renderOnto, context.ChunkResolution,
                 DrawWithResolution(tempSurface.DrawingSurface, renderOnto, context.ChunkResolution,
@@ -154,7 +155,8 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
         workingSurface.Canvas.RestoreToCount(scaled);
         workingSurface.Canvas.RestoreToCount(scaled);
     }
     }
 
 
-    private void DrawWithResolution(DrawingSurface source, DrawingSurface target, ChunkResolution resolution, SamplingOptions sampling)
+    private void DrawWithResolution(DrawingSurface source, DrawingSurface target, ChunkResolution resolution,
+        SamplingOptions sampling)
     {
     {
         int scaled = target.Canvas.Save();
         int scaled = target.Canvas.Save();
         float multiplier = (float)resolution.InvertedMultiplier();
         float multiplier = (float)resolution.InvertedMultiplier();
@@ -227,13 +229,23 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
 
 
     private void RenderPreviews(RenderContext ctx)
     private void RenderPreviews(RenderContext ctx)
     {
     {
-        var previewTexture = ctx.GetPreviewTexture(Id);
-        if (previewTexture == null || previewTexture.IsDisposed)
+        var previewTexture = ctx.GetPreviewTexturesForNode(Id);
+
+        if (previewTexture == null || previewTexture.Count == 0)
             return;
             return;
 
 
-        int saved = previewTexture.DrawingSurface.Canvas.Save();
+        foreach (var request in previewTexture)
+        {
+            RenderPreviewFor(ctx, request.Texture, request.ElementToRender);
+        }
+    }
+
+    private void RenderPreviewFor(RenderContext ctx, Texture texture, string elementToRender)
+    {
+        if (texture == null || texture.IsDisposed)
+            return;
 
 
-        VecD densityVec = ((VecD)ctx.DocumentSize).Divide(previewTexture.Size);
+        VecD densityVec = ((VecD)ctx.DocumentSize).Divide(texture.Size);
         double density = Math.Min(densityVec.X, densityVec.Y);
         double density = Math.Min(densityVec.X, densityVec.Y);
         ChunkResolution resolution = density switch
         ChunkResolution resolution = density switch
         {
         {
@@ -243,16 +255,18 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
             _ => ChunkResolution.Full
             _ => ChunkResolution.Full
         };
         };
 
 
+        int saved = texture.DrawingSurface.Canvas.Save();
+
         RenderContext previewCtx = ctx.Clone();
         RenderContext previewCtx = ctx.Clone();
         previewCtx.ChunkResolution = resolution;
         previewCtx.ChunkResolution = resolution;
 
 
-        VecD scaling = new VecD((double)previewTexture.Size.X / ctx.DocumentSize.X,
-            (double)previewTexture.Size.Y / ctx.DocumentSize.Y) * resolution.InvertedMultiplier();
-        previewTexture.DrawingSurface.Canvas.Scale((float)scaling.X, (float)scaling.Y);
+        VecD scaling = new VecD((double)texture.Size.X / ctx.DocumentSize.X,
+            (double)texture.Size.Y / ctx.DocumentSize.Y) * resolution.InvertedMultiplier();
+        texture.DrawingSurface.Canvas.Scale((float)scaling.X, (float)scaling.Y);
 
 
-        RenderPreview(previewTexture.DrawingSurface, previewCtx, "");
+        RenderPreview(texture.DrawingSurface, previewCtx, elementToRender);
 
 
-        previewTexture.DrawingSurface.Canvas.RestoreToCount(saved);
+        texture.DrawingSurface.Canvas.RestoreToCount(saved);
     }
     }
 
 
     protected Texture TryInitWorkingSurface(VecI imageSize, ChunkResolution resolution, ColorSpace processingCs, int id)
     protected Texture TryInitWorkingSurface(VecI imageSize, ChunkResolution resolution, ColorSpace processingCs, int id)

+ 11 - 20
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/StructureNode.cs

@@ -47,8 +47,6 @@ public abstract class StructureNode : RenderNode, IReadOnlyStructureNode, IRende
 
 
     public ChunkyImage? EmbeddedMask { get; set; }
     public ChunkyImage? EmbeddedMask { get; set; }
 
 
-    protected Texture renderedMask;
-
     protected static readonly Paint replacePaint =
     protected static readonly Paint replacePaint =
         new Paint() { BlendMode = Drawie.Backend.Core.Surfaces.BlendMode.Src };
         new Paint() { BlendMode = Drawie.Backend.Core.Surfaces.BlendMode.Src };
 
 
@@ -183,7 +181,8 @@ public abstract class StructureNode : RenderNode, IReadOnlyStructureNode, IRende
         RectD localBounds = new RectD(0, 0, sceneSize.X, sceneSize.Y);
         RectD localBounds = new RectD(0, 0, sceneSize.X, sceneSize.Y);
 
 
         SceneObjectRenderContext renderObjectContext = new SceneObjectRenderContext(output, renderTarget, localBounds,
         SceneObjectRenderContext renderObjectContext = new SceneObjectRenderContext(output, renderTarget, localBounds,
-            context.FrameTime, context.ChunkResolution, context.RenderOutputSize, context.DocumentSize, renderTarget == context.RenderSurface,
+            context.FrameTime, context.ChunkResolution, context.RenderOutputSize, context.DocumentSize,
+            renderTarget == context.RenderSurface,
             context.ProcessingColorSpace, context.DesiredSamplingOptions, context.Opacity);
             context.ProcessingColorSpace, context.DesiredSamplingOptions, context.Opacity);
         renderObjectContext.FullRerender = context.FullRerender;
         renderObjectContext.FullRerender = context.FullRerender;
         renderObjectContext.AffectedArea = context.AffectedArea;
         renderObjectContext.AffectedArea = context.AffectedArea;
@@ -206,22 +205,12 @@ public abstract class StructureNode : RenderNode, IReadOnlyStructureNode, IRende
 
 
                 surface.Canvas.RestoreToCount(layer);
                 surface.Canvas.RestoreToCount(layer);
             }
             }
-            else if (EmbeddedMask != null)
+            else
             {
             {
-                if (context.FullRerender)
-                {
-                    EmbeddedMask.DrawMostUpToDateRegionOn(
-                        new RectI(0, 0, EmbeddedMask.LatestSize.X, EmbeddedMask.LatestSize.Y),
-                        ChunkResolution.Full,
-                        surface, VecI.Zero, maskPaint);
-                }
-                else if (renderedMask != null)
-                {
-                    int saved = surface.Canvas.Save();
-                    surface.Canvas.Scale((float)renderResolution.Multiplier());
-                    surface.Canvas.DrawSurface(renderedMask.DrawingSurface, 0, 0, maskPaint);
-                    surface.Canvas.RestoreToCount(saved);
-                }
+                EmbeddedMask?.DrawMostUpToDateRegionOn(
+                    new RectI(0, 0, EmbeddedMask.LatestSize.X, EmbeddedMask.LatestSize.Y),
+                    context.ChunkResolution,
+                    surface, VecI.Zero, maskPaint, drawPaintOnEmpty: true);
             }
             }
         }
         }
     }
     }
@@ -321,7 +310,10 @@ public abstract class StructureNode : RenderNode, IReadOnlyStructureNode, IRende
             return false;
             return false;
         }
         }
 
 
-        renderOn.Canvas.DrawSurface(renderedMask.DrawingSurface, VecI.Zero, maskPreviewPaint);
+        img.DrawMostUpToDateRegionOn(
+            new RectI(0, 0, img.LatestSize.X, img.LatestSize.Y),
+            context.ChunkResolution,
+            renderOn, VecI.Zero, maskPreviewPaint, drawPaintOnEmpty: true);
 
 
         return true;
         return true;
     }
     }
@@ -329,7 +321,6 @@ public abstract class StructureNode : RenderNode, IReadOnlyStructureNode, IRende
     public override void Dispose()
     public override void Dispose()
     {
     {
         base.Dispose();
         base.Dispose();
-        renderedMask?.Dispose();
         EmbeddedMask?.Dispose();
         EmbeddedMask?.Dispose();
         Output.Value = null;
         Output.Value = null;
         maskPaint.Dispose();
         maskPaint.Dispose();

+ 15 - 0
src/PixiEditor.ChangeableDocument/Rendering/PreviewRenderRequest.cs

@@ -0,0 +1,15 @@
+using Drawie.Backend.Core;
+
+namespace PixiEditor.ChangeableDocument.Rendering;
+
+public record struct PreviewRenderRequest
+{
+    public Texture? Texture { get; set; }
+    public string? ElementToRender { get; set; }
+
+    public PreviewRenderRequest(Texture? texture, string? elementToRender = null)
+    {
+        Texture = texture;
+        ElementToRender = elementToRender;
+    }
+}

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

@@ -25,7 +25,7 @@ public class RenderContext
     public ColorSpace ProcessingColorSpace { get; set; }
     public ColorSpace ProcessingColorSpace { get; set; }
     public string? TargetOutput { get; set; }
     public string? TargetOutput { get; set; }
     public AffectedArea AffectedArea { get; set; }
     public AffectedArea AffectedArea { get; set; }
-    public Dictionary<Guid, Texture>? PreviewTextures { get; set; }
+    public Dictionary<Guid, List<PreviewRenderRequest>>? PreviewTextures { get; set; }
 
 
 
 
     public RenderContext(DrawingSurface renderSurface, KeyFrameTime frameTime, ChunkResolution chunkResolution,
     public RenderContext(DrawingSurface renderSurface, KeyFrameTime frameTime, ChunkResolution chunkResolution,
@@ -41,13 +41,13 @@ public class RenderContext
         DesiredSamplingOptions = desiredSampling;
         DesiredSamplingOptions = desiredSampling;
     }
     }
 
 
-    public Texture? GetPreviewTexture(Guid guid)
+    public List<PreviewRenderRequest>? GetPreviewTexturesForNode(Guid id)
     {
     {
         if (PreviewTextures is null)
         if (PreviewTextures is null)
             return null;
             return null;
-        PreviewTextures.TryGetValue(guid, out Texture? texture);
-        PreviewTextures.Remove(guid);
-        return texture;
+        PreviewTextures.TryGetValue(id, out List<PreviewRenderRequest> requests);
+        PreviewTextures.Remove(id);
+        return requests;
     }
     }
 
 
     public static DrawingApiBlendMode GetDrawingBlendMode(BlendMode blendMode)
     public static DrawingApiBlendMode GetDrawingBlendMode(BlendMode blendMode)

+ 2 - 1
src/PixiEditor/Models/DocumentModels/ActionAccumulator.cs

@@ -7,6 +7,7 @@ using PixiEditor.ChangeableDocument.Actions.Generated;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.Actions.Undo;
 using PixiEditor.ChangeableDocument.ChangeInfos;
 using PixiEditor.ChangeableDocument.ChangeInfos;
 using Drawie.Backend.Core.Bridge;
 using Drawie.Backend.Core.Bridge;
+using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.Extensions.CommonApi.UserPreferences.Settings.PixiEditor;
 using PixiEditor.Extensions.CommonApi.UserPreferences.Settings.PixiEditor;
 using PixiEditor.Helpers;
 using PixiEditor.Helpers;
 using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.Models.DocumentPassthroughActions;
@@ -141,7 +142,7 @@ internal class ActionAccumulator
                 bool updateDelayed = undoBoundaryPassed || viewportRefreshRequest || changeFrameRequest ||
                 bool updateDelayed = undoBoundaryPassed || viewportRefreshRequest || changeFrameRequest ||
                                      document.SizeBindable.LongestAxis <= LiveUpdatePerformanceThreshold;
                                      document.SizeBindable.LongestAxis <= LiveUpdatePerformanceThreshold;
 
 
-                Dictionary<Guid, Texture>? previewTextures = null;
+                Dictionary<Guid, List<PreviewRenderRequest>>? previewTextures = null;
 
 
                 if (!previewsDisabled)
                 if (!previewsDisabled)
                 {
                 {

+ 1 - 0
src/PixiEditor/Models/Rendering/AffectedAreasGatherer.cs

@@ -119,6 +119,7 @@ internal class AffectedAreasGatherer
                 case StructureMemberMask_ChangeInfo info:
                 case StructureMemberMask_ChangeInfo info:
                     AddWholeCanvasToMainImage();
                     AddWholeCanvasToMainImage();
                     AddWholeCanvasToImagePreviews(info.Id, true);
                     AddWholeCanvasToImagePreviews(info.Id, true);
+                    AddToMaskPreview(info.Id);
                     AddToNodePreviews(info.Id);
                     AddToNodePreviews(info.Id);
                     break;
                     break;
                 case StructureMemberBlendMode_ChangeInfo info:
                 case StructureMemberBlendMode_ChangeInfo info:

+ 20 - 27
src/PixiEditor/Models/Rendering/MemberPreviewUpdater.cs

@@ -30,7 +30,7 @@ internal class MemberPreviewUpdater
         AnimationKeyFramePreviewRenderer = new AnimationKeyFramePreviewRenderer(internals);
         AnimationKeyFramePreviewRenderer = new AnimationKeyFramePreviewRenderer(internals);
     }
     }
 
 
-    public Dictionary<Guid, Texture>? UpdatePreviews(HashSet<Guid> membersToUpdate,
+    public Dictionary<Guid, List<PreviewRenderRequest>> UpdatePreviews(HashSet<Guid> membersToUpdate,
         HashSet<Guid> masksToUpdate, HashSet<Guid> nodesToUpdate, HashSet<Guid> keyFramesToUpdate,
         HashSet<Guid> masksToUpdate, HashSet<Guid> nodesToUpdate, HashSet<Guid> keyFramesToUpdate,
         bool ignoreAnimationPreviews, bool renderMiniPreviews)
         bool ignoreAnimationPreviews, bool renderMiniPreviews)
     {
     {
@@ -48,16 +48,17 @@ internal class MemberPreviewUpdater
     /// </summary>
     /// </summary>
     /// <param name="members">Members that should be rendered</param>
     /// <param name="members">Members that should be rendered</param>
     /// <param name="masksToUpdate">Masks that should be rendered</param>
     /// <param name="masksToUpdate">Masks that should be rendered</param>
-    private Dictionary<Guid, Texture> UpdatePreviewPainters(HashSet<Guid> members, HashSet<Guid> masksToUpdate,
+    private Dictionary<Guid, List<PreviewRenderRequest>>? UpdatePreviewPainters(HashSet<Guid> members,
+        HashSet<Guid> masksToUpdate,
         HashSet<Guid> nodesToUpdate, HashSet<Guid> keyFramesToUpdate, bool ignoreAnimationPreviews,
         HashSet<Guid> nodesToUpdate, HashSet<Guid> keyFramesToUpdate, bool ignoreAnimationPreviews,
         bool renderLowPriorityPreviews)
         bool renderLowPriorityPreviews)
     {
     {
-        Dictionary<Guid, Texture> previewTextures = new();
+        Dictionary<Guid, List<PreviewRenderRequest>> previewTextures = new();
         //RenderWholeCanvasPreview(renderLowPriorityPreviews);
         //RenderWholeCanvasPreview(renderLowPriorityPreviews);
         if (renderLowPriorityPreviews)
         if (renderLowPriorityPreviews)
         {
         {
             RenderLayersPreview(members, previewTextures);
             RenderLayersPreview(members, previewTextures);
-            //RenderMaskPreviews(masksToUpdate);
+            RenderMaskPreviews(masksToUpdate, previewTextures);
         }
         }
 
 
         if (!ignoreAnimationPreviews)
         if (!ignoreAnimationPreviews)
@@ -102,7 +103,8 @@ internal class MemberPreviewUpdater
         painter.FrameTime = doc.AnimationHandler.ActiveFrameTime;
         painter.FrameTime = doc.AnimationHandler.ActiveFrameTime;
         painter.Repaint();
         painter.Repaint();
     }*/
     }*/
-    private void RenderLayersPreview(HashSet<Guid> memberGuids, Dictionary<Guid, Texture> previewTextures)
+    private void RenderLayersPreview(HashSet<Guid> memberGuids,
+        Dictionary<Guid, List<PreviewRenderRequest>> previewTextures)
     {
     {
         foreach (var node in doc.NodeGraphHandler.AllNodes)
         foreach (var node in doc.NodeGraphHandler.AllNodes)
         {
         {
@@ -114,13 +116,13 @@ internal class MemberPreviewUpdater
                 if (structureMemberHandler.Preview == null)
                 if (structureMemberHandler.Preview == null)
                 {
                 {
                     var member = internals.Tracker.Document.FindMember(node.Id);
                     var member = internals.Tracker.Document.FindMember(node.Id);
-                    if (member is not IPreviewRenderable previewRenderable)
-                        continue;
-
                     structureMemberHandler.Preview = Texture.ForDisplay(new VecI(30, 30));
                     structureMemberHandler.Preview = Texture.ForDisplay(new VecI(30, 30));
                 }
                 }
 
 
-                previewTextures[node.Id] = structureMemberHandler.Preview;
+                if (!previewTextures.ContainsKey(node.Id))
+                    previewTextures[node.Id] = new List<PreviewRenderRequest>();
+
+                previewTextures[node.Id].Add(new PreviewRenderRequest(structureMemberHandler.Preview));
             }
             }
         }
         }
     }
     }
@@ -206,7 +208,8 @@ internal class MemberPreviewUpdater
         }
         }
     }*/
     }*/
 
 
-    /*private void RenderMaskPreviews(HashSet<Guid> members)
+    private void RenderMaskPreviews(HashSet<Guid> members,
+        Dictionary<Guid, List<PreviewRenderRequest>> previewTextures)
     {
     {
         foreach (var node in doc.NodeGraphHandler.AllNodes)
         foreach (var node in doc.NodeGraphHandler.AllNodes)
         {
         {
@@ -219,28 +222,18 @@ internal class MemberPreviewUpdater
                 if (member is not IPreviewRenderable previewRenderable)
                 if (member is not IPreviewRenderable previewRenderable)
                     continue;
                     continue;
 
 
-                if (structureMemberHandler.MaskPreviewPainter == null)
-                {
-                    structureMemberHandler.MaskPreviewPainter = new PreviewPainter(
-                        renderer,
-                        previewRenderable,
-                        doc.AnimationHandler.ActiveFrameTime,
-                        doc.SizeBindable,
-                        internals.Tracker.Document.ProcessingColorSpace,
-                        nameof(StructureNode.EmbeddedMask));
-                }
-                else
+                if (structureMemberHandler.MaskPreview == null)
                 {
                 {
-                    structureMemberHandler.MaskPreviewPainter.FrameTime = doc.AnimationHandler.ActiveFrameTime;
-                    structureMemberHandler.MaskPreviewPainter.DocumentSize = doc.SizeBindable;
-                    structureMemberHandler.MaskPreviewPainter.ProcessingColorSpace =
-                        internals.Tracker.Document.ProcessingColorSpace;
+                    structureMemberHandler.MaskPreview = Texture.ForDisplay(new VecI(30, 30));
                 }
                 }
+                if (!previewTextures.ContainsKey(node.Id))
+                    previewTextures[node.Id] = new List<PreviewRenderRequest>();
 
 
-                structureMemberHandler.MaskPreviewPainter.Repaint();
+                previewTextures[node.Id].Add(new PreviewRenderRequest(structureMemberHandler.MaskPreview,
+                    nameof(StructureNode.EmbeddedMask)));
             }
             }
         }
         }
-    }*/
+    }
 
 
     /*private void RenderNodePreviews(HashSet<Guid> nodesGuids)
     /*private void RenderNodePreviews(HashSet<Guid> nodesGuids)
     {
     {

+ 10 - 5
src/PixiEditor/Models/Rendering/SceneRenderer.cs

@@ -44,7 +44,7 @@ internal class SceneRenderer : IDisposable
     }
     }
 
 
     public async Task RenderAsync(Dictionary<Guid, ViewportInfo> stateViewports, AffectedArea affectedArea,
     public async Task RenderAsync(Dictionary<Guid, ViewportInfo> stateViewports, AffectedArea affectedArea,
-        bool updateDelayed, Dictionary<Guid, Texture>? previewTextures)
+        bool updateDelayed, Dictionary<Guid, List<PreviewRenderRequest>>? previewTextures)
     {
     {
         await Dispatcher.UIThread.InvokeAsync(() =>
         await Dispatcher.UIThread.InvokeAsync(() =>
         {
         {
@@ -69,7 +69,7 @@ internal class SceneRenderer : IDisposable
         }, DispatcherPriority.Background);
         }, DispatcherPriority.Background);
     }
     }
 
 
-    public Texture? RenderScene(ViewportInfo viewport, AffectedArea affectedArea, Dictionary<Guid, Texture>? previewTextures = null)
+    public Texture? RenderScene(ViewportInfo viewport, AffectedArea affectedArea,Dictionary<Guid, List<PreviewRenderRequest>>? previewTextures = null)
     {
     {
         /*if (Document.Renderer.IsBusy || DocumentViewModel.Busy ||
         /*if (Document.Renderer.IsBusy || DocumentViewModel.Busy ||
             target.DeviceClipBounds.Size.ShortestAxis <= 0) return;*/
             target.DeviceClipBounds.Size.ShortestAxis <= 0) return;*/
@@ -94,7 +94,7 @@ internal class SceneRenderer : IDisposable
 
 
         IReadOnlyNodeGraph finalGraph = RenderingUtils.SolveFinalNodeGraph(targetOutput, Document);
         IReadOnlyNodeGraph finalGraph = RenderingUtils.SolveFinalNodeGraph(targetOutput, Document);
         bool shouldRerender =
         bool shouldRerender =
-            ShouldRerender(renderTargetSize, targetMatrix, resolution, viewportId, targetOutput, finalGraph);
+            ShouldRerender(renderTargetSize, targetMatrix, resolution, viewportId, targetOutput, finalGraph, previewTextures);
 
 
         if (shouldRerender)
         if (shouldRerender)
         {
         {
@@ -112,7 +112,7 @@ internal class SceneRenderer : IDisposable
         AffectedArea area,
         AffectedArea area,
         RectI? visibleDocumentRegion,
         RectI? visibleDocumentRegion,
         string? targetOutput,
         string? targetOutput,
-        IReadOnlyNodeGraph finalGraph, Dictionary<Guid, Texture>? previewTextures)
+        IReadOnlyNodeGraph finalGraph, Dictionary<Guid, List<PreviewRenderRequest>>? previewTextures)
     {
     {
         DrawingSurface renderTarget = null;
         DrawingSurface renderTarget = null;
         Texture? renderTexture = null;
         Texture? renderTexture = null;
@@ -184,7 +184,7 @@ internal class SceneRenderer : IDisposable
     private bool ShouldRerender(VecI targetSize, Matrix3X3 matrix, ChunkResolution resolution,
     private bool ShouldRerender(VecI targetSize, Matrix3X3 matrix, ChunkResolution resolution,
         Guid viewportId,
         Guid viewportId,
         string targetOutput,
         string targetOutput,
-        IReadOnlyNodeGraph finalGraph)
+        IReadOnlyNodeGraph finalGraph, Dictionary<Guid, List<PreviewRenderRequest>>? previewTextures)
     {
     {
         if (!DocumentViewModel.SceneTextures.TryGetValue(viewportId, out var cachedTexture) || cachedTexture == null ||
         if (!DocumentViewModel.SceneTextures.TryGetValue(viewportId, out var cachedTexture) || cachedTexture == null ||
             cachedTexture.IsDisposed)
             cachedTexture.IsDisposed)
@@ -192,6 +192,11 @@ internal class SceneRenderer : IDisposable
             return true;
             return true;
         }
         }
 
 
+        if(previewTextures is { Count: > 0 })
+        {
+            return true;
+        }
+
         if (lastResolution != resolution)
         if (lastResolution != resolution)
         {
         {
             lastResolution = resolution;
             lastResolution = resolution;

+ 3 - 1
src/PixiEditor/Views/Rendering/Scene.cs

@@ -353,7 +353,9 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
             int saved = -1;
             int saved = -1;
 
 
             var matrix = CalculateTransformMatrix().ToSKMatrix().ToMatrix3X3();
             var matrix = CalculateTransformMatrix().ToSKMatrix().ToMatrix3X3();
-            var cachedTexture = Document.SceneTextures[ViewportId];
+            if(!Document.SceneTextures.TryGetValue(ViewportId, out var cachedTexture))
+                return;
+
             Matrix3X3 matrixDiff = SolveMatrixDiff(matrix, cachedTexture);
             Matrix3X3 matrixDiff = SolveMatrixDiff(matrix, cachedTexture);
             var target = cachedTexture.DrawingSurface;
             var target = cachedTexture.DrawingSurface;