2
0
Эх сурвалжийг харах

Once again fixed rendering for layer (prob not last time)

flabbet 1 жил өмнө
parent
commit
46939ffa25

+ 3 - 0
src/PixiEditor.AvaloniaUI/Models/Rendering/CanvasUpdater.cs

@@ -189,6 +189,9 @@ internal class CanvasUpdater
 
     private void RenderChunk(VecI chunkPos, Surface screenSurface, ChunkResolution resolution, RectI? globalClippingRectangle, RectI? globalScaledClippingRectangle)
     {
+        if(screenSurface is null || screenSurface.IsDisposed)
+            return;
+        
         if (globalScaledClippingRectangle is not null)
         {
             screenSurface.DrawingSurface.Canvas.Save();

+ 5 - 7
src/PixiEditor.AvaloniaUI/Models/Rendering/MemberPreviewUpdater.cs

@@ -703,17 +703,15 @@ internal class MemberPreviewUpdater
                     new Surface(StructureHelpers.CalculatePreviewSize(internals.Tracker.Document.Size));
             }
 
-            float scalingX = (float)nodeVm.ResultPreview.Size.X / node.CachedResult.LatestSize.X;
-            float scalingY = (float)nodeVm.ResultPreview.Size.Y / node.CachedResult.LatestSize.Y;
+            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);
 
-            RectI region = new RectI(0, 0, node.CachedResult.LatestSize.X, node.CachedResult.LatestSize.Y);
-            
-            node.CachedResult.DrawMostUpToDateRegionOn(region, ChunkResolution.Full, nodeVm.ResultPreview.DrawingSurface,
-                VecI.Zero,
-                scalingX < smoothingThreshold ? SmoothReplacingPaint : ReplacingPaint);
+            RectI region = new RectI(0, 0, node.CachedResult.Size.X, node.CachedResult.Size.Y);
+           
+            nodeVm.ResultPreview.DrawingSurface.Canvas.DrawSurface(node.CachedResult.DrawingSurface, 0, 0, ReplacingPaint);
 
             nodeVm.ResultPreview.DrawingSurface.Canvas.Restore();
             infos.Add(new NodePreviewDirty_RenderInfo(node.Id));

+ 9 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/NodeGraph.cs

@@ -108,7 +108,15 @@ public class NodeGraph : IReadOnlyNodeGraph, IDisposable
             var node = queue.Dequeue();
             
             stopwatch.Restart();
-            node.Execute(context);
+            if (node is Node typedNode)
+            {
+                typedNode.ExecuteInternal(context);
+            }
+            else
+            {
+                node.Execute(context);
+            }
+            
             Console.WriteLine($"{node.GetType().Name} took {stopwatch.ElapsedMilliseconds}ms to execute");
         }
 

+ 69 - 30
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -71,32 +71,63 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         bool hasSurface = workingSurfaces.TryGetValue(targetResolution, out Surface workingSurface);
         VecI targetSize = (VecI)(frameImage.LatestSize * targetResolution.Multiplier());
 
-        if (Background.Value != null)
-        {
-            workingSurface = Background.Value;
-            blendPaint.BlendMode = RenderingContext.GetDrawingBlendMode(BlendMode.Value);
-        }
-        else if (!hasSurface || workingSurface.Size != targetSize || workingSurface.IsDisposed)
+        if (!hasSurface || workingSurface.Size != targetSize || workingSurface.IsDisposed)
         {
             workingSurfaces[targetResolution] = new Surface(targetSize);
             workingSurface = workingSurfaces[targetResolution];
         }
 
-        DrawLayer(frameImage, context, workingSurface);
+        if (!HasOperations())
+        {
+            if (Background.Value != null)
+            {
+                DrawBackground(workingSurface, context);
+                blendPaint.BlendMode = RenderingContext.GetDrawingBlendMode(BlendMode.Value);
+            }
+            
+            DrawLayer(frameImage, context, workingSurface);
+            Output.Value = workingSurface;
+            return workingSurface;
+        }
 
+        DrawLayer(frameImage, context, workingSurface);
+        
+        // shit gets downhill with mask on big canvases, TODO: optimize
         ApplyMaskIfPresent(workingSurface, context);
         ApplyRasterClip(workingSurface, context);
+            
+        if (Background.Value != null)
+        {
+            Surface tempSurface = new Surface(workingSurface.Size);
+            DrawBackground(tempSurface, context);
+            blendPaint.BlendMode = RenderingContext.GetDrawingBlendMode(BlendMode.Value);
+            tempSurface.DrawingSurface.Canvas.DrawSurface(workingSurface.DrawingSurface, 0, 0, blendPaint);
+            
+            Output.Value = tempSurface;
+            return tempSurface;
+        }
+            
+        Output.Value = workingSurface;
         return workingSurface;
     }
 
+    private void DrawBackground(Surface workingSurface, RenderingContext context)
+    {
+        RectI source = CalculateSourceRect(Background.Value, workingSurface.Size, context);
+        RectI target = CalculateDestinationRect(context);
+        using var snapshot = Background.Value.DrawingSurface.Snapshot(source);
+        
+        workingSurface.DrawingSurface.Canvas.DrawImage(snapshot, target.X, target.Y, blendPaint);
+    }
+
     private void DrawLayer(ChunkyImage frameImage, RenderingContext context, Surface workingSurface)
     {
-       frameImage.DrawMostUpToDateChunkOn(
-                context.ChunkToUpdate,
-                context.ChunkResolution,
-                workingSurface.DrawingSurface,
-                context.ChunkToUpdate * context.ChunkResolution.PixelSize(),
-                blendPaint);
+        frameImage.DrawMostUpToDateChunkOn(
+            context.ChunkToUpdate,
+            context.ChunkResolution,
+            workingSurface.DrawingSurface,
+            context.ChunkToUpdate * context.ChunkResolution.PixelSize(),
+            blendPaint);
     }
 
     private bool IsEmptyMask()
@@ -104,6 +135,11 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         return Mask.Value != null && MaskIsVisible.Value && !Mask.Value.LatestOrCommittedChunkExists();
     }
 
+    private bool HasOperations()
+    {
+        return (MaskIsVisible.Value && Mask.Value != null) || ClipToPreviousMember.Value;
+    }
+
     private void ApplyRasterClip(Surface surface, RenderingContext context)
     {
         if (ClipToPreviousMember.Value)
@@ -129,21 +165,16 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         if (Mask.Value != null && MaskIsVisible.Value)
         {
             Mask.Value.DrawMostUpToDateChunkOn(
-                    context.ChunkToUpdate,
-                    context.ChunkResolution,
-                    surface.DrawingSurface,
-                    context.ChunkToUpdate * context.ChunkResolution.PixelSize(),
-                    maskPaint);
+                context.ChunkToUpdate,
+                context.ChunkResolution,
+                surface.DrawingSurface,
+                context.ChunkToUpdate * context.ChunkResolution.PixelSize(),
+                maskPaint);
         }
     }
 
-    private RectD CalculateSourceRect(Surface image, VecI targetSize, RenderingContext context)
+    private RectI CalculateSourceRect(Surface image, VecI targetSize, RenderingContext context)
     {
-        if (context.ChunkResolution == null || context.ChunkToUpdate == null)
-        {
-            return new RectD(0, 0, image.Size.X, image.Size.Y);
-        }
-
         float multiplierToFit = image.Size.X / (float)targetSize.X;
         int chunkSize = context.ChunkResolution.PixelSize();
         VecI chunkPos = context.ChunkToUpdate;
@@ -153,7 +184,20 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         int width = (int)(chunkSize * multiplierToFit);
         int height = (int)(chunkSize * multiplierToFit);
 
-        return new RectD(x, y, width, height);
+        return new RectI(x, y, width, height);
+    }
+    
+    private RectI CalculateDestinationRect(RenderingContext context)
+    {
+        int chunkSize = context.ChunkResolution.PixelSize();
+        VecI chunkPos = context.ChunkToUpdate;
+
+        int x = chunkPos.X * chunkSize;
+        int y = chunkPos.Y * chunkSize;
+        int width = chunkSize;
+        int height = chunkSize;
+
+        return new RectI(x, y, width, height);
     }
 
     protected override bool CacheChanged(RenderingContext context)
@@ -191,11 +235,6 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         };
     }
 
-    private VecI GetBiggerSize(VecI size1, VecI size2)
-    {
-        return new VecI(Math.Max(size1.X, size2.X), Math.Max(size1.Y, size2.Y));
-    }
-
     IReadOnlyChunkyImage IReadOnlyImageNode.GetLayerImageAtFrame(int frame) => GetLayerImageAtFrame(frame);
 
     IReadOnlyChunkyImage IReadOnlyImageNode.GetLayerImageByKeyFrameGuid(Guid keyFrameGuid) =>

+ 18 - 10
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Node.cs

@@ -24,18 +24,18 @@ public abstract class Node : IReadOnlyNode, IDisposable
     public Surface? CachedResult { get; private set; }
 
     public virtual string InternalName { get; }
-    
+
     protected virtual bool AffectedByAnimation { get; }
-    
+
     protected virtual bool AffectedByChunkResolution { get; }
 
     protected virtual bool AffectedByChunkToUpdate { get; }
-    
+
     protected Node()
     {
         InternalName = $"PixiEditor.{GetType().Name}";
     }
-    
+
     IReadOnlyCollection<IInputProperty> IReadOnlyNode.InputProperties => inputs;
     IReadOnlyCollection<IOutputProperty> IReadOnlyNode.OutputProperties => outputs;
     public VecD Position { get; set; }
@@ -46,21 +46,29 @@ public abstract class Node : IReadOnlyNode, IDisposable
 
     public Surface? Execute(RenderingContext context)
     {
-        if(!CacheChanged(context)) return CachedResult;
-        
+        var result = ExecuteInternal(context);
+
+        var copy = new Surface(result);
+        return copy;
+    }
+
+    internal Surface ExecuteInternal(RenderingContext context)
+    {
+        if (!CacheChanged(context)) return CachedResult;
+
         CachedResult = OnExecute(context);
         if (CachedResult is { IsDisposed: true })
         {
             throw new ObjectDisposedException("Surface was disposed after execution.");
         }
-        
+
         UpdateCache(context);
         return CachedResult;
     }
 
     protected abstract Surface? OnExecute(RenderingContext context);
     public abstract bool Validate();
-    
+
     protected virtual bool CacheChanged(RenderingContext context)
     {
         return (!context.FrameTime.Equals(_lastFrameTime) && AffectedByAnimation)
@@ -68,14 +76,14 @@ public abstract class Node : IReadOnlyNode, IDisposable
                || (context.ChunkToUpdate != _lastChunkPos && AffectedByChunkToUpdate)
                || inputs.Any(x => x.CacheChanged);
     }
-    
+
     protected virtual void UpdateCache(RenderingContext context)
     {
         foreach (var input in inputs)
         {
             input.UpdateCache();
         }
-        
+
         _lastFrameTime = context.FrameTime;
         _lastResolution = context.ChunkResolution;
         _lastChunkPos = context.ChunkToUpdate;