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.

427 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. namespace AmplifyShaderEditor
  7. {
  8. [Serializable]
  9. [NodeAttributes( "Function Input", "Functions", "Function Input adds an input port to the shader function", NodeAvailabilityFlags = (int)NodeAvailability.ShaderFunction )]
  10. public sealed class FunctionInput : ParentNode
  11. {
  12. private const string InputTypeStr = "Input Type";
  13. private readonly string[] m_inputValueTypes ={ "Int",
  14. "Float",
  15. "Vector2",
  16. "Vector3",
  17. "Vector4",
  18. "Color",
  19. "Matrix 3x3",
  20. "Matrix 4x4",
  21. "Sampler 1D",
  22. "Sampler 2D",
  23. "Sampler 3D",
  24. "Sampler Cube"};
  25. [SerializeField]
  26. private int m_selectedInputTypeInt = 1;
  27. private WirePortDataType m_selectedInputType = WirePortDataType.FLOAT;
  28. [SerializeField]
  29. private string m_inputName = "Input";
  30. [SerializeField]
  31. private bool m_autoCast = false;
  32. [SerializeField]
  33. private int m_orderIndex = -1;
  34. private int m_typeId = -1;
  35. public bool m_ignoreConnection = false;
  36. public delegate string PortGeneration( ref MasterNodeDataCollector dataCollector, int index, ParentGraph graph );
  37. public PortGeneration OnPortGeneration = null;
  38. //Title editing
  39. [SerializeField]
  40. private string m_uniqueName;
  41. private bool m_isEditing;
  42. private bool m_stopEditing;
  43. private bool m_startEditing;
  44. private double m_clickTime;
  45. private double m_doubleClickTime = 0.3;
  46. private Rect m_titleClickArea;
  47. private bool m_showTitleWhenNotEditing = true;
  48. protected override void CommonInit( int uniqueId )
  49. {
  50. base.CommonInit( uniqueId );
  51. AddInputPort( WirePortDataType.FLOAT, false, Constants.EmptyPortValue );
  52. m_inputPorts[ 0 ].AutoDrawInternalData = true;
  53. //m_inputPorts[ 0 ].Visible = false;
  54. AddOutputPort( WirePortDataType.FLOAT, Constants.EmptyPortValue );
  55. m_autoWrapProperties = true;
  56. m_textLabelWidth = 100;
  57. SetTitleText( m_inputName );
  58. UpdatePorts();
  59. SetAdditonalTitleText( "( " + m_inputValueTypes[ m_selectedInputTypeInt ] + " )" );
  60. m_previewShaderGUID = "04bc8e7b317dccb4d8da601680dd8140";
  61. }
  62. public override void SetPreviewInputs()
  63. {
  64. if( !m_ignoreConnection )
  65. base.SetPreviewInputs();
  66. if( m_typeId == -1 )
  67. m_typeId = Shader.PropertyToID( "_Type" );
  68. if( m_inputPorts[ 0 ].DataType == WirePortDataType.FLOAT || m_inputPorts[ 0 ].DataType == WirePortDataType.INT )
  69. PreviewMaterial.SetInt( m_typeId, 1 );
  70. else if( m_inputPorts[ 0 ].DataType == WirePortDataType.FLOAT2 )
  71. PreviewMaterial.SetInt( m_typeId, 2 );
  72. else if( m_inputPorts[ 0 ].DataType == WirePortDataType.FLOAT3 )
  73. PreviewMaterial.SetInt( m_typeId, 3 );
  74. else
  75. PreviewMaterial.SetInt( m_typeId, 0 );
  76. }
  77. protected override void OnUniqueIDAssigned()
  78. {
  79. base.OnUniqueIDAssigned();
  80. UIUtils.RegisterFunctionInputNode( this );
  81. if( m_nodeAttribs != null )
  82. m_uniqueName = m_nodeAttribs.Name + UniqueId;
  83. }
  84. public override void Destroy()
  85. {
  86. base.Destroy();
  87. OnPortGeneration = null;
  88. UIUtils.UnregisterFunctionInputNode( this );
  89. }
  90. public override void OnInputPortConnected( int portId, int otherNodeId, int otherPortId, bool activateNode = true )
  91. {
  92. base.OnInputPortConnected( portId, otherNodeId, otherPortId, activateNode );
  93. if( AutoCast )
  94. {
  95. m_inputPorts[ 0 ].MatchPortToConnection();
  96. SetIntTypeFromPort();
  97. UpdatePorts();
  98. SetAdditonalTitleText( "( " + m_inputValueTypes[ m_selectedInputTypeInt ] + " )" );
  99. }
  100. }
  101. public override void OnConnectedOutputNodeChanges( int portId, int otherNodeId, int otherPortId, string name, WirePortDataType type )
  102. {
  103. base.OnConnectedOutputNodeChanges( portId, otherNodeId, otherPortId, name, type );
  104. if( AutoCast )
  105. {
  106. m_inputPorts[ 0 ].MatchPortToConnection();
  107. SetIntTypeFromPort();
  108. UpdatePorts();
  109. SetAdditonalTitleText( "( " + m_inputValueTypes[ m_selectedInputTypeInt ] + " )" );
  110. }
  111. }
  112. public void SetIntTypeFromPort()
  113. {
  114. switch( m_inputPorts[ 0 ].DataType )
  115. {
  116. case WirePortDataType.INT: m_selectedInputTypeInt = 0; break;
  117. default:
  118. case WirePortDataType.FLOAT: m_selectedInputTypeInt = 1; break;
  119. case WirePortDataType.FLOAT2: m_selectedInputTypeInt = 2; break;
  120. case WirePortDataType.FLOAT3: m_selectedInputTypeInt = 3; break;
  121. case WirePortDataType.FLOAT4: m_selectedInputTypeInt = 4; break;
  122. case WirePortDataType.COLOR: m_selectedInputTypeInt = 5; break;
  123. case WirePortDataType.FLOAT3x3: m_selectedInputTypeInt = 6; break;
  124. case WirePortDataType.FLOAT4x4: m_selectedInputTypeInt = 7; break;
  125. case WirePortDataType.SAMPLER1D: m_selectedInputTypeInt = 8; break;
  126. case WirePortDataType.SAMPLER2D: m_selectedInputTypeInt = 9; break;
  127. case WirePortDataType.SAMPLER3D: m_selectedInputTypeInt = 10; break;
  128. case WirePortDataType.SAMPLERCUBE: m_selectedInputTypeInt = 11; break;
  129. }
  130. }
  131. public override void Draw( DrawInfo drawInfo )
  132. {
  133. base.Draw( drawInfo );
  134. // Custom Editable Title
  135. if( ContainerGraph.LodLevel <= ParentGraph.NodeLOD.LOD3 )
  136. {
  137. if( !m_isEditing && ( ( !ContainerGraph.ParentWindow.MouseInteracted && drawInfo.CurrentEventType == EventType.MouseDown && m_titleClickArea.Contains( drawInfo.MousePosition ) ) ) )
  138. {
  139. if( ( EditorApplication.timeSinceStartup - m_clickTime ) < m_doubleClickTime )
  140. m_startEditing = true;
  141. else
  142. GUI.FocusControl( null );
  143. m_clickTime = EditorApplication.timeSinceStartup;
  144. }
  145. else if( m_isEditing && ( ( drawInfo.CurrentEventType == EventType.MouseDown && !m_titleClickArea.Contains( drawInfo.MousePosition ) ) || !EditorGUIUtility.editingTextField ) )
  146. {
  147. m_stopEditing = true;
  148. }
  149. if( m_isEditing || m_startEditing )
  150. {
  151. EditorGUI.BeginChangeCheck();
  152. GUI.SetNextControlName( m_uniqueName );
  153. m_inputName = EditorGUITextField( m_titleClickArea, string.Empty, m_inputName, UIUtils.GetCustomStyle( CustomStyle.NodeTitle ) );
  154. if( EditorGUI.EndChangeCheck() )
  155. {
  156. SetTitleText( m_inputName );
  157. UIUtils.UpdateFunctionInputData( UniqueId, m_inputName );
  158. }
  159. if( m_startEditing )
  160. EditorGUI.FocusTextInControl( m_uniqueName );
  161. }
  162. if( drawInfo.CurrentEventType == EventType.Repaint )
  163. {
  164. if( m_startEditing )
  165. {
  166. m_startEditing = false;
  167. m_isEditing = true;
  168. }
  169. if( m_stopEditing )
  170. {
  171. m_stopEditing = false;
  172. m_isEditing = false;
  173. GUI.FocusControl( null );
  174. }
  175. }
  176. }
  177. }
  178. public override void OnNodeLayout( DrawInfo drawInfo )
  179. {
  180. // RUN LAYOUT CHANGES AFTER TITLES CHANGE
  181. base.OnNodeLayout( drawInfo );
  182. m_titleClickArea = m_titlePos;
  183. m_titleClickArea.height = Constants.NODE_HEADER_HEIGHT;
  184. }
  185. public override void OnNodeRepaint( DrawInfo drawInfo )
  186. {
  187. base.OnNodeRepaint( drawInfo );
  188. if( !m_isVisible )
  189. return;
  190. // Fixed Title ( only renders when not editing )
  191. if( m_showTitleWhenNotEditing && !m_isEditing && !m_startEditing && ContainerGraph.LodLevel <= ParentGraph.NodeLOD.LOD3 )
  192. {
  193. GUI.Label( m_titleClickArea, m_content, UIUtils.GetCustomStyle( CustomStyle.NodeTitle ) );
  194. }
  195. }
  196. public override void OnNodeDoubleClicked( Vector2 currentMousePos2D )
  197. {
  198. if( currentMousePos2D.y - m_globalPosition.y > ( Constants.NODE_HEADER_HEIGHT + Constants.NODE_HEADER_EXTRA_HEIGHT ) * ContainerGraph.ParentWindow.CameraDrawInfo.InvertedZoom )
  199. {
  200. ContainerGraph.ParentWindow.ParametersWindow.IsMaximized = !ContainerGraph.ParentWindow.ParametersWindow.IsMaximized;
  201. }
  202. }
  203. public override void DrawProperties()
  204. {
  205. base.DrawProperties();
  206. EditorGUILayout.BeginVertical();
  207. EditorGUI.BeginChangeCheck();
  208. m_inputName = EditorGUILayoutTextField( "Name", m_inputName );
  209. if( EditorGUI.EndChangeCheck() )
  210. {
  211. SetTitleText( m_inputName );
  212. UIUtils.UpdateFunctionInputData( UniqueId, m_inputName );
  213. }
  214. EditorGUI.BeginChangeCheck();
  215. m_selectedInputTypeInt = EditorGUILayoutPopup( InputTypeStr, m_selectedInputTypeInt, m_inputValueTypes );
  216. if( EditorGUI.EndChangeCheck() )
  217. {
  218. UpdatePorts();
  219. SetAdditonalTitleText( "( " + m_inputValueTypes[ m_selectedInputTypeInt ] + " )" );
  220. }
  221. m_autoCast = EditorGUILayoutToggle( "Auto Cast", m_autoCast );
  222. EditorGUILayout.Separator();
  223. if( !m_inputPorts[ 0 ].IsConnected && m_inputPorts[ 0 ].ValidInternalData )
  224. {
  225. m_inputPorts[ 0 ].ShowInternalData( this, true, "Default Value" );
  226. }
  227. EditorGUILayout.EndVertical();
  228. }
  229. void UpdatePorts()
  230. {
  231. //switch( m_inputPorts[ 0 ].DataType )
  232. //{
  233. // case WirePortDataType.INT: m_selectedInputTypeInt = 0; break;
  234. // default:
  235. // case WirePortDataType.FLOAT: m_selectedInputTypeInt = 1; break;
  236. // case WirePortDataType.FLOAT2: m_selectedInputTypeInt = 2; break;
  237. // case WirePortDataType.FLOAT3: m_selectedInputTypeInt = 3; break;
  238. // //case 2: m_selectedInputType = WirePortDataType.FLOAT2; break;
  239. // //case 3: m_selectedInputType = WirePortDataType.FLOAT3; break;
  240. // //case 4: m_selectedInputType = WirePortDataType.FLOAT4; break;
  241. // //case 5: m_selectedInputType = WirePortDataType.COLOR; break;
  242. // //case 6: m_selectedInputType = WirePortDataType.FLOAT3x3; break;
  243. // //case 7: m_selectedInputType = WirePortDataType.FLOAT4x4; break;
  244. // //case 8: m_selectedInputType = WirePortDataType.SAMPLER1D; break;
  245. // //case 9: m_selectedInputType = WirePortDataType.SAMPLER2D; break;
  246. // //case 10: m_selectedInputType = WirePortDataType.SAMPLER3D; break;
  247. // //case 11: m_selectedInputType = WirePortDataType.SAMPLERCUBE; break;
  248. //}
  249. switch( m_selectedInputTypeInt )
  250. {
  251. case 0: m_selectedInputType = WirePortDataType.INT; break;
  252. default:
  253. case 1: m_selectedInputType = WirePortDataType.FLOAT; break;
  254. case 2: m_selectedInputType = WirePortDataType.FLOAT2; break;
  255. case 3: m_selectedInputType = WirePortDataType.FLOAT3; break;
  256. case 4: m_selectedInputType = WirePortDataType.FLOAT4; break;
  257. case 5: m_selectedInputType = WirePortDataType.COLOR; break;
  258. case 6: m_selectedInputType = WirePortDataType.FLOAT3x3; break;
  259. case 7: m_selectedInputType = WirePortDataType.FLOAT4x4; break;
  260. case 8: m_selectedInputType = WirePortDataType.SAMPLER1D; break;
  261. case 9: m_selectedInputType = WirePortDataType.SAMPLER2D; break;
  262. case 10: m_selectedInputType = WirePortDataType.SAMPLER3D; break;
  263. case 11: m_selectedInputType = WirePortDataType.SAMPLERCUBE; break;
  264. }
  265. ChangeInputType( m_selectedInputType, false );
  266. //This node doesn't have any restrictions but changing types should be restricted to prevent invalid connections
  267. m_outputPorts[ 0 ].ChangeTypeWithRestrictions( m_selectedInputType, PortCreateRestriction( m_selectedInputType ) );
  268. m_sizeIsDirty = true;
  269. }
  270. public int PortCreateRestriction( WirePortDataType dataType )
  271. {
  272. int restrictions = 0;
  273. WirePortDataType[] types = null;
  274. switch( dataType )
  275. {
  276. case WirePortDataType.OBJECT:
  277. break;
  278. case WirePortDataType.FLOAT:
  279. case WirePortDataType.FLOAT2:
  280. case WirePortDataType.FLOAT3:
  281. case WirePortDataType.FLOAT4:
  282. case WirePortDataType.COLOR:
  283. case WirePortDataType.INT:
  284. {
  285. types = new WirePortDataType[] { WirePortDataType.FLOAT, WirePortDataType.FLOAT2, WirePortDataType.FLOAT3, WirePortDataType.FLOAT4, WirePortDataType.COLOR, WirePortDataType.INT, WirePortDataType.OBJECT };
  286. }
  287. break;
  288. case WirePortDataType.FLOAT3x3:
  289. case WirePortDataType.FLOAT4x4:
  290. {
  291. types = new WirePortDataType[] { WirePortDataType.FLOAT3x3, WirePortDataType.FLOAT4x4, WirePortDataType.OBJECT };
  292. }
  293. break;
  294. case WirePortDataType.SAMPLER1D:
  295. case WirePortDataType.SAMPLER2D:
  296. case WirePortDataType.SAMPLER3D:
  297. case WirePortDataType.SAMPLERCUBE:
  298. {
  299. types = new WirePortDataType[] { WirePortDataType.SAMPLER1D, WirePortDataType.SAMPLER2D, WirePortDataType.SAMPLER3D, WirePortDataType.SAMPLERCUBE, WirePortDataType.OBJECT };
  300. }
  301. break;
  302. default:
  303. break;
  304. }
  305. if( types != null )
  306. {
  307. for( int i = 0; i < types.Length; i++ )
  308. {
  309. restrictions = restrictions | (int)types[ i ];
  310. }
  311. }
  312. return restrictions;
  313. }
  314. public override string GenerateShaderForOutput( int outputId, ref MasterNodeDataCollector dataCollector, bool ignoreLocalvar )
  315. {
  316. if( m_outputPorts[ outputId ].IsLocalValue( dataCollector.PortCategory ) )
  317. return m_outputPorts[ outputId ].LocalValue( dataCollector.PortCategory );
  318. string result = string.Empty;
  319. if( OnPortGeneration != null )
  320. result = OnPortGeneration( ref dataCollector, m_orderIndex, ContainerGraph.ParentWindow.CustomGraph );
  321. else
  322. result = m_inputPorts[ 0 ].GeneratePortInstructions( ref dataCollector );
  323. if( m_outputPorts[ outputId ].ConnectionCount > 1 )
  324. RegisterLocalVariable( outputId, result, ref dataCollector );
  325. else
  326. m_outputPorts[ outputId ].SetLocalValue( result, dataCollector.PortCategory );
  327. return m_outputPorts[ outputId ].LocalValue( dataCollector.PortCategory );
  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_inputName );
  333. IOUtils.AddFieldValueToString( ref nodeInfo, m_selectedInputTypeInt );
  334. IOUtils.AddFieldValueToString( ref nodeInfo, m_orderIndex );
  335. IOUtils.AddFieldValueToString( ref nodeInfo, m_autoCast );
  336. }
  337. public override void ReadFromString( ref string[] nodeParams )
  338. {
  339. base.ReadFromString( ref nodeParams );
  340. m_inputName = GetCurrentParam( ref nodeParams );
  341. m_selectedInputTypeInt = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  342. m_orderIndex = Convert.ToInt32( GetCurrentParam( ref nodeParams ) );
  343. m_autoCast = Convert.ToBoolean( GetCurrentParam( ref nodeParams ) );
  344. SetTitleText( m_inputName );
  345. UpdatePorts();
  346. SetAdditonalTitleText( "( " + m_inputValueTypes[ m_selectedInputTypeInt ] + " )" );
  347. }
  348. public WirePortDataType SelectedInputType
  349. {
  350. get { return m_selectedInputType; }
  351. }
  352. public string InputName
  353. {
  354. get { return m_inputName; }
  355. }
  356. public int OrderIndex
  357. {
  358. get { return m_orderIndex; }
  359. set { m_orderIndex = value; }
  360. }
  361. public bool AutoCast
  362. {
  363. get { return m_autoCast; }
  364. set { m_autoCast = value; }
  365. }
  366. }
  367. }