Tim Cooper
8 年前
当前提交
01630326
共有 22 个文件被更改,包括 1691 次插入 和 1544 次删除
-
752MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Editor/Drawing/GraphEditWindow.cs
-
13MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Editor/Drawing/MaterialGraphDataSource.cs
-
286MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Editor/Drawing/MaterialGraphNode.cs
-
144MaterialGraphProject/Assets/GraphFramework/SerializableGraph/Editor/Drawing/MaterialNodeData.cs
-
108MaterialGraphProject/Assets/NewUI/Editor/CustomDataView.cs
-
37MaterialGraphProject/Assets/NewUI/Editor/DataContainer.cs
-
398MaterialGraphProject/Assets/NewUI/Editor/Demo/Elements/Graph/NodeAnchor.cs
-
92MaterialGraphProject/Assets/NewUI/Editor/Demo/Elements/InvisibleBorderContainer.cs
-
60MaterialGraphProject/Assets/NewUI/Editor/Demo/Views/IMGUISampleView.cs
-
6MaterialGraphProject/Assets/NewUI/Editor/Demo/Views/NodalView.cs
-
62MaterialGraphProject/Assets/NewUI/Editor/Demo/Views/SimpleGraphView.cs
-
8MaterialGraphProject/Assets/NewUI/Editor/Elements/Data/GraphElementData.cs
-
112MaterialGraphProject/Assets/NewUI/Editor/Elements/GraphElement.cs
-
304MaterialGraphProject/Assets/NewUI/Editor/Manipulators/EdgeConnector.cs
-
2MaterialGraphProject/Assets/NewUI/Editor/Views/Data/GraphViewDataSource.cs
-
2MaterialGraphProject/Assets/NewUI/Editor/Views/Data/IGraphElementDataSource.cs
-
321MaterialGraphProject/Assets/NewUI/Editor/Views/GraphView.cs
-
430MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/NodeDrawers/AbstractMaterialNodeUI.cs
-
93MaterialGraphProject/Assets/UnityShaderEditor/Editor/Styles/NodalView.uss
-
5MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Nodes/ColorNode.cs
-
0/MaterialGraphProject/Assets/NewUI/Editor/Views/Data/IGraphElementDataSource.cs.meta
-
0/MaterialGraphProject/Assets/NewUI/Editor/Views/Data/IGraphElementDataSource.cs
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
using UnityEngine.Graphing; |
|||
using UnityEngine.MaterialGraph; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace UnityEditor.Graphing.Drawing |
|||
{ |
|||
public class GraphEditWindow : AbstractGraphEditWindow<IGraphAsset> |
|||
{ |
|||
[MenuItem("Window/Graph Editor")] |
|||
public static void OpenMenu() |
|||
{ |
|||
GetWindow<GraphEditWindow>(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public abstract class AbstractGraphEditWindow<T> : EditorWindow, ISerializationCallbackReceiver where T : class, IGraphAsset |
|||
{ |
|||
public RenderTexture rt; |
|||
|
|||
[NonSerialized] |
|||
private T m_LastSelection; |
|||
|
|||
[SerializeField] |
|||
private ScriptableObject m_LastSelectedGraphSerialized; |
|||
|
|||
private bool shouldRepaint |
|||
{ |
|||
get |
|||
{ |
|||
return m_LastSelection != null && m_LastSelection.shouldRepaint; |
|||
} |
|||
} |
|||
|
|||
private MaterialGraphView m_Contents; |
|||
|
|||
void OnEnable() |
|||
{ |
|||
m_Contents = new MaterialGraphView(); |
|||
m_Contents.name = "theView"; |
|||
m_Contents.dataProvider = new MaterialGraphDataSource(m_LastSelection); |
|||
m_Contents.StretchToParentSize(); |
|||
|
|||
windowRoot.AddChild(m_Contents); |
|||
} |
|||
|
|||
void OnDisable() |
|||
{ |
|||
windowRoot.ClearChildren(); |
|||
} |
|||
|
|||
void Update() |
|||
{ |
|||
if (shouldRepaint) |
|||
Repaint(); |
|||
} |
|||
|
|||
void OnSelectionChange() |
|||
{ |
|||
if (Selection.activeObject == null || !EditorUtility.IsPersistent(Selection.activeObject)) |
|||
return; |
|||
|
|||
if (Selection.activeObject is ScriptableObject) |
|||
{ |
|||
var selection = Selection.activeObject as T; |
|||
if (selection != m_LastSelection) |
|||
{ |
|||
var graph = selection.graph; |
|||
graph.OnEnable(); |
|||
graph.ValidateGraph(); |
|||
m_LastSelection = selection; |
|||
|
|||
m_Contents.dataProvider = new MaterialGraphDataSource(m_LastSelection); |
|||
|
|||
m_Contents.StretchToParentSize(); |
|||
|
|||
m_Contents.OnDataChanged(); |
|||
Repaint(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* |
|||
|
|||
|
|||
private void ConvertSelectionToSubGraph() |
|||
{ |
|||
if (m_Canvas.dataSource == null) |
|||
return; |
|||
|
|||
var dataSource = m_Canvas.dataSource as GraphDataSource; |
|||
if (dataSource == null) |
|||
return; |
|||
|
|||
var asset = dataSource.graphAsset; |
|||
if (asset == null) |
|||
return; |
|||
|
|||
var targetGraph = asset.graph; |
|||
if (targetGraph == null) |
|||
return; |
|||
|
|||
if (!m_Canvas.selection.Any()) |
|||
return; |
|||
|
|||
var serialzied = CopySelected.SerializeSelectedElements(m_Canvas); |
|||
var deserialized = CopySelected.DeserializeSelectedElements(serialzied); |
|||
if (deserialized == null) |
|||
return; |
|||
|
|||
string path = EditorUtility.SaveFilePanelInProject("Save subgraph", "New SubGraph", "ShaderSubGraph", ""); |
|||
path = path.Replace(Application.dataPath, "Assets"); |
|||
if (path.Length == 0) |
|||
return; |
|||
|
|||
var graphAsset = CreateInstance<MaterialSubGraphAsset>(); |
|||
graphAsset.name = Path.GetFileName(path); |
|||
graphAsset.PostCreate(); |
|||
|
|||
var graph = graphAsset.subGraph; |
|||
if (graphAsset.graph == null) |
|||
return; |
|||
|
|||
var nodeGuidMap = new Dictionary<Guid, Guid>(); |
|||
foreach (var node in deserialized.GetNodes<INode>()) |
|||
{ |
|||
var oldGuid = node.guid; |
|||
var newGuid = node.RewriteGuid(); |
|||
nodeGuidMap[oldGuid] = newGuid; |
|||
graph.AddNode(node); |
|||
} |
|||
|
|||
// remap outputs to the subgraph
|
|||
var inputEdgeNeedsRemap = new List<IEdge>(); |
|||
var outputEdgeNeedsRemap = new List<IEdge>(); |
|||
foreach (var edge in deserialized.edges) |
|||
{ |
|||
var outputSlot = edge.outputSlot; |
|||
var inputSlot = edge.inputSlot; |
|||
|
|||
Guid remappedOutputNodeGuid; |
|||
Guid remappedInputNodeGuid; |
|||
var outputRemapExists = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid); |
|||
var inputRemapExists = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid); |
|||
|
|||
// pasting nice internal links!
|
|||
if (outputRemapExists && inputRemapExists) |
|||
{ |
|||
var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId); |
|||
var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotId); |
|||
graph.Connect(outputSlotRef, inputSlotRef); |
|||
} |
|||
// one edge needs to go to outside world
|
|||
else if (outputRemapExists) |
|||
{ |
|||
inputEdgeNeedsRemap.Add(edge); |
|||
} |
|||
else if (inputRemapExists) |
|||
{ |
|||
outputEdgeNeedsRemap.Add(edge); |
|||
} |
|||
} |
|||
|
|||
// we do a grouping here as the same output can
|
|||
// point to multiple inputs
|
|||
var uniqueOutputs = outputEdgeNeedsRemap.GroupBy(edge => edge.outputSlot); |
|||
var inputsNeedingConnection = new List<KeyValuePair<IEdge, IEdge>>(); |
|||
foreach (var group in uniqueOutputs) |
|||
{ |
|||
var inputNode = graph.inputNode; |
|||
var slotId = inputNode.AddSlot(); |
|||
|
|||
var outputSlotRef = new SlotReference(inputNode.guid, slotId); |
|||
|
|||
foreach (var edge in group) |
|||
{ |
|||
var newEdge = graph.Connect(outputSlotRef, new SlotReference(nodeGuidMap[edge.inputSlot.nodeGuid], edge.inputSlot.slotId)); |
|||
inputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge)); |
|||
} |
|||
} |
|||
|
|||
var uniqueInputs = inputEdgeNeedsRemap.GroupBy(edge => edge.inputSlot); |
|||
var outputsNeedingConnection = new List<KeyValuePair<IEdge, IEdge>>(); |
|||
foreach (var group in uniqueInputs) |
|||
{ |
|||
var outputNode = graph.outputNode; |
|||
var slotId = outputNode.AddSlot(); |
|||
|
|||
var inputSlotRef = new SlotReference(outputNode.guid, slotId); |
|||
|
|||
foreach (var edge in group) |
|||
{ |
|||
var newEdge = graph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotId), inputSlotRef); |
|||
outputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge)); |
|||
} |
|||
} |
|||
AssetDatabase.CreateAsset(graphAsset, path); |
|||
|
|||
var subGraphNode = new SubGraphNode(); |
|||
targetGraph.AddNode(subGraphNode); |
|||
subGraphNode.subGraphAsset = graphAsset; |
|||
|
|||
foreach (var edgeMap in inputsNeedingConnection) |
|||
{ |
|||
targetGraph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.outputSlot.slotId)); |
|||
} |
|||
foreach (var edgeMap in outputsNeedingConnection) |
|||
{ |
|||
targetGraph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot); |
|||
} |
|||
|
|||
var toDelete = m_Canvas.selection.Where(x => x is DrawableNode).ToList(); |
|||
dataSource.DeleteElements(toDelete); |
|||
|
|||
targetGraph.ValidateGraph(); |
|||
m_Canvas.ReloadData(); |
|||
m_Canvas.Invalidate(); |
|||
m_Canvas.selection.Clear(); |
|||
|
|||
var toSelect = m_Canvas.elements.OfType<DrawableNode>().FirstOrDefault(x => x.m_Node == subGraphNode); |
|||
if (toSelect != null) |
|||
{ |
|||
toSelect.selected = true; |
|||
m_Canvas.selection.Add(toSelect); |
|||
} |
|||
m_Canvas.Repaint(); |
|||
} |
|||
|
|||
private void Rebuild() |
|||
{ |
|||
if (m_Canvas == null || m_LastSelection == null) |
|||
return; |
|||
|
|||
m_DataSource.graphAsset = m_LastSelection; |
|||
m_Canvas.ReloadData(); |
|||
}*/ |
|||
|
|||
/* void OnGUI() |
|||
{ |
|||
m_HostWindow = this; |
|||
if (m_Canvas == null) |
|||
{ |
|||
InitializeCanvas(); |
|||
} |
|||
|
|||
if (m_LastSelection == null || m_LastSelection.graph == null) |
|||
{ |
|||
GUILayout.Label("No Graph selected"); |
|||
return; |
|||
} |
|||
|
|||
m_Canvas.OnGUI(this, new Rect(0, 0, position.width - 250, position.height)); |
|||
|
|||
if (GUI.Button(new Rect(position.width - 250, 0, 250, 50), "Convert to Sub-Graph")) |
|||
ConvertSelectionToSubGraph(); |
|||
|
|||
if (GUI.Button(new Rect(position.width - 250, 70, 250, 50), "Export")) |
|||
Export(false); |
|||
|
|||
|
|||
if (GUI.Button(new Rect(position.width - 250, 140, 250, 50), "Export - quick")) |
|||
Export(true); |
|||
|
|||
|
|||
EditorGUI.ObjectField(new Rect(position.width - 250, 210, 250, 50), rt, typeof(RenderTexture), false); |
|||
}*/ |
|||
|
|||
private string m_LastPath; |
|||
|
|||
public void Export(bool quickExport) |
|||
{ |
|||
var path = quickExport ? m_LastPath : EditorUtility.SaveFilePanelInProject("Export shader to file...", "shader.shader", "shader", "Enter file name"); |
|||
m_LastPath = path; // For quick exporting
|
|||
|
|||
var ds = m_Contents.dataProvider as MaterialGraphDataSource; |
|||
if (ds != null && !string.IsNullOrEmpty(path)) |
|||
{ |
|||
ExportShader (ds.graphAsset as MaterialGraphAsset, path); |
|||
} |
|||
else |
|||
EditorUtility.DisplayDialog("Export Shader Error", "Cannot export shader", "Ok"); |
|||
} |
|||
|
|||
public static Shader ExportShader(MaterialGraphAsset graphAsset, string path) |
|||
{ |
|||
if (graphAsset == null) |
|||
return null; |
|||
|
|||
var materialGraph = graphAsset.graph as PixelGraph; |
|||
if (materialGraph == null) |
|||
return null; |
|||
|
|||
List<PropertyGenerator.TextureInfo> configuredTextures; |
|||
var shaderString = ShaderGenerator.GenerateSurfaceShader(materialGraph.pixelMasterNode, new MaterialOptions(), materialGraph.name, false, out configuredTextures); |
|||
File.WriteAllText(path, shaderString); |
|||
AssetDatabase.Refresh(); // Investigate if this is optimal
|
|||
|
|||
var shader = AssetDatabase.LoadAssetAtPath(path, typeof(Shader)) as Shader; |
|||
if (shader == null) |
|||
return null; |
|||
|
|||
var shaderImporter = AssetImporter.GetAtPath(path) as ShaderImporter; |
|||
if (shaderImporter == null) |
|||
return null; |
|||
|
|||
var textureNames = new List<string>(); |
|||
var textures = new List<Texture>(); |
|||
foreach (var textureInfo in configuredTextures.Where(x => x.modifiable == TexturePropertyChunk.ModifiableState.Modifiable)) |
|||
{ |
|||
var texture = EditorUtility.InstanceIDToObject(textureInfo.textureId) as Texture; |
|||
if (texture == null) |
|||
continue; |
|||
textureNames.Add(textureInfo.name); |
|||
textures.Add(texture); |
|||
} |
|||
shaderImporter.SetDefaultTextures(textureNames.ToArray(), textures.ToArray()); |
|||
|
|||
textureNames.Clear(); |
|||
textures.Clear(); |
|||
foreach (var textureInfo in configuredTextures.Where(x => x.modifiable == TexturePropertyChunk.ModifiableState.NonModifiable)) |
|||
{ |
|||
var texture = EditorUtility.InstanceIDToObject(textureInfo.textureId) as Texture; |
|||
if (texture == null) |
|||
continue; |
|||
textureNames.Add(textureInfo.name); |
|||
textures.Add(texture); |
|||
} |
|||
shaderImporter.SetNonModifiableTextures(textureNames.ToArray(), textures.ToArray()); |
|||
|
|||
shaderImporter.SaveAndReimport(); |
|||
|
|||
return shaderImporter.GetShader(); |
|||
} |
|||
|
|||
/*public void RenderOptions(MaterialGraph graph) |
|||
{ |
|||
EditorGUILayout.BeginHorizontal(); |
|||
GUILayout.FlexibleSpace(); |
|||
|
|||
EditorGUILayout.BeginVertical(); |
|||
m_ScrollPos = GUILayout.BeginScrollView(m_ScrollPos, EditorStyles.textArea, GUILayout.width(250), GUILayout.ExpandHeight(true)); |
|||
graph.materialOptions.DoGUI(); |
|||
EditorGUILayout.Separator(); |
|||
|
|||
m_NodeExpanded = MaterialGraphStyles.Header("Selected", m_NodeExpanded); |
|||
if (m_NodeExpanded) |
|||
DrawableMaterialNode.OnGUI(m_Canvas.selection); |
|||
|
|||
GUILayout.EndScrollView(); |
|||
if (GUILayout.Button("Export")) |
|||
m_DataSource.Export(false); |
|||
|
|||
GUILayout.EndVertical(); |
|||
EditorGUILayout.EndHorizontal(); |
|||
}*/ |
|||
|
|||
public void OnBeforeSerialize() |
|||
{ |
|||
var o = m_LastSelection as ScriptableObject; |
|||
if (o != null) |
|||
m_LastSelectedGraphSerialized = o; |
|||
} |
|||
|
|||
public void OnAfterDeserialize() |
|||
{ |
|||
if (m_LastSelectedGraphSerialized != null) |
|||
m_LastSelection = m_LastSelectedGraphSerialized as T; |
|||
|
|||
m_LastSelectedGraphSerialized = null; |
|||
} |
|||
} |
|||
} |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.IO; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
using UnityEngine.Graphing; |
|||
using UnityEngine.MaterialGraph; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace UnityEditor.Graphing.Drawing |
|||
{ |
|||
public class GraphEditWindow : AbstractGraphEditWindow<IGraphAsset> |
|||
{ |
|||
[MenuItem("Window/Graph Editor")] |
|||
public static void OpenMenu() |
|||
{ |
|||
GetWindow<GraphEditWindow>(); |
|||
} |
|||
} |
|||
|
|||
|
|||
public abstract class AbstractGraphEditWindow<T> : EditorWindow, ISerializationCallbackReceiver where T : class, IGraphAsset |
|||
{ |
|||
public RenderTexture rt; |
|||
|
|||
[NonSerialized] |
|||
private T m_LastSelection; |
|||
|
|||
[SerializeField] |
|||
private ScriptableObject m_LastSelectedGraphSerialized; |
|||
|
|||
private bool shouldRepaint |
|||
{ |
|||
get |
|||
{ |
|||
return m_LastSelection != null && m_LastSelection.shouldRepaint; |
|||
} |
|||
} |
|||
|
|||
private MaterialGraphView m_Contents; |
|||
|
|||
void OnEnable() |
|||
{ |
|||
m_Contents = new MaterialGraphView(); |
|||
m_Contents.name = "theView"; |
|||
m_Contents.dataSource = new MaterialGraphDataSource(m_LastSelection); |
|||
m_Contents.StretchToParentSize(); |
|||
|
|||
windowRoot.AddChild(m_Contents); |
|||
} |
|||
|
|||
void OnDisable() |
|||
{ |
|||
windowRoot.ClearChildren(); |
|||
} |
|||
|
|||
void Update() |
|||
{ |
|||
if (shouldRepaint) |
|||
Repaint(); |
|||
} |
|||
|
|||
void OnSelectionChange() |
|||
{ |
|||
if (Selection.activeObject == null || !EditorUtility.IsPersistent(Selection.activeObject)) |
|||
return; |
|||
|
|||
if (Selection.activeObject is ScriptableObject) |
|||
{ |
|||
var selection = Selection.activeObject as T; |
|||
if (selection != m_LastSelection) |
|||
{ |
|||
var graph = selection.graph; |
|||
graph.OnEnable(); |
|||
graph.ValidateGraph(); |
|||
m_LastSelection = selection; |
|||
|
|||
m_Contents.dataSource = new MaterialGraphDataSource(m_LastSelection); |
|||
|
|||
m_Contents.StretchToParentSize(); |
|||
Repaint(); |
|||
} |
|||
} |
|||
} |
|||
|
|||
/* |
|||
|
|||
|
|||
private void ConvertSelectionToSubGraph() |
|||
{ |
|||
if (m_Canvas.dataSource == null) |
|||
return; |
|||
|
|||
var dataSource = m_Canvas.dataSource as GraphDataSource; |
|||
if (dataSource == null) |
|||
return; |
|||
|
|||
var asset = dataSource.graphAsset; |
|||
if (asset == null) |
|||
return; |
|||
|
|||
var targetGraph = asset.graph; |
|||
if (targetGraph == null) |
|||
return; |
|||
|
|||
if (!m_Canvas.selection.Any()) |
|||
return; |
|||
|
|||
var serialzied = CopySelected.SerializeSelectedElements(m_Canvas); |
|||
var deserialized = CopySelected.DeserializeSelectedElements(serialzied); |
|||
if (deserialized == null) |
|||
return; |
|||
|
|||
string path = EditorUtility.SaveFilePanelInProject("Save subgraph", "New SubGraph", "ShaderSubGraph", ""); |
|||
path = path.Replace(Application.dataPath, "Assets"); |
|||
if (path.Length == 0) |
|||
return; |
|||
|
|||
var graphAsset = CreateInstance<MaterialSubGraphAsset>(); |
|||
graphAsset.name = Path.GetFileName(path); |
|||
graphAsset.PostCreate(); |
|||
|
|||
var graph = graphAsset.subGraph; |
|||
if (graphAsset.graph == null) |
|||
return; |
|||
|
|||
var nodeGuidMap = new Dictionary<Guid, Guid>(); |
|||
foreach (var node in deserialized.GetNodes<INode>()) |
|||
{ |
|||
var oldGuid = node.guid; |
|||
var newGuid = node.RewriteGuid(); |
|||
nodeGuidMap[oldGuid] = newGuid; |
|||
graph.AddNode(node); |
|||
} |
|||
|
|||
// remap outputs to the subgraph
|
|||
var inputEdgeNeedsRemap = new List<IEdge>(); |
|||
var outputEdgeNeedsRemap = new List<IEdge>(); |
|||
foreach (var edge in deserialized.edges) |
|||
{ |
|||
var outputSlot = edge.outputSlot; |
|||
var inputSlot = edge.inputSlot; |
|||
|
|||
Guid remappedOutputNodeGuid; |
|||
Guid remappedInputNodeGuid; |
|||
var outputRemapExists = nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid); |
|||
var inputRemapExists = nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid); |
|||
|
|||
// pasting nice internal links!
|
|||
if (outputRemapExists && inputRemapExists) |
|||
{ |
|||
var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId); |
|||
var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotId); |
|||
graph.Connect(outputSlotRef, inputSlotRef); |
|||
} |
|||
// one edge needs to go to outside world
|
|||
else if (outputRemapExists) |
|||
{ |
|||
inputEdgeNeedsRemap.Add(edge); |
|||
} |
|||
else if (inputRemapExists) |
|||
{ |
|||
outputEdgeNeedsRemap.Add(edge); |
|||
} |
|||
} |
|||
|
|||
// we do a grouping here as the same output can
|
|||
// point to multiple inputs
|
|||
var uniqueOutputs = outputEdgeNeedsRemap.GroupBy(edge => edge.outputSlot); |
|||
var inputsNeedingConnection = new List<KeyValuePair<IEdge, IEdge>>(); |
|||
foreach (var group in uniqueOutputs) |
|||
{ |
|||
var inputNode = graph.inputNode; |
|||
var slotId = inputNode.AddSlot(); |
|||
|
|||
var outputSlotRef = new SlotReference(inputNode.guid, slotId); |
|||
|
|||
foreach (var edge in group) |
|||
{ |
|||
var newEdge = graph.Connect(outputSlotRef, new SlotReference(nodeGuidMap[edge.inputSlot.nodeGuid], edge.inputSlot.slotId)); |
|||
inputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge)); |
|||
} |
|||
} |
|||
|
|||
var uniqueInputs = inputEdgeNeedsRemap.GroupBy(edge => edge.inputSlot); |
|||
var outputsNeedingConnection = new List<KeyValuePair<IEdge, IEdge>>(); |
|||
foreach (var group in uniqueInputs) |
|||
{ |
|||
var outputNode = graph.outputNode; |
|||
var slotId = outputNode.AddSlot(); |
|||
|
|||
var inputSlotRef = new SlotReference(outputNode.guid, slotId); |
|||
|
|||
foreach (var edge in group) |
|||
{ |
|||
var newEdge = graph.Connect(new SlotReference(nodeGuidMap[edge.outputSlot.nodeGuid], edge.outputSlot.slotId), inputSlotRef); |
|||
outputsNeedingConnection.Add(new KeyValuePair<IEdge, IEdge>(edge, newEdge)); |
|||
} |
|||
} |
|||
AssetDatabase.CreateAsset(graphAsset, path); |
|||
|
|||
var subGraphNode = new SubGraphNode(); |
|||
targetGraph.AddNode(subGraphNode); |
|||
subGraphNode.subGraphAsset = graphAsset; |
|||
|
|||
foreach (var edgeMap in inputsNeedingConnection) |
|||
{ |
|||
targetGraph.Connect(edgeMap.Key.outputSlot, new SlotReference(subGraphNode.guid, edgeMap.Value.outputSlot.slotId)); |
|||
} |
|||
foreach (var edgeMap in outputsNeedingConnection) |
|||
{ |
|||
targetGraph.Connect(new SlotReference(subGraphNode.guid, edgeMap.Value.inputSlot.slotId), edgeMap.Key.inputSlot); |
|||
} |
|||
|
|||
var toDelete = m_Canvas.selection.Where(x => x is DrawableNode).ToList(); |
|||
dataSource.DeleteElements(toDelete); |
|||
|
|||
targetGraph.ValidateGraph(); |
|||
m_Canvas.ReloadData(); |
|||
m_Canvas.Invalidate(); |
|||
m_Canvas.selection.Clear(); |
|||
|
|||
var toSelect = m_Canvas.elements.OfType<DrawableNode>().FirstOrDefault(x => x.m_Node == subGraphNode); |
|||
if (toSelect != null) |
|||
{ |
|||
toSelect.selected = true; |
|||
m_Canvas.selection.Add(toSelect); |
|||
} |
|||
m_Canvas.Repaint(); |
|||
} |
|||
|
|||
private void Rebuild() |
|||
{ |
|||
if (m_Canvas == null || m_LastSelection == null) |
|||
return; |
|||
|
|||
m_DataSource.graphAsset = m_LastSelection; |
|||
m_Canvas.ReloadData(); |
|||
}*/ |
|||
|
|||
/* void OnGUI() |
|||
{ |
|||
m_HostWindow = this; |
|||
if (m_Canvas == null) |
|||
{ |
|||
InitializeCanvas(); |
|||
} |
|||
|
|||
if (m_LastSelection == null || m_LastSelection.graph == null) |
|||
{ |
|||
GUILayout.Label("No Graph selected"); |
|||
return; |
|||
} |
|||
|
|||
m_Canvas.OnGUI(this, new Rect(0, 0, position.width - 250, position.height)); |
|||
|
|||
if (GUI.Button(new Rect(position.width - 250, 0, 250, 50), "Convert to Sub-Graph")) |
|||
ConvertSelectionToSubGraph(); |
|||
|
|||
if (GUI.Button(new Rect(position.width - 250, 70, 250, 50), "Export")) |
|||
Export(false); |
|||
|
|||
|
|||
if (GUI.Button(new Rect(position.width - 250, 140, 250, 50), "Export - quick")) |
|||
Export(true); |
|||
|
|||
|
|||
EditorGUI.ObjectField(new Rect(position.width - 250, 210, 250, 50), rt, typeof(RenderTexture), false); |
|||
}*/ |
|||
|
|||
private string m_LastPath; |
|||
|
|||
public void Export(bool quickExport) |
|||
{ |
|||
var path = quickExport ? m_LastPath : EditorUtility.SaveFilePanelInProject("Export shader to file...", "shader.shader", "shader", "Enter file name"); |
|||
m_LastPath = path; // For quick exporting
|
|||
|
|||
var ds = m_Contents.dataSource as MaterialGraphDataSource; |
|||
if (ds != null && !string.IsNullOrEmpty(path)) |
|||
{ |
|||
ExportShader (ds.graphAsset as MaterialGraphAsset, path); |
|||
} |
|||
else |
|||
EditorUtility.DisplayDialog("Export Shader Error", "Cannot export shader", "Ok"); |
|||
} |
|||
|
|||
public static Shader ExportShader(MaterialGraphAsset graphAsset, string path) |
|||
{ |
|||
if (graphAsset == null) |
|||
return null; |
|||
|
|||
var materialGraph = graphAsset.graph as PixelGraph; |
|||
if (materialGraph == null) |
|||
return null; |
|||
|
|||
List<PropertyGenerator.TextureInfo> configuredTextures; |
|||
var shaderString = ShaderGenerator.GenerateSurfaceShader(materialGraph.pixelMasterNode, new MaterialOptions(), materialGraph.name, false, out configuredTextures); |
|||
File.WriteAllText(path, shaderString); |
|||
AssetDatabase.Refresh(); // Investigate if this is optimal
|
|||
|
|||
var shader = AssetDatabase.LoadAssetAtPath(path, typeof(Shader)) as Shader; |
|||
if (shader == null) |
|||
return null; |
|||
|
|||
var shaderImporter = AssetImporter.GetAtPath(path) as ShaderImporter; |
|||
if (shaderImporter == null) |
|||
return null; |
|||
|
|||
var textureNames = new List<string>(); |
|||
var textures = new List<Texture>(); |
|||
foreach (var textureInfo in configuredTextures.Where(x => x.modifiable == TexturePropertyChunk.ModifiableState.Modifiable)) |
|||
{ |
|||
var texture = EditorUtility.InstanceIDToObject(textureInfo.textureId) as Texture; |
|||
if (texture == null) |
|||
continue; |
|||
textureNames.Add(textureInfo.name); |
|||
textures.Add(texture); |
|||
} |
|||
shaderImporter.SetDefaultTextures(textureNames.ToArray(), textures.ToArray()); |
|||
|
|||
textureNames.Clear(); |
|||
textures.Clear(); |
|||
foreach (var textureInfo in configuredTextures.Where(x => x.modifiable == TexturePropertyChunk.ModifiableState.NonModifiable)) |
|||
{ |
|||
var texture = EditorUtility.InstanceIDToObject(textureInfo.textureId) as Texture; |
|||
if (texture == null) |
|||
continue; |
|||
textureNames.Add(textureInfo.name); |
|||
textures.Add(texture); |
|||
} |
|||
shaderImporter.SetNonModifiableTextures(textureNames.ToArray(), textures.ToArray()); |
|||
|
|||
shaderImporter.SaveAndReimport(); |
|||
|
|||
return shaderImporter.GetShader(); |
|||
} |
|||
|
|||
/*public void RenderOptions(MaterialGraph graph) |
|||
{ |
|||
EditorGUILayout.BeginHorizontal(); |
|||
GUILayout.FlexibleSpace(); |
|||
|
|||
EditorGUILayout.BeginVertical(); |
|||
m_ScrollPos = GUILayout.BeginScrollView(m_ScrollPos, EditorStyles.textArea, GUILayout.width(250), GUILayout.ExpandHeight(true)); |
|||
graph.materialOptions.DoGUI(); |
|||
EditorGUILayout.Separator(); |
|||
|
|||
m_NodeExpanded = MaterialGraphStyles.Header("Selected", m_NodeExpanded); |
|||
if (m_NodeExpanded) |
|||
DrawableMaterialNode.OnGUI(m_Canvas.selection); |
|||
|
|||
GUILayout.EndScrollView(); |
|||
if (GUILayout.Button("Export")) |
|||
m_DataSource.Export(false); |
|||
|
|||
GUILayout.EndVertical(); |
|||
EditorGUILayout.EndHorizontal(); |
|||
}*/ |
|||
|
|||
public void OnBeforeSerialize() |
|||
{ |
|||
var o = m_LastSelection as ScriptableObject; |
|||
if (o != null) |
|||
m_LastSelectedGraphSerialized = o; |
|||
} |
|||
|
|||
public void OnAfterDeserialize() |
|||
{ |
|||
if (m_LastSelectedGraphSerialized != null) |
|||
m_LastSelection = m_LastSelectedGraphSerialized as T; |
|||
|
|||
m_LastSelectedGraphSerialized = null; |
|||
} |
|||
} |
|||
} |
|
|||
using System.Linq; |
|||
using RMGUI.GraphView; |
|||
using RMGUI.GraphView.Demo; |
|||
using UnityEditor.MaterialGraph; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
using UnityEngine.RMGUI.StyleEnums.Values; |
|||
|
|||
namespace UnityEditor.Graphing.Drawing |
|||
{ |
|||
[GUISkinStyle("window")] |
|||
[CustomDataView(typeof(MaterialNodeData))] |
|||
public class MaterialGraphNode : GraphElement |
|||
{ |
|||
VisualContainer m_SlotContainer; |
|||
// VisualContainer m_ControlsContainer;
|
|||
VisualContainer m_PreviewContainer; |
|||
|
|||
public MaterialGraphNode() |
|||
{ |
|||
content = new GUIContent(""); |
|||
|
|||
m_SlotContainer = new VisualContainer |
|||
{ |
|||
name = "slots", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
|
|||
/* m_ControlsContainer = new VisualContainer |
|||
{ |
|||
name = "controls", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
};*/ |
|||
|
|||
m_PreviewContainer = new VisualContainer |
|||
{ |
|||
name = "preview", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
|
|||
} |
|||
|
|||
public override void DoRepaint(PaintContext painter) |
|||
{ |
|||
base.DoRepaint(painter); |
|||
if (GetData<GraphElementData>() != null && GetData<GraphElementData>().selected) |
|||
{ |
|||
painter.DrawRectangleOutline(transform, position, Color.yellow); |
|||
} |
|||
} |
|||
|
|||
private void AddSlots(MaterialNodeData nodeData) |
|||
{ |
|||
m_SlotContainer.ClearChildren(); |
|||
|
|||
if (!nodeData.elements.OfType<NodeAnchorData>().Any()) |
|||
return; |
|||
|
|||
var inputs = new VisualContainer |
|||
{ |
|||
name = "input", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
m_SlotContainer.AddChild(inputs); |
|||
|
|||
// put a spacer here?
|
|||
//m_SlotContainer.AddChild(new f);
|
|||
|
|||
var outputs = new VisualContainer |
|||
{ |
|||
name = "input", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
m_SlotContainer.AddChild(outputs); |
|||
|
|||
content = new GUIContent(nodeData.name); |
|||
foreach (var anchor in nodeData.elements.OfType<NodeAnchorData>()) |
|||
{ |
|||
if (anchor.direction == Direction.Input) |
|||
inputs.AddChild(new NodeAnchor(anchor)); |
|||
else |
|||
outputs.AddChild(new NodeAnchor(anchor)); |
|||
} |
|||
|
|||
AddChild(m_SlotContainer); |
|||
} |
|||
|
|||
private void AddPreview(MaterialNodeData nodeData) |
|||
{ |
|||
m_PreviewContainer.ClearChildren(); |
|||
|
|||
if (!nodeData.elements.OfType<NodePreviewData>().Any()) |
|||
return; |
|||
|
|||
foreach (var preview in nodeData.elements.OfType<NodePreviewData>()) |
|||
{ |
|||
var image = preview.Render(new Vector2(200, 200)); |
|||
m_PreviewContainer.AddChild(new Image { image = image }); |
|||
} |
|||
|
|||
AddChild(m_PreviewContainer); |
|||
} |
|||
|
|||
public override void OnDataChanged() |
|||
{ |
|||
base.OnDataChanged(); |
|||
ClearChildren(); |
|||
|
|||
// m_ControlsContainer.ClearChildren();
|
|||
m_PreviewContainer.ClearChildren(); |
|||
|
|||
var nodeData = dataProvider as MaterialNodeData; |
|||
|
|||
if (nodeData == null) |
|||
return; |
|||
|
|||
AddSlots(nodeData); |
|||
AddPreview(nodeData); |
|||
|
|||
positionType = PositionType.Absolute; |
|||
positionLeft = nodeData.node.drawState.position.x; |
|||
positionTop = nodeData.node.drawState.position.y; |
|||
} |
|||
} |
|||
} |
|||
using System.Linq; |
|||
using RMGUI.GraphView; |
|||
using RMGUI.GraphView.Demo; |
|||
using UnityEditor.MaterialGraph; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace UnityEditor.Graphing.Drawing |
|||
{ |
|||
class PreviewImage : Image |
|||
{ |
|||
public override void DoRepaint(PaintContext args) |
|||
{ |
|||
Handles.DrawSolidRectangleWithOutline(position, Color.blue, Color.blue); |
|||
base.DoRepaint(args); |
|||
} |
|||
} |
|||
|
|||
[GUISkinStyle("window")] |
|||
[CustomDataView(typeof(MaterialNodeData))] |
|||
[CustomDataView(typeof(ColorNodeData))] |
|||
public class MaterialGraphNode : GraphElement |
|||
{ |
|||
VisualContainer m_SlotContainer; |
|||
VisualContainer m_ControlsContainer; |
|||
VisualContainer m_PreviewContainer; |
|||
|
|||
public MaterialGraphNode() |
|||
{ |
|||
content = new GUIContent(""); |
|||
|
|||
m_SlotContainer = new VisualContainer |
|||
{ |
|||
name = "slots", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
|
|||
m_ControlsContainer = new VisualContainer |
|||
{ |
|||
name = "controls", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
|
|||
m_PreviewContainer = new VisualContainer |
|||
{ |
|||
name = "preview", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
|
|||
} |
|||
|
|||
public override void DoRepaint(PaintContext painter) |
|||
{ |
|||
base.DoRepaint(painter); |
|||
if (GetData<GraphElementData>() != null && GetData<GraphElementData>().selected) |
|||
{ |
|||
painter.DrawRectangleOutline(transform, position, Color.yellow); |
|||
} |
|||
} |
|||
|
|||
private void AddSlots(MaterialNodeData nodeData) |
|||
{ |
|||
m_SlotContainer.ClearChildren(); |
|||
|
|||
if (!nodeData.elements.OfType<NodeAnchorData>().Any()) |
|||
return; |
|||
|
|||
var inputs = new VisualContainer |
|||
{ |
|||
name = "input", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
m_SlotContainer.AddChild(inputs); |
|||
|
|||
// put a spacer here?
|
|||
//m_SlotContainer.AddChild(new f);
|
|||
|
|||
var outputs = new VisualContainer |
|||
{ |
|||
name = "output", // for USS&Flexbox
|
|||
pickingMode = PickingMode.Ignore, |
|||
}; |
|||
m_SlotContainer.AddChild(outputs); |
|||
|
|||
content = new GUIContent(nodeData.name); |
|||
foreach (var anchor in nodeData.elements.OfType<NodeAnchorData>()) |
|||
{ |
|||
if (anchor.direction == Direction.Input) |
|||
inputs.AddChild(new NodeAnchor(anchor)); |
|||
else |
|||
outputs.AddChild(new NodeAnchor(anchor)); |
|||
} |
|||
|
|||
AddChild(m_SlotContainer); |
|||
} |
|||
|
|||
private void AddControls(MaterialNodeData nodeData) |
|||
{ |
|||
m_ControlsContainer.ClearChildren(); |
|||
|
|||
if (!nodeData.elements.OfType<NodeControlData>().Any()) |
|||
return; |
|||
|
|||
foreach (var controlData in nodeData.elements.OfType<NodeControlData>()) |
|||
{ |
|||
var imContainer = new IMGUIContainer() |
|||
{ |
|||
name = "element", |
|||
OnGUIHandler = controlData.OnGUIHandler, |
|||
pickingMode = PickingMode.Position |
|||
}; |
|||
m_ControlsContainer.AddChild(imContainer); |
|||
} |
|||
|
|||
AddChild(m_ControlsContainer); |
|||
} |
|||
|
|||
private void AddPreview(MaterialNodeData nodeData) |
|||
{ |
|||
m_PreviewContainer.ClearChildren(); |
|||
|
|||
if (!nodeData.elements.OfType<NodePreviewData>().Any()) |
|||
return; |
|||
|
|||
foreach (var preview in nodeData.elements.OfType<NodePreviewData>()) |
|||
{ |
|||
var image = preview.Render(new Vector2(200, 200)); |
|||
var thePreview = new PreviewImage |
|||
{ |
|||
image = image, |
|||
name = "image" |
|||
}; |
|||
m_PreviewContainer.AddChild(thePreview); |
|||
} |
|||
|
|||
AddChild(m_PreviewContainer); |
|||
} |
|||
|
|||
public override void OnDataChanged() |
|||
{ |
|||
base.OnDataChanged(); |
|||
ClearChildren(); |
|||
|
|||
m_ControlsContainer.ClearChildren(); |
|||
m_PreviewContainer.ClearChildren(); |
|||
|
|||
var nodeData = dataProvider as MaterialNodeData; |
|||
|
|||
if (nodeData == null) |
|||
return; |
|||
|
|||
AddSlots(nodeData); |
|||
AddControls(nodeData); |
|||
AddPreview(nodeData); |
|||
|
|||
/*positionType = PositionType.Absolute; |
|||
positionLeft = nodeData.node.drawState.position.x; |
|||
positionTop = nodeData.node.drawState.position.y;*/ |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using RMGUI.GraphView; |
|||
using UnityEditor.MaterialGraph; |
|||
using UnityEngine.Graphing; |
|||
using UnityEngine.MaterialGraph; |
|||
|
|||
namespace UnityEditor.Graphing.Drawing |
|||
{ |
|||
|
|||
[Serializable] |
|||
public class MaterialNodeData : GraphElementData |
|||
{ |
|||
public INode node { get; private set; } |
|||
|
|||
protected List<GraphElementData> m_Children = new List<GraphElementData>(); |
|||
|
|||
public IEnumerable<GraphElementData> elements |
|||
{ |
|||
get { return m_Children; } |
|||
} |
|||
|
|||
protected MaterialNodeData() |
|||
{} |
|||
|
|||
public void Initialize(INode inNode) |
|||
{ |
|||
node = inNode; |
|||
capabilities |= Capabilities.Movable; |
|||
|
|||
if (node == null) |
|||
return; |
|||
|
|||
name = inNode.name; |
|||
|
|||
foreach (var input in node.GetSlots<ISlot>()) |
|||
{ |
|||
var data = CreateInstance<MaterialNodeAnchorData>(); |
|||
data.Initialize(input); |
|||
m_Children.Add(data); |
|||
} |
|||
|
|||
var materialNode = inNode as AbstractMaterialNode; |
|||
if (materialNode == null || !materialNode.hasPreview) |
|||
return; |
|||
|
|||
var previewData = CreateInstance<NodePreviewData>(); |
|||
previewData.Initialize(materialNode); |
|||
m_Children.Add(previewData); |
|||
|
|||
|
|||
//position = new Rect(node.drawState.position.x, node.drawState.position.y, 100, 200);
|
|||
//position
|
|||
} |
|||
|
|||
} |
|||
} |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using RMGUI.GraphView; |
|||
using UnityEditor.MaterialGraph; |
|||
using UnityEngine; |
|||
using UnityEngine.Graphing; |
|||
using UnityEngine.MaterialGraph; |
|||
|
|||
namespace UnityEditor.Graphing.Drawing |
|||
{ |
|||
|
|||
[Serializable] |
|||
public class ColorNodeData : MaterialNodeData |
|||
{ |
|||
class ColorNodeContolData : NodeControlData |
|||
{ |
|||
public override void OnGUIHandler() |
|||
{ |
|||
EditorGUILayout.ColorField("test", Color.blue); |
|||
} |
|||
} |
|||
|
|||
protected override IEnumerable<NodeControlData> GetControlData() |
|||
{ |
|||
return new List<NodeControlData> {new ColorNodeContolData()}; |
|||
} |
|||
} |
|||
|
|||
[Serializable] |
|||
public class MaterialNodeData : GraphElementData |
|||
{ |
|||
public INode node { get; private set; } |
|||
|
|||
protected List<GraphElementData> m_Children = new List<GraphElementData>(); |
|||
|
|||
public IEnumerable<GraphElementData> elements |
|||
{ |
|||
get { return m_Children; } |
|||
} |
|||
|
|||
protected MaterialNodeData() |
|||
{} |
|||
|
|||
public void Initialize(INode inNode) |
|||
{ |
|||
node = inNode; |
|||
capabilities |= Capabilities.Movable; |
|||
|
|||
if (node == null) |
|||
return; |
|||
|
|||
name = inNode.name; |
|||
|
|||
foreach (var input in node.GetSlots<ISlot>()) |
|||
{ |
|||
var data = CreateInstance<MaterialNodeAnchorData>(); |
|||
data.Initialize(input); |
|||
m_Children.Add(data); |
|||
} |
|||
|
|||
AddPreview(inNode); |
|||
|
|||
m_Children.AddRange(GetControlData().OfType<GraphElementData>()); |
|||
|
|||
|
|||
//position = new Rect(node.drawState.position.x, node.drawState.position.y, 100, 200);
|
|||
//position
|
|||
} |
|||
|
|||
private void AddPreview(INode inNode) |
|||
{ |
|||
var materialNode = inNode as AbstractMaterialNode; |
|||
if (materialNode == null || !materialNode.hasPreview) |
|||
return; |
|||
|
|||
var previewData = CreateInstance<NodePreviewData>(); |
|||
previewData.Initialize(materialNode); |
|||
m_Children.Add(previewData); |
|||
} |
|||
|
|||
protected virtual IEnumerable<NodeControlData> GetControlData() |
|||
{ |
|||
return new NodeControlData[0]; |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using UnityEngine; |
|||
|
|||
namespace RMGUI.GraphView |
|||
{ |
|||
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] |
|||
public class CustomDataView : Attribute |
|||
{ |
|||
public CustomDataView(Type t) |
|||
{ |
|||
if (t == null) |
|||
Debug.LogError("Failed to load CustomDataView inspected type"); |
|||
dataType = t; |
|||
} |
|||
|
|||
private Type dataType { get; set; } |
|||
|
|||
// map of [datType, viewType]
|
|||
private static Dictionary<Type, Type> s_TypeMap; |
|||
|
|||
public static DataContainer Create(GraphElementData data) |
|||
{ |
|||
if (s_TypeMap == null) |
|||
{ |
|||
s_TypeMap = new Dictionary<Type, Type>(); |
|||
|
|||
// add extension methods
|
|||
AppDomain currentDomain = AppDomain.CurrentDomain; |
|||
foreach (Assembly assembly in currentDomain.GetAssemblies()) |
|||
{ |
|||
foreach (Type type in assembly.GetTypes()) |
|||
{ |
|||
var attributes = type.GetCustomAttributes(typeof(CustomDataView), false); |
|||
foreach (CustomDataView att in attributes) |
|||
{ |
|||
s_TypeMap[att.dataType] = type; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
Type viewType; |
|||
if (s_TypeMap.TryGetValue(data.GetType(), out viewType)) |
|||
{ |
|||
var dataContainer = (DataContainer)Activator.CreateInstance(viewType); |
|||
dataContainer.dataProvider = data; |
|||
return dataContainer; |
|||
} |
|||
throw new InvalidOperationException("No view in assembly for this data type" + data.GetType()); |
|||
} |
|||
} |
|||
} |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using UnityEngine; |
|||
|
|||
namespace RMGUI.GraphView |
|||
{ |
|||
[AttributeUsage(AttributeTargets.All, AllowMultiple = true)] |
|||
public class CustomDataView : Attribute |
|||
{ |
|||
public CustomDataView(Type t) |
|||
{ |
|||
if (t == null) |
|||
Debug.LogError("Failed to load CustomDataView inspected type"); |
|||
dataType = t; |
|||
} |
|||
|
|||
private Type dataType { get; set; } |
|||
|
|||
// map of [datType, viewType]
|
|||
private static Dictionary<Type, Type> s_TypeMap; |
|||
|
|||
public static DataContainer<GraphElementData> Create(GraphElementData data) |
|||
{ |
|||
if (s_TypeMap == null) |
|||
{ |
|||
s_TypeMap = new Dictionary<Type, Type>(); |
|||
|
|||
// add extension methods
|
|||
AppDomain currentDomain = AppDomain.CurrentDomain; |
|||
foreach (Assembly assembly in currentDomain.GetAssemblies()) |
|||
{ |
|||
foreach (Type type in assembly.GetTypes()) |
|||
{ |
|||
var attributes = type.GetCustomAttributes(typeof(CustomDataView), false); |
|||
foreach (CustomDataView att in attributes) |
|||
{ |
|||
s_TypeMap[att.dataType] = type; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
|
|||
Type viewType; |
|||
if (s_TypeMap.TryGetValue(data.GetType(), out viewType)) |
|||
{ |
|||
var dataContainer = (DataContainer<GraphElementData>)Activator.CreateInstance(viewType); |
|||
dataContainer.dataProvider = data; |
|||
return dataContainer; |
|||
} |
|||
throw new InvalidOperationException("No view in assembly for this data type" + data.GetType()); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
using UnityEngine.RMGUI.StyleEnums.Values; |
|||
|
|||
namespace RMGUI.GraphView.Demo |
|||
{ |
|||
[CustomDataView(typeof(NodeAnchorData))] |
|||
internal class NodeAnchor : GraphElement |
|||
{ |
|||
public const float k_NodeSize = 15.0f; |
|||
|
|||
private EdgeConnector<EdgeData> m_RegularConnector = new EdgeConnector<EdgeData>(); |
|||
private EdgeConnector<CustomEdgeData> m_CustomConnector = new EdgeConnector<CustomEdgeData>(); |
|||
|
|||
private IManipulator m_CurrentConnector; |
|||
|
|||
public NodeAnchor(NodeAnchorData data) |
|||
{ |
|||
m_CurrentConnector = m_RegularConnector; |
|||
AddManipulator(m_CurrentConnector); |
|||
|
|||
dataProvider = data; |
|||
} |
|||
|
|||
private void UpdateConnector() |
|||
{ |
|||
var nodeAnchorData = dataProvider as NodeAnchorData; |
|||
if (nodeAnchorData == null) |
|||
return; |
|||
|
|||
RemoveManipulator(m_CurrentConnector); |
|||
if (!nodeAnchorData.connected || nodeAnchorData.direction != Direction.Input) |
|||
{ |
|||
if (nodeAnchorData.orientation == Orientation.Horizontal) |
|||
{ |
|||
m_CurrentConnector = m_RegularConnector; |
|||
} |
|||
else |
|||
{ |
|||
m_CurrentConnector = m_CustomConnector; |
|||
} |
|||
AddManipulator(m_CurrentConnector); |
|||
} |
|||
} |
|||
|
|||
private Rect GetAnchorRect(NodeAnchorData nodeAnchorData) |
|||
{ |
|||
Rect rect = new Rect(); |
|||
|
|||
if (nodeAnchorData.orientation == Orientation.Horizontal) |
|||
{ |
|||
// TODO: placement could be better handled using better CSS properties to place the node anchor itself.
|
|||
if (nodeAnchorData.direction == Direction.Input) |
|||
{ |
|||
rect = new Rect(position.x + 2, position.y + 2, k_NodeSize, k_NodeSize); |
|||
} |
|||
else if (nodeAnchorData.direction == Direction.Output) |
|||
{ |
|||
rect = new Rect(position.x + position.width - (7 + k_NodeSize), position.y + 2, k_NodeSize, k_NodeSize); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (nodeAnchorData.direction == Direction.Input) |
|||
{ |
|||
rect = new Rect(position.x + (position.width - k_NodeSize)/2, position.y + 4, k_NodeSize, k_NodeSize); |
|||
} |
|||
else if (nodeAnchorData.direction == Direction.Output) |
|||
{ |
|||
rect = new Rect(position.x + (position.width - k_NodeSize)/2, position.y + position.height - k_NodeSize - 8, k_NodeSize, k_NodeSize); |
|||
} |
|||
} |
|||
return rect; |
|||
} |
|||
|
|||
protected virtual void DrawConnector() |
|||
{ |
|||
// TODO This cast here is not ideal
|
|||
var nodeAnchorData = dataProvider as NodeAnchorData; |
|||
if (nodeAnchorData == null) |
|||
return; |
|||
|
|||
var anchorColor = Color.yellow; |
|||
|
|||
anchorColor.a = 0.7f; |
|||
Rect rect = GetAnchorRect(nodeAnchorData); |
|||
Handles.DrawSolidRectangleWithOutline(rect, anchorColor, anchorColor); |
|||
|
|||
if (nodeAnchorData.highlight) |
|||
{ |
|||
var highlightColor = Color.blue; |
|||
Rect highlighRect = rect; |
|||
highlighRect.x += 4; |
|||
highlighRect.y += 4; |
|||
highlighRect.width -= 8; |
|||
highlighRect.height -= 8; |
|||
Handles.DrawSolidRectangleWithOutline(highlighRect, highlightColor, highlightColor); |
|||
} |
|||
} |
|||
|
|||
public override void DoRepaint(PaintContext args) |
|||
{ |
|||
base.DoRepaint(args); |
|||
DrawConnector(); |
|||
} |
|||
|
|||
public override void OnDataChanged() |
|||
{ |
|||
UpdateConnector(); |
|||
ClearChildren(); |
|||
|
|||
var nodeAnchorData = dataProvider as NodeAnchorData; |
|||
if (nodeAnchorData == null) |
|||
return; |
|||
|
|||
Type type = nodeAnchorData.type; |
|||
|
|||
Type genericClass = typeof(PortSource<>); |
|||
Type constructedClass = genericClass.MakeGenericType(type); |
|||
nodeAnchorData.source = Activator.CreateInstance(constructedClass); |
|||
|
|||
Label label; |
|||
// TODO: I figure this placement could be more generic with a better use of CSS placement
|
|||
if (nodeAnchorData.orientation == Orientation.Horizontal) |
|||
{ |
|||
label = new Label(new GUIContent(nodeAnchorData.name)) |
|||
{ |
|||
positionType = PositionType.Absolute, |
|||
positionTop = 0, |
|||
positionLeft = 20, |
|||
positionRight = 0, |
|||
positionBottom = 0 |
|||
}; |
|||
|
|||
if (nodeAnchorData.direction == Direction.Output) |
|||
{ |
|||
label.textAlignment = TextAnchor.UpperRight; |
|||
label.positionLeft = 0; |
|||
label.positionRight = 25; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
label = new Label(new GUIContent(type.Name)) |
|||
{ |
|||
positionType = PositionType.Absolute, |
|||
positionTop = 20, |
|||
positionLeft = 0, |
|||
positionRight = 0, |
|||
positionBottom = 0 |
|||
}; |
|||
|
|||
if (nodeAnchorData.direction == Direction.Output) |
|||
{ |
|||
label.textAlignment = TextAnchor.LowerCenter; |
|||
label.positionTop = 0; |
|||
label.positionBottom = 25; |
|||
} |
|||
else |
|||
{ |
|||
label.textAlignment = TextAnchor.UpperCenter; |
|||
} |
|||
} |
|||
|
|||
GetData<GraphElementData>().capabilities &= ~Capabilities.Selectable; |
|||
|
|||
label.pickingMode = PickingMode.Ignore; |
|||
AddChild(label); |
|||
} |
|||
|
|||
public Rect GetSelectionRect() |
|||
{ |
|||
var nodeAnchorData = dataProvider as NodeAnchorData; |
|||
if (nodeAnchorData == null) |
|||
return new Rect(); |
|||
|
|||
return GetAnchorRect(nodeAnchorData); |
|||
} |
|||
|
|||
public override Vector3 GetGlobalCenter() |
|||
{ |
|||
var center = GetSelectionRect().center; |
|||
var globalCenter = new Vector3(center.x + parent.position.x, center.y + parent.position.y); |
|||
return parent.globalTransform.MultiplyPoint3x4(globalCenter); |
|||
} |
|||
|
|||
public override bool Overlaps(Rect rect) |
|||
{ |
|||
return GetSelectionRect().Overlaps(rect); |
|||
} |
|||
|
|||
public override bool ContainsPoint(Vector2 localPoint) |
|||
{ |
|||
return GetSelectionRect().Contains(localPoint); |
|||
} |
|||
} |
|||
} |
|||
using System; |
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
using UnityEngine.RMGUI.StyleEnums.Values; |
|||
|
|||
namespace RMGUI.GraphView.Demo |
|||
{ |
|||
[CustomDataView(typeof(NodeAnchorData))] |
|||
internal class NodeAnchor : GraphElement |
|||
{ |
|||
public const float k_NodeSize = 15.0f; |
|||
|
|||
private EdgeConnector<EdgeData> m_RegularConnector = new EdgeConnector<EdgeData>(); |
|||
private EdgeConnector<CustomEdgeData> m_CustomConnector = new EdgeConnector<CustomEdgeData>(); |
|||
|
|||
private IManipulator m_CurrentConnector; |
|||
|
|||
public NodeAnchor(NodeAnchorData data) |
|||
{ |
|||
m_CurrentConnector = m_RegularConnector; |
|||
AddManipulator(m_CurrentConnector); |
|||
|
|||
dataProvider = data; |
|||
} |
|||
|
|||
private void UpdateConnector() |
|||
{ |
|||
var nodeAnchorData = dataProvider as NodeAnchorData; |
|||
if (nodeAnchorData == null) |
|||
return; |
|||
|
|||
RemoveManipulator(m_CurrentConnector); |
|||
if (!nodeAnchorData.connected || nodeAnchorData.direction != Direction.Input) |
|||
{ |
|||
if (nodeAnchorData.orientation == Orientation.Horizontal) |
|||
{ |
|||
m_CurrentConnector = m_RegularConnector; |
|||
} |
|||
else |
|||
{ |
|||
m_CurrentConnector = m_CustomConnector; |
|||
} |
|||
AddManipulator(m_CurrentConnector); |
|||
} |
|||
} |
|||
|
|||
private Rect GetAnchorRect(NodeAnchorData nodeAnchorData) |
|||
{ |
|||
Rect rect = new Rect(); |
|||
|
|||
if (nodeAnchorData.orientation == Orientation.Horizontal) |
|||
{ |
|||
// TODO: placement could be better handled using better CSS properties to place the node anchor itself.
|
|||
if (nodeAnchorData.direction == Direction.Input) |
|||
{ |
|||
rect = new Rect(position.x + 2, position.y + 2, k_NodeSize, k_NodeSize); |
|||
} |
|||
else if (nodeAnchorData.direction == Direction.Output) |
|||
{ |
|||
rect = new Rect(position.x + position.width - (7 + k_NodeSize), position.y + 2, k_NodeSize, k_NodeSize); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
if (nodeAnchorData.direction == Direction.Input) |
|||
{ |
|||
rect = new Rect(position.x + (position.width - k_NodeSize)/2, position.y + 4, k_NodeSize, k_NodeSize); |
|||
} |
|||
else if (nodeAnchorData.direction == Direction.Output) |
|||
{ |
|||
rect = new Rect(position.x + (position.width - k_NodeSize)/2, position.y + position.height - k_NodeSize - 8, k_NodeSize, k_NodeSize); |
|||
} |
|||
} |
|||
return rect; |
|||
} |
|||
|
|||
protected virtual void DrawConnector() |
|||
{ |
|||
// TODO This cast here is not ideal
|
|||
var nodeAnchorData = dataProvider as NodeAnchorData; |
|||
if (nodeAnchorData == null) |
|||
return; |
|||
|
|||
var anchorColor = Color.yellow; |
|||
|
|||
anchorColor.a = 0.7f; |
|||
Rect rect = GetAnchorRect(nodeAnchorData); |
|||
Handles.DrawSolidRectangleWithOutline(rect, anchorColor, anchorColor); |
|||
|
|||
if (nodeAnchorData.highlight) |
|||
{ |
|||
var highlightColor = Color.blue; |
|||
Rect highlighRect = rect; |
|||
highlighRect.x += 4; |
|||
highlighRect.y += 4; |
|||
highlighRect.width -= 8; |
|||
highlighRect.height -= 8; |
|||
Handles.DrawSolidRectangleWithOutline(highlighRect, highlightColor, highlightColor); |
|||
} |
|||
} |
|||
|
|||
public override void DoRepaint(PaintContext args) |
|||
{ |
|||
base.DoRepaint(args); |
|||
DrawConnector(); |
|||
} |
|||
|
|||
public override void OnDataChanged() |
|||
{ |
|||
UpdateConnector(); |
|||
ClearChildren(); |
|||
|
|||
var nodeAnchorData = dataProvider as NodeAnchorData; |
|||
if (nodeAnchorData == null) |
|||
return; |
|||
|
|||
Type type = nodeAnchorData.type; |
|||
|
|||
Type genericClass = typeof(PortSource<>); |
|||
Type constructedClass = genericClass.MakeGenericType(type); |
|||
nodeAnchorData.source = Activator.CreateInstance(constructedClass); |
|||
|
|||
Label label; |
|||
// TODO: I figure this placement could be more generic with a better use of CSS placement
|
|||
if (nodeAnchorData.orientation == Orientation.Horizontal) |
|||
{ |
|||
label = new Label(new GUIContent(nodeAnchorData.name)) |
|||
{ |
|||
positionType = PositionType.Absolute, |
|||
positionTop = 0, |
|||
positionLeft = 20, |
|||
positionRight = 0, |
|||
positionBottom = 0 |
|||
}; |
|||
|
|||
if (nodeAnchorData.direction == Direction.Output) |
|||
{ |
|||
label.textAlignment = TextAnchor.UpperRight; |
|||
label.positionLeft = 0; |
|||
label.positionRight = 25; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
label = new Label(new GUIContent(type.Name)) |
|||
{ |
|||
positionType = PositionType.Absolute, |
|||
positionTop = 20, |
|||
positionLeft = 0, |
|||
positionRight = 0, |
|||
positionBottom = 0 |
|||
}; |
|||
|
|||
if (nodeAnchorData.direction == Direction.Output) |
|||
{ |
|||
label.textAlignment = TextAnchor.LowerCenter; |
|||
label.positionTop = 0; |
|||
label.positionBottom = 25; |
|||
} |
|||
else |
|||
{ |
|||
label.textAlignment = TextAnchor.UpperCenter; |
|||
} |
|||
} |
|||
|
|||
GetData<GraphElementData>().capabilities &= ~Capabilities.Selectable; |
|||
|
|||
label.pickingMode = PickingMode.Ignore; |
|||
AddChild(label); |
|||
} |
|||
|
|||
public Rect GetSelectionRect() |
|||
{ |
|||
var nodeAnchorData = dataProvider as NodeAnchorData; |
|||
if (nodeAnchorData == null) |
|||
return new Rect(); |
|||
|
|||
return GetAnchorRect(nodeAnchorData); |
|||
} |
|||
|
|||
public override Vector3 GetGlobalCenter() |
|||
{ |
|||
var center = GetSelectionRect().center; |
|||
var globalCenter = new Vector3(center.x + parent.position.x, center.y + parent.position.y); |
|||
return parent.globalTransform.MultiplyPoint3x4(globalCenter); |
|||
} |
|||
|
|||
public override bool Overlaps(Rect rect) |
|||
{ |
|||
return GetSelectionRect().Overlaps(rect); |
|||
} |
|||
|
|||
public override bool ContainsPoint(Vector2 localPoint) |
|||
{ |
|||
return GetSelectionRect().Contains(localPoint); |
|||
} |
|||
} |
|||
} |
|
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView.Demo |
|||
{ |
|||
[CustomDataView(typeof(InvisibleBorderContainerData))] |
|||
public class InvisibleBorderContainer : GraphElement |
|||
{ |
|||
private readonly Color m_OutlineColor = new Color(0.0f, 0.0f, 0.0f, 0.5f); |
|||
|
|||
private Rect selectRect |
|||
{ |
|||
get |
|||
{ |
|||
return new Rect(position.width * 0.1f, position.height * 0.1f, position.width * 0.8f, position.height * 0.8f); |
|||
} |
|||
} |
|||
|
|||
Rect GetRectWithOutline() |
|||
{ |
|||
return new Rect(position.x + selectRect.x, position.y+selectRect.y, selectRect.width, selectRect.height); |
|||
} |
|||
|
|||
public override bool Overlaps(Rect rectangle) |
|||
{ |
|||
return GetRectWithOutline().Overlaps(rectangle); |
|||
} |
|||
|
|||
public override bool ContainsPoint(Vector2 localPoint) |
|||
{ |
|||
return GetRectWithOutline().Contains(localPoint); |
|||
} |
|||
|
|||
public override void DoRepaint(PaintContext args) |
|||
{ |
|||
Color color = m_OutlineColor; |
|||
if (GetData<GraphElementData>() != null && GetData<GraphElementData>().selected) |
|||
color = Color.blue; |
|||
Handles.DrawSolidRectangleWithOutline(position, color, color); |
|||
|
|||
Rect zone = GetRectWithOutline(); |
|||
Handles.DrawSolidRectangleWithOutline(zone, Color.green, Color.green); |
|||
} |
|||
} |
|||
} |
|||
using UnityEditor; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView.Demo |
|||
{ |
|||
[CustomDataView(typeof(InvisibleBorderContainerData))] |
|||
public class InvisibleBorderContainer : GraphElement |
|||
{ |
|||
private readonly Color m_OutlineColor = new Color(0.0f, 0.0f, 0.0f, 0.5f); |
|||
|
|||
private Rect selectRect |
|||
{ |
|||
get |
|||
{ |
|||
return new Rect(position.width * 0.1f, position.height * 0.1f, position.width * 0.8f, position.height * 0.8f); |
|||
} |
|||
} |
|||
|
|||
Rect GetRectWithOutline() |
|||
{ |
|||
return new Rect(position.x + selectRect.x, position.y+selectRect.y, selectRect.width, selectRect.height); |
|||
} |
|||
|
|||
public override bool Overlaps(Rect rectangle) |
|||
{ |
|||
return GetRectWithOutline().Overlaps(rectangle); |
|||
} |
|||
|
|||
public override bool ContainsPoint(Vector2 localPoint) |
|||
{ |
|||
return GetRectWithOutline().Contains(localPoint); |
|||
} |
|||
|
|||
public override void DoRepaint(PaintContext args) |
|||
{ |
|||
Color color = m_OutlineColor; |
|||
if (GetData<GraphElementData>() != null && GetData<GraphElementData>().selected) |
|||
color = Color.blue; |
|||
Handles.DrawSolidRectangleWithOutline(position, color, color); |
|||
|
|||
Rect zone = GetRectWithOutline(); |
|||
Handles.DrawSolidRectangleWithOutline(zone, Color.green, Color.green); |
|||
} |
|||
} |
|||
} |
|
|||
using UnityEditor; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView.Demo |
|||
{ |
|||
public class IMGUISampleView : EditorWindow |
|||
{ |
|||
[MenuItem("Window/GraphView Demo/IMGUISampleView")] |
|||
public static void ShowWindow() |
|||
{ |
|||
GetWindow<IMGUISampleView>(); |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
var view = new SimpleContentView |
|||
{ |
|||
name = "theView", |
|||
dataProvider = CreateInstance<IMGUISampleViewData>() |
|||
}; |
|||
view.StretchToParentSize(); |
|||
windowRoot.AddChild(view); |
|||
} |
|||
|
|||
void OnDisable() |
|||
{ |
|||
windowRoot.ClearChildren(); |
|||
} |
|||
} |
|||
} |
|||
using UnityEditor; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView.Demo |
|||
{ |
|||
public class IMGUISampleView : EditorWindow |
|||
{ |
|||
[MenuItem("Window/GraphView Demo/IMGUISampleView")] |
|||
public static void ShowWindow() |
|||
{ |
|||
GetWindow<IMGUISampleView>(); |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
var view = new SimpleContentView |
|||
{ |
|||
name = "theView", |
|||
dataSource = CreateInstance<IMGUISampleViewData>() |
|||
}; |
|||
view.StretchToParentSize(); |
|||
windowRoot.AddChild(view); |
|||
} |
|||
|
|||
void OnDisable() |
|||
{ |
|||
windowRoot.ClearChildren(); |
|||
} |
|||
} |
|||
} |
|
|||
using UnityEditor; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView.Demo |
|||
{ |
|||
public class SimpleGraphView : EditorWindow |
|||
{ |
|||
[MenuItem("Window/GraphView Demo/SimpleGraphView")] |
|||
public static void ShowWindow() |
|||
{ |
|||
GetWindow<SimpleGraphView>(); |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
var view = new SimpleContentView |
|||
{ |
|||
name = "theView", |
|||
dataProvider = CreateInstance<SimpleGraphViewData>() |
|||
}; |
|||
view.StretchToParentSize(); |
|||
|
|||
windowRoot.AddChild(view); |
|||
} |
|||
|
|||
void OnDisable() |
|||
{ |
|||
windowRoot.ClearChildren(); |
|||
} |
|||
} |
|||
} |
|||
using UnityEditor; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView.Demo |
|||
{ |
|||
public class SimpleGraphView : EditorWindow |
|||
{ |
|||
[MenuItem("Window/GraphView Demo/SimpleGraphView")] |
|||
public static void ShowWindow() |
|||
{ |
|||
GetWindow<SimpleGraphView>(); |
|||
} |
|||
|
|||
void OnEnable() |
|||
{ |
|||
var view = new SimpleContentView |
|||
{ |
|||
name = "theView", |
|||
dataSource = CreateInstance<SimpleGraphViewData>() |
|||
}; |
|||
view.StretchToParentSize(); |
|||
|
|||
windowRoot.AddChild(view); |
|||
} |
|||
|
|||
void OnDisable() |
|||
{ |
|||
windowRoot.ClearChildren(); |
|||
} |
|||
} |
|||
} |
|
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView |
|||
{ |
|||
public class GraphElement : DataContainer, ISelectable |
|||
{ |
|||
public override void OnDataChanged() |
|||
{ |
|||
var data = GetData<GraphElementData>(); |
|||
if (data == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// propagate selection but why?
|
|||
foreach (VisualElement ve in children) |
|||
{ |
|||
GraphElement ce = ve as GraphElement; |
|||
if (ce != null ) |
|||
{ |
|||
var childData = ce.dataProvider as GraphElementData; |
|||
if (childData != null) |
|||
{ |
|||
childData.selected = data.selected; |
|||
} |
|||
} |
|||
} |
|||
|
|||
SetPosition(data.position); |
|||
} |
|||
|
|||
public virtual bool IsSelectable() |
|||
{ |
|||
var data = GetData<GraphElementData>(); |
|||
if (data != null) |
|||
{ |
|||
return (data.capabilities & Capabilities.Selectable) == Capabilities.Selectable; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
public virtual Vector3 GetGlobalCenter() |
|||
{ |
|||
var center = position.center; |
|||
var globalCenter = new Vector3(center.x + parent.position.x, center.y + parent.position.y); |
|||
return parent.globalTransform.MultiplyPoint3x4(globalCenter); |
|||
} |
|||
|
|||
public virtual void SetPosition(Rect newPos) |
|||
{ |
|||
// set absolute position from data
|
|||
position = newPos; |
|||
} |
|||
} |
|||
} |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView |
|||
{ |
|||
public class GraphElement : DataContainer<GraphElementData>, ISelectable |
|||
{ |
|||
public override void OnDataChanged() |
|||
{ |
|||
var data = GetData<GraphElementData>(); |
|||
if (data == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
// propagate selection but why?
|
|||
foreach (VisualElement ve in children) |
|||
{ |
|||
GraphElement ce = ve as GraphElement; |
|||
if (ce != null ) |
|||
{ |
|||
var childData = ce.dataProvider; |
|||
if (childData != null) |
|||
{ |
|||
childData.selected = data.selected; |
|||
} |
|||
} |
|||
} |
|||
|
|||
SetPosition(data.position); |
|||
} |
|||
|
|||
public virtual bool IsSelectable() |
|||
{ |
|||
var data = GetData<GraphElementData>(); |
|||
if (data != null) |
|||
{ |
|||
return (data.capabilities & Capabilities.Selectable) == Capabilities.Selectable; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
public virtual Vector3 GetGlobalCenter() |
|||
{ |
|||
var center = position.center; |
|||
var globalCenter = new Vector3(center.x + parent.position.x, center.y + parent.position.y); |
|||
return parent.globalTransform.MultiplyPoint3x4(globalCenter); |
|||
} |
|||
|
|||
public virtual void SetPosition(Rect newPos) |
|||
{ |
|||
// set absolute position from data
|
|||
position = newPos; |
|||
} |
|||
} |
|||
} |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView |
|||
{ |
|||
internal class EdgeConnector<TEdgeData> : Manipulator where TEdgeData : EdgeData, new() |
|||
{ |
|||
private List<IConnectable> m_CompatibleAnchors = new List<IConnectable>(); |
|||
private TEdgeData m_EdgeDataCandidate; |
|||
|
|||
private IDataSource m_GraphViewData; |
|||
private GraphView m_GraphView; |
|||
|
|||
public MouseButton activateButton { get; set; } |
|||
|
|||
public EdgeConnector() |
|||
{ |
|||
activateButton = MouseButton.LeftMouse; |
|||
} |
|||
|
|||
public override EventPropagation HandleEvent(Event evt, VisualElement finalTarget) |
|||
{ |
|||
switch (evt.type) |
|||
{ |
|||
case EventType.MouseDown: |
|||
if (evt.button != (int)activateButton) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
IConnectable cnx = null; |
|||
var graphElement = finalTarget as GraphElement; |
|||
if (graphElement != null && graphElement.GetData<GraphElementData>() != null) |
|||
{ |
|||
var data = graphElement.GetData<GraphElementData>(); |
|||
cnx = (IConnectable)data; |
|||
m_GraphView = graphElement.GetFirstAncestorOfType<GraphView>(); |
|||
} |
|||
|
|||
if (cnx == null || m_GraphView == null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
m_GraphViewData = m_GraphView.dataProvider; |
|||
if (m_GraphViewData == null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
this.TakeCapture(); |
|||
|
|||
m_CompatibleAnchors.Clear(); |
|||
|
|||
NodeAdapter nodeAdapter = new NodeAdapter(); |
|||
|
|||
// get all available connectors
|
|||
IEnumerable<IConnectable> visibleAnchors = m_GraphView.allChildren.OfType<GraphElement>() |
|||
.Select( e => e.dataProvider) |
|||
.OfType<IConnectable>() |
|||
.Where(a => a.IsConnectable() ); |
|||
|
|||
foreach (var toCnx in visibleAnchors) |
|||
{ |
|||
if (cnx.orientation != toCnx.orientation) |
|||
continue; |
|||
|
|||
bool isBidirectional = ((cnx.direction == Direction.Bidirectional) || |
|||
(toCnx.direction == Direction.Bidirectional)); |
|||
|
|||
if (cnx.direction != toCnx.direction || isBidirectional) |
|||
{ |
|||
if (nodeAdapter.GetAdapter(cnx.source, toCnx.source) != null) |
|||
{ |
|||
toCnx.highlight = true; |
|||
m_CompatibleAnchors.Add(toCnx); |
|||
} |
|||
} |
|||
} |
|||
|
|||
m_EdgeDataCandidate = ScriptableObject.CreateInstance<TEdgeData>(); |
|||
|
|||
m_EdgeDataCandidate.position = new Rect(0, 0, 1, 1); |
|||
m_EdgeDataCandidate.left = graphElement.dataProvider as IConnectable; |
|||
m_EdgeDataCandidate.right = null; |
|||
m_EdgeDataCandidate.candidate = true; |
|||
m_EdgeDataCandidate.candidatePosition = target.LocalToGlobal(evt.mousePosition); |
|||
|
|||
m_GraphViewData.AddElement(m_EdgeDataCandidate); |
|||
|
|||
return EventPropagation.Stop; |
|||
|
|||
case EventType.MouseDrag: |
|||
if (this.HasCapture()) |
|||
{ |
|||
m_EdgeDataCandidate.candidatePosition = target.LocalToGlobal(evt.mousePosition); |
|||
return EventPropagation.Stop; |
|||
} |
|||
break; |
|||
|
|||
case EventType.MouseUp: |
|||
if (this.HasCapture() && evt.button == (int) activateButton) |
|||
{ |
|||
this.ReleaseCapture(); |
|||
|
|||
foreach (var compatibleAnchor in m_CompatibleAnchors) |
|||
{ |
|||
compatibleAnchor.highlight = false; |
|||
|
|||
if (m_GraphView != null) |
|||
{ |
|||
GraphElement anchorElement = m_GraphView.allElements.OfType<GraphElement>().First(e => e.dataProvider == (Object)compatibleAnchor); |
|||
if (anchorElement != null) |
|||
{ |
|||
if (anchorElement.globalBound.Contains(target.LocalToGlobal(evt.mousePosition))) |
|||
{ |
|||
m_EdgeDataCandidate.right = compatibleAnchor; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
m_CompatibleAnchors.Clear(); |
|||
|
|||
if (m_EdgeDataCandidate != null && m_GraphViewData != null) |
|||
{ |
|||
// Not a candidate anymore, let's see if we're actually going to add it to parent
|
|||
m_EdgeDataCandidate.candidate = false; |
|||
|
|||
if (m_EdgeDataCandidate.right == null) |
|||
{ |
|||
m_GraphViewData.RemoveElement(m_EdgeDataCandidate); |
|||
} |
|||
else |
|||
{ |
|||
m_EdgeDataCandidate.left.connected = true; |
|||
m_EdgeDataCandidate.right.connected = true; |
|||
} |
|||
} |
|||
|
|||
m_EdgeDataCandidate = null; |
|||
m_GraphViewData = null; |
|||
|
|||
return EventPropagation.Stop; |
|||
} |
|||
break; |
|||
} |
|||
|
|||
return this.HasCapture() ? EventPropagation.Stop : EventPropagation.Continue; |
|||
} |
|||
} |
|||
} |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
|
|||
namespace RMGUI.GraphView |
|||
{ |
|||
internal class EdgeConnector<TEdgeData> : Manipulator where TEdgeData : EdgeData, new() |
|||
{ |
|||
private List<IConnectable> m_CompatibleAnchors = new List<IConnectable>(); |
|||
private TEdgeData m_EdgeDataCandidate; |
|||
|
|||
private GraphView m_GraphView; |
|||
|
|||
public MouseButton activateButton { get; set; } |
|||
|
|||
public EdgeConnector() |
|||
{ |
|||
activateButton = MouseButton.LeftMouse; |
|||
} |
|||
|
|||
public override EventPropagation HandleEvent(Event evt, VisualElement finalTarget) |
|||
{ |
|||
var dataSource = m_GraphView.dataSource; |
|||
switch (evt.type) |
|||
{ |
|||
case EventType.MouseDown: |
|||
if (evt.button != (int)activateButton) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
IConnectable cnx = null; |
|||
var graphElement = finalTarget as GraphElement; |
|||
if (graphElement != null && graphElement.GetData<GraphElementData>() != null) |
|||
{ |
|||
var data = graphElement.GetData<GraphElementData>(); |
|||
cnx = (IConnectable)data; |
|||
m_GraphView = graphElement.GetFirstAncestorOfType<GraphView>(); |
|||
} |
|||
|
|||
if (cnx == null || m_GraphView == null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
if (m_GraphView.dataSource == null) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
this.TakeCapture(); |
|||
|
|||
m_CompatibleAnchors.Clear(); |
|||
|
|||
NodeAdapter nodeAdapter = new NodeAdapter(); |
|||
|
|||
// get all available connectors
|
|||
IEnumerable<IConnectable> visibleAnchors = m_GraphView.allChildren.OfType<GraphElement>() |
|||
.Select( e => e.dataProvider) |
|||
.OfType<IConnectable>() |
|||
.Where(a => a.IsConnectable() ); |
|||
|
|||
foreach (var toCnx in visibleAnchors) |
|||
{ |
|||
if (cnx.orientation != toCnx.orientation) |
|||
continue; |
|||
|
|||
bool isBidirectional = ((cnx.direction == Direction.Bidirectional) || |
|||
(toCnx.direction == Direction.Bidirectional)); |
|||
|
|||
if (cnx.direction != toCnx.direction || isBidirectional) |
|||
{ |
|||
if (nodeAdapter.GetAdapter(cnx.source, toCnx.source) != null) |
|||
{ |
|||
toCnx.highlight = true; |
|||
m_CompatibleAnchors.Add(toCnx); |
|||
} |
|||
} |
|||
} |
|||
|
|||
m_EdgeDataCandidate = ScriptableObject.CreateInstance<TEdgeData>(); |
|||
|
|||
m_EdgeDataCandidate.position = new Rect(0, 0, 1, 1); |
|||
m_EdgeDataCandidate.left = graphElement.dataProvider as IConnectable; |
|||
m_EdgeDataCandidate.right = null; |
|||
m_EdgeDataCandidate.candidate = true; |
|||
m_EdgeDataCandidate.candidatePosition = target.LocalToGlobal(evt.mousePosition); |
|||
|
|||
dataSource.AddElement(m_EdgeDataCandidate); |
|||
|
|||
return EventPropagation.Stop; |
|||
|
|||
case EventType.MouseDrag: |
|||
if (this.HasCapture()) |
|||
{ |
|||
m_EdgeDataCandidate.candidatePosition = target.LocalToGlobal(evt.mousePosition); |
|||
return EventPropagation.Stop; |
|||
} |
|||
break; |
|||
|
|||
case EventType.MouseUp: |
|||
if (this.HasCapture() && evt.button == (int) activateButton) |
|||
{ |
|||
this.ReleaseCapture(); |
|||
|
|||
foreach (var compatibleAnchor in m_CompatibleAnchors) |
|||
{ |
|||
compatibleAnchor.highlight = false; |
|||
|
|||
if (m_GraphView != null) |
|||
{ |
|||
GraphElement anchorElement = m_GraphView.allElements.OfType<GraphElement>().First(e => e.dataProvider == (Object)compatibleAnchor); |
|||
if (anchorElement != null) |
|||
{ |
|||
if (anchorElement.globalBound.Contains(target.LocalToGlobal(evt.mousePosition))) |
|||
{ |
|||
m_EdgeDataCandidate.right = compatibleAnchor; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
m_CompatibleAnchors.Clear(); |
|||
|
|||
if (m_EdgeDataCandidate != null && dataSource != null) |
|||
{ |
|||
// Not a candidate anymore, let's see if we're actually going to add it to parent
|
|||
m_EdgeDataCandidate.candidate = false; |
|||
|
|||
if (m_EdgeDataCandidate.right == null) |
|||
{ |
|||
dataSource.RemoveElement(m_EdgeDataCandidate); |
|||
} |
|||
else |
|||
{ |
|||
m_EdgeDataCandidate.left.connected = true; |
|||
m_EdgeDataCandidate.right.connected = true; |
|||
} |
|||
} |
|||
|
|||
m_EdgeDataCandidate = null; |
|||
|
|||
return EventPropagation.Stop; |
|||
} |
|||
break; |
|||
} |
|||
|
|||
return this.HasCapture() ? EventPropagation.Stop : EventPropagation.Continue; |
|||
} |
|||
} |
|||
} |
|
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
using UnityEngine.RMGUI.StyleSheets; |
|||
|
|||
namespace RMGUI.GraphView |
|||
{ |
|||
[StyleSheet("Assets/Editor/Views/GraphView.uss")] |
|||
public abstract class GraphView : DataContainer, ISelection |
|||
{ |
|||
class ContentiewContainer:VisualContainer |
|||
{ |
|||
public override bool Overlaps(Rect r) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
public VisualContainer contentViewContainer{ get; private set; } |
|||
|
|||
readonly ClassList elementsClassList = new ClassList("graphElement"); |
|||
|
|||
public VisualContainer viewport |
|||
{ |
|||
get { return this; } |
|||
} |
|||
|
|||
protected GraphView() |
|||
{ |
|||
selection = new List<ISelectable>(); |
|||
clipChildren = true; |
|||
contentViewContainer = new ContentiewContainer |
|||
{ |
|||
name = "contentViewContainer", |
|||
clipChildren = false, |
|||
position = new Rect(0, 0, 0, 0) |
|||
}; |
|||
// make it absolute and 0 sized so it acts as a transform to move children to and fro
|
|||
AddChild(contentViewContainer); |
|||
} |
|||
|
|||
public override void OnDataChanged() |
|||
{ |
|||
if (dataProvider == null) |
|||
return; |
|||
|
|||
// process removals
|
|||
var current = contentViewContainer.children.OfType<GraphElement>().ToList(); |
|||
current.AddRange(children.OfType<GraphElement>().ToList()); |
|||
foreach (var c in current) |
|||
{ |
|||
// been removed?
|
|||
if (!dataProvider.elements.Contains(c.GetData<GraphElementData>())) |
|||
{ |
|||
c.parent.RemoveChild(c); |
|||
} |
|||
} |
|||
|
|||
// process additions
|
|||
var elements = contentViewContainer.children.OfType<GraphElement>().ToList(); |
|||
elements.AddRange(children.OfType<GraphElement>().ToList()); |
|||
foreach (var elementData in dataProvider.elements) |
|||
{ |
|||
// been added?
|
|||
bool found = false; |
|||
|
|||
// TODO what the heck is a "dc" anyway?
|
|||
foreach (var dc in elements) |
|||
{ |
|||
if (dc != null && dc.dataProvider == elementData) |
|||
{ |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
if (!found) |
|||
InstanciateElement(elementData); |
|||
} |
|||
} |
|||
|
|||
// ISelection implementation
|
|||
public List<ISelectable> selection { get; protected set; } |
|||
|
|||
// functions to ISelection extensions
|
|||
public void AddToSelection(ISelectable e) |
|||
{ |
|||
GraphElement ce = e as GraphElement; |
|||
if (ce != null && ce.GetData<GraphElementData>() != null) |
|||
ce.GetData<GraphElementData>().selected = true; |
|||
selection.Add(e); |
|||
contentViewContainer.Touch(ChangeType.Repaint); |
|||
} |
|||
|
|||
public void RemoveFromSelection(ISelectable e) |
|||
{ |
|||
GraphElement ce = e as GraphElement; |
|||
if (ce != null && ce.GetData<GraphElementData>() != null) |
|||
ce.GetData<GraphElementData>().selected = false; |
|||
selection.Remove(e); |
|||
contentViewContainer.Touch(ChangeType.Repaint); |
|||
} |
|||
|
|||
public void ClearSelection() |
|||
{ |
|||
foreach (GraphElement e in selection.OfType<GraphElement>()) |
|||
{ |
|||
if (e.GetData<GraphElementData>() != null) |
|||
e.GetData<GraphElementData>().selected = false; |
|||
} |
|||
|
|||
selection.Clear(); |
|||
contentViewContainer.Touch(ChangeType.Repaint); |
|||
} |
|||
|
|||
private void InstanciateElement(GraphElementData elementData) |
|||
{ |
|||
// call factory
|
|||
var newElem = CustomDataView.Create(elementData) as GraphElement; |
|||
|
|||
if (newElem == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
newElem.SetPosition(elementData.position); |
|||
newElem.classList = elementsClassList; |
|||
newElem.dataProvider = elementData; |
|||
|
|||
if ((elementData.capabilities & Capabilities.Resizable) != 0) |
|||
{ |
|||
var resizable = new Resizer(); |
|||
newElem.AddManipulator(resizable); |
|||
newElem.AddDecorator(resizable); |
|||
newElem.borderBottom = 6; |
|||
} |
|||
|
|||
bool attachToContainer = (elementData.capabilities & Capabilities.Floating) == 0; |
|||
if (attachToContainer) |
|||
contentViewContainer.AddChild(newElem); |
|||
else |
|||
AddChild(newElem); |
|||
} |
|||
} |
|||
} |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using UnityEngine; |
|||
using UnityEngine.RMGUI; |
|||
using UnityEngine.RMGUI.StyleSheets; |
|||
|
|||
namespace RMGUI.GraphView |
|||
{ |
|||
[StyleSheet("Assets/Editor/Views/GraphView.uss")] |
|||
public abstract class GraphView : VisualContainer, ISelection |
|||
{ |
|||
private IGraphElementDataSource m_DataSource; |
|||
|
|||
public IGraphElementDataSource dataSource |
|||
{ |
|||
get { return m_DataSource; } |
|||
set |
|||
{ |
|||
if (m_DataSource == value) |
|||
return; |
|||
|
|||
RemoveWatch(); |
|||
m_DataSource = value; |
|||
OnDataChanged(); |
|||
AddWatch(); |
|||
} |
|||
} |
|||
|
|||
|
|||
class ContentiewContainer : VisualContainer |
|||
{ |
|||
public override bool Overlaps(Rect r) |
|||
{ |
|||
return true; |
|||
} |
|||
} |
|||
|
|||
public VisualContainer contentViewContainer{ get; private set; } |
|||
|
|||
readonly ClassList elementsClassList = new ClassList("graphElement"); |
|||
|
|||
public VisualContainer viewport |
|||
{ |
|||
get { return this; } |
|||
} |
|||
|
|||
protected GraphView() |
|||
{ |
|||
selection = new List<ISelectable>(); |
|||
clipChildren = true; |
|||
contentViewContainer = new ContentiewContainer |
|||
{ |
|||
name = "contentViewContainer", |
|||
clipChildren = false, |
|||
position = new Rect(0, 0, 0, 0) |
|||
}; |
|||
// make it absolute and 0 sized so it acts as a transform to move children to and fro
|
|||
AddChild(contentViewContainer); |
|||
} |
|||
|
|||
private void OnDataChanged() |
|||
{ |
|||
if (m_DataSource == null) |
|||
return; |
|||
|
|||
// process removals
|
|||
var current = contentViewContainer.children.OfType<GraphElement>().ToList(); |
|||
current.AddRange(children.OfType<GraphElement>()); |
|||
foreach (var c in current) |
|||
{ |
|||
// been removed?
|
|||
if (!m_DataSource.elements.Contains(c.GetData<GraphElementData>())) |
|||
{ |
|||
c.parent.RemoveChild(c); |
|||
} |
|||
} |
|||
|
|||
// process additions
|
|||
var elements = contentViewContainer.children.OfType<GraphElement>().ToList(); |
|||
elements.AddRange(children.OfType<GraphElement>().ToList()); |
|||
foreach (var elementData in m_DataSource.elements) |
|||
{ |
|||
// been added?
|
|||
bool found = false; |
|||
|
|||
// TODO what the heck is a "dc" anyway?
|
|||
foreach (var dc in elements) |
|||
{ |
|||
if (dc != null && dc.dataProvider == elementData) |
|||
{ |
|||
found = true; |
|||
break; |
|||
} |
|||
} |
|||
if (!found) |
|||
InstanciateElement(elementData); |
|||
} |
|||
} |
|||
|
|||
// ISelection implementation
|
|||
public List<ISelectable> selection { get; protected set; } |
|||
|
|||
// functions to ISelection extensions
|
|||
public void AddToSelection(ISelectable e) |
|||
{ |
|||
GraphElement ce = e as GraphElement; |
|||
if (ce != null && ce.GetData<GraphElementData>() != null) |
|||
ce.GetData<GraphElementData>().selected = true; |
|||
selection.Add(e); |
|||
contentViewContainer.Touch(ChangeType.Repaint); |
|||
} |
|||
|
|||
public void RemoveFromSelection(ISelectable e) |
|||
{ |
|||
GraphElement ce = e as GraphElement; |
|||
if (ce != null && ce.GetData<GraphElementData>() != null) |
|||
ce.GetData<GraphElementData>().selected = false; |
|||
selection.Remove(e); |
|||
contentViewContainer.Touch(ChangeType.Repaint); |
|||
} |
|||
|
|||
public void ClearSelection() |
|||
{ |
|||
foreach (GraphElement e in selection.OfType<GraphElement>()) |
|||
{ |
|||
if (e.GetData<GraphElementData>() != null) |
|||
e.GetData<GraphElementData>().selected = false; |
|||
} |
|||
|
|||
selection.Clear(); |
|||
contentViewContainer.Touch(ChangeType.Repaint); |
|||
} |
|||
|
|||
private void InstanciateElement(GraphElementData elementData) |
|||
{ |
|||
// call factory
|
|||
var newElem = CustomDataView.Create(elementData) as GraphElement; |
|||
|
|||
if (newElem == null) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
newElem.SetPosition(elementData.position); |
|||
newElem.classList = elementsClassList; |
|||
newElem.dataProvider = elementData; |
|||
|
|||
if ((elementData.capabilities & Capabilities.Resizable) != 0) |
|||
{ |
|||
var resizable = new Resizer(); |
|||
newElem.AddManipulator(resizable); |
|||
newElem.AddDecorator(resizable); |
|||
newElem.borderBottom = 6; |
|||
} |
|||
|
|||
bool attachToContainer = (elementData.capabilities & Capabilities.Floating) == 0; |
|||
if (attachToContainer) |
|||
contentViewContainer.AddChild(newElem); |
|||
else |
|||
AddChild(newElem); |
|||
} |
|||
|
|||
void AddWatch() |
|||
{ |
|||
if (m_DataSource != null && panel != null && m_DataSource is Object) |
|||
// TODO: consider a disposable handle?
|
|||
DataWatchService.AddDataSpy(this, (Object)m_DataSource, OnDataChanged); |
|||
} |
|||
|
|||
void RemoveWatch() |
|||
{ |
|||
if (m_DataSource != null && panel != null && m_DataSource is Object) |
|||
DataWatchService.RemoveDataSpy((Object)m_DataSource, OnDataChanged); |
|||
} |
|||
} |
|||
} |
|
|||
using System; |
|||
using System.Reflection; |
|||
using RMGUI.GraphView; |
|||
using UnityEngine; |
|||
using UnityEngine.Graphing; |
|||
using UnityEngine.MaterialGraph; |
|||
using Object = UnityEngine.Object; |
|||
|
|||
namespace UnityEditor.MaterialGraph |
|||
{ |
|||
/* [CustomDataView(typeof(NodePreviewData))] |
|||
public class NodePreview : GraphElement |
|||
{ |
|||
public NodePreview(NodePreviewData preview) |
|||
{ |
|||
dataProvider = preview; |
|||
} |
|||
|
|||
public override void DoRepaint(PaintContext args) |
|||
{ |
|||
base.DoRepaint(args); |
|||
m_WwwTexture = new Texture2D(4, 4, TextureFormat.DXT1, false); |
|||
AddChild(new Image { image = m_WwwTexture }); |
|||
|
|||
Handles.DrawSolidRectangleWithOutline(parent.position, Color.red, Color.blue); |
|||
} |
|||
}*/ |
|||
|
|||
[Serializable] |
|||
public class NodePreviewData : GraphElementData |
|||
{ |
|||
protected NodePreviewData() |
|||
{ } |
|||
|
|||
private MaterialGraphPreviewGenerator m_PreviewGenerator; |
|||
|
|||
[NonSerialized] |
|||
private int m_LastShaderVersion = -1; |
|||
|
|||
[NonSerialized] |
|||
private Material m_PreviewMaterial; |
|||
|
|||
[NonSerialized] |
|||
private Shader m_PreviewShader; |
|||
|
|||
private AbstractMaterialNode m_Node; |
|||
|
|||
private PreviewMode m_GeneratedShaderMode = PreviewMode.Preview2D; |
|||
|
|||
public Material previewMaterial |
|||
{ |
|||
get |
|||
{ |
|||
if (m_PreviewMaterial == null) |
|||
{ |
|||
m_PreviewMaterial = new Material(Shader.Find("Unlit/Color")) {hideFlags = HideFlags.HideInHierarchy}; |
|||
m_PreviewMaterial.hideFlags = HideFlags.HideInHierarchy; |
|||
} |
|||
return m_PreviewMaterial; |
|||
} |
|||
} |
|||
|
|||
private MaterialGraphPreviewGenerator previewGenerator |
|||
{ |
|||
get |
|||
{ |
|||
if (m_PreviewGenerator == null) |
|||
{ |
|||
m_PreviewGenerator = new MaterialGraphPreviewGenerator(); |
|||
} |
|||
return m_PreviewGenerator; |
|||
} |
|||
} |
|||
|
|||
public void Initialize(AbstractMaterialNode node) |
|||
{ |
|||
m_Node = node; |
|||
} |
|||
|
|||
|
|||
public Texture Render(Vector2 dimension) |
|||
{ |
|||
if (m_Node == null) |
|||
return null; |
|||
|
|||
if (m_Node.hasPreview == false) |
|||
return null; |
|||
|
|||
if (m_LastShaderVersion != m_Node.version) |
|||
{ |
|||
if (UpdatePreviewShader()) |
|||
m_LastShaderVersion = m_Node.version; |
|||
} |
|||
|
|||
return RenderPreview(dimension); |
|||
} |
|||
|
|||
protected virtual string GetPreviewShaderString() |
|||
{ |
|||
return ShaderGenerator.GeneratePreviewShader(m_Node, out m_GeneratedShaderMode); |
|||
} |
|||
|
|||
private bool UpdatePreviewShader() |
|||
{ |
|||
if (m_Node == null || m_Node.hasError) |
|||
return false; |
|||
|
|||
var resultShader = GetPreviewShaderString(); |
|||
Debug.Log("RecreateShaderAndMaterial : " + m_Node.GetVariableNameForNode() + Environment.NewLine + resultShader); |
|||
|
|||
if (string.IsNullOrEmpty(resultShader)) |
|||
return false; |
|||
|
|||
// workaround for some internal shader compiler weirdness
|
|||
// if we are in error we sometimes to not properly clean
|
|||
// out the error flags and will stay in error, even
|
|||
// if we are now valid
|
|||
if (m_PreviewShader && ShaderHasError(m_PreviewShader)) |
|||
{ |
|||
Object.DestroyImmediate(m_PreviewShader, true); |
|||
m_PreviewShader = null; |
|||
} |
|||
|
|||
if (m_PreviewShader == null) |
|||
{ |
|||
m_PreviewShader = ShaderUtil.CreateShaderAsset(resultShader); |
|||
m_PreviewShader.hideFlags = HideFlags.HideAndDontSave; |
|||
} |
|||
else |
|||
{ |
|||
ShaderUtil.UpdateShaderAsset(m_PreviewShader, resultShader); |
|||
} |
|||
|
|||
return !ShaderHasError(m_PreviewShader); |
|||
} |
|||
|
|||
public static bool ShaderHasError(Shader shader) |
|||
{ |
|||
var hasErrorsCall = typeof(ShaderUtil).GetMethod("GetShaderErrorCount", BindingFlags.Static | BindingFlags.NonPublic); |
|||
var result = hasErrorsCall.Invoke(null, new object[] {shader}); |
|||
return (int)result != 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// RenderPreview gets called in OnPreviewGUI. Nodes can override
|
|||
/// RenderPreview and do their own rendering to the render texture
|
|||
/// </summary>
|
|||
private Texture RenderPreview(Vector2 targetSize) |
|||
{ |
|||
previewMaterial.shader = m_PreviewShader; |
|||
UpdateMaterialProperties(m_Node, previewMaterial); |
|||
return previewGenerator.DoRenderPreview(previewMaterial, m_GeneratedShaderMode, new Rect(0, 0, targetSize.x, targetSize.y)); |
|||
} |
|||
|
|||
private static void SetPreviewMaterialProperty(PreviewProperty previewProperty, Material mat) |
|||
{ |
|||
switch (previewProperty.m_PropType) |
|||
{ |
|||
case PropertyType.Texture2D: |
|||
mat.SetTexture(previewProperty.m_Name, previewProperty.m_Texture); |
|||
break; |
|||
case PropertyType.Color: |
|||
mat.SetColor(previewProperty.m_Name, previewProperty.m_Color); |
|||
break; |
|||
case PropertyType.Vector2: |
|||
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4); |
|||
break; |
|||
case PropertyType.Vector3: |
|||
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4); |
|||
break; |
|||
case PropertyType.Vector4: |
|||
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4); |
|||
break; |
|||
case PropertyType.Float: |
|||
mat.SetFloat(previewProperty.m_Name, previewProperty.m_Float); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public static void UpdateMaterialProperties(AbstractMaterialNode target, Material material) |
|||
{ |
|||
var childNodes = ListPool<INode>.Get(); |
|||
NodeUtils.DepthFirstCollectNodesFromNode(childNodes, target); |
|||
|
|||
var pList = ListPool<PreviewProperty>.Get(); |
|||
for (var index = 0; index < childNodes.Count; index++) |
|||
{ |
|||
var node = childNodes[index] as AbstractMaterialNode; |
|||
if (node == null) |
|||
continue; |
|||
|
|||
node.CollectPreviewMaterialProperties(pList); |
|||
} |
|||
|
|||
foreach (var prop in pList) |
|||
SetPreviewMaterialProperty(prop, material); |
|||
|
|||
ListPool<INode>.Release(childNodes); |
|||
ListPool<PreviewProperty>.Release(pList); |
|||
} |
|||
} |
|||
} |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Reflection; |
|||
using RMGUI.GraphView; |
|||
using UnityEngine; |
|||
using UnityEngine.Graphing; |
|||
using UnityEngine.MaterialGraph; |
|||
using Object = UnityEngine.Object; |
|||
|
|||
namespace UnityEditor.MaterialGraph |
|||
{ |
|||
/* [CustomDataView(typeof(NodePreviewData))] |
|||
public class NodePreview : GraphElement |
|||
{ |
|||
public NodePreview(NodePreviewData preview) |
|||
{ |
|||
dataProvider = preview; |
|||
} |
|||
|
|||
public override void DoRepaint(PaintContext args) |
|||
{ |
|||
base.DoRepaint(args); |
|||
m_WwwTexture = new Texture2D(4, 4, TextureFormat.DXT1, false); |
|||
AddChild(new Image { image = m_WwwTexture }); |
|||
|
|||
Handles.DrawSolidRectangleWithOutline(parent.position, Color.red, Color.blue); |
|||
} |
|||
}*/ |
|||
|
|||
[Serializable] |
|||
public abstract class NodeControlData : GraphElementData |
|||
{ |
|||
protected NodeControlData() |
|||
{ } |
|||
|
|||
public abstract void OnGUIHandler(); |
|||
} |
|||
|
|||
[Serializable] |
|||
public class NodePreviewData : GraphElementData |
|||
{ |
|||
protected NodePreviewData() |
|||
{ } |
|||
|
|||
private MaterialGraphPreviewGenerator m_PreviewGenerator; |
|||
|
|||
[NonSerialized] |
|||
private int m_LastShaderVersion = -1; |
|||
|
|||
[NonSerialized] |
|||
private Material m_PreviewMaterial; |
|||
|
|||
[NonSerialized] |
|||
private Shader m_PreviewShader; |
|||
|
|||
private AbstractMaterialNode m_Node; |
|||
|
|||
private PreviewMode m_GeneratedShaderMode = PreviewMode.Preview2D; |
|||
|
|||
public Material previewMaterial |
|||
{ |
|||
get |
|||
{ |
|||
if (m_PreviewMaterial == null) |
|||
{ |
|||
m_PreviewMaterial = new Material(Shader.Find("Unlit/Color")) {hideFlags = HideFlags.HideInHierarchy}; |
|||
m_PreviewMaterial.hideFlags = HideFlags.HideInHierarchy; |
|||
} |
|||
return m_PreviewMaterial; |
|||
} |
|||
} |
|||
|
|||
private MaterialGraphPreviewGenerator previewGenerator |
|||
{ |
|||
get |
|||
{ |
|||
if (m_PreviewGenerator == null) |
|||
{ |
|||
m_PreviewGenerator = new MaterialGraphPreviewGenerator(); |
|||
} |
|||
return m_PreviewGenerator; |
|||
} |
|||
} |
|||
|
|||
public void Initialize(AbstractMaterialNode node) |
|||
{ |
|||
m_Node = node; |
|||
} |
|||
|
|||
public Texture Render(Vector2 dimension) |
|||
{ |
|||
if (m_Node == null) |
|||
return null; |
|||
|
|||
if (m_Node.hasPreview == false) |
|||
return null; |
|||
|
|||
if (m_LastShaderVersion != m_Node.version) |
|||
{ |
|||
if (UpdatePreviewShader()) |
|||
m_LastShaderVersion = m_Node.version; |
|||
} |
|||
|
|||
return RenderPreview(dimension); |
|||
} |
|||
|
|||
protected virtual string GetPreviewShaderString() |
|||
{ |
|||
// TODO: this is a workaround right now.
|
|||
if (m_Node is PixelShaderNode) |
|||
{ |
|||
|
|||
var localNode = (PixelShaderNode) m_Node; |
|||
if (localNode == null) |
|||
return string.Empty; |
|||
|
|||
var shaderName = "Hidden/PreviewShader/" + localNode.GetVariableNameForNode(); |
|||
List<PropertyGenerator.TextureInfo> defaultTextures; |
|||
//TODO: Need to get the real options somehow
|
|||
var resultShader = ShaderGenerator.GenerateSurfaceShader(localNode, new MaterialOptions(), shaderName, true, out defaultTextures); |
|||
m_GeneratedShaderMode = PreviewMode.Preview3D; |
|||
return resultShader; |
|||
} |
|||
|
|||
|
|||
return ShaderGenerator.GeneratePreviewShader(m_Node, out m_GeneratedShaderMode); |
|||
} |
|||
|
|||
private bool UpdatePreviewShader() |
|||
{ |
|||
if (m_Node == null || m_Node.hasError) |
|||
return false; |
|||
|
|||
var resultShader = GetPreviewShaderString(); |
|||
Debug.Log("RecreateShaderAndMaterial : " + m_Node.GetVariableNameForNode() + Environment.NewLine + resultShader); |
|||
|
|||
if (string.IsNullOrEmpty(resultShader)) |
|||
return false; |
|||
|
|||
// workaround for some internal shader compiler weirdness
|
|||
// if we are in error we sometimes to not properly clean
|
|||
// out the error flags and will stay in error, even
|
|||
// if we are now valid
|
|||
if (m_PreviewShader && ShaderHasError(m_PreviewShader)) |
|||
{ |
|||
Object.DestroyImmediate(m_PreviewShader, true); |
|||
m_PreviewShader = null; |
|||
} |
|||
|
|||
if (m_PreviewShader == null) |
|||
{ |
|||
m_PreviewShader = ShaderUtil.CreateShaderAsset(resultShader); |
|||
m_PreviewShader.hideFlags = HideFlags.HideAndDontSave; |
|||
} |
|||
else |
|||
{ |
|||
ShaderUtil.UpdateShaderAsset(m_PreviewShader, resultShader); |
|||
} |
|||
|
|||
return !ShaderHasError(m_PreviewShader); |
|||
} |
|||
|
|||
public static bool ShaderHasError(Shader shader) |
|||
{ |
|||
var hasErrorsCall = typeof(ShaderUtil).GetMethod("GetShaderErrorCount", BindingFlags.Static | BindingFlags.NonPublic); |
|||
var result = hasErrorsCall.Invoke(null, new object[] {shader}); |
|||
return (int)result != 0; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// RenderPreview gets called in OnPreviewGUI. Nodes can override
|
|||
/// RenderPreview and do their own rendering to the render texture
|
|||
/// </summary>
|
|||
private Texture RenderPreview(Vector2 targetSize) |
|||
{ |
|||
previewMaterial.shader = m_PreviewShader; |
|||
UpdateMaterialProperties(m_Node, previewMaterial); |
|||
return previewGenerator.DoRenderPreview(previewMaterial, m_GeneratedShaderMode, new Rect(0, 0, targetSize.x, targetSize.y)); |
|||
} |
|||
|
|||
private static void SetPreviewMaterialProperty(PreviewProperty previewProperty, Material mat) |
|||
{ |
|||
switch (previewProperty.m_PropType) |
|||
{ |
|||
case PropertyType.Texture2D: |
|||
mat.SetTexture(previewProperty.m_Name, previewProperty.m_Texture); |
|||
break; |
|||
case PropertyType.Color: |
|||
mat.SetColor(previewProperty.m_Name, previewProperty.m_Color); |
|||
break; |
|||
case PropertyType.Vector2: |
|||
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4); |
|||
break; |
|||
case PropertyType.Vector3: |
|||
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4); |
|||
break; |
|||
case PropertyType.Vector4: |
|||
mat.SetVector(previewProperty.m_Name, previewProperty.m_Vector4); |
|||
break; |
|||
case PropertyType.Float: |
|||
mat.SetFloat(previewProperty.m_Name, previewProperty.m_Float); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
public static void UpdateMaterialProperties(AbstractMaterialNode target, Material material) |
|||
{ |
|||
var childNodes = ListPool<INode>.Get(); |
|||
NodeUtils.DepthFirstCollectNodesFromNode(childNodes, target); |
|||
|
|||
var pList = ListPool<PreviewProperty>.Get(); |
|||
for (var index = 0; index < childNodes.Count; index++) |
|||
{ |
|||
var node = childNodes[index] as AbstractMaterialNode; |
|||
if (node == null) |
|||
continue; |
|||
|
|||
node.CollectPreviewMaterialProperties(pList); |
|||
} |
|||
|
|||
foreach (var prop in pList) |
|||
SetPreviewMaterialProperty(prop, material); |
|||
|
|||
ListPool<INode>.Release(childNodes); |
|||
ListPool<PreviewProperty>.Release(pList); |
|||
} |
|||
} |
|||
} |
|
|||
MaterialGraphNode { |
|||
flex-direction: column; |
|||
} |
|||
|
|||
MaterialGraphNode #slots { |
|||
flex-direction: row; |
|||
} |
|||
|
|||
MaterialGraphNode #slots #input { |
|||
flex:1; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
MaterialGraphNode #slots #output { |
|||
flex:1; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
MaterialGraphNode #controls { |
|||
flex-direction: column; |
|||
} |
|||
|
|||
MaterialGraphNode #preview { |
|||
flex-direction: column; |
|||
height: 200; |
|||
width: 200; |
|||
} |
|||
|
|||
NodeAnchor { |
|||
height: 26; |
|||
width: 100; |
|||
} |
|||
|
|||
/* Example of dynamic properties |
|||
Read from the GridBackground decorator |
|||
#contentViewContainer { |
|||
background-color:#404749; |
|||
line-color:#20293F; |
|||
thick-line-color:#030C22; |
|||
spacing:50.0; |
|||
thick-lines:10; |
|||
}*/ |
|||
MaterialGraphNode { |
|||
flex-direction: column; |
|||
} |
|||
|
|||
MaterialGraphNode #slots { |
|||
flex-direction: row; |
|||
} |
|||
|
|||
MaterialGraphNode #slots #input { |
|||
flex:1; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
MaterialGraphNode #slots #output { |
|||
flex:1; |
|||
flex-direction: column; |
|||
} |
|||
|
|||
MaterialGraphNode #controls { |
|||
flex-direction: column; |
|||
height: 26; |
|||
} |
|||
|
|||
MaterialGraphNode #controls #element{ |
|||
flex-direction: column; |
|||
flex:1; |
|||
} |
|||
|
|||
MaterialGraphNode #preview { |
|||
flex-direction: column; |
|||
} |
|||
|
|||
MaterialGraphNode #preview #image { |
|||
height: 200; |
|||
width: 200; |
|||
align-self: center; |
|||
} |
|||
|
|||
NodeAnchor { |
|||
height: 26; |
|||
} |
|||
|
|||
/* Example of dynamic properties |
|||
Read from the GridBackground decorator |
|||
#contentViewContainer { |
|||
background-color:#404749; |
|||
line-color:#20293F; |
|||
thick-line-color:#030C22; |
|||
spacing:50.0; |
|||
thick-lines:10; |
|||
}*/ |
撰写
预览
正在加载...
取消
保存
Reference in new issue