Browse Source

Merge pull request #684 from PixiEditor/fixes/05.12.2024

Fixes/05.12.2024
Krzysztof Krysiński 8 months ago
parent
commit
dad87edb1c

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit f07c85f3a8340babe79c08c585958c93b5d7a321
+Subproject commit f594ce467f0834a1ce34ab88d892a13a26694d80

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Filter.cs

@@ -26,7 +26,7 @@ public sealed class Filter : IDisposable
         }
 
         ImageFilter? image = ImageFilter;
-        if (imageFilter == null)
+        if (imageFilter != null)
         {
             image = ImageFilter == null ? imageFilter : ImageFilter.CreateCompose(imageFilter, ImageFilter);
         }

+ 1 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/FuncInputProperty.cs

@@ -18,7 +18,7 @@ public class FuncInputProperty<T> : InputProperty<Func<FuncContext, T>>, IFuncIn
         NonOverridenValue = _ => constantNonOverrideValue;
     }
 
-    protected override object FuncFactory(object toReturn)
+    protected internal override object FuncFactory(object toReturn)
     {
         Func<FuncContext, T> func = _ =>
         {

+ 1 - 33
src/PixiEditor.ChangeableDocument/Changeables/Graph/InputProperty.cs

@@ -63,7 +63,7 @@ public class InputProperty : IInputProperty
         }
     }
 
-    protected virtual object FuncFactory(object toReturn)
+    protected internal virtual object FuncFactory(object toReturn)
     {
         Func<FuncContext, object> func = _ => toReturn;
         return func;
@@ -131,38 +131,6 @@ public class InputProperty : IInputProperty
         Node = node;
         ValueType = valueType;
     }
-
-    public InputProperty Clone(Node forNode)
-    {
-        if(NonOverridenValue is ICloneable cloneable)
-            return new InputProperty(forNode, InternalPropertyName, DisplayName, cloneable.Clone(), ValueType);
-
-        if (NonOverridenValue is Enum enumVal)
-        {
-            return new InputProperty(forNode, InternalPropertyName, DisplayName, enumVal, ValueType);
-        }
-
-        if (NonOverridenValue is null || (!NonOverridenValue.GetType().IsValueType && NonOverridenValue.GetType() != typeof(string)))
-        {
-            object? nullValue = null;
-            if (ValueType.IsValueType)
-            {
-                nullValue = Activator.CreateInstance(ValueType);
-            }
-            
-            return new InputProperty(forNode, InternalPropertyName, DisplayName, nullValue, ValueType);
-        }
-        
-        /*if(!NonOverridenValue.GetType().IsValueType && NonOverridenValue.GetType() != typeof(string))
-            throw new InvalidOperationException($"Value of type {NonOverridenValue.GetType()} is not cloneable and not a primitive type");*/
-
-        if (!NonOverridenValue.GetType().IsValueType && NonOverridenValue.GetType() != typeof(string))
-        {
-            
-        }
-        
-        return new InputProperty(forNode, InternalPropertyName, DisplayName, NonOverridenValue, ValueType);
-    }
 }
 
 

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CombineSeparate/CombineVecDNode.cs

@@ -34,6 +34,7 @@ public class CombineVecDNode : Node
 
     protected override void OnExecute(RenderContext context)
     {
+        
     }
 
 

+ 7 - 8
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/ApplyFilterNode.cs

@@ -25,30 +25,29 @@ public class ApplyFilterNode : RenderNode, IRenderInput
 
     protected override void OnPaint(RenderContext context, DrawingSurface surface)
     {
-        if (Background.Value == null || Filter.Value == null)
+        if (Background.Value == null)
             return;
-        
+
         _paint.SetFilters(Filter.Value);
-        var layer = surface.Canvas.SaveLayer(_paint);
-        
+        int layer = surface.Canvas.SaveLayer(_paint);
         Background.Value.Paint(context, surface);
-        
+
         surface.Canvas.RestoreToCount(layer);
     }
 
     public override RectD? GetPreviewBounds(int frame, string elementToRenderName = "")
     {
-        return PreviewUtils.FindPreviewBounds(Background.Connection, frame, elementToRenderName); 
+        return PreviewUtils.FindPreviewBounds(Background.Connection, frame, elementToRenderName);
     }
 
     public override bool RenderPreview(DrawingSurface renderOn, ChunkResolution resolution, int frame,
         string elementToRenderName)
     {
-        if(Background.Value == null)
+        if (Background.Value == null)
             return false;
 
         RenderContext context = new(renderOn, frame, ChunkResolution.Full, VecI.One);
-        
+
         int layer = renderOn.Canvas.SaveLayer(_paint);
         Background.Value.Paint(context, renderOn);
         renderOn.Canvas.RestoreToCount(layer);

+ 4 - 1
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/FilterNodes/KernelFilterNode.cs

@@ -25,6 +25,8 @@ public class KernelFilterNode : FilterNode
     private double lastGain;
     private double lastBias;
 
+    private float[] lastKernelValues = new float[9];
+
     public KernelFilterNode()
     {
         Kernel = CreateInput(nameof(Kernel), "KERNEL", Drawie.Numerics.Kernel.Identity(3, 3));
@@ -38,7 +40,7 @@ public class KernelFilterNode : FilterNode
     {
         var kernel = Kernel.Value;
         
-        if (kernel.Equals(lastKernel) && Tile.Value == lastTile && Gain.Value == lastGain && Bias.Value == lastBias)
+        if (kernel.AsSpan().SequenceEqual(lastKernelValues) && Tile.Value == lastTile && Gain.Value == lastGain && Bias.Value == lastBias)
             return filter;
         
         lastKernel = kernel;
@@ -51,6 +53,7 @@ public class KernelFilterNode : FilterNode
         var kernelOffset = new VecI(kernel.RadiusX, kernel.RadiusY);
         
         filter = ImageFilter.CreateMatrixConvolution(kernel, (float)Gain.Value, (float)Bias.Value, kernelOffset, Tile.Value, OnAlpha.Value);
+        lastKernelValues = kernel.AsSpan().ToArray();
         return filter;
     }
 

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/MathNode.cs

@@ -22,6 +22,7 @@ public class MathNode : Node
     
     public FuncInputProperty<Float1> Y { get; }
     
+
     public MathNode()
     {
         Result = CreateFuncOutput<Float1>(nameof(Result), "RESULT", Calculate);

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

@@ -18,8 +18,6 @@ public class MergeNode : RenderNode
 
     private Paint paint = new Paint();
     
-    private static readonly Paint blendPaint = new Paint() { BlendMode = Drawie.Backend.Core.Surfaces.BlendMode.SrcOver };
-
     private int topLayer;
     private int bottomLayer;
     
@@ -58,6 +56,11 @@ public class MergeNode : RenderNode
             int saved = target.Canvas.SaveLayer();
             Bottom.Value.Paint(context, target);
 
+            if (paint == null)
+            {
+                paint = new Paint();
+            }
+            
             paint.BlendMode = RenderContext.GetDrawingBlendMode(BlendMode.Value);
             target.Canvas.SaveLayer(paint);
             

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

@@ -9,6 +9,7 @@ using PixiEditor.Common;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.Shaders;
+using Drawie.Backend.Core.Shaders.Generation;
 using Drawie.Numerics;
 
 namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
@@ -347,23 +348,26 @@ public abstract class Node : IReadOnlyNode, IDisposable
     public Node Clone()
     {
         var clone = CreateCopy();
+
         clone.DisplayName = DisplayName;
         clone.Id = Guid.NewGuid();
         clone.Position = Position;
 
         for (var i = 0; i < clone.inputs.Count; i++)
         {
-            var cloneInput = inputs[i];
-            var newInput = cloneInput.Clone(clone);
-            clone.inputs[i].NonOverridenValue = newInput.NonOverridenValue;
+            var toClone = inputs[i];
+            object value = CloneValue(toClone.NonOverridenValue, clone.inputs[i]);
+            clone.inputs[i].NonOverridenValue = value;
         }
-
-        for (var i = 0; i < clone.outputs.Count; i++)
+        
+        // This makes shader outputs copy old delegate, also I don't think it's required because output is calculated based on inputs,
+        // leaving commented in case I'm wrong
+        
+        /*for (var i = 0; i < clone.outputs.Count; i++)
         {
             var cloneOutput = outputs[i];
-            var newOutput = cloneOutput.Clone(clone);
-            clone.outputs[i].Value = newOutput.Value;
-        }
+            clone.outputs[i].Value = CloneValue(cloneOutput.Value, null);
+        }*/
 
         foreach (var keyFrame in keyFrames)
         {
@@ -421,4 +425,34 @@ public abstract class Node : IReadOnlyNode, IDisposable
     {
         return new None();
     }
+    
+    private static object CloneValue(object? value, InputProperty? input)
+    {
+        if (value is null)
+        {
+            return null;
+        }
+
+        if (input != null && value is Delegate del)
+        {
+            object constant = del.DynamicInvoke(FuncContext.NoContext);
+            if (constant is ShaderExpressionVariable expr)
+            {
+                return input.FuncFactory(expr.GetConstant());
+            }
+        }
+        
+        if (value is ICloneable cloneable)
+        {
+            return cloneable.Clone();
+        }
+
+        Type type = value.GetType();
+        if (type.IsValueType || type == typeof(string))
+        {
+            return value;
+        }
+        
+        return default;
+    }
 }

+ 0 - 25
src/PixiEditor.ChangeableDocument/Changeables/Graph/OutputProperty.cs

@@ -65,31 +65,6 @@ public class OutputProperty : IOutputProperty
 
         Disconnected?.Invoke(property, this);
     }
-
-    public OutputProperty Clone(Node clone)
-    {
-        if (Value is null || (Value is not ICloneable && !Value.GetType().IsPrimitive && Value.GetType() != typeof(string)))
-        {
-            object defaultValue = null;
-            if(ValueType.IsValueType)
-                defaultValue = Activator.CreateInstance(ValueType);
-            return new OutputProperty(clone, InternalPropertyName, DisplayName, defaultValue, ValueType);
-        }
-
-        if (Value is Enum enumVal)
-        {
-            return new OutputProperty(clone, InternalPropertyName, DisplayName, enumVal, ValueType);
-        }
-
-        /*if (Value is not ICloneable && !Value.GetType().IsPrimitive && Value.GetType() != typeof(string))
-            throw new InvalidOperationException("Value is not cloneable and not a primitive type");*/
-     
-        object value = Value is ICloneable cloneableValue ? cloneableValue.Clone() : Value;
-        
-        var newOutput = new OutputProperty(clone, InternalPropertyName, DisplayName, value, ValueType);
-
-        return newOutput;
-    }
 }
 
 public class OutputProperty<T> : OutputProperty, INodeProperty<T>

+ 3 - 0
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/DeleteNode_Change.cs

@@ -68,6 +68,8 @@ internal class DeleteNode_Change : Change
             target.AnimationData.RemoveKeyFrame(savedKeyFrameGroup.Id);
             changes.Add(new DeleteKeyFrame_ChangeInfo(savedKeyFrameGroup.Id));
         }
+        
+        node.Dispose();
 
         return changes;
     }
@@ -90,6 +92,7 @@ internal class DeleteNode_Change : Change
 
         changes.Add(createChange);
 
+        changes.AddRange(NodeOperations.CreateUpdateInputs(copy));
         changes.AddRange(NodeOperations.ConnectStructureNodeProperties(originalConnections, copy, doc.NodeGraph));
 
         RevertKeyFrames(doc, savedKeyFrameGroup, changes);

+ 23 - 0
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/NodeOperations.cs

@@ -7,7 +7,9 @@ using PixiEditor.ChangeableDocument.Changeables.Interfaces;
 using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
 using PixiEditor.ChangeableDocument.Changes.Structure;
 using Drawie.Backend.Core;
+using Drawie.Backend.Core.Shaders.Generation;
 using Drawie.Backend.Core.Surfaces;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
 
 namespace PixiEditor.ChangeableDocument.Changes.NodeGraph;
 
@@ -229,6 +231,27 @@ public static class NodeOperations
 
         return changes;
     }
+
+    public static List<IChangeInfo> CreateUpdateInputs(Node copy)
+    {
+        List<IChangeInfo> changes = new();
+        foreach (var input in copy.InputProperties)
+        {
+            object value = input.NonOverridenValue;
+            if (value is Delegate del)
+            {
+                value = del.DynamicInvoke(FuncContext.NoContext);
+                if (value is ShaderExpressionVariable expressionVariable)
+                {
+                    value = expressionVariable.GetConstant();
+                }
+            }
+            
+            changes.Add(new PropertyValueUpdated_ChangeInfo(copy.Id, input.InternalPropertyName, value));
+        }
+
+        return changes;
+    }
 }
 
 public record PropertyConnection(Guid? NodeId, string? PropertyName);

+ 1 - 1
src/PixiEditor/Models/Controllers/InputDevice/MouseInputFilter.cs

@@ -25,7 +25,7 @@ internal class MouseInputFilter
     {
         var button = args.Button;
 
-        if (button is MouseButton.XButton1 or MouseButton.XButton2)
+        if (button is MouseButton.XButton1 or MouseButton.XButton2 or MouseButton.None)
             return;
         if (buttonStates[button])
             return;

+ 5 - 1
src/PixiEditor/ViewModels/Nodes/NodePropertyViewModel.cs

@@ -36,8 +36,12 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
         get => _value;
         set
         {
+            var oldValue = _value;
             ViewModelMain.Current.NodeGraphManager.UpdatePropertyValue((node, PropertyName, value));
-            //ValueChanged?.Invoke(this, new NodePropertyValueChangedArgs(oldValue, value));
+            if(SetProperty(ref _value, value))
+            {
+                ValueChanged?.Invoke(this, new NodePropertyValueChangedArgs(oldValue, value));
+            }
         }
     }
 

+ 2 - 2
src/PixiEditor/ViewModels/SubViewModels/IoViewModel.cs

@@ -27,7 +27,7 @@ namespace PixiEditor.ViewModels.SubViewModels;
 #nullable enable
 internal class IoViewModel : SubViewModel<ViewModelMain>
 {
-    private int? previousEraseSize;
+    private double? previousEraseSize;
     private bool hadSharedToolbar;
     private bool? drawingWithRight;
     private bool startedWithEraser;
@@ -263,7 +263,7 @@ internal class IoViewModel : SubViewModel<ViewModelMain>
             if(eraserTool == null) return;
             
             var toolSize = tools.GetTool<EraserToolViewModel>().Toolbar.Settings.First(x => x.Name == "ToolSize");
-            previousEraseSize = (int)toolSize.Value;
+            previousEraseSize = (double)toolSize.Value;
             toolSize.Value = tools.ActiveTool is PenToolViewModel { PixelPerfectEnabled: true }
                 ? 1
                 : currentToolSize.Value;

+ 0 - 1
src/PixiEditor/Views/Nodes/Properties/KernelPropertyView.axaml.cs

@@ -3,7 +3,6 @@ using Avalonia.Controls;
 using Avalonia.Markup.Xaml;
 
 namespace PixiEditor.Views.Nodes.Properties;
-
 public partial class KernelPropertyView : NodePropertyView
 {
     public KernelPropertyView()

+ 2 - 1
src/PixiEditor/Views/Rendering/Scene.cs

@@ -32,6 +32,7 @@ using PixiEditor.Views.Overlays;
 using PixiEditor.Views.Overlays.Pointers;
 using PixiEditor.Views.Visuals;
 using Bitmap = Drawie.Backend.Core.Surfaces.Bitmap;
+using Color = Drawie.Backend.Core.ColorsImpl.Color;
 using Point = Avalonia.Point;
 
 namespace PixiEditor.Views.Rendering;
@@ -537,7 +538,7 @@ internal class Scene : Zoombox.Zoombox, ICustomHitTest
             return;
         }
 
-        var size = PixelSize.FromSize(Bounds.Size, root.RenderScaling);
+        var size = new PixelSize((int)Bounds.Width, (int)Bounds.Height);
         RenderFrame(size);
     }
 

+ 1 - 1
src/PixiParser

@@ -1 +1 @@
-Subproject commit 364611d097a1febb4e36ac811dc391e67ec5f871
+Subproject commit 64b02fab35d2f7fe30a8426b49ff59e1e37ed452