bfogerty
8 年前
当前提交
2f5a98bb
共有 5 个文件被更改,包括 405 次插入 和 0 次删除
-
1MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/MaterialGraphPresenter.cs
-
99MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/CustomCodeNodePresenter.cs
-
12MaterialGraphProject/Assets/UnityShaderEditor/Editor/Drawing/Presenters/CustomCodeNodePresenter.cs.meta
-
281MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Nodes/Logic/CustomCodeNode.cs
-
12MaterialGraphProject/Assets/UnityShaderEditor/Runtime/Nodes/Logic/CustomCodeNode.cs.meta
|
|||
using System; |
|||
using System.Linq; |
|||
using System.Collections.Generic; |
|||
using RMGUI.GraphView; |
|||
using UnityEditor.Graphing.Drawing; |
|||
using UnityEngine; |
|||
using UnityEngine.MaterialGraph; |
|||
|
|||
namespace UnityEditor.MaterialGraph.Drawing |
|||
{ |
|||
class CustomCodeControlPresenter : GraphControlPresenter |
|||
{ |
|||
public class CodeEditorPopup : PopupWindowContent |
|||
{ |
|||
private CustomCodeNode m_customCodeNode = null; |
|||
private Vector2 m_scroll; |
|||
|
|||
private bool m_isOpen = false; |
|||
public bool IsOpen |
|||
{ |
|||
get { return m_isOpen; } |
|||
} |
|||
|
|||
public CodeEditorPopup(CustomCodeNode customCodeNode) |
|||
{ |
|||
m_customCodeNode = customCodeNode; |
|||
} |
|||
|
|||
public override Vector2 GetWindowSize() |
|||
{ |
|||
return new Vector2(300, 300); |
|||
} |
|||
|
|||
public override void OnGUI(Rect rect) |
|||
{ |
|||
GUILayout.Label("Custom Code Editor", EditorStyles.boldLabel); |
|||
m_scroll = EditorGUILayout.BeginScrollView(m_scroll); |
|||
m_customCodeNode.Code = EditorGUILayout.TextArea(m_customCodeNode.Code, GUILayout.Height(GetWindowSize().y - 30)); |
|||
EditorGUILayout.EndScrollView(); |
|||
} |
|||
|
|||
public override void OnOpen() |
|||
{ |
|||
Debug.Log("Popup opened: " + this); |
|||
m_isOpen = true; |
|||
} |
|||
|
|||
public override void OnClose() |
|||
{ |
|||
Debug.Log("Popup closed: " + this); |
|||
if (m_isOpen) |
|||
{ |
|||
m_customCodeNode.UpdateInputAndOuputSlots(); |
|||
} |
|||
m_isOpen = false; |
|||
} |
|||
} |
|||
|
|||
private CodeEditorPopup codeEditorPopup = null; |
|||
Rect buttonRect; |
|||
public override void OnGUIHandler() |
|||
{ |
|||
base.OnGUIHandler(); |
|||
|
|||
var tNode = node as UnityEngine.MaterialGraph.CustomCodeNode; |
|||
if (tNode == null) |
|||
return; |
|||
|
|||
if (codeEditorPopup == null) |
|||
{ |
|||
codeEditorPopup = new CodeEditorPopup(tNode); |
|||
tNode.Code = "//Write your function below.\r\nvoid test(float a, float b, out float c)\r\n{\r\n\tc = a + b;\r\n}\r\n"; |
|||
} |
|||
|
|||
string buttonText = codeEditorPopup.IsOpen ? "Close Code Editor" : "Open Code Editor"; |
|||
if (GUILayout.Button(buttonText)) |
|||
{ |
|||
PopupWindow.Show(buttonRect, codeEditorPopup); |
|||
} |
|||
if (Event.current.type == EventType.Repaint) buttonRect = GUILayoutUtility.GetLastRect(); |
|||
} |
|||
|
|||
public override float GetHeight() |
|||
{ |
|||
return (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) + EditorGUIUtility.standardVerticalSpacing; |
|||
} |
|||
} |
|||
|
|||
[Serializable] |
|||
public class CustomCodePresenter : PropertyNodePresenter |
|||
{ |
|||
protected override IEnumerable<GraphElementPresenter> GetControlData() |
|||
{ |
|||
var instance = CreateInstance<CustomCodeControlPresenter>(); |
|||
instance.Initialize(node); |
|||
return new List<GraphElementPresenter>(base.GetControlData()) { instance }; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: 2c8cc961345e3fa4591080689cce37f0 |
|||
timeCreated: 1495617692 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
|
|||
using System; |
|||
using UnityEngine.Graphing; |
|||
using System.Collections; |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
using System.Text.RegularExpressions; |
|||
|
|||
|
|||
namespace UnityEngine.MaterialGraph |
|||
{ |
|||
[Title("Logic/CustomCode")] |
|||
public class CustomCodeNode : FunctionNInNOut, IGeneratesFunction |
|||
{ |
|||
[SerializeField] private string m_code; |
|||
|
|||
public class FunctionArgument |
|||
{ |
|||
public string TypeName; |
|||
public string Name; |
|||
|
|||
public FunctionArgument(string typeName, string name) |
|||
{ |
|||
this.TypeName = typeName; |
|||
this.Name = name; |
|||
} |
|||
} |
|||
|
|||
List<int> inputSlotIds = new List<int>(); |
|||
List<int> outputSlotIds = new List<int>(); |
|||
|
|||
public string Code |
|||
{ |
|||
get { return m_code; } |
|||
set |
|||
{ |
|||
if (string.Equals(m_code, value)) |
|||
return; |
|||
|
|||
m_code = value; |
|||
} |
|||
} |
|||
|
|||
public CustomCodeNode() |
|||
{ |
|||
name = "CustomCode"; |
|||
} |
|||
|
|||
protected override string GetFunctionName() |
|||
{ |
|||
string guid = System.Guid.NewGuid().ToString(); |
|||
guid = guid.Replace("-", "_"); |
|||
return "unity_CustomCode_" + GetFunctionName(GetFunctionSignature()); // + "_" + guid;
|
|||
} |
|||
|
|||
public void GenerateNodeFunction(ShaderGenerator visitor, GenerationMode generationMode) |
|||
{ |
|||
var outputString = new ShaderGenerator(); |
|||
outputString.AddShaderChunk(GetFunctionPrototype(), false); |
|||
|
|||
outputString.AddShaderChunk(GetFunctionBody(), false); |
|||
|
|||
visitor.AddShaderChunk(outputString.GetShaderString(0), true); |
|||
} |
|||
|
|||
public void UpdateInputAndOuputSlots() |
|||
{ |
|||
if (string.IsNullOrEmpty(m_code)) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
onModified(this, ModificationScope.Graph); |
|||
|
|||
string functionSignature = GetFunctionSignature(); |
|||
List<FunctionArgument> inputArguments = GetInputArguments(functionSignature); |
|||
List<FunctionArgument> outputArguments = GetOutputArguments(functionSignature); |
|||
UpdateInputSlots(inputArguments); |
|||
UpdateOutputSlots(outputArguments); |
|||
|
|||
} |
|||
|
|||
void UpdateInputSlots(List<FunctionArgument> inputArguments) |
|||
{ |
|||
if (inputArguments == null || inputArguments.Count <= 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int slotIndex = 0; |
|||
if (inputSlotIds.Count > 0) |
|||
{ |
|||
for (slotIndex = 0; slotIndex < inputSlotIds.Count; ++slotIndex) |
|||
{ |
|||
RemoveSlot(inputSlotIds[slotIndex]); |
|||
} |
|||
inputSlotIds.Clear(); |
|||
} |
|||
|
|||
List<int> slotIds = new List<int>(); |
|||
foreach (ISlot inSlot in GetSlots<ISlot>()) |
|||
{ |
|||
slotIds.Add(inSlot.id); |
|||
} |
|||
|
|||
// TODO: This is a bit of a hack. We need to find a better way
|
|||
// to handle the copying of this node.
|
|||
for (slotIndex = 0; slotIndex < slotIds.Count; ++slotIndex) |
|||
{ |
|||
RemoveSlot(slotIds[slotIndex]); |
|||
} |
|||
|
|||
for (slotIndex = 0; slotIndex < inputArguments.Count; ++slotIndex) |
|||
{ |
|||
string nativeType = inputArguments[slotIndex].TypeName; |
|||
SlotValueType valueType = SlotValueType.Vector1; |
|||
if (string.Equals(nativeType, "float2")) |
|||
{ |
|||
valueType = SlotValueType.Vector2; |
|||
} |
|||
else if (string.Equals(nativeType, "float3")) |
|||
{ |
|||
valueType = SlotValueType.Vector3; |
|||
} |
|||
else if (string.Equals(nativeType, "float4")) |
|||
{ |
|||
valueType = SlotValueType.Vector4; |
|||
} |
|||
|
|||
inputSlotIds.Add(AddSlot(inputArguments[slotIndex].Name, inputArguments[slotIndex].Name, SlotType.Input, valueType, Vector4.zero)); |
|||
} |
|||
} |
|||
|
|||
void UpdateOutputSlots(List<FunctionArgument> outputArguments) |
|||
{ |
|||
if (outputArguments == null || outputArguments.Count <= 0) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int slotIndex = 0; |
|||
if (outputSlotIds.Count > 0) |
|||
{ |
|||
for (slotIndex = 0; slotIndex < outputSlotIds.Count; ++slotIndex) |
|||
{ |
|||
RemoveSlot(outputSlotIds[slotIndex]); |
|||
} |
|||
outputSlotIds.Clear(); |
|||
} |
|||
|
|||
for (slotIndex = 0; slotIndex < outputArguments.Count; ++slotIndex) |
|||
{ |
|||
string nativeType = outputArguments[slotIndex].TypeName; |
|||
SlotValueType valueType = SlotValueType.Vector1; |
|||
if (string.Equals(nativeType, "float2")) |
|||
{ |
|||
valueType = SlotValueType.Vector2; |
|||
} |
|||
else if (string.Equals(nativeType, "float3")) |
|||
{ |
|||
valueType = SlotValueType.Vector3; |
|||
} |
|||
else if (string.Equals(nativeType, "float4")) |
|||
{ |
|||
valueType = SlotValueType.Vector4; |
|||
} |
|||
|
|||
inputSlotIds.Add(AddSlot(outputArguments[slotIndex].Name, outputArguments[slotIndex].Name, SlotType.Output, valueType, Vector4.zero)); |
|||
} |
|||
} |
|||
|
|||
string GetFunctionWithoutComments() |
|||
{ |
|||
List<string> codeWithoutComments = new List<string>(); |
|||
string[] lines = m_code.Split(new string[] {System.Environment.NewLine}, StringSplitOptions.None); |
|||
for (int i = 0; i < lines.Length; ++i) |
|||
{ |
|||
string line = lines[i].Trim(); |
|||
if (!line.StartsWith("//")) |
|||
{ |
|||
codeWithoutComments.Add(lines[i]); |
|||
continue; |
|||
} |
|||
} |
|||
|
|||
return string.Join(System.Environment.NewLine, codeWithoutComments.ToArray()); |
|||
} |
|||
|
|||
string GetFunctionSignature() |
|||
{ |
|||
// Find First { character so we can get the entire function signature;
|
|||
string codeWithoutComments = GetFunctionWithoutComments(); |
|||
int braceIndex = codeWithoutComments.IndexOf('{'); |
|||
string functionSignature = codeWithoutComments.Substring(0, braceIndex); |
|||
functionSignature = functionSignature.Trim(); |
|||
|
|||
functionSignature = Regex.Replace(functionSignature, @"\s+", " "); |
|||
|
|||
return functionSignature; |
|||
} |
|||
|
|||
string GetFunctionBody() |
|||
{ |
|||
// Find First { character so we can get the entire function signature;
|
|||
string codeWithoutComments = GetFunctionWithoutComments(); |
|||
int firstBraceIndex = codeWithoutComments.IndexOf('{'); |
|||
int lastBraceIndex = codeWithoutComments.LastIndexOf('}')+1; |
|||
string functionBody = codeWithoutComments.Substring(firstBraceIndex, lastBraceIndex - firstBraceIndex); |
|||
|
|||
return functionBody; |
|||
} |
|||
|
|||
string GetFunctionName(string functionSignature) |
|||
{ |
|||
string codeWithoutComments = GetFunctionWithoutComments(); |
|||
int firstSpace = functionSignature.IndexOf(' ') + 1; |
|||
int firstParenthesee = codeWithoutComments.IndexOf('('); |
|||
|
|||
string functionName = codeWithoutComments.Substring(firstSpace, firstParenthesee - firstSpace); |
|||
return functionName; |
|||
} |
|||
|
|||
List<FunctionArgument> GetInputArguments(string functionSignature) |
|||
{ |
|||
string codeWithoutComments = GetFunctionWithoutComments(); |
|||
int firstCharacter = codeWithoutComments.IndexOf('(') + 1; |
|||
int lastParenthesee = codeWithoutComments.IndexOf(')'); |
|||
|
|||
string argumentString = codeWithoutComments.Substring(firstCharacter, lastParenthesee - firstCharacter); |
|||
string[] arguments = argumentString.Split(new char[] {','}); |
|||
if (arguments == null || arguments.Length <= 0) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
List<FunctionArgument> inputArguments = new List<FunctionArgument>(); |
|||
foreach (string arg in arguments) |
|||
{ |
|||
string trimmedArg = arg.Trim(); |
|||
string[] components = trimmedArg.Split(new char[] {' '}); |
|||
if (string.Equals(components[0].ToLower(), "out")) |
|||
{ |
|||
break; |
|||
} |
|||
|
|||
inputArguments.Add(new FunctionArgument(components[0], components[1])); |
|||
} |
|||
|
|||
return inputArguments; |
|||
} |
|||
|
|||
List<FunctionArgument> GetOutputArguments(string functionSignature) |
|||
{ |
|||
string codeWithoutComments = GetFunctionWithoutComments(); |
|||
int firstCharacter = codeWithoutComments.IndexOf('(') + 1; |
|||
int lastParenthesee = codeWithoutComments.IndexOf(')'); |
|||
|
|||
string argumentString = codeWithoutComments.Substring(firstCharacter, lastParenthesee - firstCharacter); |
|||
string[] arguments = argumentString.Split(new char[] { ',' }); |
|||
if (arguments == null || arguments.Length <= 0) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
List<FunctionArgument> outputArguments = new List<FunctionArgument>(); |
|||
foreach (string arg in arguments) |
|||
{ |
|||
string trimmedArg = arg.Trim(); |
|||
string[] components = trimmedArg.Split(new char[] { ' ' }); |
|||
// Skip non output nodes
|
|||
if (!string.Equals(components[0].ToLower(), "out")) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
outputArguments.Add(new FunctionArgument(components[1], components[2])); |
|||
} |
|||
|
|||
return outputArguments; |
|||
} |
|||
} |
|||
} |
|
|||
fileFormatVersion: 2 |
|||
guid: a47fbd7891fadf6438af4abc1d2baab4 |
|||
timeCreated: 1495617270 |
|||
licenseType: Pro |
|||
MonoImporter: |
|||
serializedVersion: 2 |
|||
defaultReferences: [] |
|||
executionOrder: 0 |
|||
icon: {instanceID: 0} |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue