CustomExpressionNode.cs 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881
  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. using System;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEditor;
  7. using UnityEditorInternal;
  8. using System.Text.RegularExpressions;
  9. namespace AmplifyShaderEditor
  10. {
  11. public enum CustomExpressionMode
  12. {
  13. Create,
  14. Call,
  15. File
  16. }
  17. [Serializable]
  18. public class CustomExpressionInputItem
  19. {
  20. public PrecisionType Precision;
  21. public VariableQualifiers Qualifier;
  22. public WirePortDataType Type;
  23. public bool IsSamplerState;
  24. public bool IsTexture2DArray;
  25. public string CustomType;
  26. public bool IsVariable;
  27. public bool FoldoutFlag;
  28. public string FoldoutLabel;
  29. public CustomExpressionInputItem( PrecisionType precision , VariableQualifiers qualifier , string customType , bool isVariable , bool foldoutFlag , string foldoutLabel )
  30. {
  31. Precision = precision;
  32. Qualifier = qualifier;
  33. CustomType = customType;
  34. FoldoutFlag = foldoutFlag;
  35. FoldoutLabel = foldoutLabel;
  36. IsVariable = isVariable;
  37. }
  38. }
  39. [Serializable]
  40. public class CustomExpressionDependency
  41. {
  42. public int DependencyArrayIdx;
  43. public int DependencyNodeId;
  44. public CustomExpressionDependency() { DependencyArrayIdx = DependencyNodeId = -1; }
  45. public CustomExpressionDependency( string id ) { DependencyNodeId = Convert.ToInt32( id ); DependencyArrayIdx = -1; }
  46. public void Reset()
  47. {
  48. DependencyArrayIdx = -1;
  49. DependencyNodeId = -1;
  50. }
  51. }
  52. [Serializable]
  53. [NodeAttributes( "Custom Expression" , "Miscellaneous" , "Creates a custom expression or function if <b>return</b> is detected in the written code." )]
  54. public sealed class CustomExpressionNode : ParentNode
  55. {
  56. private const string WarningText = "Characters $ and @ are NOT allowed inside code since they are internally used as delimiters over the node meta.\nThey will be automatically removed when saving the shader.";
  57. private const float AddRemoveButtonLayoutWidth = 15;
  58. private const float LineAdjust = 1.15f;
  59. private const float IdentationAdjust = 5f;
  60. private const string CustomExpressionInfo = "Creates a custom expression or function according to how code is written on text area.\n\n" +
  61. "- If a return function is detected on Code text area then a function will be created.\n" +
  62. "Also in function mode a ; is expected on the end of each instruction line.\n\n" +
  63. "- If no return function is detected then an expression will be generated and used directly on the vertex/frag body.\n" +
  64. "On Expression mode a ; is not required on the end of an instruction line.\n\n" +
  65. "- You can also call a function from an external file, just make sure to add the include file via the 'Additional Directives' group " +
  66. "in the main property panel. Also works with shader functions.";
  67. private const string ReturnHelper = "return";
  68. private const double MaxTimestamp = 1;
  69. private const string DefaultExpressionNameStr = "My Custom Expression";
  70. private const string DefaultInputNameStr = "In";
  71. private const string CodeTitleStr = "Code";
  72. private const string OutputTypeStr = "Output Type";
  73. private const string CustomTypeStr = " ";
  74. private const string IsVariableStr = "Is Variable";
  75. private const string InputsStr = "Inputs";
  76. private const string InputNameStr = "Name";
  77. private const string InputTypeStr = "Type";
  78. private const string InputValueStr = "Value";
  79. private const string InputQualifierStr = "Qualifier";
  80. private const string ExpressionNameLabelStr = "Name";
  81. private const string FunctionCallModeStr = "Mode";
  82. private const string GenerateUniqueNameStr = "Set Unique";
  83. private const string AutoRegisterStr = "Auto-Register";
  84. private const string DependenciesStr = "Dependencies";
  85. private const string DefaultSamplerStateStr = "_Linear_Repeat";
  86. private const string VarRegexReplacer = @"\b{0}\b";
  87. private readonly string[] PrecisionLabelsExtraLocal = { "Float" , "Half" , "Inherit Local" };
  88. private readonly string[] AvailableWireTypesStr =
  89. {
  90. "int",
  91. "float",
  92. "float2",
  93. "float3",
  94. "float4",
  95. "float3x3",
  96. "float4x4",
  97. "sampler1D",
  98. "sampler2D",
  99. "sampler3D",
  100. "samplerCUBE",
  101. "sampler2Darray",
  102. "samplerState",
  103. "custom"};
  104. private readonly string[] AvailableOutputWireTypesStr =
  105. {
  106. "int",
  107. "float",
  108. "float2",
  109. "float3",
  110. "float4",
  111. "float3x3",
  112. "float4x4",
  113. "void",
  114. };
  115. private readonly string[] QualifiersStr =
  116. {
  117. "In",
  118. "Out",
  119. "InOut"
  120. };
  121. private readonly WirePortDataType[] AvailableWireTypes =
  122. {
  123. WirePortDataType.INT,
  124. WirePortDataType.FLOAT,
  125. WirePortDataType.FLOAT2,
  126. WirePortDataType.FLOAT3,
  127. WirePortDataType.FLOAT4,
  128. WirePortDataType.FLOAT3x3,
  129. WirePortDataType.FLOAT4x4,
  130. WirePortDataType.SAMPLER1D,
  131. WirePortDataType.SAMPLER2D,
  132. WirePortDataType.SAMPLER3D,
  133. WirePortDataType.SAMPLERCUBE,
  134. WirePortDataType.SAMPLER2DARRAY,
  135. WirePortDataType.SAMPLERSTATE,
  136. WirePortDataType.OBJECT
  137. };
  138. private readonly WirePortDataType[] AvailableOutputWireTypes =
  139. {
  140. WirePortDataType.INT,
  141. WirePortDataType.FLOAT,
  142. WirePortDataType.FLOAT2,
  143. WirePortDataType.FLOAT3,
  144. WirePortDataType.FLOAT4,
  145. WirePortDataType.FLOAT3x3,
  146. WirePortDataType.FLOAT4x4,
  147. WirePortDataType.OBJECT,
  148. };
  149. private readonly Dictionary<WirePortDataType , int> WireToIdx = new Dictionary<WirePortDataType , int>
  150. {
  151. { WirePortDataType.INT, 0},
  152. { WirePortDataType.FLOAT, 1},
  153. { WirePortDataType.FLOAT2, 2},
  154. { WirePortDataType.FLOAT3, 3},
  155. { WirePortDataType.FLOAT4, 4},
  156. { WirePortDataType.FLOAT3x3, 5},
  157. { WirePortDataType.FLOAT4x4, 6},
  158. { WirePortDataType.SAMPLER1D, 7},
  159. { WirePortDataType.SAMPLER2D, 8},
  160. { WirePortDataType.SAMPLER3D, 9},
  161. { WirePortDataType.SAMPLERCUBE, 10},
  162. { WirePortDataType.SAMPLER2DARRAY, 11},
  163. { WirePortDataType.SAMPLERSTATE, 12},
  164. { WirePortDataType.OBJECT, 13}
  165. };
  166. [SerializeField]
  167. private string m_customExpressionName = DefaultExpressionNameStr;
  168. [SerializeField]
  169. private List<CustomExpressionInputItem> m_items = new List<CustomExpressionInputItem>();
  170. [SerializeField]
  171. private string m_code = " ";
  172. [SerializeField]
  173. private int m_outputTypeIdx = 1;
  174. [SerializeField]
  175. private bool m_visibleInputsFoldout = true;
  176. [SerializeField]
  177. private CustomExpressionMode m_mode = CustomExpressionMode.Create;
  178. [SerializeField]
  179. private string m_fileGUID = string.Empty;
  180. [SerializeField]
  181. private TextAsset m_fileAsset = null;
  182. [SerializeField]
  183. private bool m_precisionSuffix = false;
  184. [SerializeField]
  185. private bool m_voidMode = false;
  186. [SerializeField]
  187. private bool m_autoRegisterMode = false;
  188. [SerializeField]
  189. private bool m_functionMode = false;
  190. [SerializeField]
  191. private int m_firstAvailablePort = 0;
  192. [SerializeField]
  193. private string m_uniqueName;
  194. [SerializeField]
  195. private bool m_generateUniqueName = true;
  196. [SerializeField]
  197. private bool m_dependenciesFoldout = false;
  198. [SerializeField]
  199. private List<CustomExpressionDependency> m_dependencies = new List<CustomExpressionDependency>();
  200. private const float ButtonLayoutWidth = 15;
  201. private bool m_repopulateNameDictionary = true;
  202. private Dictionary<string , int> m_usedNames = new Dictionary<string , int>();
  203. private double m_lastTimeNameModified = 0;
  204. private bool m_nameModified = false;
  205. private double m_lastTimeCodeModified = 0;
  206. private bool m_codeModified = false;
  207. //Title editing
  208. private bool m_isEditing;
  209. private bool m_stopEditing;
  210. private bool m_startEditing;
  211. private double m_clickTime;
  212. private double m_doubleClickTime = 0.3;
  213. private Rect m_titleClickArea;
  214. //Item Reordable List
  215. private ReordableAction m_actionType = ReordableAction.None;
  216. private int m_actionIndex = 0;
  217. private int m_lastIndex = 0;
  218. private ReorderableList m_itemReordableList = null;
  219. private ReorderableList m_dependenciesReordableList = null;
  220. protected override void CommonInit( int uniqueId )
  221. {
  222. base.CommonInit( uniqueId );
  223. AddInputPort( WirePortDataType.FLOAT , false , "In0" );
  224. m_items.Add( new CustomExpressionInputItem( PrecisionType.Inherit , VariableQualifiers.In , string.Empty , false , true , string.Empty/*"[0]"*/ ) );
  225. AddOutputPort( WirePortDataType.FLOAT , "Out" );
  226. m_textLabelWidth = 97;
  227. m_customPrecision = true;
  228. }
  229. protected override void OnUniqueIDAssigned()
  230. {
  231. base.OnUniqueIDAssigned();
  232. if( m_mode == CustomExpressionMode.Create )
  233. UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.AddNode( this );
  234. SetTitleText( m_customExpressionName );
  235. if( m_nodeAttribs != null )
  236. m_uniqueName = m_nodeAttribs.Name + OutputId;
  237. else
  238. m_uniqueName = "CustomExpression" + OutputId;
  239. }
  240. public override void OnInputPortConnected( int portId , int otherNodeId , int otherPortId , bool activateNode = true )
  241. {
  242. base.OnInputPortConnected( portId , otherNodeId , otherPortId , activateNode );
  243. CheckPortConnection( portId );
  244. }
  245. public override void OnConnectedOutputNodeChanges( int portId , int otherNodeId , int otherPortId , string name , WirePortDataType type )
  246. {
  247. base.OnConnectedOutputNodeChanges( portId , otherNodeId , otherPortId , name , type );
  248. CheckPortConnection( portId );
  249. }
  250. void CheckPortConnection( int portId )
  251. {
  252. if( portId == 0 && ( m_mode == CustomExpressionMode.Call || m_voidMode ) )
  253. {
  254. m_inputPorts[ 0 ].MatchPortToConnection();
  255. m_outputPorts[ 0 ].ChangeType( m_inputPorts[ 0 ].DataType , false );
  256. }
  257. }
  258. public override void OnNodeLogicUpdate( DrawInfo drawInfo )
  259. {
  260. base.OnNodeLogicUpdate( drawInfo );
  261. if( m_nameModified )
  262. {
  263. if( ( EditorApplication.timeSinceStartup - m_lastTimeNameModified ) > MaxTimestamp )
  264. {
  265. m_nameModified = false;
  266. m_sizeIsDirty = true;
  267. m_repopulateNameDictionary = true;
  268. }
  269. }
  270. if( m_repopulateNameDictionary )
  271. {
  272. m_repopulateNameDictionary = false;
  273. m_usedNames.Clear();
  274. for( int i = 0 ; i < m_inputPorts.Count ; i++ )
  275. {
  276. m_usedNames.Add( m_inputPorts[ i ].Name , i );
  277. }
  278. }
  279. if( m_codeModified )
  280. {
  281. if( ( EditorApplication.timeSinceStartup - m_lastTimeCodeModified ) > MaxTimestamp )
  282. {
  283. m_codeModified = false;
  284. bool functionMode = m_code.Contains( ReturnHelper );
  285. if( functionMode != m_functionMode )
  286. {
  287. m_functionMode = functionMode;
  288. CheckCallMode();
  289. }
  290. }
  291. }
  292. }
  293. bool CheckCallMode()
  294. {
  295. if( m_functionMode && m_mode == CustomExpressionMode.Call )
  296. {
  297. Mode = CustomExpressionMode.Create;
  298. m_outputTypeIdx = ( AvailableOutputWireTypesStr.Length - 1 );
  299. //m_outputPorts[ 0 ].ChangeType( AvailableOutputWireTypes[ m_outputTypeIdx ], false );
  300. m_outputPorts[ 0 ].ChangeType( m_inputPorts[ 0 ].DataType , false );
  301. m_voidMode = true;
  302. return true;
  303. }
  304. return false;
  305. }
  306. public override void Draw( DrawInfo drawInfo )
  307. {
  308. base.Draw( drawInfo );
  309. if( ContainerGraph.LodLevel <= ParentGraph.NodeLOD.LOD3 )
  310. {
  311. if( !m_isEditing && ( ( !ContainerGraph.ParentWindow.MouseInteracted && drawInfo.CurrentEventType == EventType.MouseDown && m_titleClickArea.Contains( drawInfo.MousePosition ) ) ) )
  312. {
  313. if( ( EditorApplication.timeSinceStartup - m_clickTime ) < m_doubleClickTime )
  314. m_startEditing = true;
  315. else
  316. GUI.FocusControl( null );
  317. m_clickTime = EditorApplication.timeSinceStartup;
  318. }
  319. else if( m_isEditing && ( ( drawInfo.CurrentEventType == EventType.MouseDown && !m_titleClickArea.Contains( drawInfo.MousePosition ) ) || !EditorGUIUtility.editingTextField ) )
  320. {
  321. m_stopEditing = true;
  322. }
  323. if( m_isEditing || m_startEditing )
  324. {
  325. EditorGUI.BeginChangeCheck();
  326. GUI.SetNextControlName( m_uniqueName );
  327. m_customExpressionName = EditorGUITextField( m_titleClickArea , string.Empty , m_customExpressionName , UIUtils.GetCustomStyle( CustomStyle.NodeTitle ) );
  328. if( EditorGUI.EndChangeCheck() )
  329. {
  330. SetTimedUpdate( 2 );
  331. SetTitleText( m_customExpressionName );
  332. m_sizeIsDirty = true;
  333. m_isDirty = true;
  334. }
  335. if( m_startEditing )
  336. EditorGUI.FocusTextInControl( m_uniqueName );
  337. }
  338. if( drawInfo.CurrentEventType == EventType.Repaint )
  339. {
  340. if( m_startEditing )
  341. {
  342. m_startEditing = false;
  343. m_isEditing = true;
  344. }
  345. if( m_stopEditing )
  346. {
  347. m_stopEditing = false;
  348. m_isEditing = false;
  349. GUI.FocusControl( null );
  350. }
  351. }
  352. }
  353. }
  354. public override void OnNodeLayout( DrawInfo drawInfo )
  355. {
  356. base.OnNodeLayout( drawInfo );
  357. m_titleClickArea = m_titlePos;
  358. m_titleClickArea.height = Constants.NODE_HEADER_HEIGHT;
  359. }
  360. public override void OnNodeRepaint( DrawInfo drawInfo )
  361. {
  362. base.OnNodeRepaint( drawInfo );
  363. if( !m_isVisible )
  364. return;
  365. // Fixed Title ( only renders when not editing )
  366. if( !m_isEditing && !m_startEditing && ContainerGraph.LodLevel <= ParentGraph.NodeLOD.LOD3 )
  367. {
  368. GUI.Label( m_titleClickArea , m_content , UIUtils.GetCustomStyle( CustomStyle.NodeTitle ) );
  369. }
  370. }
  371. public string GetFirstAvailableName()
  372. {
  373. string name = string.Empty;
  374. for( int i = 0 ; i < m_inputPorts.Count + 1 ; i++ )
  375. {
  376. name = DefaultInputNameStr + i;
  377. if( !m_usedNames.ContainsKey( name ) )
  378. {
  379. return name;
  380. }
  381. }
  382. Debug.LogWarning( "Could not find valid name" );
  383. return string.Empty;
  384. }
  385. public override void DrawProperties()
  386. {
  387. base.DrawProperties();
  388. NodeUtils.DrawPropertyGroup( ref m_propertiesFoldout , Constants.ParameterLabelStr , DrawBaseProperties );
  389. //NodeUtils.DrawPropertyGroup( ref m_visibleInputsFoldout, InputsStr, DrawInputs, DrawAddRemoveInputs );
  390. NodeUtils.DrawPropertyGroup( ref m_visibleInputsFoldout , InputsStr , DrawReordableInputs , DrawItemsAddRemoveInputs );
  391. EditorGUILayout.HelpBox( CustomExpressionInfo , MessageType.Info );
  392. EditorGUILayout.HelpBox( WarningText , MessageType.Warning );
  393. }
  394. string WrapCodeInFunction( bool isTemplate , string functionName , bool expressionMode )
  395. {
  396. //Hack to be used util indent is properly used
  397. int currIndent = UIUtils.ShaderIndentLevel;
  398. UIUtils.ShaderIndentLevel = isTemplate ? 0 : 1;
  399. if( !isTemplate ) UIUtils.ShaderIndentLevel++;
  400. //string functionName = UIUtils.RemoveInvalidCharacters( m_customExpressionName );
  401. string returnType = ( m_mode == CustomExpressionMode.Call || m_voidMode ) ? "void" : UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType , m_outputPorts[ 0 ].DataType );
  402. if( expressionMode )
  403. returnType = "inline " + returnType;
  404. string functionBody = UIUtils.ShaderIndentTabs + returnType + " " + functionName + "( ";
  405. int count = m_inputPorts.Count - m_firstAvailablePort;
  406. for( int i = 0 ; i < count ; i++ )
  407. {
  408. int portIdx = i + m_firstAvailablePort;
  409. string qualifier = m_items[ i ].Qualifier == VariableQualifiers.In ? string.Empty : UIUtils.QualifierToCg( m_items[ i ].Qualifier ) + " ";
  410. PrecisionType precision = m_items[ i ].Precision;
  411. if( precision == PrecisionType.Inherit )
  412. precision = CurrentPrecisionType;
  413. //string dataType = ( m_inputPorts[ portIdx ].DataType == WirePortDataType.OBJECT ) ? m_items[ i ].CustomType : UIUtils.PrecisionWirePortToCgType( precision, m_inputPorts[ portIdx ].DataType );
  414. string declaration = string.Empty;
  415. if( m_inputPorts[ portIdx ].DataType == WirePortDataType.OBJECT )
  416. declaration = m_items[ i ].CustomType + " " + m_inputPorts[ portIdx ].Name;
  417. else
  418. declaration = UIUtils.PrecisionWirePortToTypeValue( precision , m_inputPorts[ portIdx ].DataType , m_inputPorts[ portIdx ].Name );
  419. functionBody += qualifier + declaration;
  420. //functionBody += qualifier + dataType + " " + m_inputPorts[ portIdx ].Name;
  421. if( i < ( count - 1 ) )
  422. {
  423. functionBody += ", ";
  424. }
  425. }
  426. functionBody += " )\n" + UIUtils.ShaderIndentTabs + "{\n";
  427. UIUtils.ShaderIndentLevel++;
  428. {
  429. if( expressionMode )
  430. functionBody += UIUtils.ShaderIndentTabs + "return ";
  431. string[] codeLines = m_code.Split( IOUtils.LINE_TERMINATOR );
  432. for( int i = 0 ; i < codeLines.Length ; i++ )
  433. {
  434. if( codeLines[ i ].Length > 0 )
  435. {
  436. functionBody += ( ( i == 0 && expressionMode ) ? string.Empty : UIUtils.ShaderIndentTabs ) + codeLines[ i ] + ( ( ( i == codeLines.Length - 1 ) && expressionMode ) ? string.Empty : "\n" );
  437. }
  438. }
  439. if( expressionMode )
  440. functionBody += ";\n";
  441. }
  442. UIUtils.ShaderIndentLevel--;
  443. functionBody += UIUtils.ShaderIndentTabs + "}\n";
  444. UIUtils.ShaderIndentLevel = currIndent;
  445. return functionBody;
  446. }
  447. string GetFileAssetRelativePath()
  448. {
  449. Shader currentShader = m_containerGraph.ParentWindow.OutsideGraph.CurrentShader;
  450. if( currentShader != null )
  451. {
  452. string fileAssePath = AssetDatabase.GetAssetPath( m_fileAsset );
  453. if( fileAssePath.StartsWith( "Packages" ) )
  454. {
  455. return fileAssePath;
  456. }
  457. else if( fileAssePath.StartsWith( "Assets" ) )
  458. {
  459. string currentShaderPath = AssetDatabase.GetAssetPath( currentShader );
  460. string path0 = Application.dataPath + fileAssePath.Substring( 6 );
  461. string path1 = Application.dataPath + currentShaderPath.Substring( 6 );
  462. Uri path0URI = new Uri( path0 , UriKind.Absolute );
  463. Uri path1URI = new Uri( path1 , UriKind.Absolute );
  464. return path1URI.MakeRelativeUri( path0URI ).ToString();
  465. }
  466. UIUtils.ShowMessage( UniqueId , "Invalid path found in Custom Expression File Asset: " + fileAssePath , MessageSeverity.Warning );
  467. }
  468. else
  469. {
  470. UIUtils.ShowMessage( UniqueId , "Invalid shader in Custom Expression" );
  471. }
  472. return string.Empty;
  473. }
  474. void DrawBaseProperties()
  475. {
  476. EditorGUI.BeginChangeCheck();
  477. m_customExpressionName = EditorGUILayoutTextField( ExpressionNameLabelStr , m_customExpressionName );
  478. if( EditorGUI.EndChangeCheck() )
  479. {
  480. SetTimedUpdate( 2 );
  481. SetTitleText( m_customExpressionName );
  482. }
  483. EditorGUI.BeginChangeCheck();
  484. Mode = (CustomExpressionMode)EditorGUILayoutEnumPopup( FunctionCallModeStr , m_mode );
  485. if( EditorGUI.EndChangeCheck() )
  486. {
  487. if( CheckCallMode() )
  488. UIUtils.ShowMessage( UniqueId , "Call Mode cannot have return over is code.\nFalling back to Create Mode" );
  489. SetupCallMode();
  490. RecalculateInOutOutputPorts();
  491. }
  492. if( m_mode == CustomExpressionMode.File )
  493. {
  494. m_fileAsset = EditorGUILayoutObjectField( "Source" , m_fileAsset , typeof( TextAsset ) , false ) as TextAsset;
  495. m_precisionSuffix = EditorGUILayoutToggle( "Precision Suffix" , m_precisionSuffix );
  496. }
  497. else
  498. {
  499. EditorGUILayout.LabelField( CodeTitleStr );
  500. EditorGUI.BeginChangeCheck();
  501. {
  502. m_code = EditorGUILayoutTextArea( m_code , UIUtils.MainSkin.textArea );
  503. }
  504. if( EditorGUI.EndChangeCheck() )
  505. {
  506. m_codeModified = true;
  507. m_lastTimeCodeModified = EditorApplication.timeSinceStartup;
  508. }
  509. }
  510. if( m_mode == CustomExpressionMode.Create || m_mode == CustomExpressionMode.File )
  511. {
  512. DrawPrecisionProperty();
  513. bool guiEnabled = GUI.enabled;
  514. GUI.enabled = !AutoRegisterMode && Mode != CustomExpressionMode.File;
  515. m_generateUniqueName = EditorGUILayoutToggle( GenerateUniqueNameStr , m_generateUniqueName ) && !AutoRegisterMode;
  516. GUI.enabled = !m_generateUniqueName;
  517. AutoRegisterMode = EditorGUILayoutToggle( AutoRegisterStr , AutoRegisterMode ) && !m_generateUniqueName;
  518. GUI.enabled = guiEnabled;
  519. EditorGUI.BeginChangeCheck();
  520. m_outputTypeIdx = EditorGUILayoutPopup( OutputTypeStr , m_outputTypeIdx , AvailableOutputWireTypesStr );
  521. if( EditorGUI.EndChangeCheck() )
  522. {
  523. bool oldVoidValue = m_voidMode;
  524. UpdateVoidMode();
  525. if( oldVoidValue != m_voidMode )
  526. {
  527. SetupCallMode();
  528. RecalculateInOutOutputPorts();
  529. }
  530. else
  531. {
  532. m_outputPorts[ 0 ].ChangeType( AvailableOutputWireTypes[ m_outputTypeIdx ] , false );
  533. }
  534. }
  535. }
  536. NodeUtils.DrawNestedPropertyGroup( ref m_dependenciesFoldout , "Dependencies" , DrawDependencies , DrawDependenciesAddRemoveInputs );
  537. }
  538. void UpdateVoidMode()
  539. {
  540. m_voidMode = ( m_outputTypeIdx == ( AvailableOutputWireTypesStr.Length - 1 ) );
  541. }
  542. void SetupCallMode()
  543. {
  544. if( m_mode == CustomExpressionMode.Call || m_voidMode )
  545. {
  546. if( m_firstAvailablePort != 1 )
  547. {
  548. m_firstAvailablePort = 1;
  549. AddInputPortAt( 0 , WirePortDataType.FLOAT , false , DefaultInputNameStr );
  550. m_outputPorts[ 0 ].ChangeType( WirePortDataType.FLOAT , false );
  551. }
  552. }
  553. else
  554. {
  555. if( m_firstAvailablePort != 0 )
  556. {
  557. m_firstAvailablePort = 0;
  558. if( m_inputPorts[ 0 ].IsConnected )
  559. {
  560. m_containerGraph.DeleteConnection( true , UniqueId , m_inputPorts[ 0 ].PortId , false , true );
  561. }
  562. DeleteInputPortByArrayIdx( 0 );
  563. m_outputPorts[ 0 ].ChangeType( AvailableOutputWireTypes[ m_outputTypeIdx ] , false );
  564. }
  565. }
  566. }
  567. void DrawItemsAddRemoveInputs()
  568. {
  569. if( m_inputPorts.Count == m_firstAvailablePort )
  570. m_visibleInputsFoldout = false;
  571. // Add new port
  572. if( GUILayoutButton( string.Empty , UIUtils.PlusStyle , GUILayout.Width( ButtonLayoutWidth ) ) )
  573. {
  574. AddPortAt( m_inputPorts.Count );
  575. m_visibleInputsFoldout = true;
  576. EditorGUI.FocusTextInControl( null );
  577. }
  578. //Remove port
  579. if( GUILayoutButton( string.Empty , UIUtils.MinusStyle , GUILayout.Width( ButtonLayoutWidth ) ) )
  580. {
  581. RemovePortAt( m_inputPorts.Count - 1 );
  582. EditorGUI.FocusTextInControl( null );
  583. }
  584. }
  585. void DrawDependenciesAddRemoveInputs()
  586. {
  587. // Add new port
  588. if( GUILayoutButton( string.Empty , UIUtils.PlusStyle , GUILayout.Width( ButtonLayoutWidth ) ) )
  589. {
  590. m_dependencies.Add( new CustomExpressionDependency() );
  591. EditorGUI.FocusTextInControl( null );
  592. }
  593. //Remove port
  594. if( GUILayoutButton( string.Empty , UIUtils.MinusStyle , GUILayout.Width( ButtonLayoutWidth ) ) )
  595. {
  596. m_dependencies.RemoveAt( m_dependencies.Count - 1 );
  597. }
  598. }
  599. void DrawDependencies()
  600. {
  601. if( m_dependenciesReordableList == null )
  602. {
  603. m_dependenciesReordableList = new ReorderableList( m_dependencies , typeof( CustomExpressionDependency ) , true , false , false , false )
  604. {
  605. headerHeight = 0 ,
  606. footerHeight = 0 ,
  607. showDefaultBackground = false ,
  608. drawElementCallback = ( Rect rect , int index , bool isActive , bool isFocused ) =>
  609. {
  610. if( m_dependencies[ index ] != null )
  611. {
  612. rect.xMin -= 1;
  613. Rect popupPos = new Rect( rect.x , rect.y , rect.width - 2 * Constants.PlusMinusButtonLayoutWidth , EditorGUIUtility.singleLineHeight );
  614. Rect buttonPlusPos = new Rect( rect.x + rect.width - 2 * Constants.PlusMinusButtonLayoutWidth , rect.y - 2 , Constants.PlusMinusButtonLayoutWidth , Constants.PlusMinusButtonLayoutWidth );
  615. Rect buttonMinusPos = new Rect( rect.x + rect.width - Constants.PlusMinusButtonLayoutWidth , rect.y - 2 , Constants.PlusMinusButtonLayoutWidth , Constants.PlusMinusButtonLayoutWidth );
  616. EditorGUI.BeginChangeCheck();
  617. m_dependencies[ index ].DependencyArrayIdx = EditorGUIPopup( popupPos , string.Empty , m_dependencies[ index ].DependencyArrayIdx , UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.NodesArr );
  618. if( EditorGUI.EndChangeCheck() )
  619. {
  620. m_dependencies[ index ].DependencyNodeId = UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.GetNode( m_dependencies[ index ].DependencyArrayIdx ).UniqueId;
  621. if( m_dependencies[ index ].DependencyNodeId == UniqueId )
  622. {
  623. m_dependencies[ index ].Reset();
  624. }
  625. }
  626. if( GUI.Button( buttonPlusPos , string.Empty , UIUtils.PlusStyle ) )
  627. {
  628. m_actionType = ReordableAction.Add;
  629. m_actionIndex = index;
  630. }
  631. if( GUI.Button( buttonMinusPos , string.Empty , UIUtils.MinusStyle ) )
  632. {
  633. m_actionType = ReordableAction.Remove;
  634. m_actionIndex = index;
  635. }
  636. }
  637. }
  638. };
  639. }
  640. if( m_dependenciesReordableList != null )
  641. {
  642. EditorGUILayout.Space();
  643. if( m_dependencies.Count == 0 )
  644. {
  645. EditorGUILayout.HelpBox( "Your list is Empty!\nUse the plus button to add one." , MessageType.Info );
  646. }
  647. else
  648. {
  649. m_dependenciesReordableList.DoLayoutList();
  650. }
  651. EditorGUILayout.Space();
  652. }
  653. if( m_actionType != ReordableAction.None )
  654. {
  655. switch( m_actionType )
  656. {
  657. case ReordableAction.Add:
  658. m_dependencies.Insert( m_actionIndex + 1 , new CustomExpressionDependency() );
  659. break;
  660. case ReordableAction.Remove:
  661. m_dependencies.RemoveAt( m_actionIndex );
  662. break;
  663. }
  664. m_isDirty = true;
  665. m_actionType = ReordableAction.None;
  666. EditorGUI.FocusTextInControl( null );
  667. }
  668. }
  669. void DrawReordableInputs()
  670. {
  671. if( m_itemReordableList == null )
  672. {
  673. m_itemReordableList = new ReorderableList( m_items , typeof( CustomExpressionInputItem ) , true , false , false , false )
  674. {
  675. headerHeight = 0 ,
  676. footerHeight = 0 ,
  677. showDefaultBackground = false ,
  678. elementHeightCallback = ( int index ) =>
  679. {
  680. float lineHeight = EditorGUIUtility.singleLineHeight * LineAdjust;
  681. if( m_items[ index ].FoldoutFlag )
  682. {
  683. float size = 7 * lineHeight;
  684. // Take Is Variable toggle into account
  685. if( m_mode == CustomExpressionMode.Call )
  686. size += lineHeight;
  687. if( m_inputPorts[ m_firstAvailablePort + index ].DataType == WirePortDataType.OBJECT )
  688. size += lineHeight;
  689. if( !m_inputPorts[ m_firstAvailablePort + index ].IsConnected )
  690. {
  691. switch( m_inputPorts[ m_firstAvailablePort + index ].DataType )
  692. {
  693. case WirePortDataType.INT:
  694. case WirePortDataType.FLOAT:
  695. size += 0;// lineHeight;
  696. break;
  697. case WirePortDataType.FLOAT2:
  698. case WirePortDataType.FLOAT3:
  699. case WirePortDataType.FLOAT4:
  700. size += lineHeight;//2 * lineHeight;
  701. break;
  702. case WirePortDataType.FLOAT3x3:
  703. size += 5 * lineHeight;//6 * lineHeight;
  704. break;
  705. case WirePortDataType.FLOAT4x4:
  706. size += 6 * lineHeight;//8 * lineHeight;
  707. break;
  708. }
  709. }
  710. return size;
  711. }
  712. else
  713. {
  714. return lineHeight;
  715. }
  716. } ,
  717. onReorderCallback = ( ReorderableList list ) =>
  718. {
  719. int realLastIndex = m_firstAvailablePort + m_lastIndex;
  720. int realCurrIndex = m_firstAvailablePort + list.index;
  721. InputPort portA = m_inputPorts[ realLastIndex ];
  722. int originalOutputPortId = CreateOutputId( portA.PortId );
  723. SwapInputPorts( realLastIndex , realCurrIndex );
  724. if( m_outputPorts.Count > 1 )
  725. {
  726. if( list.index > m_lastIndex )
  727. {
  728. for( int i = m_lastIndex ; i <= list.index ; i++ )
  729. {
  730. if( m_items[ i ].Qualifier != VariableQualifiers.In )
  731. {
  732. int portIdx = i + m_firstAvailablePort;
  733. int oldOutputPortId;
  734. if( i < list.index )
  735. {
  736. int oldinputPortId = m_inputPorts[ portIdx ].PortId + 1;
  737. oldOutputPortId = CreateOutputId( oldinputPortId );
  738. }
  739. else
  740. {
  741. oldOutputPortId = originalOutputPortId;
  742. }
  743. m_outputPortsDict[ oldOutputPortId ].ChangePortId( CreateOutputId( m_inputPorts[ portIdx ].PortId ) );
  744. }
  745. }
  746. }
  747. else
  748. {
  749. for( int i = list.index ; i <= m_lastIndex ; i++ )
  750. {
  751. if( m_items[ i ].Qualifier != VariableQualifiers.In )
  752. {
  753. int portIdx = i + m_firstAvailablePort;
  754. int oldOutputPortId;
  755. if( i > list.index )
  756. {
  757. int oldinputPortId = m_inputPorts[ portIdx ].PortId - 1;
  758. oldOutputPortId = CreateOutputId( oldinputPortId );
  759. }
  760. else
  761. {
  762. oldOutputPortId = originalOutputPortId;
  763. }
  764. m_outputPortsDict[ oldOutputPortId ].ChangePortId( CreateOutputId( m_inputPorts[ portIdx ].PortId ) );
  765. }
  766. }
  767. }
  768. }
  769. m_outputPorts.Sort( ( A , B ) =>
  770. {
  771. return A.PortId.CompareTo( B.PortId );
  772. } );
  773. m_outputPortsDict.Clear();
  774. for( int i = 0 ; i < m_outputPorts.Count ; i++ )
  775. {
  776. m_outputPortsDict.Add( m_outputPorts[ i ].PortId , m_outputPorts[ i ] );
  777. }
  778. } ,
  779. onSelectCallback = ( ReorderableList list ) =>
  780. {
  781. m_lastIndex = list.index;
  782. } ,
  783. drawElementCallback = ( Rect rect , int index , bool isActive , bool isFocused ) =>
  784. {
  785. if( m_items[ index ] != null )
  786. {
  787. float lineHeight = EditorGUIUtility.singleLineHeight;
  788. float lineSpacing = lineHeight * LineAdjust;
  789. rect.x -= IdentationAdjust;
  790. rect.height = lineHeight;
  791. int portIdx = index + m_firstAvailablePort;
  792. Rect foldoutRect = rect;
  793. if( !m_items[ index ].FoldoutFlag )
  794. {
  795. foldoutRect.width -= 2 * AddRemoveButtonLayoutWidth;
  796. }
  797. m_items[ index ].FoldoutFlag = EditorGUIFoldout( foldoutRect , m_items[ index ].FoldoutFlag , /*m_items[ index ].FoldoutLabel + " - " +*/ m_inputPorts[ portIdx ].Name );
  798. if( m_items[ index ].FoldoutFlag )
  799. {
  800. rect.x += IdentationAdjust;
  801. //Qualifier
  802. rect.y += lineSpacing;
  803. VariableQualifiers newQualifier = (VariableQualifiers)EditorGUIPopup( rect , InputQualifierStr , (int)m_items[ index ].Qualifier , QualifiersStr );
  804. if( newQualifier != m_items[ index ].Qualifier )
  805. {
  806. VariableQualifiers oldQualifier = m_items[ index ].Qualifier;
  807. m_items[ index ].Qualifier = newQualifier;
  808. if( newQualifier == VariableQualifiers.In )
  809. {
  810. RemoveOutputPort( CreateOutputId( m_inputPorts[ portIdx ].PortId ) , false );
  811. }
  812. else if( oldQualifier == VariableQualifiers.In )
  813. {
  814. int outputId = CreateOutputId( m_inputPorts[ portIdx ].PortId );
  815. AddOutputPort( m_inputPorts[ portIdx ].DataType , m_inputPorts[ portIdx ].Name , outputId );
  816. }
  817. m_inputPorts[ portIdx ].Visible = newQualifier != VariableQualifiers.Out;
  818. m_sizeIsDirty = true;
  819. RecalculateInOutOutputPorts();
  820. }
  821. // Precision
  822. rect.y += lineSpacing;
  823. m_items[ index ].Precision = (PrecisionType)EditorGUIPopup( rect , PrecisionContent.text , (int)m_items[ index ].Precision , PrecisionLabelsExtraLocal );
  824. // Type
  825. rect.y += lineSpacing;
  826. int typeIdx = WireToIdx[ m_inputPorts[ portIdx ].DataType ];
  827. EditorGUI.BeginChangeCheck();
  828. typeIdx = EditorGUIPopup( rect , InputTypeStr , typeIdx , AvailableWireTypesStr );
  829. if( EditorGUI.EndChangeCheck() )
  830. {
  831. // actual type is need in order for texture array and sampler state to fallback correctly
  832. m_inputPorts[ portIdx ].ChangeType( AvailableWireTypes[ typeIdx ] , false );
  833. if( typeIdx == 5 || typeIdx == 6 )
  834. {
  835. m_inputPorts[ portIdx ].Matrix4x4InternalData = Matrix4x4.identity;
  836. }
  837. if( m_items[ index ].Qualifier != VariableQualifiers.In )
  838. {
  839. OutputPort currOutPort = GetOutputPortByUniqueId( CreateOutputId( m_inputPorts[ portIdx ].PortId ) );
  840. currOutPort.ChangeType( AvailableWireTypes[ typeIdx ] , false );
  841. }
  842. }
  843. if( AvailableWireTypes[ typeIdx ] == WirePortDataType.OBJECT )
  844. {
  845. rect.y += lineSpacing;
  846. m_items[ index ].CustomType = EditorGUITextField( rect , CustomTypeStr , m_items[ index ].CustomType );
  847. }
  848. //Name
  849. rect.y += lineSpacing;
  850. EditorGUI.BeginChangeCheck();
  851. {
  852. m_inputPorts[ portIdx ].Name = EditorGUITextField( rect , InputNameStr , m_inputPorts[ portIdx ].Name );
  853. }
  854. if( EditorGUI.EndChangeCheck() )
  855. {
  856. m_nameModified = true;
  857. m_lastTimeNameModified = EditorApplication.timeSinceStartup;
  858. m_inputPorts[ portIdx ].Name = UIUtils.RemoveInvalidCharacters( m_inputPorts[ portIdx ].Name );
  859. if( string.IsNullOrEmpty( m_inputPorts[ portIdx ].Name ) )
  860. {
  861. m_inputPorts[ portIdx ].Name = DefaultInputNameStr + index;
  862. }
  863. if( m_items[ index ].Qualifier != VariableQualifiers.In )
  864. {
  865. OutputPort currOutPort = GetOutputPortByUniqueId( CreateOutputId( m_inputPorts[ portIdx ].PortId ) );
  866. currOutPort.Name = m_inputPorts[ portIdx ].Name;
  867. }
  868. }
  869. if( m_mode == CustomExpressionMode.Call )
  870. {
  871. //Is Unique
  872. rect.y += lineSpacing;
  873. m_items[ index ].IsVariable = EditorGUIToggle( rect , IsVariableStr , m_items[ index ].IsVariable );
  874. }
  875. // Port Data
  876. if( !m_inputPorts[ portIdx ].IsConnected )
  877. {
  878. rect.y += lineSpacing;
  879. m_inputPorts[ portIdx ].ShowInternalData( rect , this , true , InputValueStr );
  880. }
  881. //Buttons
  882. rect.x += rect.width - 2 * AddRemoveButtonLayoutWidth;
  883. rect.y += lineSpacing;
  884. if( !m_inputPorts[ m_firstAvailablePort + index ].IsConnected )
  885. {
  886. switch( m_inputPorts[ m_firstAvailablePort + index ].DataType )
  887. {
  888. case WirePortDataType.INT:
  889. case WirePortDataType.FLOAT:
  890. rect.y += 0;// lineSpacing;
  891. break;
  892. case WirePortDataType.FLOAT2:
  893. case WirePortDataType.FLOAT3:
  894. case WirePortDataType.FLOAT4:
  895. rect.y += lineSpacing;//2 * lineSpacing;
  896. break;
  897. case WirePortDataType.FLOAT3x3:
  898. rect.y += 5 * lineSpacing;//6 * lineSpacing;
  899. break;
  900. case WirePortDataType.FLOAT4x4:
  901. rect.y += 6 * lineSpacing;//8 * lineSpacing;
  902. break;
  903. }
  904. }
  905. rect.width = AddRemoveButtonLayoutWidth;
  906. if( GUI.Button( rect , string.Empty , UIUtils.PlusStyle ) )
  907. {
  908. m_actionType = ReordableAction.Add;
  909. m_actionIndex = index;
  910. }
  911. rect.x += AddRemoveButtonLayoutWidth;
  912. if( GUI.Button( rect , string.Empty , UIUtils.MinusStyle ) )
  913. {
  914. m_actionType = ReordableAction.Remove;
  915. m_actionIndex = index;
  916. }
  917. }
  918. else
  919. {
  920. //Buttons
  921. rect.x += IdentationAdjust + rect.width - 2 * AddRemoveButtonLayoutWidth;
  922. rect.width = AddRemoveButtonLayoutWidth;
  923. if( GUI.Button( rect , string.Empty , UIUtils.PlusStyle ) )
  924. {
  925. m_actionType = ReordableAction.Add;
  926. m_actionIndex = index;
  927. }
  928. rect.x += AddRemoveButtonLayoutWidth;
  929. if( GUI.Button( rect , string.Empty , UIUtils.MinusStyle ) )
  930. {
  931. m_actionType = ReordableAction.Remove;
  932. m_actionIndex = index;
  933. }
  934. }
  935. }
  936. }
  937. };
  938. }
  939. if( m_itemReordableList != null )
  940. {
  941. EditorGUILayout.Space();
  942. if( m_items.Count == 0 )
  943. {
  944. EditorGUILayout.HelpBox( "Your list is Empty!\nUse the plus button to add one." , MessageType.Info );
  945. }
  946. else
  947. {
  948. m_itemReordableList.DoLayoutList();
  949. }
  950. EditorGUILayout.Space();
  951. }
  952. if( m_actionType != ReordableAction.None )
  953. {
  954. switch( m_actionType )
  955. {
  956. case ReordableAction.Add:
  957. AddPortAt( m_firstAvailablePort + m_actionIndex + 1 );
  958. break;
  959. case ReordableAction.Remove:
  960. RemovePortAt( m_firstAvailablePort + m_actionIndex );
  961. break;
  962. }
  963. m_isDirty = true;
  964. m_actionType = ReordableAction.None;
  965. EditorGUI.FocusTextInControl( null );
  966. }
  967. }
  968. void RecalculateInOutOutputPorts()
  969. {
  970. m_outputPorts.Sort( ( x , y ) => x.PortId.CompareTo( y.PortId ) );
  971. m_outputPortsDict.Clear();
  972. int count = m_inputPorts.Count - m_firstAvailablePort;
  973. int outputId = 1;
  974. for( int i = 0 ; i < count ; i++ )
  975. {
  976. int idx = i + m_firstAvailablePort;
  977. if( m_items[ i ].Qualifier != VariableQualifiers.In )
  978. {
  979. m_outputPorts[ outputId ].ChangeProperties( m_inputPorts[ idx ].Name , m_inputPorts[ idx ].DataType , false );
  980. m_outputPorts[ outputId ].ChangePortId( CreateOutputId( m_inputPorts[ idx ].PortId ) );
  981. outputId++;
  982. }
  983. }
  984. int outCount = m_outputPorts.Count;
  985. for( int i = 0 ; i < outCount ; i++ )
  986. {
  987. m_outputPortsDict.Add( m_outputPorts[ i ].PortId , m_outputPorts[ i ] );
  988. }
  989. }
  990. void AddPortAt( int idx )
  991. {
  992. AddInputPortAt( idx , WirePortDataType.FLOAT , false , GetFirstAvailableName() );
  993. m_items.Insert( idx - m_firstAvailablePort , new CustomExpressionInputItem( PrecisionType.Inherit , VariableQualifiers.In , string.Empty , false , true , string.Empty/* "[" + idx + "]"*/ ) );
  994. m_repopulateNameDictionary = true;
  995. RecalculateInOutOutputPorts();
  996. }
  997. void RemovePortAt( int idx )
  998. {
  999. if( m_inputPorts.Count > m_firstAvailablePort )
  1000. {
  1001. int varIdx = idx - m_firstAvailablePort;
  1002. if( m_items[ varIdx ].Qualifier != VariableQualifiers.In )
  1003. {
  1004. int id = CreateOutputId( m_inputPorts[ idx ].PortId );
  1005. RemoveOutputPort( id , false );
  1006. }
  1007. DeleteInputPortByArrayIdx( idx );
  1008. m_items.RemoveAt( varIdx );
  1009. m_repopulateNameDictionary = true;
  1010. RecalculateInOutOutputPorts();
  1011. }
  1012. }
  1013. public override void OnAfterDeserialize()
  1014. {
  1015. base.OnAfterDeserialize();
  1016. m_repopulateNameDictionary = true;
  1017. }
  1018. public string DealWithFileMode( int outputId , ref MasterNodeDataCollector dataCollector , bool ignoreLocalvar )
  1019. {
  1020. OutputPort outputPort = GetOutputPortByUniqueId( outputId );
  1021. if( outputPort.IsLocalValue( dataCollector.PortCategory ) )
  1022. return outputPort.LocalValue( dataCollector.PortCategory );
  1023. if( m_fileAsset == null && !string.IsNullOrEmpty( m_fileGUID ) )
  1024. {
  1025. m_fileAsset = AssetDatabase.LoadAssetAtPath<TextAsset>( AssetDatabase.GUIDToAssetPath( m_fileGUID ) );
  1026. }
  1027. if( m_fileAsset != null )
  1028. {
  1029. string path = GetFileAssetRelativePath();
  1030. if( !string.IsNullOrEmpty( path ) )
  1031. dataCollector.AddToIncludes( UniqueId , path );
  1032. }
  1033. int dependenciesCount = m_dependencies.Count;
  1034. Dictionary<int , CustomExpressionNode> examinedNodes = new Dictionary<int , CustomExpressionNode>();
  1035. for( int i = 0 ; i < dependenciesCount ; i++ )
  1036. {
  1037. CustomExpressionNode node = m_containerGraph.GetNode( m_dependencies[ i ].DependencyNodeId ) as CustomExpressionNode;
  1038. if( node == null )
  1039. {
  1040. node = UIUtils.CurrentWindow.OutsideGraph.GetNode( m_dependencies[ i ].DependencyNodeId ) as CustomExpressionNode;
  1041. }
  1042. if( node != null )
  1043. {
  1044. node.CheckDependencies( ref dataCollector , ref examinedNodes );
  1045. }
  1046. }
  1047. examinedNodes.Clear();
  1048. examinedNodes = null;
  1049. string expressionName = UIUtils.RemoveInvalidCharacters( m_customExpressionName );
  1050. string localVarName = "local" + expressionName;
  1051. localVarName += OutputId;
  1052. int count = m_inputPorts.Count;
  1053. if( m_voidMode )
  1054. {
  1055. string mainData = m_inputPorts[ 0 ].GeneratePortInstructions( ref dataCollector );
  1056. RegisterLocalVariable( 0 , string.Format( Constants.CodeWrapper , mainData ) , ref dataCollector , localVarName );
  1057. }
  1058. string precisionSuffix = string.Empty;
  1059. if( m_precisionSuffix )
  1060. {
  1061. switch( CurrentPrecisionType )
  1062. {
  1063. default:
  1064. case PrecisionType.Float: precisionSuffix = "_float"; break;
  1065. case PrecisionType.Half: precisionSuffix = "_half"; break;
  1066. }
  1067. }
  1068. string functionCall = expressionName + precisionSuffix + "( ";
  1069. for( int i = m_firstAvailablePort ; i < count ; i++ )
  1070. {
  1071. if( UIUtils.CurrentWindow.OutsideGraph.SamplingMacros && !UIUtils.CurrentWindow.OutsideGraph.IsSRP )
  1072. {
  1073. // we don't know what kind of sampling the user will do so we add all of them
  1074. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.Auto );
  1075. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.MipLevel );
  1076. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.MipBias );
  1077. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.Derivative );
  1078. }
  1079. string inputPortLocalVar = m_inputPorts[ i ].Name + OutputId;
  1080. int idx = i - m_firstAvailablePort;
  1081. if( m_inputPorts[ i ].DataType != WirePortDataType.OBJECT )
  1082. {
  1083. string result = m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector );
  1084. dataCollector.AddLocalVariable( UniqueId , CurrentPrecisionType , m_inputPorts[ i ].DataType , inputPortLocalVar , result );
  1085. }
  1086. else
  1087. {
  1088. string result = ( m_inputPorts[ i ].IsConnected ) ? m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector ) : m_inputPorts[ i ].InternalData.ToString();
  1089. string inputLocalVar = string.Format( Constants.CustomTypeLocalValueDecWithoutIdent , m_items[ idx ].CustomType , inputPortLocalVar , result );
  1090. dataCollector.AddLocalVariable( UniqueId , inputLocalVar );
  1091. }
  1092. if( m_items[ idx ].Qualifier != VariableQualifiers.In )
  1093. {
  1094. OutputPort currOutputPort = GetOutputPortByUniqueId( CreateOutputId( m_inputPorts[ i ].PortId ) );
  1095. currOutputPort.SetLocalValue( inputPortLocalVar , dataCollector.PortCategory );
  1096. }
  1097. functionCall += inputPortLocalVar;
  1098. if( i < ( count - 1 ) )
  1099. {
  1100. functionCall += " , ";
  1101. }
  1102. }
  1103. functionCall += " )";
  1104. if( m_voidMode )
  1105. {
  1106. dataCollector.AddLocalVariable( 0 , functionCall + ";" , true );
  1107. }
  1108. else
  1109. {
  1110. RegisterLocalVariable( 0 , functionCall , ref dataCollector , localVarName );
  1111. }
  1112. return outputPort.LocalValue( dataCollector.PortCategory );
  1113. }
  1114. public override string GenerateShaderForOutput( int outputId , ref MasterNodeDataCollector dataCollector , bool ignoreLocalvar )
  1115. {
  1116. if( Mode == CustomExpressionMode.File )
  1117. {
  1118. return DealWithFileMode( outputId , ref dataCollector , ignoreLocalvar );
  1119. }
  1120. if( string.IsNullOrEmpty( m_code ) )
  1121. {
  1122. UIUtils.ShowMessage( UniqueId , string.Format( "Custom Expression '{0}' need to have code associated" , m_customExpressionName ) , MessageSeverity.Warning );
  1123. return "0";
  1124. }
  1125. m_code = UIUtils.ForceLFLineEnding( m_code );
  1126. bool codeContainsReturn = m_code.Contains( ReturnHelper );
  1127. bool expressionMode = false;
  1128. if( !codeContainsReturn )
  1129. {
  1130. string[] codeLines = m_code.Split( IOUtils.LINE_TERMINATOR );
  1131. expressionMode = codeLines.Length == 1 && !m_voidMode;
  1132. }
  1133. if( !expressionMode &&
  1134. !codeContainsReturn &&
  1135. m_mode == CustomExpressionMode.Create && !m_voidMode )
  1136. {
  1137. UIUtils.ShowMessage( UniqueId , string.Format( "Custom Expression '{0}' has a non-void return type but no return instruction was detected" , m_customExpressionName ) , MessageSeverity.Error );
  1138. if( outputId != 0 )
  1139. UIUtils.ShowMessage( UniqueId , string.Format( "Attempting to get value on Custom Expression '{0}' from inexisting '{1}' inout/out variable" , m_customExpressionName , m_outputPorts[ outputId ].Name ) , MessageSeverity.Error );
  1140. return "0";
  1141. }
  1142. int dependenciesCount = m_dependencies.Count;
  1143. Dictionary<int , CustomExpressionNode> examinedNodes = new Dictionary<int , CustomExpressionNode>();
  1144. for( int i = 0 ; i < dependenciesCount ; i++ )
  1145. {
  1146. CustomExpressionNode node = m_containerGraph.GetNode( m_dependencies[ i ].DependencyNodeId ) as CustomExpressionNode;
  1147. if( node == null )
  1148. {
  1149. node = UIUtils.CurrentWindow.OutsideGraph.GetNode( m_dependencies[ i ].DependencyNodeId ) as CustomExpressionNode;
  1150. }
  1151. if( node != null )
  1152. {
  1153. node.CheckDependencies( ref dataCollector , ref examinedNodes );
  1154. }
  1155. }
  1156. examinedNodes.Clear();
  1157. examinedNodes = null;
  1158. OutputPort outputPort = GetOutputPortByUniqueId( outputId );
  1159. if( outputPort.IsLocalValue( dataCollector.PortCategory ) )
  1160. return outputPort.LocalValue( dataCollector.PortCategory );
  1161. string expressionName = UIUtils.RemoveInvalidCharacters( m_customExpressionName );
  1162. string localVarName = "local" + expressionName;
  1163. if( m_generateUniqueName )
  1164. {
  1165. expressionName += OutputId;
  1166. }
  1167. localVarName += OutputId;
  1168. int count = m_inputPorts.Count;
  1169. if( count > 0 )
  1170. {
  1171. if( m_mode == CustomExpressionMode.Call || m_voidMode )
  1172. {
  1173. string mainData = m_inputPorts[ 0 ].GeneratePortInstructions( ref dataCollector );
  1174. RegisterLocalVariable( 0 , string.Format( Constants.CodeWrapper , mainData ) , ref dataCollector , localVarName );
  1175. }
  1176. if( codeContainsReturn )
  1177. {
  1178. string function = WrapCodeInFunction( dataCollector.IsTemplate , expressionName , false );
  1179. string functionCall = expressionName + "( ";
  1180. for( int i = m_firstAvailablePort ; i < count ; i++ )
  1181. {
  1182. if( UIUtils.CurrentWindow.OutsideGraph.SamplingMacros && !UIUtils.CurrentWindow.OutsideGraph.IsSRP )
  1183. {
  1184. // we don't know what kind of sampling the user will do so we add all of them
  1185. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.Auto );
  1186. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.MipLevel );
  1187. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.MipBias );
  1188. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.Derivative );
  1189. }
  1190. string inputPortLocalVar = m_inputPorts[ i ].Name + OutputId;
  1191. int idx = i - m_firstAvailablePort;
  1192. if( m_inputPorts[ i ].DataType != WirePortDataType.OBJECT )
  1193. {
  1194. string result = m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector );
  1195. if ( !m_inputPorts[ i ].IsConnected && m_inputPorts[ i ].DataType == WirePortDataType.SAMPLERSTATE )
  1196. {
  1197. result = GeneratorUtils.GenerateSamplerState( ref dataCollector, UniqueId, DefaultSamplerStateStr, VariableMode.Create );
  1198. }
  1199. dataCollector.AddLocalVariable( UniqueId , CurrentPrecisionType , m_inputPorts[ i ].DataType , inputPortLocalVar , result );
  1200. }
  1201. else
  1202. {
  1203. string result = ( m_inputPorts[ i ].IsConnected ) ? m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector ) : m_inputPorts[ i ].InternalData.ToString();
  1204. string inputLocalVar = string.Format( Constants.CustomTypeLocalValueDecWithoutIdent , m_items[ idx ].CustomType , inputPortLocalVar , result );
  1205. dataCollector.AddLocalVariable( UniqueId , inputLocalVar );
  1206. }
  1207. if( m_items[ idx ].Qualifier != VariableQualifiers.In )
  1208. {
  1209. OutputPort currOutputPort = GetOutputPortByUniqueId( CreateOutputId( m_inputPorts[ i ].PortId ) );
  1210. currOutputPort.SetLocalValue( inputPortLocalVar , dataCollector.PortCategory );
  1211. }
  1212. functionCall += inputPortLocalVar;
  1213. if( i < ( count - 1 ) )
  1214. {
  1215. functionCall += " , ";
  1216. }
  1217. }
  1218. functionCall += " )";
  1219. if( m_mode == CustomExpressionMode.Call || m_voidMode )
  1220. {
  1221. dataCollector.AddLocalVariable( 0 , functionCall + ";" , true );
  1222. }
  1223. else
  1224. {
  1225. RegisterLocalVariable( 0 , functionCall , ref dataCollector , localVarName );
  1226. }
  1227. dataCollector.AddFunction( expressionName , function );
  1228. }
  1229. else
  1230. {
  1231. string localCode = m_code;
  1232. if( m_mode == CustomExpressionMode.Call || m_voidMode )
  1233. {
  1234. for( int i = m_firstAvailablePort ; i < count ; i++ )
  1235. {
  1236. int idx = i - m_firstAvailablePort;
  1237. if( !m_items[ idx ].IsVariable ||
  1238. m_items[ idx ].Qualifier != VariableQualifiers.In ||
  1239. !m_inputPorts[ i ].IsConnected
  1240. )
  1241. {
  1242. string inputPortLocalVar = m_inputPorts[ i ].Name + OutputId;
  1243. string nameToReplaceRegex = string.Format( VarRegexReplacer , m_inputPorts[ i ].Name );
  1244. localCode = Regex.Replace( localCode , nameToReplaceRegex , inputPortLocalVar , RegexOptions.Multiline );
  1245. //localCode = localCode.Replace( m_inputPorts[ i ].Name, inputPortLocalVar );
  1246. if( m_inputPorts[ i ].IsConnected )
  1247. {
  1248. string result = m_inputPorts[ i ].GenerateShaderForOutput( ref dataCollector , m_inputPorts[ i ].DataType , true , true );
  1249. if( m_inputPorts[ i ].DataType == WirePortDataType.OBJECT )
  1250. {
  1251. dataCollector.AddLocalVariable( UniqueId , m_items[ idx ].CustomType + " " + inputPortLocalVar , result + ";" );
  1252. }
  1253. else
  1254. {
  1255. dataCollector.AddLocalVariable( UniqueId , CurrentPrecisionType , m_inputPorts[ i ].DataType , inputPortLocalVar , result );
  1256. }
  1257. }
  1258. else
  1259. {
  1260. if( m_inputPorts[ i ].DataType == WirePortDataType.OBJECT )
  1261. {
  1262. dataCollector.AddLocalVariable( UniqueId , m_items[ idx ].CustomType + " " + inputPortLocalVar , m_inputPorts[ i ].WrappedInternalData + ";" );
  1263. }
  1264. else
  1265. {
  1266. string result = m_inputPorts[ i ].WrappedInternalData;
  1267. if ( m_inputPorts[ i ].DataType == WirePortDataType.SAMPLERSTATE )
  1268. {
  1269. result = GeneratorUtils.GenerateSamplerState( ref dataCollector, UniqueId, DefaultSamplerStateStr, VariableMode.Create );
  1270. }
  1271. dataCollector.AddLocalVariable( UniqueId, CurrentPrecisionType, m_inputPorts[ i ].DataType, inputPortLocalVar, result );
  1272. }
  1273. }
  1274. if( m_items[ idx ].Qualifier != VariableQualifiers.In )
  1275. {
  1276. OutputPort currOutputPort = GetOutputPortByUniqueId( CreateOutputId( m_inputPorts[ i ].PortId ) );
  1277. currOutputPort.SetLocalValue( inputPortLocalVar , dataCollector.PortCategory );
  1278. }
  1279. }
  1280. else
  1281. {
  1282. // Not Unique
  1283. string result = m_inputPorts[ i ].GenerateShaderForOutput( ref dataCollector , m_inputPorts[ i ].DataType , true , true );
  1284. string nameToReplaceRegex = string.Format( VarRegexReplacer , m_inputPorts[ i ].Name );
  1285. localCode = Regex.Replace( localCode , nameToReplaceRegex , result , RegexOptions.Multiline );
  1286. //localCode = localCode.Replace( m_inputPorts[ i ].Name, result );
  1287. }
  1288. }
  1289. localCode = string.Format( Constants.InlineCodeWrapper , localCode );
  1290. string[] codeLines = localCode.Split( '\n' );
  1291. for( int codeIdx = 0 ; codeIdx < codeLines.Length ; codeIdx++ )
  1292. {
  1293. dataCollector.AddLocalVariable( 0 , codeLines[ codeIdx ] , true );
  1294. }
  1295. }
  1296. else
  1297. {
  1298. string function = WrapCodeInFunction( dataCollector.IsTemplate , expressionName , true );
  1299. string functionCall = expressionName + "( ";
  1300. for( int i = m_firstAvailablePort ; i < count ; i++ )
  1301. {
  1302. if( UIUtils.CurrentWindow.OutsideGraph.SamplingMacros && !UIUtils.CurrentWindow.OutsideGraph.IsSRP )
  1303. {
  1304. // we don't know what kind of sampling the user will do so we add all of them
  1305. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.Auto );
  1306. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.MipLevel );
  1307. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.MipBias );
  1308. GeneratorUtils.AddCustomStandardSamplingMacros( ref dataCollector , m_inputPorts[ i ].DataType , MipType.Derivative );
  1309. }
  1310. string inputPortLocalVar = m_inputPorts[ i ].Name + OutputId;
  1311. int idx = i - m_firstAvailablePort;
  1312. if( m_inputPorts[ i ].DataType != WirePortDataType.OBJECT )
  1313. {
  1314. string result = m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector );
  1315. dataCollector.AddLocalVariable( UniqueId , CurrentPrecisionType , m_inputPorts[ i ].DataType , inputPortLocalVar , result );
  1316. }
  1317. else
  1318. {
  1319. string result = ( m_inputPorts[ i ].IsConnected ) ? m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector ) : m_inputPorts[ i ].InternalData.ToString();
  1320. string inputLocalVar = string.Format( Constants.CustomTypeLocalValueDecWithoutIdent , m_items[ idx ].CustomType , inputPortLocalVar , result );
  1321. dataCollector.AddLocalVariable( UniqueId , inputLocalVar );
  1322. }
  1323. if( m_items[ idx ].Qualifier != VariableQualifiers.In )
  1324. {
  1325. OutputPort currOutputPort = GetOutputPortByUniqueId( CreateOutputId( m_inputPorts[ i ].PortId ) );
  1326. currOutputPort.SetLocalValue( inputPortLocalVar , dataCollector.PortCategory );
  1327. }
  1328. functionCall += inputPortLocalVar;
  1329. if( i < ( count - 1 ) )
  1330. {
  1331. functionCall += " , ";
  1332. }
  1333. }
  1334. functionCall += " )";
  1335. RegisterLocalVariable( 0 , functionCall , ref dataCollector , localVarName );
  1336. dataCollector.AddFunction( expressionName , function );
  1337. }
  1338. }
  1339. return outputPort.LocalValue( dataCollector.PortCategory );
  1340. }
  1341. else
  1342. {
  1343. if( m_code.Contains( ReturnHelper ) )
  1344. {
  1345. string function = WrapCodeInFunction( dataCollector.IsTemplate , expressionName , false );
  1346. dataCollector.AddFunction( expressionName , function );
  1347. string functionCall = expressionName + "()";
  1348. RegisterLocalVariable( 0 , functionCall , ref dataCollector , localVarName );
  1349. }
  1350. else
  1351. {
  1352. RegisterLocalVariable( 0 , string.Format( Constants.CodeWrapper , m_code ) , ref dataCollector , localVarName );
  1353. }
  1354. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  1355. }
  1356. }
  1357. int CreateOutputId( int inputId )
  1358. {
  1359. return ( inputId + 1 );
  1360. }
  1361. int CreateInputId( int outputId )
  1362. {
  1363. return outputId - 1;
  1364. }
  1365. void UpdateOutputPorts()
  1366. {
  1367. int count = m_inputPorts.Count - m_firstAvailablePort;
  1368. for( int i = 0 ; i < count ; i++ )
  1369. {
  1370. if( m_items[ i ].Qualifier != VariableQualifiers.In )
  1371. {
  1372. int portIdx = i + m_firstAvailablePort;
  1373. int outputPortId = CreateOutputId( m_inputPorts[ portIdx ].PortId );
  1374. AddOutputPort( m_inputPorts[ portIdx ].DataType , m_inputPorts[ portIdx ].Name , outputPortId );
  1375. }
  1376. }
  1377. }
  1378. public override void ReadFromString( ref string[] nodeParams )
  1379. {
  1380. // This node is, by default, created with one input port
  1381. base.ReadFromString( ref nodeParams );
  1382. m_code = GetCurrentParam( ref nodeParams );
  1383. m_code = m_code.Replace( Constants.LineFeedSeparator , '\n' );
  1384. m_code = m_code.Replace( Constants.SemiColonSeparator , ';' );
  1385. m_outputTypeIdx = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  1386. if( m_outputTypeIdx >= AvailableWireTypes.Length )
  1387. {
  1388. UIUtils.ShowMessage( UniqueId , "Sampler types were removed as a valid output custom expression type" );
  1389. m_outputTypeIdx = 1;
  1390. }
  1391. UpdateVoidMode();
  1392. m_outputPorts[ 0 ].ChangeType( AvailableWireTypes[ m_outputTypeIdx ] , false );
  1393. if( UIUtils.CurrentShaderVersion() > 12001 )
  1394. {
  1395. if( UIUtils.CurrentShaderVersion() > 18901 )
  1396. {
  1397. m_mode = (CustomExpressionMode)Enum.Parse( typeof( CustomExpressionMode ) , GetCurrentParam( ref nodeParams ) );
  1398. }
  1399. else
  1400. {
  1401. bool mode = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  1402. m_mode = mode ? CustomExpressionMode.Call : CustomExpressionMode.Create;
  1403. }
  1404. if( m_mode == CustomExpressionMode.Call || m_voidMode )
  1405. {
  1406. m_firstAvailablePort = 1;
  1407. AddInputPortAt( 0 , WirePortDataType.FLOAT , false , DefaultInputNameStr );
  1408. }
  1409. }
  1410. if( m_mode == CustomExpressionMode.Call || m_mode == CustomExpressionMode.File )
  1411. UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.RemoveNode( this );
  1412. int count = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  1413. if( count == 0 )
  1414. {
  1415. DeleteInputPortByArrayIdx( m_firstAvailablePort );
  1416. m_items.Clear();
  1417. }
  1418. else
  1419. {
  1420. for( int i = 0 ; i < count ; i++ )
  1421. {
  1422. bool foldoutValue = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  1423. string name = GetCurrentParam( ref nodeParams );
  1424. WirePortDataType type = (WirePortDataType)Enum.Parse( typeof( WirePortDataType ) , GetCurrentParam( ref nodeParams ) );
  1425. string internalData = GetCurrentParam( ref nodeParams );
  1426. VariableQualifiers qualifier = VariableQualifiers.In;
  1427. if( UIUtils.CurrentShaderVersion() > 12001 )
  1428. {
  1429. qualifier = (VariableQualifiers)Enum.Parse( typeof( VariableQualifiers ) , GetCurrentParam( ref nodeParams ) );
  1430. }
  1431. string customType = string.Empty;
  1432. if( UIUtils.CurrentShaderVersion() > 15311 )
  1433. {
  1434. customType = GetCurrentParam( ref nodeParams );
  1435. }
  1436. PrecisionType precision = PrecisionType.Float;
  1437. if( UIUtils.CurrentShaderVersion() > 15607 )
  1438. {
  1439. precision = (PrecisionType)Enum.Parse( typeof( PrecisionType ) , GetCurrentParam( ref nodeParams ) );
  1440. }
  1441. bool isVariable = false;
  1442. if( UIUtils.CurrentShaderVersion() > 16600 )
  1443. {
  1444. isVariable = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  1445. }
  1446. int portIdx = i + m_firstAvailablePort;
  1447. if( i == 0 )
  1448. {
  1449. m_inputPorts[ portIdx ].ChangeProperties( name , type , false );
  1450. m_inputPorts[ portIdx ].Visible = qualifier != VariableQualifiers.Out;
  1451. m_items[ 0 ].Qualifier = qualifier;
  1452. m_items[ 0 ].FoldoutFlag = foldoutValue;
  1453. m_items[ 0 ].CustomType = customType;
  1454. m_items[ 0 ].Precision = precision;
  1455. m_items[ 0 ].IsVariable = isVariable;
  1456. }
  1457. else
  1458. {
  1459. m_items.Add( new CustomExpressionInputItem( precision , qualifier , customType , isVariable , foldoutValue , string.Empty/*"[" + i + "]"*/ ) );
  1460. AddInputPort( type , false , name );
  1461. m_inputPorts[ m_inputPorts.Count - 1 ].Visible = qualifier != VariableQualifiers.Out;
  1462. }
  1463. m_inputPorts[ i ].InternalData = internalData;
  1464. }
  1465. }
  1466. if( UIUtils.CurrentShaderVersion() > 7205 )
  1467. {
  1468. m_customExpressionName = GetCurrentParam( ref nodeParams );
  1469. SetTitleText( m_customExpressionName );
  1470. }
  1471. if( UIUtils.CurrentShaderVersion() > 14401 )
  1472. {
  1473. m_generateUniqueName = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  1474. }
  1475. if( UIUtils.CurrentShaderVersion() > 15102 )
  1476. {
  1477. m_autoRegisterMode = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  1478. }
  1479. if( UIUtils.CurrentShaderVersion() > 15403 )
  1480. {
  1481. int dependencyCount = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  1482. for( int i = 0 ; i < dependencyCount ; i++ )
  1483. {
  1484. m_dependencies.Add( new CustomExpressionDependency( GetCurrentParam( ref nodeParams ) ) );
  1485. }
  1486. }
  1487. if( UIUtils.CurrentShaderVersion() > 18901 )
  1488. {
  1489. m_fileGUID = GetCurrentParam( ref nodeParams );
  1490. if( !string.IsNullOrEmpty( m_fileGUID ) )
  1491. {
  1492. m_fileAsset = AssetDatabase.LoadAssetAtPath<TextAsset>( AssetDatabase.GUIDToAssetPath( m_fileGUID ) );
  1493. }
  1494. m_precisionSuffix = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  1495. }
  1496. if( m_mode == CustomExpressionMode.Create )
  1497. {
  1498. UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.AddNode( this );
  1499. }
  1500. UpdateOutputPorts();
  1501. m_repopulateNameDictionary = true;
  1502. m_functionMode = m_code.Contains( ReturnHelper );
  1503. CheckCallMode();
  1504. }
  1505. public override void WriteToString( ref string nodeInfo , ref string connectionsInfo )
  1506. {
  1507. base.WriteToString( ref nodeInfo , ref connectionsInfo );
  1508. m_code = m_code.Replace( Constants.LineFeedSeparator.ToString() , string.Empty );
  1509. m_code = m_code.Replace( Constants.SemiColonSeparator.ToString() , string.Empty );
  1510. m_code = UIUtils.ForceLFLineEnding( m_code );
  1511. string parsedCode = m_code.Replace( '\n' , Constants.LineFeedSeparator );
  1512. parsedCode = parsedCode.Replace( ';' , Constants.SemiColonSeparator );
  1513. IOUtils.AddFieldValueToString( ref nodeInfo , parsedCode );
  1514. IOUtils.AddFieldValueToString( ref nodeInfo , m_outputTypeIdx );
  1515. //IOUtils.AddFieldValueToString( ref nodeInfo, m_mode == CustomExpressionMode.Call );
  1516. IOUtils.AddFieldValueToString( ref nodeInfo , m_mode );
  1517. int count = m_inputPorts.Count - m_firstAvailablePort;
  1518. IOUtils.AddFieldValueToString( ref nodeInfo , count );
  1519. for( int i = 0 ; i < count ; i++ )
  1520. {
  1521. int portIdx = m_firstAvailablePort + i;
  1522. IOUtils.AddFieldValueToString( ref nodeInfo , m_items[ i ].FoldoutFlag );
  1523. IOUtils.AddFieldValueToString( ref nodeInfo , m_inputPorts[ portIdx ].Name );
  1524. IOUtils.AddFieldValueToString( ref nodeInfo , m_inputPorts[ portIdx ].DataType );
  1525. IOUtils.AddFieldValueToString( ref nodeInfo , m_inputPorts[ portIdx ].InternalData );
  1526. IOUtils.AddFieldValueToString( ref nodeInfo , m_items[ i ].Qualifier );
  1527. IOUtils.AddFieldValueToString( ref nodeInfo , m_items[ i ].CustomType );
  1528. IOUtils.AddFieldValueToString( ref nodeInfo , m_items[ i ].Precision );
  1529. IOUtils.AddFieldValueToString( ref nodeInfo , m_items[ i ].IsVariable );
  1530. }
  1531. IOUtils.AddFieldValueToString( ref nodeInfo , m_customExpressionName );
  1532. IOUtils.AddFieldValueToString( ref nodeInfo , m_generateUniqueName );
  1533. IOUtils.AddFieldValueToString( ref nodeInfo , m_autoRegisterMode );
  1534. count = m_dependencies.Count;
  1535. IOUtils.AddFieldValueToString( ref nodeInfo , count );
  1536. for( int i = 0 ; i < count ; i++ )
  1537. {
  1538. IOUtils.AddFieldValueToString( ref nodeInfo , m_dependencies[ i ].DependencyNodeId );
  1539. }
  1540. m_fileGUID = ( m_fileAsset == null ) ? string.Empty :
  1541. AssetDatabase.AssetPathToGUID( AssetDatabase.GetAssetPath( m_fileAsset ) );
  1542. IOUtils.AddFieldValueToString( ref nodeInfo , m_fileGUID );
  1543. IOUtils.AddFieldValueToString( ref nodeInfo , m_precisionSuffix );
  1544. }
  1545. public override void Destroy()
  1546. {
  1547. base.Destroy();
  1548. if( m_mode == CustomExpressionMode.Create )
  1549. {
  1550. UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.RemoveNode( this );
  1551. }
  1552. m_items.Clear();
  1553. m_items = null;
  1554. m_dependencies.Clear();
  1555. m_dependencies = null;
  1556. m_itemReordableList = null;
  1557. }
  1558. public void CheckDependencies( ref MasterNodeDataCollector dataCollector , ref Dictionary<int , CustomExpressionNode> examinedNodes )
  1559. {
  1560. if( !examinedNodes.ContainsKey( UniqueId ) && m_mode == CustomExpressionMode.Create && !m_generateUniqueName )
  1561. {
  1562. int dependencyCount = m_dependencies.Count;
  1563. for( int d = 0 ; d < dependencyCount ; d++ )
  1564. {
  1565. if( !examinedNodes.ContainsKey( m_dependencies[ d ].DependencyNodeId ) )
  1566. {
  1567. CustomExpressionNode dNode = m_containerGraph.GetNode( m_dependencies[ d ].DependencyNodeId ) as CustomExpressionNode;
  1568. if( dNode == null )
  1569. {
  1570. dNode = UIUtils.CurrentWindow.OutsideGraph.GetNode( m_dependencies[ d ].DependencyNodeId ) as CustomExpressionNode;
  1571. }
  1572. if( dNode != null )
  1573. {
  1574. dNode.CheckDependencies( ref dataCollector , ref examinedNodes );
  1575. }
  1576. }
  1577. }
  1578. dataCollector.AddFunction( ExpressionName , EncapsulatedCode( dataCollector.IsTemplate ) );
  1579. examinedNodes.Add( UniqueId , this );
  1580. }
  1581. }
  1582. public string EncapsulatedCode( bool isTemplate )
  1583. {
  1584. string functionName = UIUtils.RemoveInvalidCharacters( m_customExpressionName );
  1585. if( m_generateUniqueName )
  1586. {
  1587. functionName += OutputId;
  1588. }
  1589. return WrapCodeInFunction( isTemplate , functionName , false );
  1590. }
  1591. public CustomExpressionMode Mode
  1592. {
  1593. get { return m_mode; }
  1594. set
  1595. {
  1596. if( m_mode != value )
  1597. {
  1598. m_mode = value;
  1599. if( m_mode == CustomExpressionMode.Call )
  1600. {
  1601. AutoRegisterMode = false;
  1602. m_generateUniqueName = false;
  1603. UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.RemoveNode( this );
  1604. }
  1605. else if( m_mode == CustomExpressionMode.File )
  1606. {
  1607. m_generateUniqueName = false;
  1608. UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.RemoveNode( this );
  1609. }
  1610. else if( m_mode == CustomExpressionMode.Create )
  1611. {
  1612. UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.AddNode( this );
  1613. }
  1614. }
  1615. }
  1616. }
  1617. public string ExpressionName
  1618. {
  1619. get
  1620. {
  1621. string expressionName = UIUtils.RemoveInvalidCharacters( m_customExpressionName );
  1622. if( m_generateUniqueName )
  1623. {
  1624. expressionName += OutputId;
  1625. }
  1626. return expressionName;
  1627. }
  1628. }
  1629. public override string DataToArray { get { return m_customExpressionName; } }
  1630. public bool AutoRegisterMode
  1631. {
  1632. get { return m_autoRegisterMode; }
  1633. set
  1634. {
  1635. if( value != m_autoRegisterMode )
  1636. {
  1637. m_autoRegisterMode = value;
  1638. }
  1639. }
  1640. }
  1641. public override void RefreshExternalReferences()
  1642. {
  1643. base.RefreshExternalReferences();
  1644. int portCount = m_inputPorts.Count;
  1645. for( int i = 0 ; i < portCount ; i++ )
  1646. {
  1647. if( m_inputPorts[ i ].DataType == WirePortDataType.COLOR )
  1648. {
  1649. m_inputPorts[ i ].ChangeType( WirePortDataType.FLOAT4 , false ); ;
  1650. }
  1651. }
  1652. int dependencyCount = m_dependencies.Count;
  1653. for( int i = 0 ; i < dependencyCount ; i++ )
  1654. {
  1655. m_dependencies[ i ].DependencyArrayIdx = UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.GetNodeRegisterIdx( m_dependencies[ i ].DependencyNodeId );
  1656. }
  1657. //Fixing bug where user could set main output port as OBJECT
  1658. if( m_outputPorts[ 0 ].DataType == WirePortDataType.OBJECT && ( m_voidMode || m_mode == CustomExpressionMode.Call ) )
  1659. {
  1660. m_outputPorts[ 0 ].ChangeType( m_inputPorts[ 0 ].DataType , false );
  1661. }
  1662. }
  1663. public override void FireTimedUpdate()
  1664. {
  1665. UIUtils.CurrentWindow.OutsideGraph.CustomExpressionOnFunctionMode.UpdateDataOnNode( UniqueId , m_customExpressionName );
  1666. }
  1667. public List<CustomExpressionDependency> Dependencies { get { return m_dependencies; } }
  1668. }
  1669. }