Browse Source

Added computed value debug tooltips

Krzysztof Krysiński 3 months ago
parent
commit
24b4531b2e

+ 1 - 1
src/Drawie

@@ -1 +1 @@
-Subproject commit c53ef1e999160717ec52c9149a74d41d86da721b
+Subproject commit 8bf655ed21046c4a534c3f7f08fdaa01a9ab34d8

+ 4 - 0
src/PixiEditor.ChangeableDocument/ChangeInfos/NodeGraph/ComputedPropertyValue_ChangeInfo.cs

@@ -0,0 +1,4 @@
+namespace PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
+
+public record ComputedPropertyValue_ChangeInfo(Guid Node, string PropertyName, bool IsInput, object? Value)
+    : IChangeInfo;

+ 5 - 3
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/CreateImageNode.cs

@@ -3,6 +3,7 @@ using Drawie.Backend.Core;
 using Drawie.Backend.Core.Bridge;
 using Drawie.Backend.Core.Bridge;
 using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.ColorsImpl.Paintables;
 using Drawie.Backend.Core.ColorsImpl.Paintables;
+using Drawie.Backend.Core.Numerics;
 using Drawie.Backend.Core.Surfaces;
 using Drawie.Backend.Core.Surfaces;
 using Drawie.Backend.Core.Surfaces.ImageData;
 using Drawie.Backend.Core.Surfaces.ImageData;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
 using Drawie.Backend.Core.Surfaces.PaintImpl;
@@ -22,7 +23,8 @@ public class CreateImageNode : Node, IPreviewRenderable
 
 
     public RenderInputProperty Content { get; }
     public RenderInputProperty Content { get; }
 
 
-    public InputProperty<VecD> ContentOffset { get; }
+    public InputProperty<Matrix3X3> ContentMatrix { get; }
+
 
 
     public RenderOutputProperty RenderOutput { get; }
     public RenderOutputProperty RenderOutput { get; }
 
 
@@ -34,7 +36,7 @@ public class CreateImageNode : Node, IPreviewRenderable
         Size = CreateInput(nameof(Size), "SIZE", new VecI(32, 32)).WithRules(v => v.Min(VecI.One));
         Size = CreateInput(nameof(Size), "SIZE", new VecI(32, 32)).WithRules(v => v.Min(VecI.One));
         Fill = CreateInput<Paintable>(nameof(Fill), "FILL", new ColorPaintable(Colors.Transparent));
         Fill = CreateInput<Paintable>(nameof(Fill), "FILL", new ColorPaintable(Colors.Transparent));
         Content = CreateRenderInput(nameof(Content), "CONTENT");
         Content = CreateRenderInput(nameof(Content), "CONTENT");
-        ContentOffset = CreateInput(nameof(ContentOffset), "CONTENT_OFFSET", VecD.Zero);
+        ContentMatrix = CreateInput<Matrix3X3>(nameof(ContentMatrix), "MATRIX", Matrix3X3.Identity);
         RenderOutput = CreateRenderOutput("RenderOutput", "RENDER_OUTPUT", () => new Painter(OnPaint));
         RenderOutput = CreateRenderOutput("RenderOutput", "RENDER_OUTPUT", () => new Painter(OnPaint));
     }
     }
 
 
@@ -72,7 +74,7 @@ public class CreateImageNode : Node, IPreviewRenderable
         RenderContext ctx = new RenderContext(surface.DrawingSurface, context.FrameTime, context.ChunkResolution,
         RenderContext ctx = new RenderContext(surface.DrawingSurface, context.FrameTime, context.ChunkResolution,
             context.DocumentSize, context.ProcessingColorSpace);
             context.DocumentSize, context.ProcessingColorSpace);
 
 
-        surface.DrawingSurface.Canvas.Translate((float)-ContentOffset.Value.X, (float)-ContentOffset.Value.Y);
+        surface.DrawingSurface.Canvas.SetMatrix(surface.DrawingSurface.Canvas.TotalMatrix.Concat(ContentMatrix.Value));
 
 
         Content.Value?.Paint(ctx, surface.DrawingSurface);
         Content.Value?.Paint(ctx, surface.DrawingSurface);
 
 

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

@@ -30,7 +30,7 @@ public class SampleImageNode : Node
 
 
     private Half4 GetColor(FuncContext context)
     private Half4 GetColor(FuncContext context)
     {
     {
-        if (Image.Value is null)
+        if (Image.Value is null || Image.Value.IsDisposed)
         {
         {
             return new Half4("");
             return new Half4("");
         }
         }

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

@@ -1,5 +1,6 @@
 using Drawie.Backend.Core;
 using Drawie.Backend.Core;
 using Drawie.Backend.Core.ColorsImpl;
 using Drawie.Backend.Core.ColorsImpl;
+using Drawie.Backend.Core.Numerics;
 using Drawie.Backend.Core.Surfaces.ImageData;
 using Drawie.Backend.Core.Surfaces.ImageData;
 using Drawie.Numerics;
 using Drawie.Numerics;
 
 
@@ -24,6 +25,7 @@ public class TextureCache : IDisposable
             if (clear)
             if (clear)
             {
             {
                 texture.DrawingSurface.Canvas.Clear(Colors.Transparent);
                 texture.DrawingSurface.Canvas.Clear(Colors.Transparent);
+                texture.DrawingSurface.Canvas.SetMatrix(Matrix3X3.Identity);
             }
             }
 
 
             return texture;
             return texture;

+ 8 - 0
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/VectorLayerNode.cs

@@ -19,6 +19,7 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
 public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorNode, IRasterizable, IScalable
 public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorNode, IRasterizable, IScalable
 {
 {
     public OutputProperty<ShapeVectorData> Shape { get; }
     public OutputProperty<ShapeVectorData> Shape { get; }
+    public OutputProperty<Matrix3X3> Matrix { get; }
 
 
     public Matrix3X3 TransformationMatrix
     public Matrix3X3 TransformationMatrix
     {
     {
@@ -50,6 +51,13 @@ public class VectorLayerNode : LayerNode, ITransformableObject, IReadOnlyVectorN
     {
     {
         AllowHighDpiRendering = true;
         AllowHighDpiRendering = true;
         Shape = CreateOutput<ShapeVectorData>("Shape", "SHAPE", null);
         Shape = CreateOutput<ShapeVectorData>("Shape", "SHAPE", null);
+        Matrix = CreateOutput<Matrix3X3>("Matrix", "MATRIX", Matrix3X3.Identity);
+    }
+
+    protected override void OnExecute(RenderContext context)
+    {
+        base.OnExecute(context);
+        Matrix.Value = TransformationMatrix;
     }
     }
 
 
     protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,
     protected override void DrawWithoutFilters(SceneObjectRenderContext ctx, DrawingSurface workingSurface,

+ 80 - 0
src/PixiEditor.ChangeableDocument/Changes/NodeGraph/GetComputedPropertyValue_Change.cs

@@ -0,0 +1,80 @@
+using Drawie.Backend.Core.Shaders.Generation;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
+using PixiEditor.ChangeableDocument.ChangeInfos.NodeGraph;
+
+namespace PixiEditor.ChangeableDocument.Changes.NodeGraph;
+
+internal class GetComputedPropertyValue_Change : Change
+{
+    private readonly Guid nodeId;
+    private readonly string propertyName;
+    private readonly bool isInput;
+
+    [GenerateMakeChangeAction]
+    public GetComputedPropertyValue_Change(Guid nodeId, string propertyName, bool isInput)
+    {
+        this.nodeId = nodeId;
+        this.propertyName = propertyName;
+        this.isInput = isInput;
+    }
+
+    public override bool InitializeAndValidate(Document target)
+    {
+        var foundNode = target.FindNode(nodeId);
+        if (foundNode == null)
+        {
+            return false;
+        }
+
+        if (isInput)
+        {
+            return foundNode.InputProperties.Any(x => x.InternalPropertyName == propertyName);
+        }
+
+        return foundNode.OutputProperties.Any(x => x.InternalPropertyName == propertyName);
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Apply(Document target, bool firstApply,
+        out bool ignoreInUndo)
+    {
+        var node = target.FindNode(nodeId);
+        ignoreInUndo = true;
+
+        if (node == null)
+        {
+            return new None();
+        }
+
+        object value;
+        if (isInput)
+        {
+            value = node.GetInputProperty(propertyName).Value;
+        }
+        else
+        {
+            value = node.GetOutputProperty(propertyName).Value;
+        }
+        if (value is Delegate del)
+        {
+            try
+            {
+                value = del.DynamicInvoke(FuncContext.NoContext);
+            }
+            catch (Exception e)
+            {
+                return new None();
+            }
+        }
+        if(value is ShaderExpressionVariable variable)
+        {
+            value = variable.GetConstant();
+        }
+
+        return new ComputedPropertyValue_ChangeInfo(nodeId, propertyName, isInput, value);
+    }
+
+    public override OneOf<None, IChangeInfo, List<IChangeInfo>> Revert(Document target)
+    {
+        return new None();
+    }
+}

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

@@ -1036,5 +1036,6 @@
   "AUTOSAVE_OPEN_FOLDER": "Open autosave folder",
   "AUTOSAVE_OPEN_FOLDER": "Open autosave folder",
    "AUTOSAVE_OPEN_FOLDER_DESCRIPTIVE": "Open the folder where autosaves are stored",
    "AUTOSAVE_OPEN_FOLDER_DESCRIPTIVE": "Open the folder where autosaves are stored",
   "AUTOSAVE_TOGGLE_DESCRIPTIVE": "Enable/disable autosave",
   "AUTOSAVE_TOGGLE_DESCRIPTIVE": "Enable/disable autosave",
-  "ERROR_GRAPH": "Graph Setup produced an error. Fix it the node graph"
+  "ERROR_GRAPH": "Graph Setup produced an error. Fix it the node graph",
+  "COLOR_MATRIX_FILTER_NODE": "Color Matrix Filter"
 }
 }

+ 35 - 0
src/PixiEditor/Models/DocumentModels/DocumentUpdater.cs

@@ -23,6 +23,7 @@ using PixiEditor.Models.DocumentPassthroughActions;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Layers;
 using Drawie.Numerics;
 using Drawie.Numerics;
+using PixiEditor.ChangeableDocument.Changeables.Graph.Context;
 using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.Dialogs;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors.Features;
 using PixiEditor.Models.DocumentModels.UpdateableChangeExecutors.Features;
 using PixiEditor.ViewModels.Document;
 using PixiEditor.ViewModels.Document;
@@ -223,6 +224,9 @@ internal class DocumentUpdater
             case MarkAsAutosaved_PassthroughAction info:
             case MarkAsAutosaved_PassthroughAction info:
                 MarkAsAutosaved(info);
                 MarkAsAutosaved(info);
                 break;
                 break;
+            case ComputedPropertyValue_ChangeInfo info:
+                ProcessComputedPropertyValue(info);
+                break;
         }
         }
     }
     }
 
 
@@ -871,4 +875,35 @@ internal class DocumentUpdater
     {
     {
         doc.InternalMarkSaveState(info.Type);
         doc.InternalMarkSaveState(info.Type);
     }
     }
+
+    private void ProcessComputedPropertyValue(ComputedPropertyValue_ChangeInfo info)
+    {
+        object finalValue = info.Value;
+        if (info.Value != null && !info.Value.GetType().IsValueType && info.Value is not string)
+        {
+            bool valueToStringIsDefault = info.Value.GetType().FullName == info.Value.ToString();
+            if (valueToStringIsDefault)
+            {
+                finalValue = info.Value?.GetType().Name ?? finalValue;
+            }
+        }
+
+        NodeViewModel node = doc.StructureHelper.FindNode<NodeViewModel>(info.Node);
+        INodePropertyHandler property;
+        if (info.IsInput)
+        {
+            property = node.FindInputProperty(info.PropertyName);
+        }
+        else
+        {
+            property = node.FindOutputProperty(info.PropertyName);
+        }
+
+        if (property is null)
+        {
+            return;
+        }
+
+        property.InternalSetComputedValue(finalValue);
+    }
 }
 }

+ 1 - 0
src/PixiEditor/Models/Handlers/INodeGraphHandler.cs

@@ -21,4 +21,5 @@ internal interface INodeGraphHandler
    public void RemoveConnection(Guid nodeId, string property);
    public void RemoveConnection(Guid nodeId, string property);
    public void RemoveConnections(Guid nodeId);
    public void RemoveConnections(Guid nodeId);
    public void UpdateAvailableRenderOutputs();
    public void UpdateAvailableRenderOutputs();
+   public void GetComputedPropertyValue(INodePropertyHandler property);
 }
 }

+ 3 - 0
src/PixiEditor/Models/Handlers/INodePropertyHandler.cs

@@ -9,6 +9,7 @@ public interface INodePropertyHandler
     public string PropertyName { get; set; }
     public string PropertyName { get; set; }
     public string DisplayName { get; set; }
     public string DisplayName { get; set; }
     public object Value { get; set; }
     public object Value { get; set; }
+    public object ComputedValue { get; set; }
     public bool IsInput { get; }
     public bool IsInput { get; }
     public INodePropertyHandler? ConnectedOutput { get; set; }
     public INodePropertyHandler? ConnectedOutput { get; set; }
     public ObservableCollection<INodePropertyHandler> ConnectedInputs { get; }
     public ObservableCollection<INodePropertyHandler> ConnectedInputs { get; }
@@ -16,4 +17,6 @@ public interface INodePropertyHandler
     public event NodePropertyValueChanged ValueChanged;
     public event NodePropertyValueChanged ValueChanged;
     public INodeHandler Node { get; set; }
     public INodeHandler Node { get; set; }
     public Type PropertyType { get; }
     public Type PropertyType { get; }
+    public void UpdateComputedValue();
+    public void InternalSetComputedValue(object value);
 }
 }

+ 2 - 0
src/PixiEditor/Styles/Templates/NodeSocket.axaml

@@ -7,11 +7,13 @@
                 <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                 <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                     <Grid Name="PART_ConnectPort">
                     <Grid Name="PART_ConnectPort">
                         <Panel Width="20" Height="20" Margin="-5, 0" Background="Transparent"
                         <Panel Width="20" Height="20" Margin="-5, 0" Background="Transparent"
+                               ToolTip.ShowDelay="0" ToolTip.ShowOnDisabled="True" ToolTip.Tip="{Binding Property.ComputedValue, RelativeSource={RelativeSource TemplatedParent}}"
                                IsVisible="{Binding !IsFunc, RelativeSource={RelativeSource TemplatedParent}}">
                                IsVisible="{Binding !IsFunc, RelativeSource={RelativeSource TemplatedParent}}">
                             <Ellipse Width="10" Height="10" RenderTransform="rotate(90deg)"
                             <Ellipse Width="10" Height="10" RenderTransform="rotate(90deg)"
                                      Fill="{TemplateBinding SocketBrush}" />
                                      Fill="{TemplateBinding SocketBrush}" />
                         </Panel>
                         </Panel>
                         <Panel Margin="-5, 0" Width="20" Height="20" Background="Transparent"
                         <Panel Margin="-5, 0" Width="20" Height="20" Background="Transparent"
+                               ToolTip.ShowDelay="0" ToolTip.ShowOnDisabled="True" ToolTip.Tip="{Binding Property.ComputedValue, RelativeSource={RelativeSource TemplatedParent}}"
                                IsVisible="{Binding IsFunc, RelativeSource={RelativeSource TemplatedParent}}">
                                IsVisible="{Binding IsFunc, RelativeSource={RelativeSource TemplatedParent}}">
                             <Rectangle Width="10" Height="10"
                             <Rectangle Width="10" Height="10"
                                        RadiusX="2" RadiusY="2"
                                        RadiusX="2" RadiusY="2"

+ 5 - 0
src/PixiEditor/ViewModels/Document/NodeGraphViewModel.cs

@@ -223,6 +223,11 @@ internal class NodeGraphViewModel : ViewModelBase, INodeGraphHandler, IDisposabl
         Internals.ActionAccumulator.AddFinishedActions(new UpdatePropertyValue_Action(node.Id, property, value));
         Internals.ActionAccumulator.AddFinishedActions(new UpdatePropertyValue_Action(node.Id, property, value));
     }
     }
 
 
+    public void GetComputedPropertyValue(INodePropertyHandler property)
+    {
+        Internals.ActionAccumulator.AddFinishedActions(new GetComputedPropertyValue_Action(property.Node.Id, property.PropertyName, property.IsInput));
+    }
+
     public void EndChangeNodePosition()
     public void EndChangeNodePosition()
     {
     {
         Internals.ActionAccumulator.AddFinishedActions(new EndNodePosition_Action());
         Internals.ActionAccumulator.AddFinishedActions(new EndNodePosition_Action());

+ 25 - 4
src/PixiEditor/ViewModels/Nodes/NodePropertyViewModel.cs

@@ -1,10 +1,7 @@
 using System.Collections.ObjectModel;
 using System.Collections.ObjectModel;
 using Avalonia;
 using Avalonia;
 using Avalonia.Media;
 using Avalonia.Media;
-using Avalonia.Styling;
-using Avalonia.Threading;
 using Drawie.Backend.Core.Shaders.Generation;
 using Drawie.Backend.Core.Shaders.Generation;
-using PixiEditor.Models.DocumentModels;
 using PixiEditor.Models.Events;
 using PixiEditor.Models.Events;
 using PixiEditor.Models.Handlers;
 using PixiEditor.Models.Handlers;
 using PixiEditor.ViewModels.Nodes.Properties;
 using PixiEditor.ViewModels.Nodes.Properties;
@@ -23,6 +20,8 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
     private IBrush socketBrush;
     private IBrush socketBrush;
     private string errors = string.Empty;
     private string errors = string.Empty;
 
 
+    private object computedValue;
+
     private ObservableCollection<INodePropertyHandler> connectedInputs = new();
     private ObservableCollection<INodePropertyHandler> connectedInputs = new();
     private INodePropertyHandler? connectedOutput;
     private INodePropertyHandler? connectedOutput;
 
 
@@ -41,13 +40,25 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
         {
         {
             var oldValue = _value;
             var oldValue = _value;
             ViewModelMain.Current.NodeGraphManager.UpdatePropertyValue((node, PropertyName, value));
             ViewModelMain.Current.NodeGraphManager.UpdatePropertyValue((node, PropertyName, value));
-            if(SetProperty(ref _value, value))
+            if (SetProperty(ref _value, value))
             {
             {
                 ValueChanged?.Invoke(this, new NodePropertyValueChangedArgs(oldValue, value));
                 ValueChanged?.Invoke(this, new NodePropertyValueChangedArgs(oldValue, value));
             }
             }
         }
         }
     }
     }
 
 
+    public object ComputedValue
+    {
+        get
+        {
+            return computedValue;
+        }
+        set
+        {
+            SetProperty(ref computedValue, value);
+        }
+    }
+
     public bool IsInput
     public bool IsInput
     {
     {
         get => isInput;
         get => isInput;
@@ -184,6 +195,16 @@ internal abstract class NodePropertyViewModel : ViewModelBase, INodePropertyHand
         return (NodePropertyViewModel)Activator.CreateInstance(viewModelType, node, type);
         return (NodePropertyViewModel)Activator.CreateInstance(viewModelType, node, type);
     }
     }
 
 
+    public void UpdateComputedValue()
+    {
+        ViewModelMain.Current.NodeGraphManager.GetComputedPropertyValue(this);
+    }
+
+    public void InternalSetComputedValue(object value)
+    {
+        computedValue = value;
+        OnPropertyChanged(nameof(ComputedValue));
+    }
 
 
     public void InternalSetValue(object? value)
     public void InternalSetValue(object? value)
     {
     {

+ 6 - 0
src/PixiEditor/ViewModels/SubViewModels/NodeGraphManagerViewModel.cs

@@ -90,4 +90,10 @@ internal class NodeGraphManagerViewModel : SubViewModel<ViewModelMain>
     {
     {
         Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.EndChangeNodePosition();
         Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.EndChangeNodePosition();
     }
     }
+
+    [Command.Internal("PixiEditor.NodeGraph.GetComputedPropertyValue")]
+    public void GetComputedPropertyValue(INodePropertyHandler property)
+    {
+        Owner.DocumentManagerSubViewModel.ActiveDocument?.NodeGraph.GetComputedPropertyValue(property);
+    }
 }
 }

+ 7 - 0
src/PixiEditor/Views/Nodes/Properties/NodeSocket.cs

@@ -52,6 +52,8 @@ public class NodeSocket : TemplatedControl
         ConnectPort.PointerPressed += ConnectPortOnPointerPressed;
         ConnectPort.PointerPressed += ConnectPortOnPointerPressed;
         ConnectPort.PointerReleased += ConnectPortOnPointerReleased;
         ConnectPort.PointerReleased += ConnectPortOnPointerReleased;
         ConnectPort.PointerMoved += ConnectPortOnPointerMoved;
         ConnectPort.PointerMoved += ConnectPortOnPointerMoved;
+        ConnectPort.PointerEntered += ConnectPortOnPointerEntered;
+
     }
     }
 
 
     private void ConnectPortOnPointerPressed(object? sender, PointerPressedEventArgs e)
     private void ConnectPortOnPointerPressed(object? sender, PointerPressedEventArgs e)
@@ -70,5 +72,10 @@ public class NodeSocket : TemplatedControl
         e.Source = this;
         e.Source = this;
         e.Pointer.Capture(null);
         e.Pointer.Capture(null);
     }
     }
+
+    private void ConnectPortOnPointerEntered(object? sender, PointerEventArgs e)
+    {
+        Property.UpdateComputedValue();
+    }
 }
 }