You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

475 lines
14 KiB

  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. using UnityEngine;
  4. using UnityEditor;
  5. using System;
  6. using System.Collections.Generic;
  7. namespace AmplifyShaderEditor
  8. {
  9. public struct AppendData
  10. {
  11. public WirePortDataType PortType;
  12. public int OldPortId;
  13. public int NewPortId;
  14. public AppendData( WirePortDataType portType, int oldPortId, int newPortId )
  15. {
  16. PortType = portType;
  17. OldPortId = oldPortId;
  18. NewPortId = newPortId;
  19. }
  20. }
  21. [Serializable]
  22. [NodeAttributes( "Append", "Vector Operators", "Append channels to create a new component", null, KeyCode.V )]
  23. public sealed class DynamicAppendNode : ParentNode
  24. {
  25. private const string OutputTypeStr = "Output type";
  26. private const string OutputFormatStr = "({0}({1}))";
  27. [SerializeField]
  28. private WirePortDataType m_selectedOutputType = WirePortDataType.FLOAT4;
  29. [SerializeField]
  30. private int m_selectedOutputTypeInt = 2;
  31. private readonly string[] m_outputValueTypes ={ "Vector2",
  32. "Vector3",
  33. "Vector4",
  34. "Color"};
  35. [SerializeField]
  36. private int[] m_occupiedChannels = { -1, -1, -1, -1 };
  37. [SerializeField]
  38. private int m_maskId;
  39. [SerializeField]
  40. private Vector4 m_maskValue = Vector4.one;
  41. protected override void CommonInit( int uniqueId )
  42. {
  43. base.CommonInit( uniqueId );
  44. AddInputPort( WirePortDataType.FLOAT, false, Constants.ChannelNamesVector[ 0 ] );
  45. AddInputPort( WirePortDataType.FLOAT, false, Constants.ChannelNamesVector[ 1 ] );
  46. AddInputPort( WirePortDataType.FLOAT, false, Constants.ChannelNamesVector[ 2 ] );
  47. AddInputPort( WirePortDataType.FLOAT, false, Constants.ChannelNamesVector[ 3 ] );
  48. AddOutputPort( m_selectedOutputType, Constants.EmptyPortValue );
  49. m_textLabelWidth = 90;
  50. m_autoWrapProperties = true;
  51. m_useInternalPortData = true;
  52. m_hasLeftDropdown = true;
  53. m_previewShaderGUID = "bfcd2919fe75bbf428fbbe583f463a9e";
  54. }
  55. public override void OnEnable()
  56. {
  57. base.OnEnable();
  58. m_maskId = Shader.PropertyToID( "_Mask" );
  59. }
  60. void NewUpdateBehaviorConn( int portId, bool onLoading )
  61. {
  62. InputPort inputPort = GetInputPortByUniqueId( portId );
  63. int channelsRequired = UIUtils.GetChannelsAmount( onLoading ? inputPort.DataType : inputPort.ConnectionType( 0 ) );
  64. int availableChannels = UIUtils.GetChannelsAmount( m_selectedOutputType );
  65. // Invalidate previously used channels
  66. for( int i = 0; i < availableChannels; i++ )
  67. {
  68. if( m_occupiedChannels[ i ] == portId )
  69. {
  70. m_occupiedChannels[ i ] = -1;
  71. m_inputPorts[ i ].Visible = true;
  72. }
  73. }
  74. // Lock available channels to port
  75. int len = Mathf.Min( portId + channelsRequired, availableChannels );
  76. int channelsUsed = 0;
  77. for( int i = portId; i < len; i++ )
  78. {
  79. if( m_occupiedChannels[ i ] == -1 )
  80. {
  81. m_occupiedChannels[ i ] = portId;
  82. channelsUsed += 1;
  83. }
  84. else
  85. {
  86. break;
  87. }
  88. }
  89. if( !onLoading )
  90. inputPort.ChangeType( UIUtils.GetWireTypeForChannelAmount( channelsUsed ), false );
  91. if( channelsUsed > 1 && portId < availableChannels - 1 )
  92. {
  93. channelsUsed -= 1;
  94. int i = portId + 1;
  95. for( ; channelsUsed > 0; i++, --channelsUsed )
  96. {
  97. m_inputPorts[ i ].Visible = false;
  98. }
  99. }
  100. m_sizeIsDirty = true;
  101. }
  102. void NewUpdateBehaviorDisconn( int portId )
  103. {
  104. int availableChannels = UIUtils.GetChannelsAmount( m_selectedOutputType );
  105. // Invalidate previously used channels
  106. for( int i = 0; i < availableChannels; i++ )
  107. {
  108. if( m_occupiedChannels[ i ] == portId )
  109. {
  110. m_occupiedChannels[ i ] = -1;
  111. m_inputPorts[ i ].Visible = true;
  112. m_inputPorts[ i ].ChangeType( WirePortDataType.FLOAT, false );
  113. }
  114. }
  115. m_sizeIsDirty = true;
  116. }
  117. void RenamePorts()
  118. {
  119. int channel = 0;
  120. for( int i = 0; i < 4; i++ )
  121. {
  122. if( m_inputPorts[ i ].Visible )
  123. {
  124. string name = string.Empty;
  125. int usedChannels = UIUtils.GetChannelsAmount( m_inputPorts[ i ].DataType );
  126. bool isColor = ( m_selectedOutputType == WirePortDataType.COLOR );
  127. for( int j = 0; j < usedChannels; j++ )
  128. {
  129. if( channel < Constants.ChannelNamesVector.Length )
  130. name += isColor ? Constants.ChannelNamesColor[ channel++ ] : Constants.ChannelNamesVector[ channel++ ];
  131. }
  132. m_inputPorts[ i ].Name = name;
  133. }
  134. }
  135. CalculatePreviewData();
  136. }
  137. void UpdatePortTypes()
  138. {
  139. ChangeOutputType( m_selectedOutputType, false );
  140. int availableChannels = UIUtils.GetChannelsAmount( m_selectedOutputType );
  141. int usedChannels = 0;
  142. while( usedChannels < availableChannels )
  143. {
  144. int channelsRequired = m_inputPorts[ usedChannels ].IsConnected ? UIUtils.GetChannelsAmount( m_inputPorts[ usedChannels ].DataType ) : 0;
  145. if( channelsRequired > 0 )
  146. {
  147. if( ( usedChannels + channelsRequired ) < availableChannels )
  148. {
  149. usedChannels += channelsRequired;
  150. }
  151. else
  152. {
  153. m_inputPorts[ usedChannels ].Visible = true;
  154. WirePortDataType newType = UIUtils.GetWireTypeForChannelAmount( availableChannels - usedChannels );
  155. m_inputPorts[ usedChannels ].ChangeType( newType, false );
  156. usedChannels = availableChannels;
  157. break;
  158. }
  159. }
  160. else
  161. {
  162. m_occupiedChannels[ usedChannels ] = -1;
  163. m_inputPorts[ usedChannels ].Visible = true;
  164. m_inputPorts[ usedChannels ].ChangeType( WirePortDataType.FLOAT, false );
  165. usedChannels += 1;
  166. }
  167. }
  168. for( int i = usedChannels; i < availableChannels; i++ )
  169. {
  170. m_occupiedChannels[ i ] = -1;
  171. m_inputPorts[ i ].Visible = true;
  172. m_inputPorts[ i ].ChangeType( WirePortDataType.FLOAT, false );
  173. }
  174. for( int i = availableChannels; i < 4; i++ )
  175. {
  176. m_occupiedChannels[ i ] = -1;
  177. m_inputPorts[ i ].Visible = false;
  178. m_inputPorts[ i ].ChangeType( WirePortDataType.FLOAT, false );
  179. }
  180. m_sizeIsDirty = true;
  181. }
  182. public override void OnInputPortConnected( int portId, int otherNodeId, int otherPortId, bool activateNode = true )
  183. {
  184. base.OnInputPortConnected( portId, otherNodeId, otherPortId, activateNode );
  185. if( ( m_containerGraph.IsLoading || m_isNodeBeingCopied ) && UIUtils.CurrentShaderVersion() < 13206 )
  186. return;
  187. NewUpdateBehaviorConn( portId, ( UIUtils.IsLoading|| m_isNodeBeingCopied ) );
  188. RenamePorts();
  189. }
  190. public override void OnInputPortDisconnected( int portId )
  191. {
  192. base.OnInputPortDisconnected( portId );
  193. if( ( UIUtils.IsLoading || m_isNodeBeingCopied ) && UIUtils.CurrentShaderVersion() < 13206 )
  194. return;
  195. NewUpdateBehaviorDisconn( portId );
  196. RenamePorts();
  197. }
  198. public override void OnConnectedOutputNodeChanges( int portId, int otherNodeId, int otherPortId, string name, WirePortDataType type )
  199. {
  200. base.OnConnectedOutputNodeChanges( portId, otherNodeId, otherPortId, name, type );
  201. if( ( UIUtils.IsLoading || m_isNodeBeingCopied ) && UIUtils.CurrentShaderVersion() < 13206 )
  202. return;
  203. NewUpdateBehaviorConn( portId, ( UIUtils.IsLoading || m_isNodeBeingCopied ) );
  204. RenamePorts();
  205. }
  206. void SetupPorts()
  207. {
  208. switch( m_selectedOutputTypeInt )
  209. {
  210. case 0: m_selectedOutputType = WirePortDataType.FLOAT2; break;
  211. case 1: m_selectedOutputType = WirePortDataType.FLOAT3; break;
  212. case 2: m_selectedOutputType = WirePortDataType.FLOAT4; break;
  213. case 3: m_selectedOutputType = WirePortDataType.COLOR; break;
  214. }
  215. UpdatePortTypes();
  216. RenamePorts();
  217. }
  218. public override void Draw( DrawInfo drawInfo )
  219. {
  220. base.Draw( drawInfo );
  221. if( m_dropdownEditing )
  222. {
  223. EditorGUI.BeginChangeCheck();
  224. m_selectedOutputTypeInt = EditorGUIPopup( m_dropdownRect, m_selectedOutputTypeInt, m_outputValueTypes, UIUtils.PropertyPopUp );
  225. if( EditorGUI.EndChangeCheck() )
  226. {
  227. SetupPorts();
  228. m_dropdownEditing = false;
  229. }
  230. }
  231. }
  232. public override void DrawProperties()
  233. {
  234. base.DrawProperties();
  235. EditorGUILayout.BeginVertical();
  236. EditorGUI.BeginChangeCheck();
  237. m_selectedOutputTypeInt = EditorGUILayoutPopup( OutputTypeStr, m_selectedOutputTypeInt, m_outputValueTypes );
  238. if( EditorGUI.EndChangeCheck() )
  239. {
  240. SetupPorts();
  241. }
  242. EditorGUILayout.EndVertical();
  243. }
  244. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalVar )
  245. {
  246. if( m_outputPorts[ 0 ].IsLocalValue( dataCollector.PortCategory ) )
  247. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  248. string result = string.Empty;
  249. for( int i = 0; i < 4; i++ )
  250. {
  251. if( m_inputPorts[ i ].Visible )
  252. {
  253. if( i > 0 )
  254. {
  255. result += " , ";
  256. }
  257. result += m_inputPorts[ i ].GeneratePortInstructions( ref dataCollector );
  258. }
  259. }
  260. result = string.Format( OutputFormatStr,
  261. UIUtils.FinalPrecisionWirePortToCgType( m_currentPrecisionType, m_selectedOutputType ),
  262. result );
  263. RegisterLocalVariable( 0, result, ref dataCollector, "appendResult" + OutputId );
  264. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  265. }
  266. public override void ReadFromString( ref string[] nodeParams )
  267. {
  268. base.ReadFromString( ref nodeParams );
  269. m_selectedOutputType = (WirePortDataType)Enum.Parse( typeof( WirePortDataType ), GetCurrentParam( ref nodeParams ) );
  270. switch( m_selectedOutputType )
  271. {
  272. case WirePortDataType.FLOAT2: m_selectedOutputTypeInt = 0; break;
  273. case WirePortDataType.FLOAT3: m_selectedOutputTypeInt = 1; break;
  274. case WirePortDataType.FLOAT4: m_selectedOutputTypeInt = 2; break;
  275. case WirePortDataType.COLOR: m_selectedOutputTypeInt = 3; break;
  276. }
  277. }
  278. public override void ReadFromDeprecated( ref string[] nodeParams, Type oldType = null )
  279. {
  280. m_selectedOutputType = (WirePortDataType)Enum.Parse( typeof( WirePortDataType ), GetCurrentParam( ref nodeParams ) );
  281. switch( m_selectedOutputType )
  282. {
  283. case WirePortDataType.FLOAT2: m_selectedOutputTypeInt = 0; break;
  284. case WirePortDataType.FLOAT3: m_selectedOutputTypeInt = 1; break;
  285. case WirePortDataType.FLOAT4: m_selectedOutputTypeInt = 2; break;
  286. case WirePortDataType.COLOR: m_selectedOutputTypeInt = 3; break;
  287. }
  288. for( int i = 0; i < 4; i++ )
  289. {
  290. m_inputPorts[i].FloatInternalData = Convert.ToSingle( GetCurrentParam( ref nodeParams ) );
  291. }
  292. }
  293. public override void RefreshExternalReferences()
  294. {
  295. base.RefreshExternalReferences();
  296. if( UIUtils.CurrentShaderVersion() < 13206 )
  297. {
  298. //TODO: MAKE THIS LESS BRUTE FORCE
  299. List<AppendData> reroutes = new List<AppendData>();
  300. int availableChannel = 0;
  301. for( int i = 0; i < 4 && availableChannel < 4; i++ )
  302. {
  303. int channelsAmount = UIUtils.GetChannelsAmount( m_inputPorts[ i ].DataType );
  304. if( m_inputPorts[ i ].IsConnected /*&& availableChannel != i*/ )
  305. {
  306. reroutes.Add( new AppendData( m_inputPorts[ i ].DataType, i, availableChannel ) );
  307. }
  308. availableChannel += channelsAmount;
  309. }
  310. if( reroutes.Count > 0 )
  311. {
  312. for( int i = reroutes.Count - 1; i > -1; i-- )
  313. {
  314. int nodeId = m_inputPorts[ reroutes[ i ].OldPortId ].ExternalReferences[ 0 ].NodeId;
  315. int portId = m_inputPorts[ reroutes[ i ].OldPortId ].ExternalReferences[ 0 ].PortId;
  316. m_containerGraph.DeleteConnection( true, UniqueId, reroutes[ i ].OldPortId, false, false, false );
  317. m_containerGraph.CreateConnection( UniqueId, reroutes[ i ].NewPortId, nodeId, portId, false );
  318. NewUpdateBehaviorConn( reroutes[ i ].NewPortId, true );
  319. }
  320. }
  321. availableChannel = UIUtils.GetChannelsAmount( m_selectedOutputType );
  322. int currChannelIdx = 0;
  323. for( ; currChannelIdx < availableChannel; currChannelIdx++ )
  324. {
  325. if( m_inputPorts[ currChannelIdx ].Visible )
  326. {
  327. int channelsAmount = UIUtils.GetChannelsAmount( m_inputPorts[ currChannelIdx ].DataType );
  328. for( int j = currChannelIdx + 1; j < currChannelIdx + channelsAmount; j++ )
  329. {
  330. m_inputPorts[ j ].Visible = false;
  331. }
  332. }
  333. }
  334. for( ; currChannelIdx < 4; currChannelIdx++ )
  335. {
  336. m_inputPorts[ currChannelIdx ].Visible = false;
  337. }
  338. }
  339. SetupPorts();
  340. m_sizeIsDirty = true;
  341. }
  342. void CalculatePreviewData()
  343. {
  344. switch( m_outputPorts[ 0 ].DataType )
  345. {
  346. default: m_maskValue = Vector4.zero; break;
  347. case WirePortDataType.INT:
  348. case WirePortDataType.FLOAT: m_maskValue = new Vector4( 1, 0, 0, 0 ); break;
  349. case WirePortDataType.FLOAT2: m_maskValue = new Vector4( 1, 1, 0, 0 ); break;
  350. case WirePortDataType.FLOAT3: m_maskValue = new Vector4( 1, 1, 1, 0 ); break;
  351. case WirePortDataType.FLOAT4:
  352. case WirePortDataType.COLOR: m_maskValue = Vector4.one; break;
  353. }
  354. m_previewMaterialPassId = -1;
  355. switch( m_inputPorts[ 0 ].DataType )
  356. {
  357. case WirePortDataType.INT:
  358. case WirePortDataType.FLOAT:
  359. {
  360. switch( m_inputPorts[ 1 ].DataType )
  361. {
  362. case WirePortDataType.FLOAT:
  363. case WirePortDataType.INT:
  364. {
  365. if( m_inputPorts[ 2 ].DataType == WirePortDataType.FLOAT ||
  366. m_inputPorts[ 2 ].DataType == WirePortDataType.INT )
  367. {
  368. m_previewMaterialPassId = 0;
  369. }
  370. else if( m_inputPorts[ 2 ].DataType == WirePortDataType.FLOAT2 )
  371. {
  372. m_previewMaterialPassId = 1;
  373. }
  374. }
  375. break;
  376. case WirePortDataType.FLOAT2: m_previewMaterialPassId = 2; break;
  377. case WirePortDataType.FLOAT3: m_previewMaterialPassId = 3; break;
  378. }
  379. }; break;
  380. case WirePortDataType.FLOAT2:
  381. {
  382. if( m_inputPorts[ 2 ].DataType == WirePortDataType.FLOAT ||
  383. m_inputPorts[ 2 ].DataType == WirePortDataType.INT )
  384. {
  385. m_previewMaterialPassId = 4;
  386. }
  387. else if( m_inputPorts[ 2 ].DataType == WirePortDataType.FLOAT2 )
  388. {
  389. m_previewMaterialPassId = 5;
  390. }
  391. }; break;
  392. case WirePortDataType.FLOAT3: m_previewMaterialPassId = 6; break;
  393. case WirePortDataType.FLOAT4:
  394. case WirePortDataType.COLOR: m_previewMaterialPassId = 7; break;
  395. }
  396. if( m_previewMaterialPassId == -1 )
  397. {
  398. m_previewMaterialPassId = 0;
  399. if( DebugConsoleWindow.DeveloperMode )
  400. {
  401. UIUtils.ShowMessage( "Could not find pass ID for append" , MessageSeverity.Error );
  402. }
  403. }
  404. }
  405. public override void SetPreviewInputs()
  406. {
  407. base.SetPreviewInputs();
  408. PreviewMaterial.SetVector( m_maskId, m_maskValue );
  409. }
  410. public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
  411. {
  412. base.WriteToString( ref nodeInfo, ref connectionsInfo );
  413. IOUtils.AddFieldValueToString( ref nodeInfo, m_selectedOutputType );
  414. }
  415. }
  416. }