GlobalArrayNode.cs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489
  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. //
  4. // Custom Node Global Array
  5. // Donated by Johann van Berkel
  6. using System;
  7. using UnityEngine;
  8. using UnityEditor;
  9. namespace AmplifyShaderEditor
  10. {
  11. [Serializable]
  12. [NodeAttributes( "Global Array" , "Constants And Properties" , "The node returns a value from a global array, which you can configure by entering the name of the array in the node's settings." , null , KeyCode.None , true , false , null , null , "Johann van Berkel" )]
  13. public sealed class GlobalArrayNode : ParentNode
  14. {
  15. private const string DefaultArrayName = "MyGlobalArray";
  16. private const string TypeStr = "Type";
  17. private const string AutoRangeCheckStr = "Range Check";
  18. private const string ArrayFormatStr = "{0}[{1}]";
  19. private const string JaggedArrayFormatStr = "{0}[{1}][{2}]";
  20. private const string IsJaggedStr = "Is Jagged";
  21. private const string AutoRegisterStr = "Auto-Register";
  22. private readonly string[] AvailableTypesLabel = { "Float" , "Color" , "Vector4" , "Matrix4x4" };
  23. private readonly WirePortDataType[] AvailableTypesValues = { WirePortDataType.FLOAT , WirePortDataType.COLOR , WirePortDataType.FLOAT4 , WirePortDataType.FLOAT4x4 };
  24. [SerializeField]
  25. private string m_name = DefaultArrayName;
  26. [SerializeField]
  27. private int m_indexX = 0;
  28. [SerializeField]
  29. private int m_indexY = 0;
  30. [SerializeField]
  31. private int m_arrayLengthX = 1;
  32. [SerializeField]
  33. private int m_arrayLengthY = 1;
  34. [SerializeField]
  35. private int m_type = 0;
  36. [SerializeField]
  37. private bool m_autoRangeCheck = false;
  38. [SerializeField]
  39. private bool m_isJagged = false;
  40. [SerializeField]
  41. private bool m_autoRegister = false;
  42. //////////////////////////////////////////////////////////////////
  43. private readonly Color ReferenceHeaderColor = new Color( 0.6f , 3.0f , 1.25f , 1.0f );
  44. [SerializeField]
  45. private TexReferenceType m_referenceType = TexReferenceType.Object;
  46. [SerializeField]
  47. private int m_referenceArrayId = -1;
  48. [SerializeField]
  49. private int m_referenceNodeId = -1;
  50. private GlobalArrayNode m_referenceNode = null;
  51. private bool m_updated = false;
  52. protected override void CommonInit( int uniqueId )
  53. {
  54. base.CommonInit( uniqueId );
  55. AddInputPort( WirePortDataType.INT , false , "Index" , -1 , MasterNodePortCategory.Fragment , 0 );
  56. AddInputPort( WirePortDataType.INT , false , "Index Y" , -1 , MasterNodePortCategory.Fragment , 2 );
  57. AddInputPort( WirePortDataType.INT , false , "Array Length" , -1 , MasterNodePortCategory.Fragment , 1 );
  58. AddInputPort( WirePortDataType.INT , false , "Array Length Y" , -1 , MasterNodePortCategory.Fragment , 3 );
  59. AddOutputPort( WirePortDataType.FLOAT , "Out" );
  60. m_textLabelWidth = 95;
  61. m_autoWrapProperties = true;
  62. SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr , m_name ) );
  63. UpdatePorts();
  64. }
  65. protected override void OnUniqueIDAssigned()
  66. {
  67. base.OnUniqueIDAssigned();
  68. UIUtils.CurrentWindow.OutsideGraph.GlobalArrayNodes.AddNode( this );
  69. }
  70. public override void Destroy()
  71. {
  72. base.Destroy();
  73. UIUtils.CurrentWindow.OutsideGraph.GlobalArrayNodes.RemoveNode( this );
  74. }
  75. void UpdatePorts()
  76. {
  77. InputPort indexXPort = GetInputPortByUniqueId( 0 );
  78. InputPort arrayLengthPortX = GetInputPortByUniqueId( 1 );
  79. InputPort indexYPort = GetInputPortByUniqueId( 2 );
  80. InputPort arrayLengthPortY = GetInputPortByUniqueId( 3 );
  81. if( m_referenceType == TexReferenceType.Object )
  82. {
  83. m_headerColorModifier = Color.white;
  84. SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr , m_name ) );
  85. arrayLengthPortX.Visible = true;
  86. if( m_isJagged )
  87. {
  88. indexXPort.Name = "Index X";
  89. arrayLengthPortX.Name = "Array Length X";
  90. indexYPort.Visible = true;
  91. arrayLengthPortY.Visible = true;
  92. }
  93. else
  94. {
  95. indexXPort.Name = "Index";
  96. arrayLengthPortX.Name = "Array Length";
  97. indexYPort.Visible = false;
  98. arrayLengthPortY.Visible = false;
  99. }
  100. }
  101. else if( m_referenceNodeId > -1 )
  102. {
  103. m_headerColorModifier = ReferenceHeaderColor;
  104. if( m_referenceNode == null )
  105. m_referenceNode = UIUtils.GetNode( m_referenceNodeId ) as GlobalArrayNode;
  106. if( m_referenceNode != null )
  107. {
  108. SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr , m_referenceNode.DataToArray ) );
  109. arrayLengthPortX.Visible = false;
  110. arrayLengthPortY.Visible = false;
  111. if( m_referenceNode.IsJagged )
  112. {
  113. indexXPort.Name = "Index X";
  114. indexYPort.Visible = true;
  115. }
  116. else
  117. {
  118. indexXPort.Name = "Index";
  119. indexYPort.Visible = false;
  120. }
  121. }
  122. }
  123. m_sizeIsDirty = true;
  124. }
  125. void DrawObjectProperties()
  126. {
  127. EditorGUI.BeginChangeCheck();
  128. m_name = EditorGUILayoutStringField( "Name" , m_name );
  129. if( EditorGUI.EndChangeCheck() )
  130. {
  131. m_updated = true;
  132. m_name = UIUtils.RemoveInvalidCharacters( m_name );
  133. if( string.IsNullOrEmpty( m_name ) )
  134. m_name = DefaultArrayName;
  135. UIUtils.UpdateGlobalArrayDataNode( UniqueId , m_name );
  136. SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr , m_name ) );
  137. }
  138. m_autoRegister = EditorGUILayoutToggle( AutoRegisterStr , m_autoRegister );
  139. EditorGUI.BeginChangeCheck();
  140. m_isJagged = EditorGUILayoutToggle( IsJaggedStr , m_isJagged );
  141. if( EditorGUI.EndChangeCheck() )
  142. {
  143. m_updated = true;
  144. UpdatePorts();
  145. }
  146. InputPort indexXPort = GetInputPortByUniqueId( 0 );
  147. if( !indexXPort.IsConnected )
  148. {
  149. EditorGUI.BeginChangeCheck();
  150. m_indexX = EditorGUILayoutIntField( indexXPort.Name , m_indexX );
  151. if( EditorGUI.EndChangeCheck() )
  152. {
  153. m_indexX = Mathf.Clamp( m_indexX , 0 , ( ArrayLengthX - 1 ) );
  154. }
  155. }
  156. if( m_isJagged )
  157. {
  158. InputPort indexYPort = GetInputPortByUniqueId( 2 );
  159. if( !indexYPort.IsConnected )
  160. {
  161. EditorGUI.BeginChangeCheck();
  162. m_indexY = EditorGUILayoutIntField( indexYPort.Name , m_indexY );
  163. if( EditorGUI.EndChangeCheck() )
  164. {
  165. m_indexY = Mathf.Clamp( m_indexY , 0 , ( ArrayLengthY - 1 ) );
  166. }
  167. }
  168. }
  169. InputPort arrayLengthXPort = GetInputPortByUniqueId( 1 );
  170. if( !arrayLengthXPort.IsConnected )
  171. {
  172. EditorGUI.BeginChangeCheck();
  173. m_arrayLengthX = EditorGUILayoutIntField( arrayLengthXPort.Name , m_arrayLengthX );
  174. if( EditorGUI.EndChangeCheck() )
  175. {
  176. m_arrayLengthX = Mathf.Max( 1 , m_arrayLengthX );
  177. }
  178. }
  179. if( m_isJagged )
  180. {
  181. InputPort arrayLengthYPort = GetInputPortByUniqueId( 3 );
  182. if( !arrayLengthYPort.IsConnected )
  183. {
  184. EditorGUI.BeginChangeCheck();
  185. m_arrayLengthY = EditorGUILayoutIntField( arrayLengthYPort.Name , m_arrayLengthY );
  186. if( EditorGUI.EndChangeCheck() )
  187. {
  188. m_arrayLengthY = Mathf.Max( 1 , m_arrayLengthY );
  189. }
  190. }
  191. }
  192. EditorGUI.BeginChangeCheck();
  193. m_type = EditorGUILayoutPopup( TypeStr , m_type , AvailableTypesLabel );
  194. if( EditorGUI.EndChangeCheck() )
  195. {
  196. m_outputPorts[ 0 ].ChangeType( (WirePortDataType)AvailableTypesValues[ m_type ] , false );
  197. }
  198. m_autoRangeCheck = EditorGUILayoutToggle( AutoRangeCheckStr , m_autoRangeCheck );
  199. }
  200. public override void OnNodeLayout( DrawInfo drawInfo )
  201. {
  202. base.OnNodeLayout( drawInfo );
  203. m_updated = false;
  204. if( m_referenceType == TexReferenceType.Instance )
  205. {
  206. if( m_referenceNodeId > -1 && m_referenceNode == null )
  207. {
  208. m_referenceNode = UIUtils.GetNode( m_referenceNodeId ) as GlobalArrayNode;
  209. if( m_referenceNode == null )
  210. {
  211. m_referenceNodeId = -1;
  212. }
  213. }
  214. if( m_referenceNode != null && m_referenceNode.Updated )
  215. {
  216. UpdatePorts();
  217. }
  218. }
  219. }
  220. void DrawInstancedProperties()
  221. {
  222. string[] arr = UIUtils.GlobalArrayNodeArr();
  223. bool guiEnabledBuffer = GUI.enabled;
  224. if( arr != null && arr.Length > 0 )
  225. {
  226. GUI.enabled = true;
  227. }
  228. else
  229. {
  230. m_referenceArrayId = -1;
  231. m_referenceNodeId = -1;
  232. m_referenceNode = null;
  233. GUI.enabled = false;
  234. }
  235. EditorGUI.BeginChangeCheck();
  236. m_referenceArrayId = EditorGUILayoutPopup( Constants.AvailableReferenceStr , m_referenceArrayId , arr );
  237. if( EditorGUI.EndChangeCheck() )
  238. {
  239. m_referenceNode = UIUtils.GetGlobalArrayNode( m_referenceArrayId );
  240. if( m_referenceNode != null )
  241. {
  242. m_referenceNodeId = m_referenceNode.UniqueId;
  243. }
  244. UpdatePorts();
  245. }
  246. GUI.enabled = guiEnabledBuffer;
  247. InputPort indexXPort = GetInputPortByUniqueId( 0 );
  248. if( !indexXPort.IsConnected )
  249. {
  250. EditorGUI.BeginChangeCheck();
  251. m_indexX = EditorGUILayoutIntField( indexXPort.Name , m_indexX );
  252. if( EditorGUI.EndChangeCheck() )
  253. {
  254. m_indexX = Mathf.Clamp( m_indexX , 0 , ( ArrayLengthX - 1 ) );
  255. }
  256. }
  257. if( m_isJagged )
  258. {
  259. InputPort indexYPort = GetInputPortByUniqueId( 2 );
  260. if( !indexYPort.IsConnected )
  261. {
  262. EditorGUI.BeginChangeCheck();
  263. m_indexY = EditorGUILayoutIntField( indexYPort.Name , m_indexY );
  264. if( EditorGUI.EndChangeCheck() )
  265. {
  266. m_indexY = Mathf.Clamp( m_indexY , 0 , ( ArrayLengthY - 1 ) );
  267. }
  268. }
  269. }
  270. }
  271. public override void DrawProperties()
  272. {
  273. EditorGUI.BeginChangeCheck();
  274. m_referenceType = (TexReferenceType)EditorGUILayoutPopup( Constants.ReferenceTypeStr , (int)m_referenceType , Constants.ReferenceArrayLabels );
  275. if( EditorGUI.EndChangeCheck() )
  276. {
  277. UpdatePorts();
  278. }
  279. if( m_referenceType == TexReferenceType.Object )
  280. DrawObjectProperties();
  281. else
  282. DrawInstancedProperties();
  283. }
  284. public string GetArrayValue( string indexX , string indexY = null )
  285. {
  286. if( m_isJagged )
  287. return string.Format( JaggedArrayFormatStr , m_name , indexX , indexY );
  288. return string.Format( ArrayFormatStr , m_name , indexX );
  289. }
  290. public string GenerateInstancedShaderForOutput( int outputId , ref MasterNodeDataCollector dataCollector , bool ignoreLocalvar )
  291. {
  292. string result = string.Empty;
  293. if( m_referenceNode != null )
  294. {
  295. InputPort indexXPort = GetInputPortByUniqueId( 0 );
  296. if( m_referenceNode.IsJagged )
  297. {
  298. InputPort indexYPort = GetInputPortByUniqueId( 2 );
  299. string arrayIndexX = indexXPort.IsConnected ? indexXPort.GeneratePortInstructions( ref dataCollector ) : m_indexX.ToString();
  300. string arrayIndexY = indexYPort.IsConnected ? indexYPort.GeneratePortInstructions( ref dataCollector ) : m_indexY.ToString();
  301. result = m_referenceNode.GetArrayValue( arrayIndexX , arrayIndexY );
  302. }
  303. else
  304. {
  305. string arrayIndexX = indexXPort.IsConnected ? indexXPort.GeneratePortInstructions( ref dataCollector ) : m_indexX.ToString();
  306. result = m_referenceNode.GetArrayValue( arrayIndexX );
  307. }
  308. }
  309. m_outputPorts[ 0 ].SetLocalValue( result , dataCollector.PortCategory );
  310. return result;
  311. }
  312. public override string GenerateShaderForOutput( int outputId , ref MasterNodeDataCollector dataCollector , bool ignoreLocalvar )
  313. {
  314. if( m_outputPorts[ 0 ].IsLocalValue( dataCollector.PortCategory ) )
  315. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  316. if( m_referenceType == TexReferenceType.Instance )
  317. return GenerateInstancedShaderForOutput( outputId , ref dataCollector , ignoreLocalvar );
  318. string dataType = UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType , AvailableTypesValues[ m_type ] );
  319. InputPort indexXPort = GetInputPortByUniqueId( 0 );
  320. InputPort arrayLengthXPort = GetInputPortByUniqueId( 1 );
  321. string result = string.Empty;
  322. if( m_isJagged )
  323. {
  324. InputPort indexYPort = GetInputPortByUniqueId( 2 );
  325. InputPort arrayLengthYPort = GetInputPortByUniqueId( 3 );
  326. string arrayIndexX = indexXPort.IsConnected ? indexXPort.GeneratePortInstructions( ref dataCollector ) : m_indexX.ToString();
  327. string arrayLengthX = arrayLengthXPort.IsConnected ? arrayLengthXPort.GeneratePortInstructions( ref dataCollector ) : ArrayLengthX.ToString();
  328. string arrayIndexY = indexYPort.IsConnected ? indexYPort.GeneratePortInstructions( ref dataCollector ) : m_indexY.ToString();
  329. string arrayLengthY = arrayLengthYPort.IsConnected ? arrayLengthYPort.GeneratePortInstructions( ref dataCollector ) : ArrayLengthY.ToString();
  330. dataCollector.AddToUniforms( UniqueId , dataType , string.Format( JaggedArrayFormatStr , m_name , arrayLengthX , arrayLengthY ) );
  331. if( m_autoRangeCheck )
  332. {
  333. arrayIndexX = string.Format( "clamp({0},0,({1} - 1))" , arrayIndexX , arrayLengthX );
  334. arrayIndexY = string.Format( "clamp({0},0,({1} - 1))" , arrayIndexY , arrayLengthY );
  335. }
  336. result = string.Format( JaggedArrayFormatStr , m_name , arrayIndexX , arrayIndexY );
  337. }
  338. else
  339. {
  340. string arrayIndex = indexXPort.IsConnected ? indexXPort.GeneratePortInstructions( ref dataCollector ) : m_indexX.ToString();
  341. string arrayLength = arrayLengthXPort.IsConnected ? arrayLengthXPort.GeneratePortInstructions( ref dataCollector ) : ArrayLengthX.ToString();
  342. dataCollector.AddToUniforms( UniqueId , dataType , string.Format( ArrayFormatStr , m_name , arrayLength ) );
  343. if( m_autoRangeCheck )
  344. arrayIndex = string.Format( "clamp({0},0,({1} - 1))" , arrayIndex , arrayLength );
  345. result = string.Format( ArrayFormatStr , m_name , arrayIndex );
  346. }
  347. m_outputPorts[ 0 ].SetLocalValue( result , dataCollector.PortCategory );
  348. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  349. }
  350. public void CheckIfAutoRegister( ref MasterNodeDataCollector dataCollector )
  351. {
  352. if( m_referenceType == TexReferenceType.Object && m_autoRegister && m_connStatus != NodeConnectionStatus.Connected )
  353. {
  354. string dataType = UIUtils.PrecisionWirePortToCgType( CurrentPrecisionType , AvailableTypesValues[ m_type ] );
  355. if( m_isJagged )
  356. {
  357. dataCollector.AddToUniforms( UniqueId , dataType , string.Format( JaggedArrayFormatStr , m_name , ArrayLengthX , ArrayLengthY ) );
  358. }
  359. else
  360. {
  361. dataCollector.AddToUniforms( UniqueId , dataType , string.Format( ArrayFormatStr , m_name , ArrayLengthX ) );
  362. }
  363. }
  364. }
  365. public override void WriteToString( ref string nodeInfo , ref string connectionsInfo )
  366. {
  367. base.WriteToString( ref nodeInfo , ref connectionsInfo );
  368. IOUtils.AddFieldValueToString( ref nodeInfo , m_name );
  369. IOUtils.AddFieldValueToString( ref nodeInfo , m_indexX );
  370. IOUtils.AddFieldValueToString( ref nodeInfo , m_arrayLengthX );
  371. IOUtils.AddFieldValueToString( ref nodeInfo , m_type );
  372. IOUtils.AddFieldValueToString( ref nodeInfo , m_autoRangeCheck );
  373. IOUtils.AddFieldValueToString( ref nodeInfo , m_isJagged );
  374. IOUtils.AddFieldValueToString( ref nodeInfo , m_indexY );
  375. IOUtils.AddFieldValueToString( ref nodeInfo , m_arrayLengthY );
  376. IOUtils.AddFieldValueToString( ref nodeInfo , m_autoRegister );
  377. IOUtils.AddFieldValueToString( ref nodeInfo , m_referenceType );
  378. IOUtils.AddFieldValueToString( ref nodeInfo , m_referenceNodeId );
  379. }
  380. public override void ReadFromString( ref string[] nodeParams )
  381. {
  382. base.ReadFromString( ref nodeParams );
  383. m_name = GetCurrentParam( ref nodeParams );
  384. m_indexX = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  385. m_arrayLengthX = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  386. m_type = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  387. m_autoRangeCheck = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  388. if( UIUtils.CurrentShaderVersion() > 15801 )
  389. {
  390. m_isJagged = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  391. m_indexY = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  392. m_arrayLengthY = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  393. m_autoRegister = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  394. m_referenceType = (TexReferenceType)Enum.Parse( typeof( TexReferenceType ) , GetCurrentParam( ref nodeParams ) );
  395. m_referenceNodeId = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  396. }
  397. SetAdditonalTitleText( string.Format( Constants.SubTitleValueFormatStr , m_name ) );
  398. UpdatePorts();
  399. }
  400. public override void RefreshExternalReferences()
  401. {
  402. base.RefreshExternalReferences();
  403. if( m_referenceType == TexReferenceType.Instance && m_referenceNodeId > -1 )
  404. {
  405. m_referenceNode = UIUtils.GetNode( m_referenceNodeId ) as GlobalArrayNode;
  406. if( m_referenceNode != null )
  407. {
  408. m_referenceArrayId = UIUtils.GetGlobalArrayNodeRegisterId( m_referenceNodeId );
  409. UpdatePorts();
  410. }
  411. else
  412. {
  413. m_referenceNodeId = -1;
  414. }
  415. }
  416. }
  417. public int ArrayLengthX { get { return ( m_referenceNode != null ) ? m_referenceNode.ArrayLengthX : m_arrayLengthX; } }
  418. public int ArrayLengthY { get { return ( m_referenceNode != null ) ? m_referenceNode.ArrayLengthY : m_arrayLengthY; } }
  419. public bool AutoRegister { get { return m_autoRegister; } }
  420. public bool IsJagged { get { return m_isJagged; } }
  421. public bool Updated { get { return m_updated; } }
  422. public override string DataToArray { get { return m_name; } }
  423. }
  424. }