Compare commits
8 Commits
NewSearchW
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
8e8a996812 | ||
|
c56311277c | ||
|
20818926de | ||
|
e60d3604c0 | ||
|
05600f7bc1 | ||
|
b1b129c8c1 | ||
|
a3d79f09b2 | ||
|
4cd9878a97 |
@ -10,6 +10,13 @@ namespace ImageProcessingGraph.Editor
|
|||||||
{
|
{
|
||||||
public FieldInfo fieldInfo;
|
public FieldInfo fieldInfo;
|
||||||
private VisualElement _exposedPropertyContainer;
|
private VisualElement _exposedPropertyContainer;
|
||||||
|
|
||||||
|
public delegate void OnPortConnectedEvent();
|
||||||
|
public OnPortConnectedEvent OnPortConnected;
|
||||||
|
|
||||||
|
public delegate void OnPortDisconnectedEvent();
|
||||||
|
public OnPortDisconnectedEvent OnPortDisconnected;
|
||||||
|
|
||||||
public VisualElement ExposedPropertyContainer
|
public VisualElement ExposedPropertyContainer
|
||||||
{
|
{
|
||||||
set
|
set
|
||||||
@ -27,6 +34,24 @@ namespace ImageProcessingGraph.Editor
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void Connect(Edge edge)
|
||||||
|
{
|
||||||
|
base.Connect(edge);
|
||||||
|
OnPortConnected?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Disconnect(Edge edge)
|
||||||
|
{
|
||||||
|
base.Disconnect(edge);
|
||||||
|
OnPortDisconnected?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void PublicOnConnected(Port obj)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
public static IPTPort Create(IEdgeConnectorListener connectorListener, bool isInput, Type type)
|
public static IPTPort Create(IEdgeConnectorListener connectorListener, bool isInput, Type type)
|
||||||
{
|
{
|
||||||
var port = new IPTPort(Orientation.Horizontal, isInput ? Direction.Input : Direction.Output,
|
var port = new IPTPort(Orientation.Horizontal, isInput ? Direction.Input : Direction.Output,
|
||||||
|
@ -53,8 +53,7 @@ namespace ImageProcessingGraph.Editor
|
|||||||
Stopwatch stopwatch = new Stopwatch();
|
Stopwatch stopwatch = new Stopwatch();
|
||||||
stopwatch.Start();
|
stopwatch.Start();
|
||||||
|
|
||||||
if (runOrder == null)
|
runOrder = GetExecutionOrder(this.nodes, this.connections);
|
||||||
runOrder = GetExecutionOrder(this.nodes, this.connections);
|
|
||||||
|
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
|
|
||||||
@ -67,6 +66,12 @@ namespace ImageProcessingGraph.Editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach (var VARIABLE in runOrder)
|
||||||
|
{
|
||||||
|
if(!VARIABLE.RunCleanUp())
|
||||||
|
failed = true;
|
||||||
|
}
|
||||||
|
|
||||||
// Stop the stopwatch after running the nodes
|
// Stop the stopwatch after running the nodes
|
||||||
stopwatch.Stop();
|
stopwatch.Stop();
|
||||||
|
|
||||||
|
@ -125,6 +125,26 @@ namespace ImageProcessingGraph.Editor
|
|||||||
Debug.Log("Uppies");
|
Debug.Log("Uppies");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool RunCleanUp()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this.CleanUp();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
onFailed?.Invoke();
|
||||||
|
Debug.LogError(e);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void CleanUp()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void SetPosition(Rect position) => this.position = position;
|
public void SetPosition(Rect position) => this.position = position;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
using System;
|
using System;
|
||||||
|
#if UNITY_2022_1_OR_NEWER
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
#else
|
||||||
|
using UnityEditor.UIElements;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
namespace ImageProcessingGraph.Editor
|
namespace ImageProcessingGraph.Editor
|
||||||
{
|
{
|
||||||
@ -20,4 +25,5 @@ namespace ImageProcessingGraph.Editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows;
|
||||||
|
|
||||||
namespace ImageProcessingGraph.Editor.Nodes.NodeAttributes
|
namespace ImageProcessingGraph.Editor.Nodes.NodeAttributes
|
||||||
{
|
{
|
||||||
@ -8,16 +9,19 @@ namespace ImageProcessingGraph.Editor.Nodes.NodeAttributes
|
|||||||
private string name;
|
private string name;
|
||||||
private string menuItem;
|
private string menuItem;
|
||||||
private string ussPath;
|
private string ussPath;
|
||||||
|
private Type editorType;
|
||||||
|
|
||||||
public string Title => name;
|
public string Title => name;
|
||||||
public string MenuItem => menuItem;
|
public string MenuItem => menuItem;
|
||||||
public string UssPath => ussPath;
|
public string UssPath => ussPath;
|
||||||
|
public Type EditorType => editorType;
|
||||||
|
|
||||||
public NodeInfoAttribute(string name, string menuItem = "", bool requiresImage = false, string ussPath = null)
|
public NodeInfoAttribute(string name, string menuItem = "", bool requiresImage = false, string ussPath = null, Type editorType = null)
|
||||||
{
|
{
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.menuItem = menuItem;
|
this.menuItem = menuItem;
|
||||||
this.ussPath = ussPath;
|
this.ussPath = ussPath;
|
||||||
|
this.editorType = editorType;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6,12 +6,12 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace ImageProcessingGraph.Editor.Nodes.Output
|
namespace ImageProcessingGraph.Editor.Nodes.Output
|
||||||
{
|
{
|
||||||
[NodeInfo("Texture Export", "Export/Export Texture", true)]
|
[NodeInfo("Texture Export", "Export/Texture Export", true)]
|
||||||
public class Texture2DOutput : BaseImageNode
|
public class Texture2DOutput : BaseImageNode
|
||||||
{
|
{
|
||||||
[NodeAttributes.Input("")] public ImageData inputPixels;
|
[NodeAttributes.Input("")] public ImageData inputPixels;
|
||||||
[NodeAttributes.Input("File Name")] public string fileName;
|
[NodeAttributes.Input("File Name")] public string fileName;
|
||||||
[NodeAttributes.Input("File Path")] public string fileDirectory;
|
[NodeAttributes.Input("File Directory")] public string fileDirectory;
|
||||||
|
|
||||||
public enum ExportType
|
public enum ExportType
|
||||||
{
|
{
|
||||||
@ -20,16 +20,36 @@ namespace ImageProcessingGraph.Editor.Nodes.Output
|
|||||||
}
|
}
|
||||||
|
|
||||||
[NodeAttributes.Input("Export Type")] public ExportType exportType;
|
[NodeAttributes.Input("Export Type")] public ExportType exportType;
|
||||||
|
[NodeAttributes.Input("Texture Type")] public TextureImporterType textureType;
|
||||||
|
|
||||||
|
[NodeAttributes.Output("Output Texture")] public Texture2D textureOutput;
|
||||||
|
|
||||||
public override void Process()
|
public override void Process()
|
||||||
{
|
{
|
||||||
|
|
||||||
switch (exportType)
|
switch (exportType)
|
||||||
{
|
{
|
||||||
case ExportType.Texture2D:
|
case ExportType.Texture2D:
|
||||||
AssetDatabase.CreateAsset(inputPixels.ToTexture2D(), $"{fileDirectory}/{fileName}.asset");
|
string pathT2D = $"{fileDirectory}/{fileName}.asset";
|
||||||
|
AssetDatabase.CreateAsset(inputPixels.ToTexture2D(), pathT2D);
|
||||||
|
textureOutput = AssetDatabase.LoadAssetAtPath<Texture2D>(pathT2D);
|
||||||
break;
|
break;
|
||||||
case ExportType.PNG:
|
case ExportType.PNG:
|
||||||
inputPixels.ExportPNG($"{fileDirectory}/{fileName}.png");
|
string pathPNG = $"{fileDirectory}/{fileName}.png";
|
||||||
|
inputPixels.ExportPNG(pathPNG);
|
||||||
|
|
||||||
|
AssetDatabase.ImportAsset(pathPNG);
|
||||||
|
|
||||||
|
TextureImporter textureImporter = AssetImporter.GetAtPath(pathPNG) as TextureImporter;
|
||||||
|
if (textureImporter != null)
|
||||||
|
{
|
||||||
|
textureImporter.textureType = textureType;
|
||||||
|
EditorUtility.SetDirty(AssetDatabase.LoadAssetAtPath<Texture2D>(pathPNG));
|
||||||
|
textureImporter.SaveAndReimport();
|
||||||
|
}
|
||||||
|
AssetDatabase.ImportAsset(pathPNG);
|
||||||
|
|
||||||
|
textureOutput = AssetDatabase.LoadAssetAtPath<Texture2D>(pathPNG);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace ImageProcessingGraph.Editor.Nodes.Import_Nodes
|
namespace ImageProcessingGraph.Editor.Nodes.Import_Nodes
|
||||||
{
|
{
|
||||||
[NodeInfo("Texture Import", "Imports/Import Texture", true)]
|
[NodeInfo("Texture Import", "Imports/Import Texture")]
|
||||||
public class Texture2DImport : BaseImageNode
|
public class Texture2DImport : BaseImageNode
|
||||||
{
|
{
|
||||||
[NodeAttributes.Input("")]
|
[NodeAttributes.Input("")]
|
||||||
@ -16,7 +16,7 @@ namespace ImageProcessingGraph.Editor.Nodes.Import_Nodes
|
|||||||
public ImageData textureOutput;
|
public ImageData textureOutput;
|
||||||
[NodeAttributes.Output("File Name")]
|
[NodeAttributes.Output("File Name")]
|
||||||
public string fileName;
|
public string fileName;
|
||||||
[NodeAttributes.Output("File Path")]
|
[NodeAttributes.Output("File Directory")]
|
||||||
public string filePath;
|
public string filePath;
|
||||||
|
|
||||||
public override void Process()
|
public override void Process()
|
||||||
@ -42,8 +42,8 @@ namespace ImageProcessingGraph.Editor.Nodes.Import_Nodes
|
|||||||
this.fileName = textureImport.name;
|
this.fileName = textureImport.name;
|
||||||
this.filePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(textureImport));
|
this.filePath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(textureImport));
|
||||||
}
|
}
|
||||||
else
|
// else
|
||||||
Debug.LogError("UH!");
|
// Debug.LogError("UH!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b462f37a291b49a696e3b4b554d26868
|
||||||
|
timeCreated: 1745899248
|
@ -0,0 +1,135 @@
|
|||||||
|
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
|
||||||
|
using UnityEngine;
|
||||||
|
using Unity.Collections;
|
||||||
|
using Unity.Jobs;
|
||||||
|
using Unity.Burst;
|
||||||
|
|
||||||
|
namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode
|
||||||
|
{
|
||||||
|
[NodeInfo("View Texture", "Utility/View Texture", false, null , editorType: typeof(ViewTextureNodeEditor))]
|
||||||
|
public partial class ViewTextureNode : BaseImageNode
|
||||||
|
{
|
||||||
|
[NodeAttributes.Input("Texture")] public Texture2D texture;
|
||||||
|
[NodeAttributes.Input("Image Data")] public ImageData imageData;
|
||||||
|
|
||||||
|
public delegate void OnImageUpdated();
|
||||||
|
public OnImageUpdated onImageUpdated;
|
||||||
|
|
||||||
|
public Texture2D cachedRGB;
|
||||||
|
public Texture2D cachedR;
|
||||||
|
public Texture2D cachedG;
|
||||||
|
public Texture2D cachedB;
|
||||||
|
public Texture2D cachedA;
|
||||||
|
|
||||||
|
public override void Process()
|
||||||
|
{
|
||||||
|
if (texture == null)
|
||||||
|
{
|
||||||
|
texture = imageData.ToTexture2D();
|
||||||
|
}
|
||||||
|
|
||||||
|
GenerateChannelTextures(texture);
|
||||||
|
|
||||||
|
onImageUpdated?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CleanUp()
|
||||||
|
{
|
||||||
|
texture = null;
|
||||||
|
imageData = default;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void GenerateChannelTextures(Texture2D source)
|
||||||
|
{
|
||||||
|
var pixels = source.GetPixels();
|
||||||
|
int length = pixels.Length;
|
||||||
|
|
||||||
|
NativeArray<Color> inputPixels = new NativeArray<Color>(pixels, Allocator.TempJob);
|
||||||
|
|
||||||
|
NativeArray<Color> outputR = new NativeArray<Color>(length, Allocator.TempJob);
|
||||||
|
NativeArray<Color> outputG = new NativeArray<Color>(length, Allocator.TempJob);
|
||||||
|
NativeArray<Color> outputB = new NativeArray<Color>(length, Allocator.TempJob);
|
||||||
|
NativeArray<Color> outputA = new NativeArray<Color>(length, Allocator.TempJob);
|
||||||
|
|
||||||
|
var jobR = new ChannelJob(ChannelType.R, inputPixels, outputR);
|
||||||
|
var jobG = new ChannelJob(ChannelType.G, inputPixels, outputG);
|
||||||
|
var jobB = new ChannelJob(ChannelType.B, inputPixels, outputB);
|
||||||
|
var jobA = new ChannelJob(ChannelType.A, inputPixels, outputA);
|
||||||
|
|
||||||
|
JobHandle handleR = jobR.Schedule(length, 64);
|
||||||
|
JobHandle handleG = jobG.Schedule(length, 64);
|
||||||
|
JobHandle handleB = jobB.Schedule(length, 64);
|
||||||
|
JobHandle handleA = jobA.Schedule(length, 64);
|
||||||
|
|
||||||
|
var handles = new NativeArray<JobHandle>(4, Allocator.Temp);
|
||||||
|
handles[0] = handleR;
|
||||||
|
handles[1] = handleG;
|
||||||
|
handles[2] = handleB;
|
||||||
|
handles[3] = handleA;
|
||||||
|
|
||||||
|
JobHandle.CompleteAll(handles);
|
||||||
|
handles.Dispose();
|
||||||
|
|
||||||
|
|
||||||
|
cachedRGB = source;
|
||||||
|
cachedR = CreateTexture(source.width, source.height, outputR);
|
||||||
|
cachedG = CreateTexture(source.width, source.height, outputG);
|
||||||
|
cachedB = CreateTexture(source.width, source.height, outputB);
|
||||||
|
cachedA = CreateTexture(source.width, source.height, outputA);
|
||||||
|
|
||||||
|
inputPixels.Dispose();
|
||||||
|
outputR.Dispose();
|
||||||
|
outputG.Dispose();
|
||||||
|
outputB.Dispose();
|
||||||
|
outputA.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Texture2D CreateTexture(int width, int height, NativeArray<Color> colors)
|
||||||
|
{
|
||||||
|
Texture2D tex = new Texture2D(width, height, TextureFormat.RGBA32, false);
|
||||||
|
tex.SetPixels(colors.ToArray());
|
||||||
|
tex.Apply();
|
||||||
|
return tex;
|
||||||
|
}
|
||||||
|
|
||||||
|
[BurstCompile]
|
||||||
|
private struct ChannelJob : IJobParallelFor
|
||||||
|
{
|
||||||
|
public ChannelType channelType;
|
||||||
|
[ReadOnly] public NativeArray<Color> input;
|
||||||
|
public NativeArray<Color> output;
|
||||||
|
|
||||||
|
public ChannelJob(ChannelType type, NativeArray<Color> input, NativeArray<Color> output)
|
||||||
|
{
|
||||||
|
this.channelType = type;
|
||||||
|
this.input = input;
|
||||||
|
this.output = output;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Execute(int index)
|
||||||
|
{
|
||||||
|
Color c = input[index];
|
||||||
|
switch (channelType)
|
||||||
|
{
|
||||||
|
case ChannelType.R:
|
||||||
|
output[index] = new Color(c.r, c.r, c.r, 1f);
|
||||||
|
break;
|
||||||
|
case ChannelType.G:
|
||||||
|
output[index] = new Color(c.g, c.g, c.g, 1f);
|
||||||
|
break;
|
||||||
|
case ChannelType.B:
|
||||||
|
output[index] = new Color(c.b, c.b, c.b, 1f);
|
||||||
|
break;
|
||||||
|
case ChannelType.A:
|
||||||
|
output[index] = new Color(c.a, c.a, c.a, 1f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ChannelType
|
||||||
|
{
|
||||||
|
R, G, B, A
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 461687d0e0d346ac9dd5960b76db7538
|
||||||
|
timeCreated: 1745899335
|
@ -0,0 +1,104 @@
|
|||||||
|
using ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
|
namespace ImageProcessingGraph.Editor.Nodes.Types.Image.Utilities.ViewNode
|
||||||
|
{
|
||||||
|
public class ViewTextureNodeEditor : ImageProcessingGraphNodeVisual
|
||||||
|
{
|
||||||
|
private UnityEngine.UIElements.Image viewableImage;
|
||||||
|
private Foldout foldout;
|
||||||
|
private VisualElement buttonRow;
|
||||||
|
|
||||||
|
public ViewTextureNodeEditor(BaseImageNode node, ImageProcessingGraphViewWindow window) : base(node, window)
|
||||||
|
{
|
||||||
|
//Port 0 is Texture2D
|
||||||
|
//Port 1 is ImageData
|
||||||
|
|
||||||
|
IPTPort tex2DPort = InputPorts[0] as IPTPort;
|
||||||
|
IPTPort imageDataPort = InputPorts[1] as IPTPort;
|
||||||
|
|
||||||
|
tex2DPort.OnPortConnected += () => { imageDataPort.style.display = DisplayStyle.None; };
|
||||||
|
|
||||||
|
tex2DPort.OnPortDisconnected += () => { imageDataPort.style.display = DisplayStyle.Flex; };
|
||||||
|
|
||||||
|
imageDataPort.OnPortConnected += () => { tex2DPort.style.display = DisplayStyle.None; };
|
||||||
|
|
||||||
|
imageDataPort.OnPortDisconnected += () => { tex2DPort.style.display = DisplayStyle.Flex; };
|
||||||
|
|
||||||
|
this.Q("output").style.display = DisplayStyle.None;
|
||||||
|
|
||||||
|
ViewTextureNode viewImageNode = node as ViewTextureNode;
|
||||||
|
|
||||||
|
foldout = new Foldout
|
||||||
|
{
|
||||||
|
text = "Texture Viewer",
|
||||||
|
value = true
|
||||||
|
};
|
||||||
|
foldout.style.backgroundColor = new Color(63f / 255f, 63f / 255f, 63f / 255f, 205f / 255f);
|
||||||
|
foldout.contentContainer.style.justifyContent = Justify.Center;
|
||||||
|
Add(foldout);
|
||||||
|
|
||||||
|
viewableImage = new UnityEngine.UIElements.Image
|
||||||
|
{
|
||||||
|
scaleMode = ScaleMode.ScaleToFit
|
||||||
|
};
|
||||||
|
viewableImage.style.width = 256;
|
||||||
|
viewableImage.style.height = 256;
|
||||||
|
viewableImage.style.backgroundColor = Color.black;
|
||||||
|
foldout.Add(viewableImage);
|
||||||
|
|
||||||
|
viewImageNode.onImageUpdated += () => { viewableImage.image = viewImageNode.texture; };
|
||||||
|
|
||||||
|
buttonRow = new VisualElement
|
||||||
|
{
|
||||||
|
style =
|
||||||
|
{
|
||||||
|
flexDirection = FlexDirection.Row,
|
||||||
|
justifyContent = Justify.SpaceBetween,
|
||||||
|
alignItems = Align.Center,
|
||||||
|
marginTop = 8,
|
||||||
|
marginBottom = 8,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
string[] channels = { "RGB", "R", "G", "B", "A" };
|
||||||
|
foreach (var channel in channels)
|
||||||
|
{
|
||||||
|
var btn = new Button(() => OnChannelClicked(viewImageNode, channel))
|
||||||
|
{
|
||||||
|
text = channel
|
||||||
|
};
|
||||||
|
btn.style.flexGrow = 1;
|
||||||
|
buttonRow.Add(btn);
|
||||||
|
}
|
||||||
|
|
||||||
|
foldout.Add(buttonRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnChannelClicked(ViewTextureNode viewNode, string channel)
|
||||||
|
{
|
||||||
|
switch (channel)
|
||||||
|
{
|
||||||
|
case "RGB":
|
||||||
|
viewableImage.image = viewNode.cachedRGB;
|
||||||
|
break;
|
||||||
|
case "R":
|
||||||
|
viewableImage.image = viewNode.cachedR;
|
||||||
|
break;
|
||||||
|
case "G":
|
||||||
|
viewableImage.image = viewNode.cachedG;
|
||||||
|
break;
|
||||||
|
case "B":
|
||||||
|
viewableImage.image = viewNode.cachedB;
|
||||||
|
break;
|
||||||
|
case "A":
|
||||||
|
viewableImage.image = viewNode.cachedA;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Debug.LogError("[ViewTextureNodeEditor] Unknown channel clicked! Did you hack reality again?");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 83fd847c22794f0a92efbecd18c528c0
|
||||||
|
timeCreated: 1745899443
|
@ -25,26 +25,25 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind
|
|||||||
|
|
||||||
public void OnDropOutsidePort(Edge edge, Vector2 position)
|
public void OnDropOutsidePort(Edge edge, Vector2 position)
|
||||||
{
|
{
|
||||||
// window.searchProvider.target = (VisualElement)window.focusController.focusedElement;
|
window.searchProvider.target = (VisualElement)window.focusController.focusedElement;
|
||||||
// SearchWindow.Open(new SearchWindowContext(position), window.searchProvider);
|
|
||||||
|
|
||||||
|
// ⚡ Override the search window open with a customized search tree
|
||||||
|
SearchWindow.Open(new SearchWindowContext(position), new ImageProcessingGraphSearchProvider.CustomSearchProviderForEdge(window.searchProvider, edge, (IPTPort)edge.input, (IPTPort)edge.output));
|
||||||
|
|
||||||
|
// Remove connections as you did
|
||||||
List<GraphConnection> connections = new List<GraphConnection>();
|
List<GraphConnection> connections = new List<GraphConnection>();
|
||||||
|
|
||||||
foreach (var conn in window.asset.Connections)
|
foreach (var conn in window.asset.Connections)
|
||||||
{
|
{
|
||||||
if (conn.internalEdge == edge)
|
if (conn.internalEdge == edge)
|
||||||
{
|
|
||||||
connections.Add(conn);
|
connections.Add(conn);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var VARIABLE in connections)
|
foreach (var VARIABLE in connections)
|
||||||
{
|
{
|
||||||
window.asset.Connections.Remove(VARIABLE);
|
window.asset.Connections.Remove(VARIABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(edge.input != null)
|
if (edge.input != null)
|
||||||
if(edge.input.node != null)
|
if (edge.input.node != null)
|
||||||
((ImageProcessingGraphNodeVisual)edge.input.node).ToggleExposedVariable((IPTPort)edge.input, true);
|
((ImageProcessingGraphNodeVisual)edge.input.node).ToggleExposedVariable((IPTPort)edge.input, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,23 +14,25 @@ namespace ImageProcessingGraph.Editor.Windows
|
|||||||
|
|
||||||
public static void Open(ImageProcessingGraphAsset asset)
|
public static void Open(ImageProcessingGraphAsset asset)
|
||||||
{
|
{
|
||||||
ImageProcessingGraphEditorWindow[] windows = Resources.FindObjectsOfTypeAll<ImageProcessingGraphEditorWindow>();
|
var existingWindows = Resources.FindObjectsOfTypeAll<ImageProcessingGraphEditorWindow>();
|
||||||
|
foreach (var w in existingWindows)
|
||||||
foreach (var w in windows)
|
|
||||||
{
|
{
|
||||||
w.Focus();
|
if (w.CurrentGraph == asset)
|
||||||
return;
|
{
|
||||||
|
w.Focus(); // 👁 focus the OG window
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageProcessingGraphEditorWindow window =
|
var window = CreateWindow<ImageProcessingGraphEditorWindow>(typeof(SceneView));
|
||||||
CreateWindow<ImageProcessingGraphEditorWindow>(typeof(ImageProcessingGraphEditorWindow),
|
window.titleContent = new GUIContent($"{asset.name}",
|
||||||
typeof(SceneView));
|
EditorGUIUtility.ObjectContent(null, typeof(ImageProcessingGraphAsset)).image);
|
||||||
|
|
||||||
window.titleContent = new GUIContent($"{asset.name}", EditorGUIUtility.ObjectContent(null, typeof(ImageProcessingGraphAsset)).image
|
|
||||||
);
|
|
||||||
window.Load(asset);
|
window.Load(asset);
|
||||||
|
window.Focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void OnEnable()
|
void OnEnable()
|
||||||
{
|
{
|
||||||
if(currentGraph != null)
|
if(currentGraph != null)
|
||||||
|
@ -29,12 +29,13 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind
|
|||||||
{
|
{
|
||||||
this.AddToClassList("image-node-visual");
|
this.AddToClassList("image-node-visual");
|
||||||
this.window = window;
|
this.window = window;
|
||||||
|
|
||||||
graphNode = node;
|
graphNode = node;
|
||||||
Type typeInfo = node.GetType();
|
|
||||||
|
|
||||||
|
|
||||||
|
Type typeInfo = node.GetType();
|
||||||
NodeInfoAttribute info = typeInfo.GetCustomAttribute<NodeInfoAttribute>();
|
NodeInfoAttribute info = typeInfo.GetCustomAttribute<NodeInfoAttribute>();
|
||||||
title = info.Title;
|
title = info.Title;
|
||||||
|
this.name = typeInfo.Name;
|
||||||
|
|
||||||
string[] depths = info.MenuItem.Split('/');
|
string[] depths = info.MenuItem.Split('/');
|
||||||
foreach (var depth in depths)
|
foreach (var depth in depths)
|
||||||
@ -70,16 +71,6 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind
|
|||||||
CreateInputPorts(inputFieldInfo);
|
CreateInputPorts(inputFieldInfo);
|
||||||
CreateOutputPorts(outputFieldInfo);
|
CreateOutputPorts(outputFieldInfo);
|
||||||
|
|
||||||
foreach (Port input in InputPorts)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (Port input in OutputPorts)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
defaaStyleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Unity Image Processing/Node.uss");
|
defaaStyleSheet = AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Unity Image Processing/Node.uss");
|
||||||
if (defaaStyleSheet == null)
|
if (defaaStyleSheet == null)
|
||||||
{
|
{
|
||||||
@ -103,9 +94,6 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind
|
|||||||
if (styleSheets.Contains(errorStyleSheet))
|
if (styleSheets.Contains(errorStyleSheet))
|
||||||
styleSheets.Remove(errorStyleSheet);
|
styleSheets.Remove(errorStyleSheet);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
this.name = typeInfo.Name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateInputPorts(List<FieldInfo> fields)
|
private void CreateInputPorts(List<FieldInfo> fields)
|
||||||
@ -120,6 +108,7 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind
|
|||||||
port.portName = label;
|
port.portName = label;
|
||||||
InputPorts.Add(port);
|
InputPorts.Add(port);
|
||||||
|
|
||||||
|
|
||||||
inputContainer.Add(port);
|
inputContainer.Add(port);
|
||||||
ExposeVariableToPort(port, field);
|
ExposeVariableToPort(port, field);
|
||||||
port.fieldInfo = field;
|
port.fieldInfo = field;
|
||||||
@ -324,6 +313,17 @@ namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Wind
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void BuildContextualMenu(ContextualMenuPopulateEvent evt)
|
||||||
|
{
|
||||||
|
evt.menu.InsertAction(evt.menu.MenuItems().Count, "Open Documentation", OpenDocumentation);
|
||||||
|
evt.menu.AppendSeparator();
|
||||||
|
base.BuildContextualMenu(evt);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OpenDocumentation(DropdownMenuAction obj)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public void SavePosition() => graphNode.SetPosition(GetPosition());
|
public void SavePosition() => graphNode.SetPosition(GetPosition());
|
||||||
}
|
}
|
||||||
|
@ -1,92 +1,282 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
|
||||||
using UnityEditor;
|
|
||||||
using UnityEditor.Search;
|
|
||||||
using UnityEditor.Experimental.GraphView;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Codice.Client.Common;
|
||||||
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
|
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
|
||||||
using Object = UnityEngine.Object;
|
using UnityEditor;
|
||||||
static class IPT_SearchProvider
|
using UnityEditor.Experimental.GraphView;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEngine.UIElements;
|
||||||
|
using Input = ImageProcessingGraph.Editor.Nodes.NodeAttributes.Input;
|
||||||
|
|
||||||
|
namespace ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows
|
||||||
{
|
{
|
||||||
internal static string id = "IPT_Tree";
|
public struct SearchContextElement
|
||||||
internal static List<SearchContextElement> elements;
|
|
||||||
|
|
||||||
[SearchItemProvider]
|
|
||||||
internal static SearchProvider CreateProvider()
|
|
||||||
{
|
{
|
||||||
return new SearchProvider(id, "IPT Nodes")
|
public object target { get; private set; }
|
||||||
|
public string title { get; private set; }
|
||||||
|
|
||||||
|
public Dictionary<int, Type> ImportPortTypes { get; private set; }
|
||||||
|
public Dictionary<int, Type> ExportPortTypes { get; private set; }
|
||||||
|
public int portID;
|
||||||
|
|
||||||
|
public SearchContextElement(object target, string title, Dictionary<int, Type> importPortTypes,
|
||||||
|
Dictionary<int, Type> exportPortTypes, int portID)
|
||||||
{
|
{
|
||||||
filterId = "tree:",
|
this.target = target;
|
||||||
priority = 99999,
|
this.title = title;
|
||||||
showDetailsOptions = ShowDetailsOptions.Inspector | ShowDetailsOptions.Actions,
|
this.ImportPortTypes = importPortTypes;
|
||||||
fetchItems = (context, items, provider) => FetchItems(context, provider),
|
this.ExportPortTypes = exportPortTypes;
|
||||||
fetchLabel = (item, context) => item.label,
|
this.portID = portID;
|
||||||
fetchDescription = (item, context) => item.description,
|
|
||||||
toObject = (item, type) => item.data as Object
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IEnumerable<SearchItem> FetchItems(SearchContext context, SearchProvider provider)
|
|
||||||
{
|
|
||||||
if (elements == null)
|
|
||||||
BuildElements();
|
|
||||||
|
|
||||||
foreach (var element in elements)
|
|
||||||
{
|
|
||||||
if (!element.title.ToLower().Contains(context.searchQuery.ToLower()))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// var item = provider.CreateItem(context, element.title, element.title, $"Node: {element.title}", 0, element.target);
|
|
||||||
var item = provider.CreateItem(context, element.title, element.title, element.title, null, element.target);
|
|
||||||
yield return item;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void BuildElements()
|
public class ImageProcessingGraphSearchProvider : ScriptableObject, ISearchWindowProvider
|
||||||
{
|
{
|
||||||
elements = new List<SearchContextElement>();
|
public ImageProcessingGraphViewWindow graph;
|
||||||
|
public VisualElement target;
|
||||||
|
|
||||||
foreach (var type in TypeCache.GetTypesWithAttribute<NodeInfoAttribute>())
|
public static List<SearchContextElement> elements;
|
||||||
|
private Assembly[] assemblies;
|
||||||
|
|
||||||
|
public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
|
||||||
{
|
{
|
||||||
var attr = type.GetCustomAttribute<NodeInfoAttribute>();
|
List<SearchTreeEntry> tree = new List<SearchTreeEntry>();
|
||||||
if (string.IsNullOrEmpty(attr.MenuItem))
|
tree.Add(new SearchTreeGroupEntry(new GUIContent("Nodes"), 0));
|
||||||
continue;
|
|
||||||
|
|
||||||
var node = Activator.CreateInstance(type);
|
elements = new List<SearchContextElement>();
|
||||||
elements.Add(new SearchContextElement(node, attr.MenuItem));
|
|
||||||
}
|
|
||||||
|
|
||||||
elements.Sort((entry1, entry2) =>
|
foreach (var type in TypeCache.GetTypesWithAttribute<NodeInfoAttribute>())
|
||||||
{
|
|
||||||
string[] splits1 = entry1.title.Split('/');
|
|
||||||
string[] splits2 = entry2.title.Split('/');
|
|
||||||
|
|
||||||
for (int i = 0; i < splits1.Length; i++)
|
|
||||||
{
|
{
|
||||||
if (i >= splits2.Length) return 1;
|
var attr = type.GetCustomAttribute<NodeInfoAttribute>();
|
||||||
int value = splits1[i].CompareTo(splits2[i]);
|
NodeInfoAttribute info = attr as NodeInfoAttribute;
|
||||||
if (value != 0)
|
var node = Activator.CreateInstance(type);
|
||||||
{
|
if (string.IsNullOrEmpty(info.MenuItem)) continue;
|
||||||
if (splits1.Length != splits2.Length && (i == splits1.Length - 1 || i == splits2.Length - 1))
|
|
||||||
return splits1.Length < splits2.Length ? 1 : -1;
|
|
||||||
|
|
||||||
return value;
|
var Fields = type.GetFields();
|
||||||
|
Dictionary<int, Type> ImportPortTypes = new Dictionary<int, Type>();
|
||||||
|
Dictionary<int, Type> OutputPortTypes = new Dictionary<int, Type>();
|
||||||
|
|
||||||
|
foreach (var field in Fields)
|
||||||
|
{
|
||||||
|
if (field.GetCustomAttribute<Input>() != null)
|
||||||
|
ImportPortTypes.Add(ImportPortTypes.Count, field.FieldType);
|
||||||
|
if (field.GetCustomAttribute<Output>() != null)
|
||||||
|
OutputPortTypes.Add(OutputPortTypes.Count, field.FieldType);
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.Add(new SearchContextElement(node, info.MenuItem, ImportPortTypes, OutputPortTypes, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
elements.Sort((entry1, entry2) =>
|
||||||
|
{
|
||||||
|
string[] splits1 = entry1.title.Split('/');
|
||||||
|
string[] splits2 = entry2.title.Split('/');
|
||||||
|
|
||||||
|
for (int i = 0; i < splits1.Length; i++)
|
||||||
|
{
|
||||||
|
if (i >= splits2.Length) return 1;
|
||||||
|
|
||||||
|
int value = splits1[i].CompareTo(splits2[i]);
|
||||||
|
if (value != 0)
|
||||||
|
{
|
||||||
|
if (splits1.Length != splits2.Length && (i == splits1.Length - 1 || i == splits2.Length - 1))
|
||||||
|
return splits1.Length < splits2.Length ? 1 : -1;
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
List<string> groups = new List<string>();
|
||||||
|
|
||||||
|
foreach (var element in elements)
|
||||||
|
{
|
||||||
|
string[] entryTitle = element.title.Split('/');
|
||||||
|
|
||||||
|
string groupName = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < entryTitle.Length - 1; i++)
|
||||||
|
{
|
||||||
|
groupName += entryTitle[i];
|
||||||
|
if (!groups.Contains(groupName))
|
||||||
|
{
|
||||||
|
tree.Add(new SearchTreeGroupEntry(new GUIContent(groupName), i + 1));
|
||||||
|
groups.Add(groupName);
|
||||||
|
}
|
||||||
|
|
||||||
|
groupName += '/';
|
||||||
|
}
|
||||||
|
|
||||||
|
SearchTreeEntry entry = new SearchTreeEntry(new GUIContent(entryTitle.Last()));
|
||||||
|
entry.level = entryTitle.Length;
|
||||||
|
entry.userData = element;
|
||||||
|
tree.Add(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnSelectEntry(SearchTreeEntry SearchTreeEntry, SearchWindowContext context)
|
||||||
|
{
|
||||||
|
var mousePos =
|
||||||
|
graph.ChangeCoordinatesTo(graph, context.screenMousePosition - graph.Window.position.position);
|
||||||
|
var graphMousePosition = graph.contentViewContainer.WorldToLocal(mousePos);
|
||||||
|
|
||||||
|
SearchContextElement element = (SearchContextElement)SearchTreeEntry.userData;
|
||||||
|
|
||||||
|
BaseImageNode node = (BaseImageNode)element.target;
|
||||||
|
node.SetPosition(new Rect(graphMousePosition, new Vector2()));
|
||||||
|
graph.Add(node);
|
||||||
|
node.asset = graph.asset;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SearchTreeEntry> CreateSearchTreeForEdge(SearchWindowContext context, Edge edge)
|
||||||
|
{
|
||||||
|
var tree = new List<SearchTreeEntry>();
|
||||||
|
tree.Add(new SearchTreeGroupEntry(new GUIContent("Compatible Nodes"), 0));
|
||||||
|
|
||||||
|
elements = new List<SearchContextElement>();
|
||||||
|
var groups = new List<string>();
|
||||||
|
|
||||||
|
var sourcePort = edge.output ?? edge.input;
|
||||||
|
bool isSourceOutput = edge.output != null;
|
||||||
|
Type targetType = (sourcePort as IPTPort)?.portType;
|
||||||
|
|
||||||
|
if (targetType == null)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("Could not determine port type from edge!");
|
||||||
|
return tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var type in TypeCache.GetTypesWithAttribute<NodeInfoAttribute>())
|
||||||
|
{
|
||||||
|
var attr = type.GetCustomAttribute<NodeInfoAttribute>();
|
||||||
|
if (string.IsNullOrEmpty(attr.MenuItem)) continue;
|
||||||
|
|
||||||
|
var node = Activator.CreateInstance(type);
|
||||||
|
var fields = type.GetFields();
|
||||||
|
|
||||||
|
// Get all ports
|
||||||
|
var inputPorts = fields.Where(f => f.GetCustomAttribute<Input>() != null).ToList();
|
||||||
|
var outputPorts = fields.Where(f => f.GetCustomAttribute<Output>() != null).ToList();
|
||||||
|
|
||||||
|
// REVERSED LOGIC:
|
||||||
|
// If dragging from output, we want compatible INPUT ports
|
||||||
|
// If dragging from input, we want compatible OUTPUT ports
|
||||||
|
var compatiblePorts = isSourceOutput
|
||||||
|
? inputPorts.Where(f => f.FieldType.IsAssignableFrom(targetType)).ToList()
|
||||||
|
: outputPorts.Where(f => targetType.IsAssignableFrom(f.FieldType)).ToList();
|
||||||
|
|
||||||
|
if (compatiblePorts.Count == 0) continue;
|
||||||
|
|
||||||
|
// Build group hierarchy
|
||||||
|
var menuPath = attr.MenuItem.Split('/');
|
||||||
|
var currentGroupPath = "";
|
||||||
|
|
||||||
|
for (int i = 0; i < menuPath.Length - 1; i++)
|
||||||
|
{
|
||||||
|
currentGroupPath += menuPath[i];
|
||||||
|
if (!groups.Contains(currentGroupPath))
|
||||||
|
{
|
||||||
|
tree.Add(new SearchTreeGroupEntry(new GUIContent(menuPath[i]), i + 1));
|
||||||
|
groups.Add(currentGroupPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
currentGroupPath += "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
// // Add node entry
|
||||||
|
// var nodeTitle = $"{type.Name}: {menuPath.Last()}";
|
||||||
|
// tree.Add(new SearchTreeEntry(new GUIContent(nodeTitle))
|
||||||
|
// {
|
||||||
|
// level = menuPath.Length,
|
||||||
|
// userData = new SearchContextElement(
|
||||||
|
// node,
|
||||||
|
// nodeTitle,
|
||||||
|
// inputPorts.ToDictionary(f => inputPorts.IndexOf(f), f => f.FieldType),
|
||||||
|
// outputPorts.ToDictionary(f => outputPorts.IndexOf(f), f => f.FieldType))
|
||||||
|
// });
|
||||||
|
|
||||||
|
// Add compatible port entries
|
||||||
|
foreach (var portField in compatiblePorts)
|
||||||
|
{
|
||||||
|
var portList = portField.GetCustomAttribute<Input>() != null ? inputPorts : outputPorts;
|
||||||
|
int portIndex = portList.IndexOf(portField);
|
||||||
|
|
||||||
|
var portTitle = $"{attr.Title}: {portField.Name}";
|
||||||
|
tree.Add(new SearchTreeEntry(new GUIContent(portTitle))
|
||||||
|
{
|
||||||
|
level = menuPath.Length,
|
||||||
|
userData = new SearchContextElement(
|
||||||
|
node,
|
||||||
|
portTitle,
|
||||||
|
inputPorts.ToDictionary(f => inputPorts.IndexOf(f), f => f.FieldType),
|
||||||
|
outputPorts.ToDictionary(f => outputPorts.IndexOf(f), f => f.FieldType),
|
||||||
|
portIndex)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
|
||||||
});
|
return tree;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
public class CustomSearchProviderForEdge : ScriptableObject, ISearchWindowProvider
|
||||||
public class SearchContextElement
|
{
|
||||||
{
|
private readonly ImageProcessingGraphSearchProvider original;
|
||||||
public object target;
|
private readonly Edge edge;
|
||||||
public string title;
|
private readonly IPTPort inputPort;
|
||||||
|
private readonly IPTPort outputPort;
|
||||||
public SearchContextElement(object target, string title)
|
|
||||||
{
|
public CustomSearchProviderForEdge(ImageProcessingGraphSearchProvider original, Edge edge, IPTPort inputPort, IPTPort outputPort)
|
||||||
this.target = target;
|
{
|
||||||
this.title = title;
|
this.original = original;
|
||||||
|
this.edge = edge;
|
||||||
|
this.inputPort = inputPort;
|
||||||
|
this.outputPort = outputPort;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SearchTreeEntry> CreateSearchTree(SearchWindowContext context)
|
||||||
|
{
|
||||||
|
return original.CreateSearchTreeForEdge(context, edge);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnSelectEntry(SearchTreeEntry selectedEntry, SearchWindowContext context)
|
||||||
|
{
|
||||||
|
var mousePos =
|
||||||
|
original.graph.ChangeCoordinatesTo(original.graph, context.screenMousePosition - original.graph.Window.position.position);
|
||||||
|
var graphMousePosition = original.graph.contentViewContainer.WorldToLocal(mousePos);
|
||||||
|
|
||||||
|
SearchContextElement element = (SearchContextElement)selectedEntry.userData;
|
||||||
|
|
||||||
|
BaseImageNode node = (BaseImageNode)element.target;
|
||||||
|
node.SetPosition(new Rect(graphMousePosition, new Vector2()));
|
||||||
|
original.graph.Add(node);
|
||||||
|
node.asset = original.graph.asset;
|
||||||
|
|
||||||
|
|
||||||
|
Edge edge = new Edge();
|
||||||
|
|
||||||
|
if (inputPort != null)
|
||||||
|
{
|
||||||
|
edge = inputPort.ConnectTo(original.graph.nodeDictionary[node.ID].OutputPorts[element.portID]);
|
||||||
|
}
|
||||||
|
else if (outputPort != null)
|
||||||
|
{
|
||||||
|
edge = outputPort.ConnectTo(original.graph.nodeDictionary[node.ID].InputPorts[element.portID]);
|
||||||
|
}
|
||||||
|
|
||||||
|
original.graph.CreateEdge(edge);
|
||||||
|
original.graph.AddElement((GraphElement)edge);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,12 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using ImageProcessingGraph.Editor.Nodes.NodeAttributes;
|
||||||
using ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows;
|
using ImageProcessingGraph.Editor.Unity_Image_Processing.Scripts.Editor.Windows;
|
||||||
using ImageProcessingGraph.Editor.Windows;
|
using ImageProcessingGraph.Editor.Windows;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEditor.Experimental.GraphView;
|
using UnityEditor.Experimental.GraphView;
|
||||||
using UnityEditor.Search;
|
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using UnityEngine.UIElements;
|
using UnityEngine.UIElements;
|
||||||
|
|
||||||
@ -21,7 +23,7 @@ namespace ImageProcessingGraph.Editor
|
|||||||
public Dictionary<string, ImageProcessingGraphNodeVisual> nodeDictionary;
|
public Dictionary<string, ImageProcessingGraphNodeVisual> nodeDictionary;
|
||||||
public Dictionary<Edge, GraphConnection> connectionDictionary;
|
public Dictionary<Edge, GraphConnection> connectionDictionary;
|
||||||
|
|
||||||
// internal ImageProcessingGraphSearchProvider searchProvider;
|
internal ImageProcessingGraphSearchProvider searchProvider;
|
||||||
internal ImageProcessingGraphEdgeConnectorListener edgeConnectorListener;
|
internal ImageProcessingGraphEdgeConnectorListener edgeConnectorListener;
|
||||||
|
|
||||||
private bool isDropdownEnabled = false;
|
private bool isDropdownEnabled = false;
|
||||||
@ -38,8 +40,8 @@ namespace ImageProcessingGraph.Editor
|
|||||||
nodeDictionary = new Dictionary<string, ImageProcessingGraphNodeVisual>();
|
nodeDictionary = new Dictionary<string, ImageProcessingGraphNodeVisual>();
|
||||||
connectionDictionary = new Dictionary<Edge, GraphConnection>();
|
connectionDictionary = new Dictionary<Edge, GraphConnection>();
|
||||||
|
|
||||||
// searchProvider = ScriptableObject.CreateInstance<ImageProcessingGraphSearchProvider>();
|
searchProvider = ScriptableObject.CreateInstance<ImageProcessingGraphSearchProvider>();
|
||||||
// searchProvider.graph = this;
|
searchProvider.graph = this;
|
||||||
|
|
||||||
edgeConnectorListener = new ImageProcessingGraphEdgeConnectorListener(this);
|
edgeConnectorListener = new ImageProcessingGraphEdgeConnectorListener(this);
|
||||||
|
|
||||||
@ -71,19 +73,15 @@ namespace ImageProcessingGraph.Editor
|
|||||||
DrawNodes();
|
DrawNodes();
|
||||||
DrawConnections();
|
DrawConnections();
|
||||||
|
|
||||||
foreach (var conn in asset.Connections)
|
|
||||||
{
|
|
||||||
if (conn.internalEdge == null)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//GetNode(conn.inputPort.nodeID).ToggleExposedVariable(conn.internalEdge.input, true);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
graphViewChanged += OnGraphViewChanged;
|
graphViewChanged += OnGraphViewChanged;
|
||||||
Undo.undoRedoEvent += UndoEvent;
|
|
||||||
|
Undo.undoRedoPerformed += UndoRedoPerformed;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UndoRedoPerformed()
|
||||||
|
{
|
||||||
|
DrawNodes();
|
||||||
|
DrawConnections();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateButtons()
|
private void CreateButtons()
|
||||||
@ -235,12 +233,6 @@ namespace ImageProcessingGraph.Editor
|
|||||||
return compatiblePorts;
|
return compatiblePorts;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UndoEvent(in UndoRedoInfo undo)
|
|
||||||
{
|
|
||||||
DrawNodes();
|
|
||||||
DrawConnections();
|
|
||||||
}
|
|
||||||
|
|
||||||
private GraphViewChange OnGraphViewChanged(GraphViewChange graphviewchange)
|
private GraphViewChange OnGraphViewChanged(GraphViewChange graphviewchange)
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -300,7 +292,7 @@ namespace ImageProcessingGraph.Editor
|
|||||||
|
|
||||||
#region Edges
|
#region Edges
|
||||||
|
|
||||||
void CreateEdge(Edge edge)
|
public void CreateEdge(Edge edge)
|
||||||
{
|
{
|
||||||
ImageProcessingGraphNodeVisual outputNode = (ImageProcessingGraphNodeVisual)edge.output.node;
|
ImageProcessingGraphNodeVisual outputNode = (ImageProcessingGraphNodeVisual)edge.output.node;
|
||||||
ImageProcessingGraphNodeVisual inputNode = (ImageProcessingGraphNodeVisual)edge.input.node;
|
ImageProcessingGraphNodeVisual inputNode = (ImageProcessingGraphNodeVisual)edge.input.node;
|
||||||
@ -444,7 +436,18 @@ namespace ImageProcessingGraph.Editor
|
|||||||
{
|
{
|
||||||
node.typeName = node.GetType().AssemblyQualifiedName;
|
node.typeName = node.GetType().AssemblyQualifiedName;
|
||||||
|
|
||||||
ImageProcessingGraphNodeVisual editorNode = new ImageProcessingGraphNodeVisual(node, this);
|
var infoAttr = node.GetType().GetCustomAttribute<NodeInfoAttribute>();
|
||||||
|
|
||||||
|
ImageProcessingGraphNodeVisual editorNode = null;
|
||||||
|
if (typeof(ImageProcessingGraphNodeVisual).IsAssignableFrom(infoAttr.EditorType))
|
||||||
|
{
|
||||||
|
editorNode = (ImageProcessingGraphNodeVisual)Activator.CreateInstance(infoAttr.EditorType, node, this);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
editorNode = new ImageProcessingGraphNodeVisual(node, this);
|
||||||
|
}
|
||||||
|
|
||||||
editorNode.SetPosition(node.Position);
|
editorNode.SetPosition(node.Position);
|
||||||
|
|
||||||
graphNodes.Add(editorNode);
|
graphNodes.Add(editorNode);
|
||||||
@ -492,10 +495,8 @@ namespace ImageProcessingGraph.Editor
|
|||||||
|
|
||||||
private void ShowSearchWindow(NodeCreationContext obj)
|
private void ShowSearchWindow(NodeCreationContext obj)
|
||||||
{
|
{
|
||||||
// searchProvider.target = (VisualElement)focusController.focusedElement;
|
searchProvider.target = (VisualElement)focusController.focusedElement;
|
||||||
// SearchWindow.Open(new SearchWindowContext(obj.screenMousePosition), searchProvider);
|
SearchWindow.Open(new SearchWindowContext(obj.screenMousePosition), searchProvider);
|
||||||
|
|
||||||
SearchService.ShowContextual("IPT_Tree");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -6,9 +6,11 @@ A tool for applying image transformations and effects using a graph-based node s
|
|||||||
|
|
||||||
- **Tested on:**
|
- **Tested on:**
|
||||||
- Unity 2022.3.50f1
|
- Unity 2022.3.50f1
|
||||||
|
- Unity 2021.3.16f1
|
||||||
- Unity 6000.0.19f1 (Unity 6)
|
- Unity 6000.0.19f1 (Unity 6)
|
||||||
|
|
||||||
- **Supported versions:**
|
- **Supported versions:**
|
||||||
|
- Unity 2021.3
|
||||||
- Unity 2022.0
|
- Unity 2022.0
|
||||||
- Unity 2023.0
|
- Unity 2023.0
|
||||||
- Unity 6000.0
|
- Unity 6000.0
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "com.chromium.imageprocessingrah",
|
"name": "com.chromium.imageprocessingrah",
|
||||||
"version": "0.0.0",
|
"version": "0.0.1",
|
||||||
"displayName": "Image Processing Graph",
|
"displayName": "Image Processing Graph",
|
||||||
"description": "Stuffs",
|
"description": "Stuffs",
|
||||||
"unity": "2022.3",
|
"unity": "2021.3",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"com.unity.burst": "1.8.17"
|
"com.unity.burst": "1.8.17"
|
||||||
},
|
},
|
||||||
|
Loading…
x
Reference in New Issue
Block a user