您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
281 行
9.7 KiB
281 行
9.7 KiB
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;
|
|
}
|
|
}
|
|
}
|