From 499d187c96f57efb8d5fbf206a99773f42b11344 Mon Sep 17 00:00:00 2001 From: Chromium <62724067+Chromum@users.noreply.github.com> Date: Sun, 27 Apr 2025 20:05:39 +0100 Subject: [PATCH] Made outline around errored node as well as fixed NativeArray on texture import being disposed --- Editor/Scripts/Editor/Data Types/IPTPort.cs | 3 ++ Editor/Scripts/Editor/Data Types/ImageData.cs | 6 ++- .../Editor/ImageProcessingGraphAsset.cs | 15 ++++++- .../Editor/Nodes/Base/BaseImageNode.cs | 21 ++++++++-- .../Nodes/Types/Image/Channels/RGBASplit.cs | 4 +- .../Types/Image/Export/Texture2DOutput.cs | 2 +- .../Image/Utilities/SingleChannelColor.cs | 4 +- .../Windows/ImageProcessingGraphNodeVisual.cs | 42 +++++++++++++++---- .../Windows/ImageProcessingGraphViewWindow.cs | 27 ++++++++++-- Node.uss | 7 ++++ Node.uss.meta | 3 ++ 11 files changed, 110 insertions(+), 24 deletions(-) create mode 100644 Node.uss create mode 100644 Node.uss.meta diff --git a/Editor/Scripts/Editor/Data Types/IPTPort.cs b/Editor/Scripts/Editor/Data Types/IPTPort.cs index 9e93b40..2cfdb0c 100644 --- a/Editor/Scripts/Editor/Data Types/IPTPort.cs +++ b/Editor/Scripts/Editor/Data Types/IPTPort.cs @@ -1,4 +1,5 @@ using System; +using System.Reflection; using UnityEditor.Experimental.GraphView; using UnityEngine.UIElements; @@ -6,6 +7,8 @@ namespace ImageProcessingGraph.Editor { public class IPTPort : Port { + public FieldInfo fieldInfo; + protected IPTPort(Orientation portOrientation, Direction portDirection, Capacity portCapacity, Type type) : base(portOrientation, portDirection, portCapacity, type) { diff --git a/Editor/Scripts/Editor/Data Types/ImageData.cs b/Editor/Scripts/Editor/Data Types/ImageData.cs index 53d7ae8..4670507 100644 --- a/Editor/Scripts/Editor/Data Types/ImageData.cs +++ b/Editor/Scripts/Editor/Data Types/ImageData.cs @@ -37,7 +37,7 @@ public struct ImageData /// The source texture to extract pixel data from. public ImageData(Texture2D sourceTexture) { - PixelData = sourceTexture.GetPixelData(0); + PixelData = new NativeArray(sourceTexture.GetPixelData(0), Allocator.Persistent); Dimensions = (sourceTexture.width, sourceTexture.height); isRGBA = sourceTexture.format == TextureFormat.RGBA32; } @@ -70,7 +70,7 @@ public struct ImageData byte[] data = texture.EncodeToPNG(); string thePath; - if (path.StartsWith("Assets\\")) + if (path.StartsWith("Assets/")) { thePath = path.Substring("Assets/".Length); } @@ -79,6 +79,8 @@ public struct ImageData thePath = path; } + thePath.Replace("/", "\\"); + if (data != null) { System.IO.File.WriteAllBytes(Path.Combine(Application.dataPath, thePath), data); diff --git a/Editor/Scripts/Editor/ImageProcessingGraphAsset.cs b/Editor/Scripts/Editor/ImageProcessingGraphAsset.cs index 176b7b7..0c43cf0 100644 --- a/Editor/Scripts/Editor/ImageProcessingGraphAsset.cs +++ b/Editor/Scripts/Editor/ImageProcessingGraphAsset.cs @@ -21,6 +21,11 @@ namespace ImageProcessingGraph.Editor public List Nodes => nodes; public List Connections => connections; + + public delegate void OnRunEvent(); + public event OnRunEvent OnRun; + public OnRunEvent OnRunEnd; + public ImageProcessingGraphAsset() { nodes = new List(); @@ -42,6 +47,8 @@ namespace ImageProcessingGraph.Editor public void RunGraph() { + OnRun?.Invoke(); + // Create and start the stopwatch to measure time Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); @@ -49,9 +56,15 @@ namespace ImageProcessingGraph.Editor if (runOrder == null) runOrder = GetExecutionOrder(this.nodes, this.connections); + bool failed = false; + foreach (var VARIABLE in runOrder) { - VARIABLE.RunNode(); + if (!VARIABLE.RunNode()) + { + failed = true; + break; + } } // Stop the stopwatch after running the nodes diff --git a/Editor/Scripts/Editor/Nodes/Base/BaseImageNode.cs b/Editor/Scripts/Editor/Nodes/Base/BaseImageNode.cs index 3325d43..7271ceb 100644 --- a/Editor/Scripts/Editor/Nodes/Base/BaseImageNode.cs +++ b/Editor/Scripts/Editor/Nodes/Base/BaseImageNode.cs @@ -26,10 +26,13 @@ namespace ImageProcessingGraph.Editor public ImageProcessingGraphAsset asset; + public delegate void OnFailed(); + public event OnFailed onFailed; + public BaseImageNode() { guid = Guid.NewGuid().ToString(); - + /*Type t = this.GetType(); Debug.Log(t.Name);*/ } @@ -101,10 +104,20 @@ namespace ImageProcessingGraph.Editor } - public void RunNode() + public bool RunNode() { - SetNodeInputs(); - this.Process(); + try + { + SetNodeInputs(); + this.Process(); + return true; + } + catch (Exception e) + { + onFailed?.Invoke(); + Debug.LogError(e); + return false; + } } public virtual void Process() diff --git a/Editor/Scripts/Editor/Nodes/Types/Image/Channels/RGBASplit.cs b/Editor/Scripts/Editor/Nodes/Types/Image/Channels/RGBASplit.cs index d1dca6f..958b1ba 100644 --- a/Editor/Scripts/Editor/Nodes/Types/Image/Channels/RGBASplit.cs +++ b/Editor/Scripts/Editor/Nodes/Types/Image/Channels/RGBASplit.cs @@ -23,10 +23,10 @@ namespace ImageProcessingGraph.Editor.Nodes.Fun_Nodes.Texture public override void Process() { - int length = inputTexture.PixelData.Length; + int length = inputTexture.PixelData.Length;; // Allocate NativeArrays for the pixel data and the individual RGBA channels - NativeArray pixelData = new NativeArray(inputTexture.PixelData, Allocator.Persistent); + NativeArray pixelData = inputTexture.PixelData; NativeArray rChannel = new NativeArray(length, Allocator.Persistent); NativeArray gChannel = new NativeArray(length, Allocator.Persistent); NativeArray bChannel = new NativeArray(length, Allocator.Persistent); diff --git a/Editor/Scripts/Editor/Nodes/Types/Image/Export/Texture2DOutput.cs b/Editor/Scripts/Editor/Nodes/Types/Image/Export/Texture2DOutput.cs index 0f6029d..2d224f2 100644 --- a/Editor/Scripts/Editor/Nodes/Types/Image/Export/Texture2DOutput.cs +++ b/Editor/Scripts/Editor/Nodes/Types/Image/Export/Texture2DOutput.cs @@ -6,7 +6,7 @@ using UnityEngine; namespace ImageProcessingGraph.Editor.Nodes.Output { - [NodeInfo("Texture Export", "Export/Texture2D", true)] + [NodeInfo("Texture Export", "Export/Export Texture", true)] public class Texture2DOutput : BaseImageNode { [NodeAttributes.Input("")] public ImageData inputPixels; diff --git a/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/SingleChannelColor.cs b/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/SingleChannelColor.cs index 3b3c5ab..efce42c 100644 --- a/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/SingleChannelColor.cs +++ b/Editor/Scripts/Editor/Nodes/Types/Image/Utilities/SingleChannelColor.cs @@ -23,7 +23,7 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities { int pixelCount = Width * Height; - NativeArray outputData = new NativeArray(pixelCount * 4, Allocator.TempJob); + NativeArray outputData = new NativeArray(pixelCount * 4, Allocator.Persistent); CreateSingleColorJob job = new CreateSingleColorJob { @@ -36,8 +36,6 @@ namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities job.Run(); OutputColor = new SplitChannelData(outputData.ToArray(), (Width, Height)); - - outputData.Dispose(); } [BurstCompile] diff --git a/Editor/Scripts/Editor/Windows/ImageProcessingGraphNodeVisual.cs b/Editor/Scripts/Editor/Windows/ImageProcessingGraphNodeVisual.cs index 342a163..027c9c2 100644 --- a/Editor/Scripts/Editor/Windows/ImageProcessingGraphNodeVisual.cs +++ b/Editor/Scripts/Editor/Windows/ImageProcessingGraphNodeVisual.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; using ImageProcessingGraph.Editor.Nodes.NodeAttributes; +using UnityEditor; using UnityEditor.Experimental.GraphView; using UnityEditor.UIElements; using UnityEngine; @@ -21,6 +22,8 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind private ImageProcessingGraphViewWindow window; + private StyleSheet errorStyleSheet; + public ImageProcessingGraphNodeVisual(BaseImageNode node, ImageProcessingGraphViewWindow window) { this.AddToClassList("image-node-visual"); @@ -62,9 +65,27 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind } } - + CreateInputPorts(inputFieldInfo); CreateOutputPorts(outputFieldInfo); + + errorStyleSheet = AssetDatabase.LoadAssetAtPath("Assets/Unity Image Processing/Node.uss"); + if (errorStyleSheet == null) + { + errorStyleSheet = EditorGUIUtility.Load("Packages/com.chromium.imageprocessingrah/Node.uss") as StyleSheet; + } + + graphNode.onFailed += () => + { + styleSheets.Add(errorStyleSheet); + }; + + window.asset.OnRun += () => + { + if (styleSheets.Contains(errorStyleSheet)) + styleSheets.Remove(errorStyleSheet); + }; + this.name = typeInfo.Name; } @@ -74,10 +95,6 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind for (var index = 0; index < fields.Count; index++) { var field = fields[index]; - /* - Port port = InstantiatePort(Orientation.Horizontal, Direction.Input, Port.Capacity.Multi, field.FieldType); - */ - var port = IPTPort.Create(window.edgeConnectorListener, true, field.FieldType); string label = field.GetCustomAttribute().Label; @@ -87,7 +104,8 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind inputContainer.Add(port); ExposeVariableToPort(port, field); - + port.fieldInfo = field; + } } @@ -102,13 +120,14 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind if (label != "") port.portName = label; OutputPorts.Add(port); - outputContainer.Add(port); + + port.fieldInfo = field; } } // Exposes a variable on the port for editing when it's not connected - private void ExposeVariableToPort(Port port, FieldInfo field) + public void ExposeVariableToPort(Port port, FieldInfo field) { // Only expose when the port is not connected if (port.connections.Count() == 0) @@ -207,6 +226,13 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind else { // If the port is connected, remove the exposed UI element + List children = new List(); + + foreach (var child in port.Children()) + { + children.Add(child); + } + var existingPropertyFieldContainer = port.Q("property-field-container"); if (existingPropertyFieldContainer != null) { diff --git a/Editor/Scripts/Editor/Windows/ImageProcessingGraphViewWindow.cs b/Editor/Scripts/Editor/Windows/ImageProcessingGraphViewWindow.cs index 573dafa..9fc4930 100644 --- a/Editor/Scripts/Editor/Windows/ImageProcessingGraphViewWindow.cs +++ b/Editor/Scripts/Editor/Windows/ImageProcessingGraphViewWindow.cs @@ -290,15 +290,34 @@ namespace ImageProcessingGraph.Editor GraphConnection connection = new GraphConnection(inputNode.GraphNode.ID,inputIndex, inputType,outputNode.GraphNode.ID, outputIndex, outputType, edge); + edge.output.Connect(edge); + edge.input.Connect(edge); + + IPTPort portIn = (IPTPort)edge.output; + IPTPort portOut = (IPTPort)edge.output; + + if (portIn.fieldInfo != null) + inputNode.ExposeVariableToPort(edge.input, portOut.fieldInfo); + asset.Connections.Add(connection); } - private void RemoveEdge(Edge variable) + private void RemoveEdge(Edge edge) { - if (connectionDictionary.TryGetValue(variable, out GraphConnection connection)) + if (connectionDictionary.TryGetValue(edge, out GraphConnection connection)) { asset.Connections.Remove(connection); - connectionDictionary.Remove(variable); + connectionDictionary.Remove(edge); + + edge.output.Disconnect(edge); + edge.input.Disconnect(edge); + + ImageProcessingGraphNodeVisual inputNode = (ImageProcessingGraphNodeVisual)edge.input.node; + + IPTPort portIn = (IPTPort)edge.input; + + if(portIn.fieldInfo != null) + inputNode.ExposeVariableToPort(edge.input, portIn.fieldInfo); } } @@ -319,6 +338,8 @@ namespace ImageProcessingGraph.Editor Edge edge = inPort.ConnectTo(outPort); AddElement(edge); connectionDictionary.Add(edge, conn); + + } } diff --git a/Node.uss b/Node.uss new file mode 100644 index 0000000..7364771 --- /dev/null +++ b/Node.uss @@ -0,0 +1,7 @@ +#node-border +{ + border-bottom-color: red; + border-left-color: red; + border-right-color: red; + border-top-color: red; +} \ No newline at end of file diff --git a/Node.uss.meta b/Node.uss.meta new file mode 100644 index 0000000..641a61e --- /dev/null +++ b/Node.uss.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f213bce165884ca7ae5d567d6bb7f3cb +timeCreated: 1745777804 \ No newline at end of file