Browse Source

Changed Evaluator to be normal class

flabbet 1 year ago
parent
commit
6012ea7443

+ 2 - 0
src/PixiEditor.AvaloniaUI/Models/Handlers/IDocument.cs

@@ -6,6 +6,7 @@ using PixiEditor.AvaloniaUI.Helpers;
 using PixiEditor.AvaloniaUI.Models.DocumentModels.Public;
 using PixiEditor.AvaloniaUI.Models.Structures;
 using PixiEditor.AvaloniaUI.Models.Tools;
+using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core.ColorsImpl;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface;
@@ -40,6 +41,7 @@ internal interface IDocument : IHandler
     public double HorizontalSymmetryAxisYBindable { get; }
     public double VerticalSymmetryAxisXBindable { get; }
     public IDocumentOperations Operations { get; }
+    public DocumentEvaluator Renderer { get; }
     public void RemoveSoftSelectedMember(IStructureMemberHandler member);
     public void ClearSoftSelectedMembers();
     public void AddSoftSelectedMember(IStructureMemberHandler member);

+ 1 - 1
src/PixiEditor.AvaloniaUI/Models/Rendering/CanvasUpdater.cs

@@ -195,7 +195,7 @@ internal class CanvasUpdater
             screenSurface.DrawingSurface.Canvas.ClipRect((RectD)globalScaledClippingRectangle);
         }
 
-        DocumentEvaluator.RenderChunk(chunkPos, resolution, internals.Tracker.Document.NodeGraph, doc.AnimationHandler.ActiveFrameBindable, globalClippingRectangle).Switch(
+        doc.Renderer.RenderChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameBindable, globalClippingRectangle).Switch(
             (Chunk chunk) =>
             {
                 screenSurface.DrawingSurface.Canvas.DrawSurface(chunk.Surface.DrawingSurface, chunkPos.Multiply(chunk.PixelSize), ReplacingPaint);

+ 2 - 3
src/PixiEditor.AvaloniaUI/Models/Rendering/MemberPreviewUpdater.cs

@@ -438,8 +438,7 @@ internal class MemberPreviewUpdater
                 _ => ChunkResolution.Eighth,
             };
             var pos = chunkPos * resolution.PixelSize();
-            var rendered = DocumentEvaluator.RenderChunk(chunkPos, resolution,
-                internals.Tracker.Document.NodeGraph, doc.AnimationHandler.ActiveFrameBindable);
+            var rendered = doc.Renderer.RenderChunk(chunkPos, resolution, doc.AnimationHandler.ActiveFrameBindable);
             doc.PreviewSurface.DrawingSurface.Canvas.Save();
             doc.PreviewSurface.DrawingSurface.Canvas.Scale(scaling);
             doc.PreviewSurface.DrawingSurface.Canvas.ClipRect((RectD)cumulative.GlobalArea);
@@ -551,7 +550,7 @@ internal class MemberPreviewUpdater
             var pos = chunk * ChunkResolution.Full.PixelSize();
             // drawing in full res here is kinda slow
             // we could switch to a lower resolution based on (canvas size / preview size) to make it run faster
-            OneOf<Chunk, EmptyChunk> rendered = DocumentEvaluator.RenderChunk(chunk, ChunkResolution.Full, folder,
+            OneOf<Chunk, EmptyChunk> rendered = doc.Renderer.RenderChunk(chunk, ChunkResolution.Full, folder,
                 doc.AnimationHandler.ActiveFrameBindable);
             if (rendered.IsT0)
             {

+ 4 - 2
src/PixiEditor.AvaloniaUI/ViewModels/Document/DocumentViewModel.cs

@@ -151,6 +151,7 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
     public DocumentStructureModule StructureHelper { get; }
     public DocumentToolsModule Tools { get; }
     public DocumentOperationsModule Operations { get; }
+    public DocumentEvaluator Renderer { get; }
     public DocumentEventsModule EventInlet { get; }
 
     public ActionDisplayList ActionDisplays { get; } =
@@ -231,6 +232,8 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
         PreviewSurface = new Surface(new VecI(previewSize.X, previewSize.Y));
 
         ReferenceLayerViewModel = new(this, Internals);
+
+        Renderer = new DocumentEvaluator(Internals.Tracker.Document);
     }
 
     /// <summary>
@@ -559,8 +562,7 @@ internal partial class DocumentViewModel : PixiObservableObject, IDocument
             if (scope == DocumentScope.AllLayers)
             {
                 VecI chunkPos = OperationHelper.GetChunkPos(pos, ChunkyImage.FullChunkSize);
-                return DocumentEvaluator.RenderChunk(chunkPos, ChunkResolution.Full,
-                        Internals.Tracker.Document.NodeGraph,
+                return Renderer.RenderChunk(chunkPos, ChunkResolution.Full,
                         frame)
                     .Match(
                         chunk =>

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Document.cs

@@ -100,7 +100,7 @@ internal class Document : IChangeable, IReadOnlyDocument, IDisposable
         }
         else
         {
-            image = new Surface(layer.Execute(new RenderingContext(frame)));
+            image = new Surface(layer.Execute(new RenderingContext(frame, Size)));
         }
         
         //todo: idk if it's correct

+ 16 - 38
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/ImageLayerNode.cs

@@ -67,9 +67,9 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
     private Surface RenderImage(ChunkyImage frameImage, RenderingContext context)
     {
-        ChunkResolution targetResolution = context.Resolution ?? ChunkResolution.Full;
+        ChunkResolution targetResolution = context.ChunkResolution;
         bool hasSurface = workingSurfaces.TryGetValue(targetResolution, out Surface workingSurface);
-        VecI targetSize = (VecI)(frameImage.LatestSize * context.Resolution!.Value.Multiplier());
+        VecI targetSize = (VecI)(frameImage.LatestSize * targetResolution.Multiplier());
 
         if (Background.Value != null)
         {
@@ -91,21 +91,12 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
 
     private void DrawLayer(ChunkyImage frameImage, RenderingContext context, Surface workingSurface)
     {
-        if (context.ChunkToUpdate == null)
-        {
-            frameImage.DrawMostUpToDateRegionOn(
-                new RectI(0, 0, frameImage.LatestSize.X, frameImage.LatestSize.Y),
-                ChunkResolution.Full, workingSurface.DrawingSurface, VecI.Zero, blendPaint);
-        }
-        else
-        {
-            frameImage.DrawMostUpToDateChunkOn(
-                context.ChunkToUpdate.Value,
-                context.Resolution.Value,
+       frameImage.DrawMostUpToDateChunkOn(
+                context.ChunkToUpdate,
+                context.ChunkResolution,
                 workingSurface.DrawingSurface,
-                context.ChunkToUpdate.Value * context.Resolution.Value.PixelSize(),
+                context.ChunkToUpdate * context.ChunkResolution.PixelSize(),
                 blendPaint);
-        }
     }
 
     private bool IsEmptyMask()
@@ -118,12 +109,9 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
         if (ClipToPreviousMember.Value)
         {
             RectI? clippingRect = null;
-            if (context.Resolution.HasValue && context.ChunkToUpdate.HasValue)
-            {
-                VecI chunkStart = context.ChunkToUpdate.Value * context.Resolution.Value.PixelSize();
-                VecI size = new VecI(context.Resolution.Value.PixelSize());
-                clippingRect = new RectI(chunkStart, size);
-            }
+            VecI chunkStart = context.ChunkToUpdate * context.ChunkResolution.PixelSize();
+            VecI size = new VecI(context.ChunkResolution.PixelSize());
+            clippingRect = new RectI(chunkStart, size);
 
             OperationHelper.ClampAlpha(surface.DrawingSurface, Background.Value, clippingRect);
         }
@@ -140,35 +128,25 @@ public class ImageLayerNode : LayerNode, IReadOnlyImageNode
     {
         if (Mask.Value != null && MaskIsVisible.Value)
         {
-            ChunkyImage mask = Mask.Value;
-            if (context.Resolution.HasValue && context.ChunkToUpdate.HasValue)
-            {
-                mask.DrawMostUpToDateChunkOn(
-                    context.ChunkToUpdate.Value,
-                    context.Resolution.Value,
+            Mask.Value.DrawMostUpToDateChunkOn(
+                    context.ChunkToUpdate,
+                    context.ChunkResolution,
                     surface.DrawingSurface,
-                    context.ChunkToUpdate.Value * context.Resolution.Value.PixelSize(),
+                    context.ChunkToUpdate * context.ChunkResolution.PixelSize(),
                     maskPaint);
-            }
-            else
-            {
-                mask.DrawMostUpToDateRegionOn(
-                    new RectI(0, 0, mask.LatestSize.X, mask.LatestSize.Y),
-                    ChunkResolution.Full, surface.DrawingSurface, VecI.Zero, maskPaint);
-            }
         }
     }
 
     private RectD CalculateSourceRect(Surface image, VecI targetSize, RenderingContext context)
     {
-        if (context.Resolution == null || context.ChunkToUpdate == null)
+        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.Resolution.Value.PixelSize();
-        VecI chunkPos = context.ChunkToUpdate.Value;
+        int chunkSize = context.ChunkResolution.PixelSize();
+        VecI chunkPos = context.ChunkToUpdate;
 
         int x = (int)(chunkPos.X * chunkSize * multiplierToFit);
         int y = (int)(chunkPos.Y * chunkSize * multiplierToFit);

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

@@ -63,7 +63,7 @@ public abstract class Node : IReadOnlyNode, IDisposable
     protected virtual bool CacheChanged(RenderingContext context)
     {
         return (!context.FrameTime.Equals(_lastFrameTime) && AffectedByAnimation)
-               || (context.Resolution != _lastResolution && AffectedByChunkResolution)
+               || (context.ChunkResolution != _lastResolution && AffectedByChunkResolution)
                || (context.ChunkToUpdate != _lastChunkPos && AffectedByChunkToUpdate)
                || inputs.Any(x => x.CacheChanged);
     }
@@ -76,7 +76,7 @@ public abstract class Node : IReadOnlyNode, IDisposable
         }
         
         _lastFrameTime = context.FrameTime;
-        _lastResolution = context.Resolution;
+        _lastResolution = context.ChunkResolution;
         _lastChunkPos = context.ChunkToUpdate;
     }
 

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyDocument.cs

@@ -1,6 +1,7 @@
 using System.Diagnostics.CodeAnalysis;
 using PixiEditor.ChangeableDocument.Changeables.Graph;
 using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
+using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core.Numerics;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.Numerics;
@@ -45,7 +46,7 @@ public interface IReadOnlyDocument
     /// The position of the vertical symmetry axis (Mirrors left and right)
     /// </summary>
     double VerticalSymmetryAxisX { get; }
-
+    
     /// <summary>
     /// Performs the specified action on each readonly member of the document
     /// </summary>

+ 14 - 7
src/PixiEditor.ChangeableDocument/Rendering/DocumentEvaluator.cs

@@ -1,20 +1,27 @@
 using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
+using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.DrawingApi.Core.Surface.ImageData;
 using PixiEditor.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Rendering;
 
-public static class DocumentEvaluator
+public class DocumentEvaluator
 {
-    public static OneOf<Chunk, EmptyChunk> RenderChunk(VecI chunkPos, ChunkResolution resolution,
-        IReadOnlyNodeGraph graph, int frame, RectI? globalClippingRect = null)
+    public DocumentEvaluator(IReadOnlyDocument document)
     {
-        using RenderingContext context = new(frame, chunkPos, resolution);
+        Document = document;
+    }
+
+    private IReadOnlyDocument Document { get; }
+    
+    public OneOf<Chunk, EmptyChunk> RenderChunk(VecI chunkPos, ChunkResolution resolution, int frame, RectI? globalClippingRect = null)
+    {
+        using RenderingContext context = new(frame, chunkPos, resolution, Document.Size);
         try
         {
             RectI? transformedClippingRect = TransformClipRect(globalClippingRect, resolution, chunkPos);
 
-            Surface? evaluated = graph.Execute(context);
+            Surface? evaluated = Document.NodeGraph.Execute(context);
             if (evaluated is null)
             {
                 return new EmptyChunk();
@@ -52,10 +59,10 @@ public static class DocumentEvaluator
         }
     }
 
-    public static OneOf<Chunk, EmptyChunk> RenderChunk(VecI chunkPos, ChunkResolution resolution,
+    public OneOf<Chunk, EmptyChunk> RenderChunk(VecI chunkPos, ChunkResolution resolution,
         IReadOnlyNode node, int frame, RectI? globalClippingRect = null)
     {
-        using RenderingContext context = new(frame, chunkPos, resolution);
+        using RenderingContext context = new(frame, chunkPos, resolution, Document.Size);
         try
         {
             RectI? transformedClippingRect = TransformClipRect(globalClippingRect, resolution, chunkPos);

+ 13 - 5
src/PixiEditor.ChangeableDocument/Rendering/RenderingContext.cs

@@ -16,19 +16,27 @@ public class RenderingContext : IDisposable
     public Paint ReplacingPaintWithOpacity = new () { BlendMode = DrawingApiBlendMode.Src };
 
     public KeyFrameTime FrameTime { get; }
-    public VecI? ChunkToUpdate { get; }
-    public ChunkResolution? Resolution { get; }
+    public VecI ChunkToUpdate { get; }
+    public ChunkResolution ChunkResolution { get; }
+    
+    /// <summary>
+    ///     This surface is unique to each rendering context and is used to draw on to avoid leaking
+    /// internal node surfaces and cloning them. It is disposed after rendering.
+    /// </summary>
+    public Surface WorkingSurface { get; }
 
-    public RenderingContext(KeyFrameTime frameTime)
+    public RenderingContext(KeyFrameTime frameTime, VecI docSize)
     {
         FrameTime = frameTime;
+        WorkingSurface = new Surface(docSize);
     }
     
-    public RenderingContext(KeyFrameTime frameTime, VecI chunkToUpdate, ChunkResolution resolution)
+    public RenderingContext(KeyFrameTime frameTime, VecI chunkToUpdate, ChunkResolution chunkResolution, VecI docSize)
     {
         FrameTime = frameTime;
         ChunkToUpdate = chunkToUpdate;
-        Resolution = resolution;
+        ChunkResolution = chunkResolution;
+        WorkingSurface = new Surface(docSize);
     }
 
     public static DrawingApiBlendMode GetDrawingBlendMode(BlendMode blendMode)