diff --git a/Examples/Nodes/BaseNode.cs b/Examples/Nodes/BaseNode.cs
index 1a7bbd4..1338a36 100644
--- a/Examples/Nodes/BaseNode.cs
+++ b/Examples/Nodes/BaseNode.cs
@@ -1,16 +1,15 @@
-using System.Collections;
-using System.Collections.Generic;
-using UnityEngine;
-
-public class BaseNode : Node {
-
- // Use this for initialization
- void Start () {
-
- }
-
- // Update is called once per frame
- void Update () {
-
- }
-}
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+public class BaseNode : Node {
+
+ protected override void Init() {
+ inputs = new NodePort[2];
+ inputs[0] = CreateNodeInput("IntInput", typeof(int));
+ inputs[1] = CreateNodeInput("StringInput", typeof(string));
+ outputs = new NodePort[1];
+ outputs[0] = CreateNodeOutput("StringOutput", typeof(string));
+ }
+}
diff --git a/Scripts/Editor/NodeEditorAction.cs b/Scripts/Editor/NodeEditorAction.cs
index 3c2cbe4..a38e07f 100644
--- a/Scripts/Editor/NodeEditorAction.cs
+++ b/Scripts/Editor/NodeEditorAction.cs
@@ -12,7 +12,6 @@ public static class NodeEditorAction {
public static void Controls(NodeEditorWindow window) {
Event e = Event.current;
-
switch (e.type) {
case EventType.ScrollWheel:
@@ -22,8 +21,26 @@ public static class NodeEditorAction {
case EventType.MouseDrag:
if (e.button == 0) {
if (window.activeNode != null) {
- window.activeNode.position.position = window.WindowToGridPosition(e.mousePosition) + dragOffset;
- window.Repaint();
+ if (window.hoveredPort != null || window.tempConnection != null) {
+ if (window.tempConnection == null) {
+ if (window.hoveredPort.direction == NodePort.IO.Output) {
+ dragging = true;
+ int inputNodeId = window.graph.GetNodeId(window.activeNode);
+ int outputPortId = window.activeNode.GetOutputPortId(window.hoveredPort);
+ window.tempConnection = new NodeConnection(inputNodeId, outputPortId, -1,-1);
+ }
+ else {
+ Debug.Log("input");
+ /*int outputNodeId = window.graph.GetNodeId(window.activeNode);
+ int outputPortId = window.activeNode.GetInputPortId(window.hoveredPort);
+ window.tempConnection = new NodeConnection(-1,-1,outputNodeId,outputPortId);*/
+ }
+ }
+ }
+ else {
+ window.activeNode.position.position = window.WindowToGridPosition(e.mousePosition) + dragOffset;
+ window.Repaint();
+ }
}
}
else if (e.button == 1) {
@@ -36,6 +53,7 @@ public static class NodeEditorAction {
break;
case EventType.MouseDown:
dragging = false;
+ window.Repaint();
window.SelectNode(window.hoveredNode);
if (window.hoveredNode != null) {
dragOffset = window.hoveredNode.position.position - window.WindowToGridPosition(e.mousePosition);
@@ -43,11 +61,15 @@ public static class NodeEditorAction {
window.Repaint();
break;
case EventType.MouseUp:
+ window.tempConnection = null;
if (dragging) return;
if (e.button == 1) {
NodeEditorGUI.RightClickContextMenu(window);
}
+ break;
+ case EventType.repaint:
+
break;
}
}
diff --git a/Scripts/Editor/NodeEditorGUI.cs b/Scripts/Editor/NodeEditorGUI.cs
index b897355..472ff83 100644
--- a/Scripts/Editor/NodeEditorGUI.cs
+++ b/Scripts/Editor/NodeEditorGUI.cs
@@ -8,6 +8,10 @@ namespace UNEC {
/// Contains GUI methods
public static class NodeEditorGUI {
+ public static void DrawConnection(Vector2 from, Vector2 to, Color col) {
+ Handles.DrawBezier(from, to, from, to, col, new Texture2D(2, 2), 2);
+ }
+
public static void BeginZoomed(Rect rect, float zoom) {
GUI.EndClip();
diff --git a/Scripts/Editor/NodeEditorResources.cs b/Scripts/Editor/NodeEditorResources.cs
index ebee646..ec262cf 100644
--- a/Scripts/Editor/NodeEditorResources.cs
+++ b/Scripts/Editor/NodeEditorResources.cs
@@ -1,5 +1,6 @@
using UnityEngine;
using UnityEditor;
+using System;
namespace UNEC {
public static class NodeEditorResources {
@@ -15,6 +16,53 @@ namespace UNEC {
private static Color arteryColor = new Color(0.34f, 0.34f, 0.34f);
private static Color crossColor = new Color(0.45f, 0.45f, 0.45f);
+ public static Styles styles = new Styles();
+
+ public class Styles {
+ GUIStyle inputInt, inputString, inputFloat, inputObject, inputTexture, inputColor;
+ GUIStyle outputInt, outputString, outputFloat, outputObject, outputTexture, outputColor;
+
+ public Styles() {
+ inputObject = new GUIStyle((GUIStyle)"flow shader in 0");
+ inputString = new GUIStyle((GUIStyle)"flow shader in 1");
+ inputInt = new GUIStyle((GUIStyle)"flow shader in 2");
+ inputFloat = new GUIStyle((GUIStyle)"flow shader in 3");
+ inputColor = new GUIStyle((GUIStyle)"flow shader in 4");
+ inputTexture = new GUIStyle((GUIStyle)"flow shader in 5");
+ outputObject = new GUIStyle((GUIStyle)"flow shader out 0");
+ outputString = new GUIStyle((GUIStyle)"flow shader out 1");
+ outputInt = new GUIStyle((GUIStyle)"flow shader out 2");
+ outputFloat = new GUIStyle((GUIStyle)"flow shader out 3");
+ outputColor = new GUIStyle((GUIStyle)"flow shader out 4");
+ outputTexture = new GUIStyle((GUIStyle)"flow shader out 5");
+
+ foreach (GUIStyle style in new GUIStyle[] { inputInt, inputString, inputFloat, inputObject, inputTexture, inputColor, outputInt, outputString, outputFloat, outputObject, outputTexture, outputColor }) {
+ style.normal.textColor = Color.black;
+ style.fixedHeight = 18;
+ style.alignment = TextAnchor.MiddleLeft;
+ style.onHover.textColor = Color.red;
+ }
+ }
+
+ public GUIStyle GetInputStyle(Type type) {
+ if (type == typeof(int)) return inputInt;
+ else if (type == typeof(string)) return inputString;
+ else if (type == typeof(Texture2D)) return inputTexture;
+ else if (type == typeof(float)) return inputFloat;
+ else if (type == typeof(Color)) return inputColor;
+ else return inputObject;
+ }
+
+ public GUIStyle GetOutputStyle(Type type) {
+ if (type == typeof(int)) return outputInt;
+ else if (type == typeof(string)) return outputString;
+ else if (type == typeof(Texture2D)) return outputTexture;
+ else if (type == typeof(float)) return outputFloat;
+ else if (type == typeof(Color)) return outputColor;
+ else return outputObject;
+ }
+ }
+
public static Texture2D GenerateGridTexture() {
Texture2D tex = new Texture2D(64,64);
Color[] cols = new Color[64 * 64];
diff --git a/Scripts/Editor/NodeEditorWindow.cs b/Scripts/Editor/NodeEditorWindow.cs
index 75bc975..26517fd 100644
--- a/Scripts/Editor/NodeEditorWindow.cs
+++ b/Scripts/Editor/NodeEditorWindow.cs
@@ -6,10 +6,14 @@ using UNEC;
public class NodeEditorWindow : EditorWindow {
+ private Dictionary portConnectionPoints = new Dictionary();
+
public NodeGraph graph { get { return _graph != null ? _graph : _graph = new NodeGraph(); } }
public NodeGraph _graph;
public Node hoveredNode;
public Node activeNode { get; private set; }
+ public NodePort hoveredPort;
+ public NodeConnection? tempConnection;
public Vector2 panOffset { get { return _panOffset; } set { _panOffset = value; Repaint(); } }
private Vector2 _panOffset;
@@ -28,36 +32,92 @@ public class NodeEditorWindow : EditorWindow {
Matrix4x4 m = GUI.matrix;
NodeEditorAction.Controls(this);
-
NodeEditorGUI.DrawGrid(position, zoom, panOffset);
DrawNodes();
+ DrawTempConnection();
NodeEditorGUI.DrawToolbar(this);
GUI.matrix = m;
}
+ /// Draw a connection as we are dragging it
+ private void DrawTempConnection() {
+ if (tempConnection.HasValue) {
+ Node inputNode = graph.GetNode(tempConnection.Value.inputNodeId);
+ if (inputNode != null) {
+ NodePort outputPort = inputNode.GetOutput(tempConnection.Value.outputPortId);
+ Vector2 startPoint = GridToWindowPosition( portConnectionPoints[outputPort]);
+ Vector2 endPoint = Event.current.mousePosition;
+ Vector2 startTangent = startPoint;
+ startTangent.x = Mathf.Lerp(startPoint.x,endPoint.x,0.7f);
+ Vector2 endTangent = endPoint;
+ endTangent.x = Mathf.Lerp(endPoint.x, startPoint.x, 0.7f);
+ Handles.DrawBezier(startPoint, endPoint, startTangent, endTangent, Color.gray, null, 4);
+ Handles.DrawBezier(startPoint, endPoint, startTangent, endTangent, Color.white, null, 2);
+ Repaint();
+ }
+ }
+ }
private void DrawNodes() {
+ portConnectionPoints.Clear();
+ Event e = Event.current;
+
BeginWindows();
NodeEditorGUI.BeginZoomed(position, zoom);
- Event e = Event.current;
+ if (e.type == EventType.repaint) {
+ hoveredPort = null;
+ }
hoveredNode = null;
foreach (KeyValuePair kvp in graph.nodes) {
Node node = kvp.Value;
int id = kvp.Key;
//Get node position
- Vector2 windowPos = GridToWindowPositionNoClipped(node.position.position);
+ Vector2 nodePos = GridToWindowPositionNoClipped(node.position.position);
- Rect windowRect = new Rect(windowPos, new Vector2(200, 200));
+ Rect windowRect = new Rect(nodePos, new Vector2(200, 200));
if (windowRect.Contains(e.mousePosition)) hoveredNode = node;
GUIStyle style = (node == activeNode) ? (GUIStyle)"flow node 0 on" : (GUIStyle)"flow node 0";
- GUI.Box(windowRect, node.ToString(), style);
+ GUILayout.BeginArea(windowRect, node.ToString(), style);
+ GUILayout.BeginHorizontal();
+
+ //Inputs
+ GUILayout.BeginVertical();
+ for (int i = 0; i < node.InputCount; i++) {
+ NodePort input = node.GetInput(i);
+ Rect r = GUILayoutUtility.GetRect(new GUIContent(input.name), NodeEditorResources.styles.GetInputStyle(input.type));
+ GUI.Label(r, input.name, NodeEditorResources.styles.GetInputStyle(input.type));
+ if (e.type == EventType.repaint) {
+ if (r.Contains(e.mousePosition)) hoveredPort = input;
+ }
+ portConnectionPoints.Add(input, new Vector2(r.xMin, r.yMin + (r.height * 0.5f)) + node.position.position);
+ }
+ GUILayout.EndVertical();
+ //Outputs
+ GUILayout.BeginVertical();
+ for (int i = 0; i < node.OutputCount; i++) {
+ NodePort output = node.GetOutput(i);
+ Rect r = GUILayoutUtility.GetRect(new GUIContent(output.name), NodeEditorResources.styles.GetOutputStyle(output.type));
+ GUI.Label(r, output.name, NodeEditorResources.styles.GetOutputStyle(output.type));
+ if (e.type == EventType.repaint) {
+ if (r.Contains(e.mousePosition)) hoveredPort = output;
+ }
+ portConnectionPoints.Add(output, new Vector2(r.xMax, r.yMin + (r.height * 0.5f)) + node.position.position);
+ }
+ GUILayout.EndVertical();
- if (windowRect.position != windowPos) {
- windowPos = windowRect.position;
- node.position.position = WindowToGridPosition(windowPos);
+ GUILayout.EndHorizontal();
+
+ GUILayout.Label("More stuff");
+ EditorGUILayout.Toggle("aDF",false);
+
+ GUILayout.EndArea();
+
+ if (windowRect.position != nodePos) {
+ nodePos = windowRect.position;
+ node.position.position = WindowToGridPosition(nodePos);
//Vector2 newPos = windowRect =
}
@@ -78,7 +138,8 @@ public class NodeEditorWindow : EditorWindow {
}
public Vector2 GridToWindowPosition(Vector2 gridPosition) {
- return (position.size * 0.5f) + (panOffset / zoom) + gridPosition;
+ //Vector2 center = position.size * 0.5f;
+ return (position.size * 0.5f) + (panOffset / zoom) + (gridPosition/zoom);
}
public Vector2 GridToWindowPositionNoClipped(Vector2 gridPosition) {
@@ -91,4 +152,5 @@ public class NodeEditorWindow : EditorWindow {
public void SelectNode(Node node) {
activeNode = node;
}
+
}
\ No newline at end of file
diff --git a/Scripts/Node.cs b/Scripts/Node.cs
index 8c8b74c..ec3612c 100644
--- a/Scripts/Node.cs
+++ b/Scripts/Node.cs
@@ -1,8 +1,51 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
+using System;
+using UNEC;
/// Base class for all nodes
public abstract class Node {
public Rect position = new Rect(0,0,200,200);
+ protected NodePort[] inputs = new NodePort[0];
+ protected NodePort[] outputs = new NodePort[0];
+
+ public int InputCount { get { return inputs.Length; } }
+ public int OutputCount { get { return outputs.Length; } }
+
+ protected Node() {
+ Init();
+ }
+
+ abstract protected void Init();
+
+ public int GetInputPortId(NodePort input) {
+ for (int i = 0; i < inputs.Length; i++) {
+ if (input == inputs[i]) return i;
+
+ }
+ return -1;
+ }
+ public int GetOutputPortId(NodePort output) {
+ for (int i = 0; i < outputs.Length; i++) {
+ if (output == outputs[i]) return i;
+
+ }
+ return -1;
+ }
+
+ public NodePort GetInput(int portId) {
+ return inputs[portId];
+ }
+
+ public NodePort GetOutput(int portId) {
+ return outputs[portId];
+ }
+
+ public NodePort CreateNodeInput(string name, Type type, bool enabled = true) {
+ return new NodePort(name, type, this, enabled);
+ }
+ public NodePort CreateNodeOutput(string name, Type type, bool enabled = true) {
+ return new NodePort(name, type, this, enabled);
+ }
}
diff --git a/Scripts/NodeConnection.cs b/Scripts/NodeConnection.cs
new file mode 100644
index 0000000..f5ef29c
--- /dev/null
+++ b/Scripts/NodeConnection.cs
@@ -0,0 +1,22 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace UNEC {
+ /// Data travels from Input Node's Output port to Output Node's Input port
+ public struct NodeConnection {
+ public int inputNodeId { get { return _inputNodeId; } }
+ public int inputPortId { get { return _inputPortId; } }
+ public int outputNodeId { get { return _outputNodeId; } }
+ public int outputPortId { get { return _outputPortId; } }
+ [SerializeField] private int _inputNodeId, _inputPortId, _outputNodeId, _outputPortId;
+
+ /// Data travels from Input Node's Output port to Output Node's Input port
+ public NodeConnection(int inputNodeId, int outputPortId, int outputNodeId, int inputPortId) {
+ _inputNodeId = inputNodeId;
+ _outputPortId = outputPortId;
+ _outputNodeId = outputNodeId;
+ _inputPortId = inputPortId;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Scripts/NodeConnection.cs.meta b/Scripts/NodeConnection.cs.meta
new file mode 100644
index 0000000..819c7d8
--- /dev/null
+++ b/Scripts/NodeConnection.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 1f29a204e0cc2934e8f9cb2010723de9
+timeCreated: 1505747662
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Scripts/NodeGraph.cs b/Scripts/NodeGraph.cs
index d902fb7..1a4df9b 100644
--- a/Scripts/NodeGraph.cs
+++ b/Scripts/NodeGraph.cs
@@ -2,11 +2,13 @@
using System.Collections.Generic;
using UnityEngine;
using System;
+using UNEC;
/// Base class for all node graphs
public class NodeGraph {
public Dictionary nodes = new Dictionary();
+ private List connections = new List();
public T AddNode() where T : Node {
T node = default(T);
@@ -22,27 +24,37 @@ public class NodeGraph {
}
public void RemoveNode(Node node) {
- int id = GetNodeID(node);
+ int id = GetNodeId(node);
if (id != -1) nodes.Remove(id);
else Debug.LogWarning("Node " + node.ToString() + " is not part of NodeGraph");
}
- public void RemoveNode(int id) {
- nodes.Remove(id);
+ public void RemoveNode(int nodeId) {
+ nodes.Remove(nodeId);
}
- public int GetNodeID(Node node) {
+ public int GetNodeId(Node node) {
foreach(var kvp in nodes) {
if (kvp.Value == node) return kvp.Key;
}
return -1;
}
- public Node GetNode(int id) {
- if (nodes.ContainsKey(id)) return nodes[id];
+ public Node GetNode(int nodeId) {
+ if (nodes.ContainsKey(nodeId)) return nodes[nodeId];
return null;
}
+ public void AddConnection(NodePort input, NodePort output) {
+ int inputNodeId = GetNodeId(input.node);
+ int outputPortId = input.node.GetInputPortId(output);
+
+ int outputNodeId = GetNodeId(output.node);
+ int inputPortId = output.node.GetInputPortId(input);
+
+ NodeConnection connection = new NodeConnection(inputNodeId, inputPortId, outputNodeId, outputPortId);
+ }
+
private int GetUniqueID() {
int id = 0;
while (nodes.ContainsKey(id)) id++;
@@ -51,5 +63,6 @@ public class NodeGraph {
public void Clear() {
nodes.Clear();
+ connections.Clear();
}
}
diff --git a/Scripts/NodePort.cs b/Scripts/NodePort.cs
new file mode 100644
index 0000000..1a4e603
--- /dev/null
+++ b/Scripts/NodePort.cs
@@ -0,0 +1,45 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System;
+
+public class NodePort {
+ public enum IO { None, Input, Output}
+
+ public IO direction {
+ get {
+ for (int i = 0; i < node.InputCount; i++) {
+ if (node.GetInput(i) == this) return IO.Input;
+ }
+ for (int i = 0; i < node.OutputCount; i++) {
+ if (node.GetOutput(i) == this) return IO.Output;
+ }
+ return IO.None;
+ }
+ }
+ public Node node { get; private set; }
+ public string name { get { return _name; } set { _name = value; } }
+ [SerializeField]
+ private string _name;
+ public Type type { get; private set; }
+ [SerializeField]
+ private string _type;
+ public bool enabled { get { return _enabled; } set { _enabled = value; } }
+ [SerializeField]
+ private bool _enabled;
+
+ public NodePort(string name, Type type, Node node, bool enabled) {
+ _name = name;
+ _enabled = enabled;
+ this.type = type;
+ _type = type.FullName;
+ this.node = node;
+ }
+
+ public NodePort GetConnection() {
+ return null;
+ }
+ public NodePort[] GetConnections() {
+ return null;
+ }
+}
diff --git a/Scripts/NodePort.cs.meta b/Scripts/NodePort.cs.meta
new file mode 100644
index 0000000..3863705
--- /dev/null
+++ b/Scripts/NodePort.cs.meta
@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 7dd2f76ac25c6f44c9426dff3e7491a3
+timeCreated: 1505734054
+licenseType: Free
+MonoImporter:
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant: