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.

330 lines
9.0 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.Linq;
  7. using System.Collections.Generic;
  8. using System.Reflection;
  9. namespace AmplifyShaderEditor
  10. {
  11. public class ShortcutKeyData
  12. {
  13. public bool IsPressed;
  14. public System.Type NodeType;
  15. public string Name;
  16. public ShortcutKeyData( System.Type type, string name )
  17. {
  18. NodeType = type;
  19. Name = name;
  20. IsPressed = false;
  21. }
  22. }
  23. public class GraphContextMenu
  24. {
  25. private List<ContextMenuItem> m_items;
  26. private List<ContextMenuItem> m_itemFunctions;
  27. private Dictionary<System.Type, NodeAttributes> m_itemsDict;
  28. private Dictionary<System.Type, NodeAttributes> m_deprecatedItemsDict;
  29. private Dictionary<System.Type, System.Type> m_castTypes;
  30. private Dictionary<KeyCode, ShortcutKeyData> m_shortcutTypes;
  31. private KeyCode m_lastKeyPressed;
  32. private ParentGraph m_currentGraph;
  33. private bool m_correctlyLoaded = false;
  34. public GraphContextMenu( ParentGraph currentGraph )
  35. {
  36. m_currentGraph = currentGraph;
  37. m_correctlyLoaded = RefreshNodes( currentGraph );
  38. }
  39. private Type[] GetTypesInNamespace( Assembly assembly, string nameSpace )
  40. {
  41. return assembly.GetTypes().Where( t => String.Equals( t.Namespace, nameSpace, StringComparison.Ordinal ) ).ToArray();
  42. }
  43. public bool RefreshNodes( ParentGraph currentGraph )
  44. {
  45. if( m_items != null )
  46. {
  47. m_items.Clear();
  48. m_items = null;
  49. }
  50. if( m_itemFunctions != null )
  51. {
  52. m_itemFunctions.Clear();
  53. m_itemFunctions = null;
  54. }
  55. m_items = new List<ContextMenuItem>();
  56. m_itemFunctions = new List<ContextMenuItem>();
  57. if( m_itemsDict != null )
  58. m_itemsDict.Clear();
  59. m_itemsDict = new Dictionary<System.Type, NodeAttributes>();
  60. if( m_deprecatedItemsDict != null )
  61. m_deprecatedItemsDict.Clear();
  62. m_deprecatedItemsDict = new Dictionary<System.Type, NodeAttributes>();
  63. if( m_castTypes != null )
  64. m_castTypes.Clear();
  65. m_castTypes = new Dictionary<System.Type, System.Type>();
  66. if( m_shortcutTypes != null )
  67. m_shortcutTypes.Clear();
  68. m_shortcutTypes = new Dictionary<KeyCode, ShortcutKeyData>();
  69. m_lastKeyPressed = KeyCode.None;
  70. // Fetch all available nodes by their attributes
  71. try
  72. {
  73. //IEnumerable<System.Type> availableTypes = AppDomain.CurrentDomain.GetAssemblies().ToList().SelectMany( type => type.GetTypes() );
  74. Type[] availableTypes = GetTypesInNamespace( Assembly.GetExecutingAssembly(), "AmplifyShaderEditor" );
  75. foreach( System.Type type in availableTypes )
  76. {
  77. foreach( NodeAttributes attribute in Attribute.GetCustomAttributes( type ).OfType<NodeAttributes>() )
  78. {
  79. if( attribute.Available && !attribute.Deprecated )
  80. {
  81. //if ( !UIUtils.CurrentWindow.IsShaderFunctionWindow && attribute.AvailableInFunctionsOnly )
  82. // continue;
  83. if( !UIUtils.HasColorCategory( attribute.Category ) )
  84. {
  85. if( !String.IsNullOrEmpty( attribute.CustomCategoryColor ) )
  86. {
  87. try
  88. {
  89. Color color = new Color();
  90. ColorUtility.TryParseHtmlString( attribute.CustomCategoryColor, out color );
  91. UIUtils.AddColorCategory( attribute.Category, color );
  92. }
  93. catch( Exception e )
  94. {
  95. Debug.LogException( e );
  96. UIUtils.AddColorCategory( attribute.Category, Constants.DefaultCategoryColor );
  97. }
  98. }
  99. //else
  100. //{
  101. // UIUtils.AddColorCategory( attribute.Category, Constants.DefaultCategoryColor );
  102. //}
  103. }
  104. if( attribute.CastType != null && attribute.CastType.Length > 0 && type != null )
  105. {
  106. for( int i = 0; i < attribute.CastType.Length; i++ )
  107. {
  108. m_castTypes.Add( attribute.CastType[ i ], type );
  109. }
  110. }
  111. if( attribute.ShortcutKey != KeyCode.None && type != null )
  112. m_shortcutTypes.Add( attribute.ShortcutKey, new ShortcutKeyData( type, attribute.Name ) );
  113. ContextMenuItem newItem = new ContextMenuItem( attribute, type, attribute.Name, attribute.Category, attribute.Description, null, attribute.ShortcutKey );
  114. if( UIUtils.GetNodeAvailabilityInBitArray( attribute.NodeAvailabilityFlags, NodeAvailability.SurfaceShader ) )
  115. m_items.Add( newItem );
  116. else if( UIUtils.GetNodeAvailabilityInBitArray( attribute.NodeAvailabilityFlags, currentGraph.ParentWindow.CurrentNodeAvailability ) )
  117. m_items.Add( newItem );
  118. else if( UIUtils.GetNodeAvailabilityInBitArray( attribute.NodeAvailabilityFlags, currentGraph.CurrentCanvasMode ) )
  119. m_items.Add( newItem );
  120. m_itemsDict.Add( type, attribute );
  121. m_itemFunctions.Add( newItem );
  122. }
  123. else
  124. {
  125. m_deprecatedItemsDict.Add( type, attribute );
  126. }
  127. }
  128. }
  129. }
  130. catch( ReflectionTypeLoadException exception )
  131. {
  132. Debug.LogException( exception );
  133. return false;
  134. }
  135. string[] guids = AssetDatabase.FindAssets( "t:AmplifyShaderFunction" );
  136. List<AmplifyShaderFunction> allFunctions = new List<AmplifyShaderFunction>();
  137. for( int i = 0; i < guids.Length; i++ )
  138. {
  139. allFunctions.Add( AssetDatabase.LoadAssetAtPath<AmplifyShaderFunction>( AssetDatabase.GUIDToAssetPath( guids[ i ] ) ) );
  140. }
  141. int functionCount = allFunctions.Count;
  142. if( functionCount > 0 )
  143. {
  144. m_castTypes.Add( typeof( AmplifyShaderFunction ), typeof( FunctionNode ) );
  145. }
  146. for( int i = 0; i < functionCount; i++ )
  147. {
  148. NodeAttributes attribute = new NodeAttributes( allFunctions[ i ].FunctionName, allFunctions[ i ].CustomNodeCategory, allFunctions[ i ].Description, KeyCode.None, true, 0, int.MaxValue, typeof( AmplifyShaderFunction ) );
  149. System.Type type = typeof( FunctionNode );
  150. ContextMenuItem newItem = new ContextMenuItem( attribute, type, attribute.Name, attribute.Category, attribute.Description, allFunctions[ i ], attribute.ShortcutKey );
  151. m_items.Add( newItem );
  152. m_itemFunctions.Add( newItem );
  153. }
  154. //Sort out the final list by name
  155. m_items.Sort( ( x, y ) => x.Category.CompareTo( y.Category ) );
  156. m_itemFunctions.Sort( ( x, y ) => x.Category.CompareTo( y.Category ) );
  157. return true;
  158. }
  159. public void Destroy()
  160. {
  161. for( int i = 0; i < m_items.Count; i++ )
  162. {
  163. m_items[ i ].Destroy();
  164. }
  165. for( int i = 0; i < m_itemFunctions.Count; i++ )
  166. {
  167. if( m_itemFunctions[ i ] != null )
  168. m_itemFunctions[ i ].Destroy();
  169. }
  170. m_items.Clear();
  171. m_items = null;
  172. m_itemFunctions.Clear();
  173. m_itemFunctions = null;
  174. m_itemsDict.Clear();
  175. m_itemsDict = null;
  176. m_deprecatedItemsDict.Clear();
  177. m_deprecatedItemsDict = null;
  178. m_castTypes.Clear();
  179. m_castTypes = null;
  180. m_shortcutTypes.Clear();
  181. m_shortcutTypes = null;
  182. }
  183. public NodeAttributes GetNodeAttributesForType( System.Type type )
  184. {
  185. if( type == null )
  186. {
  187. Debug.LogError( "Invalid type detected" );
  188. return null;
  189. }
  190. if( m_itemsDict.ContainsKey( type ) )
  191. return m_itemsDict[ type ];
  192. return null;
  193. }
  194. public NodeAttributes GetDeprecatedNodeAttributesForType( System.Type type )
  195. {
  196. if( m_deprecatedItemsDict.ContainsKey( type ) )
  197. return m_deprecatedItemsDict[ type ];
  198. return null;
  199. }
  200. public void UpdateKeyPress( KeyCode key )
  201. {
  202. if( key == KeyCode.None )
  203. return;
  204. m_lastKeyPressed = key;
  205. if( m_shortcutTypes.ContainsKey( key ) )
  206. {
  207. m_shortcutTypes[ key ].IsPressed = true;
  208. }
  209. }
  210. public void UpdateKeyReleased( KeyCode key )
  211. {
  212. if( key == KeyCode.None )
  213. return;
  214. if( m_shortcutTypes.ContainsKey( key ) )
  215. {
  216. m_shortcutTypes[ key ].IsPressed = false;
  217. }
  218. }
  219. public void ResetShortcutKeyStates()
  220. {
  221. foreach( KeyValuePair<KeyCode, ShortcutKeyData> kvp in m_shortcutTypes )
  222. {
  223. kvp.Value.IsPressed = false;
  224. }
  225. }
  226. public ParentNode CreateNodeFromCastType( System.Type type )
  227. {
  228. if( m_castTypes.ContainsKey( type ) )
  229. {
  230. ParentNode newNode = (ParentNode)ScriptableObject.CreateInstance( m_castTypes[ type ] );
  231. return newNode;
  232. }
  233. return null;
  234. }
  235. public ParentNode CreateNodeFromShortcutKey()
  236. {
  237. if( m_lastKeyPressed == KeyCode.None )
  238. return null;
  239. if( m_shortcutTypes.ContainsKey( m_lastKeyPressed ) && m_shortcutTypes[ m_lastKeyPressed ].IsPressed )
  240. {
  241. ParentNode newNode = (ParentNode)ScriptableObject.CreateInstance( m_shortcutTypes[ m_lastKeyPressed ].NodeType );
  242. return newNode;
  243. }
  244. return null;
  245. }
  246. public bool CheckShortcutKey()
  247. {
  248. if( m_lastKeyPressed == KeyCode.None )
  249. return false;
  250. if( m_shortcutTypes.ContainsKey( m_lastKeyPressed ) && m_shortcutTypes[ m_lastKeyPressed ].IsPressed )
  251. {
  252. return true;
  253. }
  254. return false;
  255. }
  256. public List<ContextMenuItem> MenuItems
  257. {
  258. get
  259. {
  260. if( m_currentGraph.ParentWindow.IsShaderFunctionWindow )
  261. return m_itemFunctions;
  262. else
  263. return m_items;
  264. }
  265. }
  266. public List<ContextMenuItem> ItemFunctions { get { return m_itemFunctions; } }
  267. public KeyCode LastKeyPressed
  268. {
  269. get { return m_lastKeyPressed; }
  270. }
  271. public Dictionary<KeyCode, ShortcutKeyData> NodeShortcuts { get { return m_shortcutTypes; } }
  272. public bool CorrectlyLoaded { get { return m_correctlyLoaded; } }
  273. }
  274. }