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.

390 lines
11 KiB

  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. //
  4. // Custom Node Swizzle
  5. // Donated by Tobias Pott - @ Tobias Pott
  6. // www.tobiaspott.de
  7. using System;
  8. using UnityEditor;
  9. using UnityEngine;
  10. namespace AmplifyShaderEditor
  11. {
  12. [Serializable]
  13. [NodeAttributes( "Swizzle", "Vector Operators", "Swizzle components of vector types", null, KeyCode.Z, true, false, null, null, "Tobias Pott - @TobiasPott" )]
  14. public sealed class SwizzleNode : SingleInputOp
  15. {
  16. private const string OutputTypeStr = "Output type";
  17. [SerializeField]
  18. private WirePortDataType m_selectedOutputType = WirePortDataType.FLOAT4;
  19. [SerializeField]
  20. private int m_selectedOutputTypeInt = 3;
  21. [SerializeField]
  22. private int[] m_selectedOutputSwizzleTypes = new int[] { 0, 1, 2, 3 };
  23. [SerializeField]
  24. private int m_maskId;
  25. [SerializeField]
  26. private Vector4 m_maskValue = Vector4.one;
  27. private readonly string[] SwizzleVectorChannels = { "x", "y", "z", "w" };
  28. private readonly string[] SwizzleColorChannels = { "r", "g", "b", "a" };
  29. private readonly string[] SwizzleChannelLabels = { "Channel 0", "Channel 1", "Channel 2", "Channel 3" };
  30. private readonly string[] m_outputValueTypes ={ "Float",
  31. "Vector 2",
  32. "Vector 3",
  33. "Vector 4"};
  34. protected override void CommonInit( int uniqueId )
  35. {
  36. base.CommonInit( uniqueId );
  37. m_inputPorts[ 0 ].CreatePortRestrictions( WirePortDataType.FLOAT,
  38. WirePortDataType.FLOAT2,
  39. WirePortDataType.FLOAT3,
  40. WirePortDataType.FLOAT4,
  41. WirePortDataType.COLOR,
  42. WirePortDataType.INT );
  43. m_inputPorts[ 0 ].DataType = WirePortDataType.FLOAT4;
  44. m_outputPorts[ 0 ].DataType = m_selectedOutputType;
  45. m_textLabelWidth = 90;
  46. m_autoWrapProperties = true;
  47. m_autoUpdateOutputPort = false;
  48. m_hasLeftDropdown = true;
  49. m_previewShaderGUID = "d20531704ce28b14bafb296f291f6608";
  50. SetAdditonalTitleText( "Value( XYZW )" );
  51. CalculatePreviewData();
  52. }
  53. public override void OnEnable()
  54. {
  55. base.OnEnable();
  56. m_maskId = Shader.PropertyToID( "_Mask" );
  57. }
  58. public override void SetPreviewInputs()
  59. {
  60. base.SetPreviewInputs();
  61. PreviewMaterial.SetVector( m_maskId, m_maskValue );
  62. }
  63. void CalculatePreviewData()
  64. {
  65. switch( m_outputPorts[ 0 ].DataType )
  66. {
  67. default: m_maskValue = Vector4.zero; break;
  68. case WirePortDataType.INT:
  69. case WirePortDataType.FLOAT: m_maskValue = new Vector4( 1, 0, 0, 0 ); break;
  70. case WirePortDataType.FLOAT2: m_maskValue = new Vector4( 1, 1, 0, 0 ); break;
  71. case WirePortDataType.FLOAT3: m_maskValue = new Vector4( 1, 1, 1, 0 ); break;
  72. case WirePortDataType.FLOAT4:
  73. case WirePortDataType.COLOR: m_maskValue = Vector4.one; break;
  74. }
  75. m_previewMaterialPassId = -1;
  76. float passValue = 0;
  77. for( int i = 3; i > -1; i-- )
  78. {
  79. if( m_selectedOutputSwizzleTypes[ i ] > 0 )
  80. {
  81. passValue += Mathf.Pow( 4, 3 - i ) * m_selectedOutputSwizzleTypes[ i ];
  82. }
  83. }
  84. m_previewMaterialPassId = (int)passValue;
  85. if( m_previewMaterialPassId == -1 )
  86. {
  87. m_previewMaterialPassId = 0;
  88. if( DebugConsoleWindow.DeveloperMode )
  89. {
  90. UIUtils.ShowMessage( "Could not find pass ID for swizzle", MessageSeverity.Error );
  91. }
  92. }
  93. }
  94. public override void AfterCommonInit()
  95. {
  96. base.AfterCommonInit();
  97. if ( PaddingTitleLeft == 0 )
  98. {
  99. PaddingTitleLeft = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
  100. if ( PaddingTitleRight == 0 )
  101. PaddingTitleRight = Constants.PropertyPickerWidth + Constants.IconsLeftRightMargin;
  102. }
  103. }
  104. public override void OnConnectedOutputNodeChanges( int outputPortId, int otherNodeId, int otherPortId, string name, WirePortDataType type )
  105. {
  106. base.OnConnectedOutputNodeChanges( outputPortId, otherNodeId, otherPortId, name, type );
  107. UpdatePorts();
  108. }
  109. public override void OnInputPortConnected( int portId, int otherNodeId, int otherPortId, bool activateNode = true )
  110. {
  111. base.OnInputPortConnected( portId, otherNodeId, otherPortId, activateNode );
  112. UpdatePorts();
  113. }
  114. public override void OnInputPortDisconnected( int portId )
  115. {
  116. base.OnInputPortDisconnected( portId );
  117. UpdatePorts();
  118. }
  119. public override void Draw( DrawInfo drawInfo )
  120. {
  121. base.Draw( drawInfo );
  122. if ( m_dropdownEditing )
  123. {
  124. EditorGUI.BeginChangeCheck();
  125. m_selectedOutputTypeInt = EditorGUIPopup( m_dropdownRect, m_selectedOutputTypeInt, m_outputValueTypes, UIUtils.PropertyPopUp );
  126. if ( EditorGUI.EndChangeCheck() )
  127. {
  128. switch ( m_selectedOutputTypeInt )
  129. {
  130. case 0: m_selectedOutputType = WirePortDataType.FLOAT; break;
  131. case 1: m_selectedOutputType = WirePortDataType.FLOAT2; break;
  132. case 2: m_selectedOutputType = WirePortDataType.FLOAT3; break;
  133. case 3: m_selectedOutputType = WirePortDataType.FLOAT4; break;
  134. }
  135. UpdatePorts();
  136. m_dropdownEditing = false;
  137. }
  138. }
  139. }
  140. public override void DrawProperties()
  141. {
  142. EditorGUILayout.BeginVertical();
  143. EditorGUI.BeginChangeCheck();
  144. m_selectedOutputTypeInt = EditorGUILayoutPopup( OutputTypeStr, m_selectedOutputTypeInt, m_outputValueTypes );
  145. if ( EditorGUI.EndChangeCheck() )
  146. {
  147. switch ( m_selectedOutputTypeInt )
  148. {
  149. case 0: m_selectedOutputType = WirePortDataType.FLOAT; break;
  150. case 1: m_selectedOutputType = WirePortDataType.FLOAT2; break;
  151. case 2: m_selectedOutputType = WirePortDataType.FLOAT3; break;
  152. case 3: m_selectedOutputType = WirePortDataType.FLOAT4; break;
  153. }
  154. UpdatePorts();
  155. }
  156. EditorGUILayout.EndVertical();
  157. // Draw base properties
  158. base.DrawProperties();
  159. EditorGUILayout.BeginVertical();
  160. int count = 0;
  161. switch ( m_selectedOutputType )
  162. {
  163. case WirePortDataType.FLOAT4:
  164. case WirePortDataType.COLOR:
  165. count = 4;
  166. break;
  167. case WirePortDataType.FLOAT3:
  168. count = 3;
  169. break;
  170. case WirePortDataType.FLOAT2:
  171. count = 2;
  172. break;
  173. case WirePortDataType.INT:
  174. case WirePortDataType.FLOAT:
  175. count = 1;
  176. break;
  177. case WirePortDataType.OBJECT:
  178. case WirePortDataType.FLOAT3x3:
  179. case WirePortDataType.FLOAT4x4:
  180. break;
  181. }
  182. EditorGUI.BeginChangeCheck();
  183. if ( m_inputPorts[ 0 ].DataType == WirePortDataType.COLOR )
  184. {
  185. for ( int i = 0; i < count; i++ )
  186. {
  187. m_selectedOutputSwizzleTypes[ i ] = EditorGUILayoutPopup( SwizzleChannelLabels[ i ], m_selectedOutputSwizzleTypes[ i ], SwizzleColorChannels );
  188. }
  189. }
  190. else
  191. {
  192. for ( int i = 0; i < count; i++ )
  193. {
  194. m_selectedOutputSwizzleTypes[ i ] = EditorGUILayoutPopup( SwizzleChannelLabels[ i ], m_selectedOutputSwizzleTypes[ i ], SwizzleVectorChannels );
  195. }
  196. }
  197. if ( EditorGUI.EndChangeCheck() )
  198. {
  199. UpdatePorts();
  200. }
  201. EditorGUILayout.EndVertical();
  202. }
  203. void UpdatePorts()
  204. {
  205. ChangeOutputType( m_selectedOutputType, false );
  206. int count = 0;
  207. switch ( m_selectedOutputType )
  208. {
  209. case WirePortDataType.FLOAT4:
  210. case WirePortDataType.COLOR:
  211. count = 4;
  212. break;
  213. case WirePortDataType.FLOAT3:
  214. count = 3;
  215. break;
  216. case WirePortDataType.FLOAT2:
  217. count = 2;
  218. break;
  219. case WirePortDataType.INT:
  220. case WirePortDataType.FLOAT:
  221. count = 1;
  222. break;
  223. case WirePortDataType.OBJECT:
  224. case WirePortDataType.FLOAT3x3:
  225. case WirePortDataType.FLOAT4x4:
  226. break;
  227. }
  228. int inputMaxChannelId = 0;
  229. switch ( m_inputPorts[ 0 ].DataType )
  230. {
  231. case WirePortDataType.FLOAT4:
  232. case WirePortDataType.COLOR:
  233. inputMaxChannelId = 3;
  234. break;
  235. case WirePortDataType.FLOAT3:
  236. inputMaxChannelId = 2;
  237. break;
  238. case WirePortDataType.FLOAT2:
  239. inputMaxChannelId = 1;
  240. break;
  241. case WirePortDataType.INT:
  242. case WirePortDataType.FLOAT:
  243. inputMaxChannelId = 0;
  244. break;
  245. case WirePortDataType.OBJECT:
  246. case WirePortDataType.FLOAT3x3:
  247. case WirePortDataType.FLOAT4x4:
  248. break;
  249. }
  250. for ( int i = 0; i < count; i++ )
  251. {
  252. m_selectedOutputSwizzleTypes[ i ] = Mathf.Clamp( m_selectedOutputSwizzleTypes[ i ], 0, inputMaxChannelId );
  253. }
  254. // Update Title
  255. string additionalText = string.Empty;
  256. for ( int i = 0; i < count; i++ )
  257. {
  258. additionalText += GetSwizzleComponentForChannel( m_selectedOutputSwizzleTypes[ i ] ).ToUpper();
  259. }
  260. if ( additionalText.Length > 0 )
  261. SetAdditonalTitleText( "Value( " + additionalText + " )" );
  262. else
  263. SetAdditonalTitleText( string.Empty );
  264. CalculatePreviewData();
  265. m_sizeIsDirty = true;
  266. }
  267. public string GetSwizzleComponentForChannel( int channel )
  268. {
  269. if ( m_inputPorts[ 0 ].DataType == WirePortDataType.COLOR )
  270. {
  271. return SwizzleColorChannels[ channel ];
  272. }
  273. else
  274. {
  275. return SwizzleVectorChannels[ channel ];
  276. }
  277. }
  278. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalVar )
  279. {
  280. if ( m_outputPorts[ 0 ].IsLocalValue( dataCollector.PortCategory ) )
  281. return m_outputPorts[ 0 ].LocalValue( dataCollector.PortCategory );
  282. string value = string.Format( "({0}).", m_inputPorts[ 0 ].GeneratePortInstructions( ref dataCollector ) );
  283. int count = 0;
  284. switch ( m_selectedOutputType )
  285. {
  286. case WirePortDataType.FLOAT4:
  287. case WirePortDataType.COLOR:
  288. count = 4;
  289. break;
  290. case WirePortDataType.FLOAT3:
  291. count = 3;
  292. break;
  293. case WirePortDataType.FLOAT2:
  294. count = 2;
  295. break;
  296. case WirePortDataType.INT:
  297. case WirePortDataType.FLOAT:
  298. count = 1;
  299. break;
  300. case WirePortDataType.OBJECT:
  301. case WirePortDataType.FLOAT3x3:
  302. case WirePortDataType.FLOAT4x4:
  303. break;
  304. }
  305. for ( int i = 0; i < count; i++ )
  306. {
  307. value += GetSwizzleComponentForChannel( m_selectedOutputSwizzleTypes[ i ] );
  308. }
  309. return CreateOutputLocalVariable( 0, value, ref dataCollector );
  310. }
  311. public override void ReadFromString( ref string[] nodeParams )
  312. {
  313. base.ReadFromString( ref nodeParams );
  314. m_selectedOutputType = ( WirePortDataType ) Enum.Parse( typeof( WirePortDataType ), GetCurrentParam( ref nodeParams ) );
  315. switch ( m_selectedOutputType )
  316. {
  317. case WirePortDataType.FLOAT: m_selectedOutputTypeInt = 0; break;
  318. case WirePortDataType.FLOAT2: m_selectedOutputTypeInt = 1; break;
  319. case WirePortDataType.FLOAT3: m_selectedOutputTypeInt = 2; break;
  320. case WirePortDataType.COLOR:
  321. case WirePortDataType.FLOAT4: m_selectedOutputTypeInt = 3; break;
  322. }
  323. for ( int i = 0; i < m_selectedOutputSwizzleTypes.Length; i++ )
  324. {
  325. m_selectedOutputSwizzleTypes[ i ] = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  326. }
  327. UpdatePorts();
  328. }
  329. public override void WriteToString( ref string nodeInfo, ref string connectionsInfo )
  330. {
  331. base.WriteToString( ref nodeInfo, ref connectionsInfo );
  332. IOUtils.AddFieldValueToString( ref nodeInfo, m_selectedOutputType );
  333. for ( int i = 0; i < m_selectedOutputSwizzleTypes.Length; i++ )
  334. {
  335. IOUtils.AddFieldValueToString( ref nodeInfo, m_selectedOutputSwizzleTypes[ i ] );
  336. }
  337. }
  338. }
  339. }