Browse Source

Separate Channels node

flabbet 10 months ago
parent
commit
2b2e55f68b

+ 108 - 46
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/SeparateChannelsNode.cs

@@ -1,12 +1,15 @@
-using PixiEditor.ChangeableDocument.Rendering;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
+using PixiEditor.ChangeableDocument.Helpers;
+using PixiEditor.ChangeableDocument.Rendering;
 using PixiEditor.DrawingApi.Core;
+using PixiEditor.DrawingApi.Core.Surfaces;
 using PixiEditor.DrawingApi.Core.Surfaces.PaintImpl;
 using PixiEditor.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.CombineSeparate;
 
 [NodeInfo("SeparateChannels")]
-public class SeparateChannelsNode : Node
+public class SeparateChannelsNode : Node, IRenderInput, IPreviewRenderable
 {
     private readonly Paint _paint = new();
     
@@ -20,73 +23,132 @@ public class SeparateChannelsNode : Node
     private readonly ColorFilter _blueGrayscaleFilter = ColorFilter.CreateColorMatrix(ColorMatrix.UseBlue + ColorMatrix.MapBlueToRedGreen + ColorMatrix.OpaqueAlphaOffset);
     private readonly ColorFilter _alphaGrayscaleFilter = ColorFilter.CreateColorMatrix(ColorMatrix.MapAlphaToRedGreenBlue + ColorMatrix.OpaqueAlphaOffset);
 
-    public OutputProperty<Texture?> Red { get; }
+    public RenderOutputProperty Red { get; }
     
-    public OutputProperty<Texture?> Green { get; }
+    public RenderOutputProperty Green { get; }
     
-    public OutputProperty<Texture?> Blue { get; }
+    public RenderOutputProperty Blue { get; }
 
-    public OutputProperty<Texture?> Alpha { get; }
+    public RenderOutputProperty Alpha { get; }
     
-    public InputProperty<Texture?> Image { get; }
+    public RenderInputProperty Image { get; } 
     
     public InputProperty<bool> Grayscale { get; }
 
     public SeparateChannelsNode()
     {
-        Red = CreateOutput<Texture>(nameof(Red), "RED", null);
-        Green = CreateOutput<Texture>(nameof(Green), "GREEN", null);
-        Blue = CreateOutput<Texture>(nameof(Blue), "BLUE", null);
-        Alpha = CreateOutput<Texture>(nameof(Alpha), "ALPHA", null);
+        Red = CreateRenderOutput("Red", "RED", () => new Painter(PaintRed));
+        Green = CreateRenderOutput("Green","GREEN", () => new Painter(PaintGreen)); 
+        Blue = CreateRenderOutput("Blue", "BLUE", () => new Painter(PaintBlue));
+        Alpha = CreateRenderOutput("Alpha", "ALPHA", () => new Painter(PaintAlpha));
         
-        Image = CreateInput<Texture>(nameof(Image), "IMAGE", null);
+        Image = CreateRenderInput("Image", "IMAGE");
         Grayscale = CreateInput(nameof(Grayscale), "GRAYSCALE", false);
     }
     
-    protected override void OnExecute(RenderContext context)
+    private void PaintRed(RenderContext context, DrawingSurface drawingSurface)
+    {
+        Paint(context, drawingSurface, _redFilter, _redGrayscaleFilter);
+    }
+    
+    private void PaintGreen(RenderContext context, DrawingSurface drawingSurface)
     {
-        var image = Image.Value;
+        Paint(context, drawingSurface, _greenFilter, _greenGrayscaleFilter);
+    }
+    
+    private void PaintBlue(RenderContext context, DrawingSurface drawingSurface)
+    {
+        Paint(context, drawingSurface, _blueFilter, _blueGrayscaleFilter);
+    }
+    
+    private void PaintAlpha(RenderContext context, DrawingSurface drawingSurface)
+    {
+        Paint(context, drawingSurface, _alphaFilter, _alphaGrayscaleFilter);
+    }
 
-        if (image == null)
-            return;
+    private void Paint(RenderContext context, DrawingSurface drawingSurface, ColorFilter colorFilter, ColorFilter grayscaleFilter)
+    {
+        bool grayscale = Grayscale.Value;
         
-        var grayscale = Grayscale.Value;
-
-        var red = !grayscale ? _redFilter : _redGrayscaleFilter;
-        var green = !grayscale ? _greenFilter : _greenGrayscaleFilter;
-        var blue = !grayscale ? _blueFilter : _blueGrayscaleFilter;
-        var alpha = !grayscale ? _alphaFilter : _alphaGrayscaleFilter;
-
-        Red.Value = GetImage(image, red, 0);
-        Green.Value = GetImage(image, green, 1);
-        Blue.Value = GetImage(image, blue, 2);
-        Alpha.Value = GetImage(image, alpha, 3);
-
-        var previewSurface = RequestTexture(4, image.Size * 2);
-
-        var size = image.Size;
+        ColorFilter filter = grayscale ? grayscaleFilter : colorFilter; 
+        _paint.ColorFilter = filter;
         
-        var redPos = new VecI();
-        var greenPos = new VecI(size.X, 0);
-        var bluePos = new VecI(0, size.Y);
-        var alphaPos = new VecI(size.X, size.Y);
+        int saved = drawingSurface.Canvas.SaveLayer(_paint);
         
-        previewSurface.DrawingSurface.Canvas.DrawSurface(Red.Value.DrawingSurface, redPos, context.ReplacingPaintWithOpacity);
-        previewSurface.DrawingSurface.Canvas.DrawSurface(Green.Value.DrawingSurface, greenPos, context.ReplacingPaintWithOpacity);
-        previewSurface.DrawingSurface.Canvas.DrawSurface(Blue.Value.DrawingSurface, bluePos, context.ReplacingPaintWithOpacity);
-        previewSurface.DrawingSurface.Canvas.DrawSurface(Alpha.Value.DrawingSurface, alphaPos, context.ReplacingPaintWithOpacity);
+        Image.Value.Paint(context, drawingSurface);
+        
+        drawingSurface.Canvas.RestoreToCount(saved);
     }
 
-    private Texture GetImage(Texture image, ColorFilter filter, int id)
+    protected override void OnExecute(RenderContext context)
     {
-        var imageSurface = RequestTexture(id, image.Size);
-
-        _paint.ColorFilter = filter;
-        imageSurface.DrawingSurface.Canvas.DrawSurface(image.DrawingSurface, 0, 0, _paint);
+        Red.ChainToPainterValue();
+        Green.ChainToPainterValue();
+        Blue.ChainToPainterValue();
+        Alpha.ChainToPainterValue();
+    }
 
-        return imageSurface;
+    public override Node CreateCopy() => new SeparateChannelsNode();
+    RenderInputProperty IRenderInput.Background => Image;
+    public RectD? GetPreviewBounds(int frame, string elementToRenderName = "")
+    {
+        RectD? bounds = PreviewUtils.FindPreviewBounds(Image.Connection, frame, elementToRenderName);
+        return bounds.HasValue ? new RectD(0, 0, bounds.Value.Width * 2, bounds.Value.Height * 2) : null;
     }
 
+    public bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame, string elementToRenderName)
+    {
+        if (Image.Value == null)
+            return false;
+
+        RectD? bounds = GetPreviewBounds(frame, elementToRenderName);
+        
+        if (bounds == null)
+            return false;
 
-    public override Node CreateCopy() => new SeparateChannelsNode();
+        using RenderContext context = new(renderOn, frame, resolution, VecI.One);
+        
+        _paint.ColorFilter = Grayscale.Value ? _redGrayscaleFilter : _redFilter;
+        RectD localBounds = bounds.Value with { Width = bounds.Value.Width / 2, Height = bounds.Value.Height / 2, };
+        int saved = renderOn.Canvas.SaveLayer(_paint, localBounds);
+        
+        renderOn.Canvas.Scale(0.8f, 0.8f);
+        renderOn.Canvas.Translate((float)-bounds.Value.Width / 2f, (float)-bounds.Value.Height / 2f);
+        
+        Image.Value.Paint(context, renderOn);
+        
+        renderOn.Canvas.RestoreToCount(saved);
+        
+        localBounds = new RectD(bounds.Value.Width / 2f, 0, bounds.Value.Width / 2, bounds.Value.Height / 2); 
+        _paint.ColorFilter = Grayscale.Value ? _greenGrayscaleFilter : _greenFilter;
+        saved = renderOn.Canvas.SaveLayer(_paint, localBounds);
+        
+        renderOn.Canvas.Scale(0.8f, 0.8f);
+        renderOn.Canvas.Translate((float)bounds.Value.Width / 8f, (float)-bounds.Value.Height / 2f);
+        Image.Value.Paint(context, renderOn);
+        
+        renderOn.Canvas.RestoreToCount(saved);
+        
+        _paint.ColorFilter = Grayscale.Value ? _blueGrayscaleFilter : _blueFilter;
+        localBounds = new RectD(0, bounds.Value.Height / 2f, bounds.Value.Width / 2, bounds.Value.Height / 2);
+        saved = renderOn.Canvas.SaveLayer(_paint, localBounds);
+        
+        renderOn.Canvas.Scale(0.8f, 0.8f);
+        renderOn.Canvas.Translate((float)-bounds.Value.Width / 2f, (float)bounds.Value.Height / 8f);
+        Image.Value.Paint(context, renderOn);
+        
+        renderOn.Canvas.RestoreToCount(saved);
+        
+        _paint.ColorFilter = Grayscale.Value ? _alphaGrayscaleFilter : _alphaFilter;
+        localBounds = new RectD(bounds.Value.Width / 2f, bounds.Value.Height / 2f, bounds.Value.Width / 2, bounds.Value.Height / 2);
+        saved = renderOn.Canvas.SaveLayer(_paint, localBounds);
+        
+        renderOn.Canvas.Scale(0.8f, 0.8f);
+        renderOn.Canvas.Translate((float)bounds.Value.Width / 8f, (float)bounds.Value.Height / 8f);
+        Image.Value.Paint(context, renderOn);
+        
+        renderOn.Canvas.RestoreToCount(saved);
+
+        return true;
+    }
 }

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

@@ -34,12 +34,7 @@ public class ApplyFilterNode : RenderNode, IRenderInput
 
     public override RectD? GetPreviewBounds(int frame, string elementToRenderName = "")
     {
-        if (Background.Connection != null && Background.Connection.Node is IPreviewRenderable previousPreview)
-        {
-            return previousPreview.GetPreviewBounds(frame, elementToRenderName);
-        }
-        
-        return null;
+        return PreviewUtils.FindPreviewBounds(Background.Connection, frame, elementToRenderName); 
     }
 
     public override bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame,

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

@@ -45,24 +45,14 @@ public class OutputNode : Node, IRenderInput, IPreviewRenderable
 
     public bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame, string elementToRenderName)
     {
-        var executionQueue = GraphUtils.CalculateExecutionQueue(this);
-        
-        foreach (var node in executionQueue)
+        if (Input.Value == null)
         {
-            if(node == this)
-            {
-                continue;
-            }
-            
-            if (node is IPreviewRenderable previewRenderable)
-            {
-                if (!previewRenderable.RenderPreview(renderOn, resolution, frame, elementToRenderName))
-                {
-                    return false;
-                }
-            }
+            return false;
         }
-
+        
+        using RenderContext context = new(renderOn, frame, resolution, VecI.One);
+        Input.Value.Paint(context, renderOn);
+        
         return true;
     }
 }

+ 17 - 0
src/PixiEditor.ChangeableDocument/Helpers/PreviewUtils.cs

@@ -0,0 +1,17 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
+using PixiEditor.Numerics;
+
+namespace PixiEditor.ChangeableDocument.Helpers;
+
+public static class PreviewUtils
+{
+    public static RectD? FindPreviewBounds(IOutputProperty? connectionProperty, int frame, string elementToRenderName)
+    {
+        if (connectionProperty is { Node: IPreviewRenderable previousPreview })
+        {
+            return previousPreview.GetPreviewBounds(frame, elementToRenderName);
+        }
+
+        return null;
+    }
+}