Browse Source

Added folder mask and clipping

flabbet 10 months ago
parent
commit
d5940a69f3

+ 62 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/GraphUtils.cs

@@ -0,0 +1,62 @@
+using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Graph;
+
+public static class GraphUtils
+{
+    public static Queue<IReadOnlyNode> CalculateExecutionQueue(IReadOnlyNode outputNode)
+    {
+        var finalQueue = new HashSet<IReadOnlyNode>();
+        var queueNodes = new Queue<IReadOnlyNode>();
+        queueNodes.Enqueue(outputNode);
+
+        while (queueNodes.Count > 0)
+        {
+            var node = queueNodes.Dequeue();
+            
+            if (finalQueue.Contains(node))
+            {
+                continue;
+            }
+            
+            bool canAdd = true;
+
+            foreach (var input in node.InputProperties)
+            {
+                if (input.Connection == null)
+                {
+                    continue;
+                }
+
+                if (finalQueue.Contains(input.Connection.Node))
+                {
+                    continue;
+                }
+
+                canAdd = false;
+                
+                if (finalQueue.Contains(input.Connection.Node))
+                {
+                    finalQueue.Remove(input.Connection.Node);
+                    finalQueue.Add(input.Connection.Node);
+                }
+
+                if (!queueNodes.Contains(input.Connection.Node))
+                {
+                    queueNodes.Enqueue(input.Connection.Node);
+                }
+            }
+            
+            if (canAdd)
+            {
+                finalQueue.Add(node);
+            }
+            else
+            {
+                queueNodes.Enqueue(node);
+            }
+        }
+
+        return new Queue<IReadOnlyNode>(finalQueue);
+    }
+}

+ 8 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Interfaces/IClipSource.cs

@@ -0,0 +1,8 @@
+using PixiEditor.DrawingApi.Core.Surfaces;
+
+namespace PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
+
+public interface IClipSource
+{
+    public void DrawOnTexture(SceneObjectRenderContext context, DrawingSurface drawOnto);
+}

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

@@ -38,58 +38,7 @@ public class NodeGraph : IReadOnlyNodeGraph, IDisposable
 
     public Queue<IReadOnlyNode> CalculateExecutionQueue(IReadOnlyNode outputNode)
     {
-        var finalQueue = new HashSet<IReadOnlyNode>();
-        var queueNodes = new Queue<IReadOnlyNode>();
-        queueNodes.Enqueue(outputNode);
-
-        while (queueNodes.Count > 0)
-        {
-            var node = queueNodes.Dequeue();
-            
-            if (finalQueue.Contains(node))
-            {
-                continue;
-            }
-            
-            bool canAdd = true;
-
-            foreach (var input in node.InputProperties)
-            {
-                if (input.Connection == null)
-                {
-                    continue;
-                }
-
-                if (finalQueue.Contains(input.Connection.Node))
-                {
-                    continue;
-                }
-
-                canAdd = false;
-                
-                if (finalQueue.Contains(input.Connection.Node))
-                {
-                    finalQueue.Remove(input.Connection.Node);
-                    finalQueue.Add(input.Connection.Node);
-                }
-
-                if (!queueNodes.Contains(input.Connection.Node))
-                {
-                    queueNodes.Enqueue(input.Connection.Node);
-                }
-            }
-            
-            if (canAdd)
-            {
-                finalQueue.Add(node);
-            }
-            else
-            {
-                queueNodes.Enqueue(node);
-            }
-        }
-
-        return new Queue<IReadOnlyNode>(finalQueue);
+        return GraphUtils.CalculateExecutionQueue(outputNode);
     }
 
     void IReadOnlyNodeGraph.AddNode(IReadOnlyNode node) => AddNode((Node)node);

+ 38 - 81
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FolderNode.cs

@@ -9,7 +9,7 @@ using PixiEditor.Numerics;
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 
 [NodeInfo("Folder")]
-public class FolderNode : StructureNode, IReadOnlyFolderNode
+public class FolderNode : StructureNode, IReadOnlyFolderNode, IClipSource
 {
     public RenderInputProperty Content { get; }
 
@@ -18,9 +18,9 @@ public class FolderNode : StructureNode, IReadOnlyFolderNode
         Content = CreateRenderInput("Content", "CONTENT", ctx =>
         {
             RectD? bounds = new RectD(VecI.Zero, ctx.DocumentSize);
-            
+
             // Folder doesn't need to do anything if no operations are present
-            if (bounds == null || !HasOperations()) 
+            if (bounds == null || (!HasOperations() && BlendMode.Value == Enums.BlendMode.Normal))
             {
                 return Output.GetFirstRenderTarget(ctx);
             }
@@ -33,109 +33,50 @@ public class FolderNode : StructureNode, IReadOnlyFolderNode
 
     public override Node CreateCopy() => new FolderNode { MemberName = MemberName };
 
+    public override VecD ScenePosition => Content.Value?.DeviceClipBounds.Size / 2f ?? VecD.Zero;
+    public override VecD SceneSize => Content.Value?.DeviceClipBounds.Size ?? VecD.Zero;
 
-    protected override void OnExecute(RenderContext context)
+    public override void Render(SceneObjectRenderContext sceneContext)
     {
-        base.OnExecute(context);
-
-        /*if(Background.Value == null && Content.Value == null)
-        {
-            Output.Value = null;
-            return;
-        }
-
+        RectD bounds = RectD.Create(VecI.Zero, sceneContext.DocumentSize);
         if (!IsVisible.Value || Opacity.Value <= 0 || IsEmptyMask())
         {
-            Output.Value = Background.Value;
+            Output.Value = sceneContext.RenderSurface;
             return;
         }
 
-        blendPaint.Color = new Color(255, 255, 255, 255);
-        blendPaint.BlendMode = DrawingApi.Core.Surfaces.BlendMode.Src;
-
-        if (Content.Value == null)
+        if (Content.Connection == null || (!HasOperations() && BlendMode.Value == Enums.BlendMode.Normal))
         {
             return;
         }
 
-        VecI size = Content.Value?.Size ?? VecI.Zero;
-
-        var outputWorkingSurface = RequestTexture(0, size);
-        var filterlessWorkingSurface = RequestTexture(1, size);
-
-        if (Background.Value != null)
-        {
-            DrawBackground(filterlessWorkingSurface.DrawingSurface, context);
-            blendPaint.BlendMode = RenderingContext.GetDrawingBlendMode(BlendMode.Value);
-        }
+        VecI size = (VecI)bounds.Size;
+        var outputWorkingSurface = RequestTexture(0, size, false);
 
-        if (Content.Value != null)
+        if (RenderTarget.Value != null)
         {
-            blendPaint.Color = blendPaint.Color.WithAlpha((byte)Math.Round(Opacity.Value * 255));
-            DrawSurface(filterlessWorkingSurface.DrawingSurface, Content.Value, context, null);
+            blendPaint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
         }
 
-        FilterlessOutput.Value = filterlessWorkingSurface;
+        ApplyMaskIfPresent(outputWorkingSurface.DrawingSurface, sceneContext);
 
-        if (!HasOperations())
+        if (RenderTarget.Value != null)
         {
-            if (Background.Value != null)
-            {
-                blendPaint.Color = new Color(255, 255, 255, 255);
-                blendPaint.BlendMode = DrawingApi.Core.Surfaces.BlendMode.Src;
-                DrawBackground(outputWorkingSurface.DrawingSurface, context);
-                blendPaint.BlendMode = RenderingContext.GetDrawingBlendMode(BlendMode.Value);
-            }
-
-            if (Content.Value != null)
+            Texture tempSurface = RequestTexture(1, outputWorkingSurface.Size);
+            if (RenderTarget.Connection.Node is IClipSource clipSource)
             {
-                blendPaint.Color = blendPaint.Color.WithAlpha((byte)Math.Round(Opacity.Value * 255));
-                DrawSurface(outputWorkingSurface.DrawingSurface, Content.Value.DrawingSurface, context, Filters.Value);
+                DrawClipSource(tempSurface.DrawingSurface, clipSource, sceneContext);
             }
 
-            Output.Value = outputWorkingSurface.DrawingSurface;
-        }
-
-        if (Content.Value != null)
-        {
-            DrawSurface(outputWorkingSurface.DrawingSurface, Content.Value.DrawingSurface, context, Filters.Value);
-
-            ApplyMaskIfPresent(outputWorkingSurface, context);
-        }
-
-        if (Background.Value != null)
-        {
-            Texture tempSurface = RequestTexture(2, outputWorkingSurface.Size);
-            DrawBackground(tempSurface.DrawingSurface, context);
-
-            ApplyRasterClip(outputWorkingSurface, tempSurface);
-
-            blendPaint.Color = blendPaint.Color.WithAlpha((byte)Math.Round(Opacity.Value * 255));
-            blendPaint.BlendMode = RenderingContext.GetDrawingBlendMode(BlendMode.Value);
+            ApplyRasterClip(outputWorkingSurface.DrawingSurface, tempSurface.DrawingSurface);
+            blendPaint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
             tempSurface.DrawingSurface.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0, blendPaint);
 
-            Output.Value = tempSurface.DrawingSurface;
+            sceneContext.RenderSurface.Canvas.DrawSurface(tempSurface.DrawingSurface, 0, 0, blendPaint);
+            outputWorkingSurface.DrawingSurface.Canvas.Clear();
             return;
         }
 
-        Output.Value = outputWorkingSurface.DrawingSurface;*/
-    }
-
-    public override VecD ScenePosition => Content.Value?.DeviceClipBounds.Size / 2f ?? VecD.Zero;
-    public override VecD SceneSize => Content.Value?.DeviceClipBounds.Size ?? VecD.Zero;
-
-    public override void Render(SceneObjectRenderContext sceneContext)
-    {
-        RectD bounds = RectD.Create(VecI.Zero, sceneContext.DocumentSize); 
-        
-        if(Content.Connection == null || !HasOperations())
-        {
-            return;
-        }
-        
-        VecI size = (VecI)bounds.Size;
-        var outputWorkingSurface = RequestTexture(0, size, false);
-        
         sceneContext.RenderSurface.Canvas.DrawSurface(outputWorkingSurface.DrawingSurface, 0, 0, blendPaint);
         outputWorkingSurface.DrawingSurface.Canvas.Clear();
     }
@@ -206,4 +147,20 @@ public class FolderNode : StructureNode, IReadOnlyFolderNode
             MaskIsVisible = MaskIsVisible
         };
     }*/
+    public void DrawOnTexture(SceneObjectRenderContext context, DrawingSurface drawOnto)
+    {
+        if (Content.Connection != null)
+        {
+            var executionQueue = GraphUtils.CalculateExecutionQueue(Content.Connection.Node);
+            
+            while (executionQueue.Count > 0)
+            {
+                IReadOnlyNode node = executionQueue.Dequeue();
+                if (node is IClipSource clipSource)
+                {
+                    clipSource.DrawOnTexture(context, drawOnto);
+                }
+            }
+        }
+    }
 }

+ 8 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/LayerNode.cs

@@ -9,7 +9,7 @@ using PixiEditor.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 
-public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
+public abstract class LayerNode : StructureNode, IReadOnlyLayerNode, IClipSource
 {
     protected Dictionary<(ChunkResolution, int), Texture> workingSurfaces =
         new Dictionary<(ChunkResolution, int), Texture>();
@@ -80,10 +80,10 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
             {
                 Texture tempSurface = TryInitWorkingSurface(size, context.ChunkResolution, 4);
                 tempSurface.DrawingSurface.Canvas.Clear();
-                if (RenderTarget.Connection.Node is LayerNode layerNode)
+                if (RenderTarget.Connection.Node is IClipSource clipSource)
                 {
                     // TODO: This probably should work with StructureMembers not Layers only
-                    DrawPreviousLayer(tempSurface.DrawingSurface, layerNode, context);
+                    DrawClipSource(tempSurface.DrawingSurface, clipSource, context);
                 }
 
                 ApplyRasterClip(outputWorkingSurface.DrawingSurface, tempSurface.DrawingSurface);
@@ -168,4 +168,9 @@ public abstract class LayerNode : StructureNode, IReadOnlyLayerNode
     }
 
     public abstract bool RenderPreview(Texture renderOn, VecI chunk, ChunkResolution resolution, int frame);
+
+    void IClipSource.DrawOnTexture(SceneObjectRenderContext context, DrawingSurface drawOnto)
+    {
+        DrawLayerOnTexture(context, drawOnto, false);
+    }
 }

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

@@ -187,10 +187,10 @@ public abstract class StructureNode : Node, IReadOnlyStructureNode, IRenderInput
         return (MaskIsVisible.Value && (EmbeddedMask != null || CustomMask.Value != null)) || ClipToPreviousMember;
     }
 
-    protected void DrawPreviousLayer(DrawingSurface drawOnto, LayerNode previousNode, SceneObjectRenderContext context)
+    protected void DrawClipSource(DrawingSurface drawOnto, IClipSource clipSource, SceneObjectRenderContext context)
     {
         blendPaint.Color = Colors.White;
-        previousNode.DrawLayerOnTexture(context, drawOnto, false);
+        clipSource.DrawOnTexture(context, drawOnto);
     }
 
     protected void DrawSurface(DrawingSurface workingSurface, DrawingSurface source, RenderContext context,

+ 1 - 1
src/PixiEditor/Data/Localization/Languages/en.json

@@ -440,7 +440,7 @@
   "BOTTOM_LEFT": "Bottom left",
   "BOTTOM_CENTER": "Bottom center",
   "BOTTOM_RIGHT": "Bottom right",
-  "CLIP_TO_BELOW": "Clip to layer below",
+  "CLIP_TO_BELOW": "Clip to member below",
   "MOVE_UPWARDS": "Move upwards",
   "MOVE_DOWNWARDS": "Move downwards",
   "MERGE_SELECTED": "Merge selected",