Browse Source

Implemented partial resolution rendering to graph

Krzysztof Krysiński 2 months ago
parent
commit
e8201aa070

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

@@ -56,7 +56,7 @@ public class CreateImageNode : Node, IPreviewRenderable
 
     private Texture Render(RenderContext context)
     {
-        var surface = textureCache.RequestTexture(0, Size.Value, context.ProcessingColorSpace, false);
+        var surface = textureCache.RequestTexture(0, (VecI)(Size.Value * context.ChunkResolution.Multiplier()), context.ProcessingColorSpace, false);
 
         if (Fill.Value is ColorPaintable colorPaintable)
         {
@@ -76,6 +76,8 @@ public class CreateImageNode : Node, IPreviewRenderable
 
         surface.DrawingSurface.Canvas.SetMatrix(surface.DrawingSurface.Canvas.TotalMatrix.Concat(ContentMatrix.Value));
 
+        surface.DrawingSurface.Canvas.Scale((float)context.ChunkResolution.Multiplier());
+
         Content.Value?.Paint(ctx, surface.DrawingSurface);
 
         surface.DrawingSurface.Canvas.RestoreToCount(saved);
@@ -85,8 +87,12 @@ public class CreateImageNode : Node, IPreviewRenderable
     private void OnPaint(RenderContext context, DrawingSurface surface)
     {
         if(Output.Value == null || Output.Value.IsDisposed) return;
-        
+
+        int saved = surface.Canvas.Save();
+        surface.Canvas.Scale((float)context.ChunkResolution.InvertedMultiplier());
         surface.Canvas.DrawSurface(Output.Value.DrawingSurface, 0, 0);
+
+        surface.Canvas.RestoreToCount(saved);
     }
 
     public override Node CreateCopy() => new CreateImageNode();

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

@@ -25,8 +25,10 @@ public class DocumentInfoNode : Node
         Size.Value = context.DocumentSize;
         Center.Value = new VecD(context.DocumentSize.X / 2.0, context.DocumentSize.Y / 2.0);
 
-        RenderOutputSize.Value = context.RenderOutputSize;
-        RenderOutputCenter.Value = new VecI(context.RenderOutputSize.X / 2, context.RenderOutputSize.Y / 2);
+        var resolutionMultiplier = context.ChunkResolution.InvertedMultiplier();
+        VecI renderOutputSize = (VecI)(context.RenderOutputSize * resolutionMultiplier);
+        RenderOutputSize.Value = renderOutputSize;
+        RenderOutputCenter.Value = new VecI(renderOutputSize.X / 2, renderOutputSize.Y / 2);
     }
 
     public override Node CreateCopy()

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

@@ -75,8 +75,9 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
 
         var adjustedResolution = AllowHighDpiRendering ? ChunkResolution.Full : context.ChunkResolution;
 
+        // Full because scene already handles texture resolution
         var outputWorkingSurface =
-            TryInitWorkingSurface(size, adjustedResolution, context.ProcessingColorSpace, 1);
+            TryInitWorkingSurface(size, ChunkResolution.Full, context.ProcessingColorSpace, 1);
         outputWorkingSurface.DrawingSurface.Canvas.Clear();
         outputWorkingSurface.DrawingSurface.Canvas.Save();
         if (AllowHighDpiRendering)

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

@@ -33,6 +33,8 @@ public class ModifyImageRightNode : RenderNode, IPairNode, ICustomShaderNode
     {
         Coordinate = CreateFuncInput(nameof(Coordinate), "UV", new Float2("coords"));
         Color = CreateFuncInput(nameof(Color), "COLOR", new Half4(""));
+
+        RendersInAbsoluteCoordinates = true;
     }
 
     protected override void OnPaint(RenderContext renderContext, DrawingSurface targetSurface)

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

@@ -45,6 +45,8 @@ public abstract class Node : IReadOnlyNode, IDisposable
 
     private KeyFrameTime lastFrameTime;
 
+    private VecI lastRenderSize = new VecI(0, 0);
+
     protected internal bool IsDisposed => _isDisposed;
     private bool _isDisposed;
 
@@ -81,7 +83,7 @@ public abstract class Node : IReadOnlyNode, IDisposable
 
     protected virtual bool CacheChanged(RenderContext context)
     {
-        bool changed = false;
+        bool changed = lastRenderSize != context.RenderOutputSize;
 
         if (CacheTrigger.HasFlag(CacheTriggerFlags.Inputs))
         {
@@ -110,6 +112,8 @@ public abstract class Node : IReadOnlyNode, IDisposable
 
         lastFrameTime = context.FrameTime;
 
+        lastRenderSize = context.RenderOutputSize;
+
         lastContentCacheHash = GetContentCacheHash();
     }
 

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

@@ -32,13 +32,8 @@ public class OutputNode : Node, IRenderInput, IPreviewRenderable
     {
         if (!string.IsNullOrEmpty(context.TargetOutput)) return;
 
-        lastDocumentSize = context.RenderOutputSize;
-
-        int saved = context.RenderSurface.Canvas.Save();
-        context.RenderSurface.Canvas.ClipRect(new RectD(0, 0, context.RenderOutputSize.X, context.RenderOutputSize.Y));
         Input.Value?.Paint(context, context.RenderSurface);
-
-        context.RenderSurface.Canvas.RestoreToCount(saved);
+        lastDocumentSize = context.DocumentSize;
     }
 
     RenderInputProperty IRenderInput.Background => Input;

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

@@ -17,6 +17,8 @@ public abstract class RenderNode : Node, IPreviewRenderable, IHighDpiRenderNode
 
     public bool AllowHighDpiRendering { get; set; } = false;
 
+    public bool RendersInAbsoluteCoordinates { get; set; } = false;
+
     private TextureCache textureCache = new();
 
     private VecI lastDocumentSize = VecI.Zero;
@@ -39,7 +41,7 @@ public abstract class RenderNode : Node, IPreviewRenderable, IHighDpiRenderNode
             }
         }
 
-        lastDocumentSize = context.RenderOutputSize;
+        lastDocumentSize = context.DocumentSize;
     }
 
     protected virtual void Paint(RenderContext context, DrawingSurface surface)
@@ -47,7 +49,7 @@ public abstract class RenderNode : Node, IPreviewRenderable, IHighDpiRenderNode
         DrawingSurface target = surface;
         bool useIntermediate = !AllowHighDpiRendering
                                && context.RenderOutputSize is { X: > 0, Y: > 0 }
-                               && surface.DeviceClipBounds.Size != context.RenderOutputSize;
+                               && (surface.DeviceClipBounds.Size != context.RenderOutputSize || (RendersInAbsoluteCoordinates && !surface.Canvas.TotalMatrix.IsIdentity));
         if (useIntermediate)
         {
             Texture intermediate = textureCache.RequestTexture(-6451, context.RenderOutputSize, context.ProcessingColorSpace);
@@ -58,7 +60,18 @@ public abstract class RenderNode : Node, IPreviewRenderable, IHighDpiRenderNode
 
         if (useIntermediate)
         {
+            if (RendersInAbsoluteCoordinates)
+            {
+                surface.Canvas.Save();
+                surface.Canvas.Scale((float)context.ChunkResolution.InvertedMultiplier());
+            }
+
             surface.Canvas.DrawSurface(target, 0, 0);
+
+            if (RendersInAbsoluteCoordinates)
+            {
+                surface.Canvas.Restore();
+            }
         }
     }
 

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

@@ -42,14 +42,14 @@ public class ShaderNode : RenderNode, IRenderInput, ICustomShaderNode
 
         paint = new Paint();
         Output.FirstInChain = null;
+
+        RendersInAbsoluteCoordinates = true;
     }
 
     protected override void OnExecute(RenderContext context)
     {
         base.OnExecute(context);
 
-        lastDocumentSize = context.RenderOutputSize;
-
         if (lastShaderCode != ShaderCode.Value)
         {
             GenerateShader(context);
@@ -60,6 +60,7 @@ public class ShaderNode : RenderNode, IRenderInput, ICustomShaderNode
             shader = shader.WithUpdatedUniforms(uniforms);
         }
 
+        lastDocumentSize = context.DocumentSize;
         paint.Shader = shader;
     }
 

+ 2 - 11
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Workspace/CustomOutputNode.cs

@@ -41,24 +41,15 @@ public class CustomOutputNode : Node, IRenderInput, IPreviewRenderable
         {
             VecI targetSize = Size.Value.ShortestAxis <= 0
                 ? context.RenderOutputSize
-                : Size.Value;
+                : (VecI)(Size.Value * context.ChunkResolution.Multiplier());
 
             lastDocumentSize = targetSize;
 
             DrawingSurface targetSurface = context.RenderSurface;
 
-            if(context.RenderOutputSize != targetSize)
-            {
-                targetSurface = textureCache.RequestTexture(0, targetSize, context.ProcessingColorSpace).DrawingSurface;
-            }
-
             int saved = targetSurface.Canvas.Save();
-            targetSurface.Canvas.ClipRect(new RectD(0, 0, targetSize.X, targetSize.Y));
-
-            RenderContext outputContext = new RenderContext(context.RenderSurface, context.FrameTime, context.ChunkResolution,
-                targetSize, context.DocumentSize, context.ProcessingColorSpace, context.Opacity) { TargetOutput = OutputName.Value, };
 
-            Input.Value?.Paint(outputContext, targetSurface);
+            Input.Value?.Paint(context, targetSurface);
 
             targetSurface.Canvas.RestoreToCount(saved);
 

+ 13 - 9
src/PixiEditor/Models/Rendering/SceneRenderer.cs

@@ -69,13 +69,20 @@ internal class SceneRenderer : IDisposable
     {
         DrawingSurface renderTarget = target;
         Texture? renderTexture = null;
-        bool restoreCanvas = false;
+        int restoreCanvasTo;
 
         VecI finalSize = SolveRenderOutputSize(targetOutput, finalGraph, Document.Size);
         if (RenderInOutputSize(finalGraph))
         {
+            finalSize = (VecI)(finalSize * resolution.Multiplier());
+
             renderTexture = Texture.ForProcessing(finalSize, Document.ProcessingColorSpace);
             renderTarget = renderTexture.DrawingSurface;
+            renderTexture.DrawingSurface.Canvas.Save();
+            renderTexture.DrawingSurface.Canvas.Scale((float)resolution.Multiplier());
+
+            restoreCanvasTo = target.Canvas.Save();
+            target.Canvas.Scale((float)resolution.InvertedMultiplier());
         }
         else
         {
@@ -83,12 +90,13 @@ internal class SceneRenderer : IDisposable
 
             renderTarget = renderTexture.DrawingSurface;
 
-            target.Canvas.Save();
+            restoreCanvasTo = target.Canvas.Save();
             renderTarget.Canvas.Save();
 
             renderTarget.Canvas.SetMatrix(target.Canvas.TotalMatrix);
             target.Canvas.SetMatrix(Matrix3X3.Identity);
-            restoreCanvas = true;
+            renderTarget.Canvas.ClipRect(new RectD(0, 0, finalSize.X, finalSize.Y));
+            resolution = ChunkResolution.Full;
         }
 
         RenderContext context = new(renderTarget, DocumentViewModel.AnimationHandler.ActiveFrameTime,
@@ -99,11 +107,7 @@ internal class SceneRenderer : IDisposable
         if (renderTexture != null)
         {
             target.Canvas.DrawSurface(renderTexture.DrawingSurface, 0, 0);
-
-            if (restoreCanvas)
-            {
-                target.Canvas.Restore();
-            }
+            target.Canvas.RestoreToCount(restoreCanvasTo);
         }
 
         return renderTexture;
@@ -160,7 +164,7 @@ internal class SceneRenderer : IDisposable
         }
 
         bool renderInDocumentSize = RenderInOutputSize(finalGraph);
-        VecI compareSize = renderInDocumentSize ? Document.Size : target.DeviceClipBounds.Size;
+        VecI compareSize = renderInDocumentSize ? (VecI)(Document.Size * resolution.Multiplier()) : target.DeviceClipBounds.Size;
 
         if (cachedTexture.DrawingSurface.DeviceClipBounds.Size != compareSize)
         {