CustomShaderInspector.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953
  1. // Amplify Shader Editor - Visual Shader Editing Tool
  2. // Copyright (c) Amplify Creations, Lda <info@amplify.pt>
  3. using System;
  4. using System.Reflection;
  5. using System.Globalization;
  6. using UnityEngine;
  7. using UnityEditor;
  8. using AmplifyShaderEditor;
  9. namespace AmplifyShaderEditor
  10. {
  11. [CustomEditor( typeof( Shader ) )]
  12. internal class CustomShaderInspector : Editor
  13. {
  14. internal class Styles
  15. {
  16. public static Texture2D errorIcon = EditorGUIUtilityEx.LoadIcon( "console.erroricon.sml" );
  17. public static Texture2D warningIcon = EditorGUIUtilityEx.LoadIcon( "console.warnicon.sml" );
  18. #if UNITY_2020_1_OR_NEWER
  19. public static GUIContent togglePreprocess = EditorGUIUtilityEx.TextContent( "Preprocess only|Show preprocessor output instead of compiled shader code" );
  20. #if UNITY_2020_2_OR_NEWER
  21. public static GUIContent toggleStripLineDirective = EditorGUIUtility.TrTextContent( "Strip #line directives", "Strip #line directives from preprocessor output" );
  22. #endif
  23. #endif
  24. public static GUIContent showSurface = EditorGUIUtilityEx.TextContent( "Show generated code|Show generated code of a surface shader" );
  25. public static GUIContent showFF = EditorGUIUtilityEx.TextContent( "Show generated code|Show generated code of a fixed function shader" );
  26. public static GUIContent showCurrent = new GUIContent( "Compile and show code | ▾" );
  27. public static GUIStyle messageStyle = "CN StatusInfo";
  28. public static GUIStyle evenBackground = "CN EntryBackEven";
  29. public static GUIContent no = EditorGUIUtilityEx.TextContent( "no" );
  30. public static GUIContent builtinShader = EditorGUIUtilityEx.TextContent( "Built-in shader" );
  31. public static GUIContent arrayValuePopupButton = EditorGUIUtilityEx.TextContent( "..." );
  32. }
  33. #if UNITY_2020_1_OR_NEWER
  34. private static bool s_PreprocessOnly = false;
  35. #if UNITY_2020_2_OR_NEWER
  36. private static bool s_StripLineDirectives = true;
  37. #endif
  38. #endif
  39. private const float kSpace = 5f;
  40. const float kValueFieldWidth = 200.0f;
  41. const float kArrayValuePopupBtnWidth = 25.0f;
  42. private static readonly string[] kPropertyTypes = new string[]
  43. {
  44. "Color: ",
  45. "Vector: ",
  46. "Float: ",
  47. "Range: ",
  48. "Texture: "
  49. };
  50. private static readonly string[] kTextureTypes = new string[]
  51. {
  52. "No Texture?: ",
  53. "1D?: ",
  54. "2D: ",
  55. "3D: ",
  56. "Cube: ",
  57. "2DArray: ",
  58. "Any texture: "
  59. };
  60. private static readonly int kErrorViewHash = "ShaderErrorView".GetHashCode();
  61. private Vector2 m_ScrollPosition = Vector2.zero;
  62. private PreviewRenderUtility m_previewRenderUtility;
  63. private Material m_material;
  64. private Mesh m_previewMesh;
  65. private Vector2 m_mouseDelta;
  66. private Transform m_cameraTransform;
  67. private bool m_allowOpenInCanvas = true;
  68. private static int m_sliderHashCode = -1;
  69. private const float MaxDeltaY = 90;
  70. private const int DefaultMouseSpeed = 1;
  71. private const int ShiftMouseSpeed = 3;
  72. private const float DeltaMultiplier = 135f;
  73. private void ValidateData()
  74. {
  75. if ( m_previewRenderUtility == null )
  76. {
  77. m_previewRenderUtility = new PreviewRenderUtility();
  78. m_cameraTransform = m_previewRenderUtility.camera.transform;
  79. m_cameraTransform.position = new Vector3( 0, 0, -4 );
  80. m_cameraTransform.rotation = Quaternion.identity;
  81. }
  82. if ( m_material == null )
  83. {
  84. m_material = new Material( target as Shader );
  85. m_material.hideFlags = HideFlags.DontSave;
  86. }
  87. if ( m_previewMesh == null )
  88. {
  89. m_previewMesh = Resources.GetBuiltinResource<Mesh>( "Sphere.fbx" );
  90. }
  91. if ( m_sliderHashCode < 0 )
  92. {
  93. "Slider".GetHashCode();
  94. }
  95. }
  96. public override bool HasPreviewGUI()
  97. {
  98. ValidateData();
  99. return true;
  100. }
  101. public static Vector2 CheckMouseMovement( Vector2 scrollPosition, Rect position )
  102. {
  103. int controlID = GUIUtility.GetControlID( m_sliderHashCode, FocusType.Passive );
  104. Event current = Event.current;
  105. switch ( current.GetTypeForControl( controlID ) )
  106. {
  107. case EventType.MouseDown:
  108. {
  109. if ( position.Contains( current.mousePosition ) && position.width > 50f )
  110. {
  111. GUIUtility.hotControl = controlID;
  112. current.Use();
  113. EditorGUIUtility.SetWantsMouseJumping( 1 );
  114. }
  115. }
  116. break;
  117. case EventType.MouseUp:
  118. {
  119. if ( GUIUtility.hotControl == controlID )
  120. {
  121. GUIUtility.hotControl = 0;
  122. }
  123. EditorGUIUtility.SetWantsMouseJumping( 0 );
  124. }
  125. break;
  126. case EventType.MouseDrag:
  127. {
  128. if ( GUIUtility.hotControl == controlID )
  129. {
  130. scrollPosition -= DeltaMultiplier * current.delta * ( float ) ( ( current.shift ) ? ShiftMouseSpeed : DefaultMouseSpeed ) / Mathf.Min( position.width, position.height );
  131. scrollPosition.y = Mathf.Clamp( scrollPosition.y, -MaxDeltaY, MaxDeltaY );
  132. current.Use();
  133. }
  134. }
  135. break;
  136. }
  137. return scrollPosition;
  138. }
  139. public override void OnPreviewGUI( Rect r, GUIStyle background )
  140. {
  141. m_mouseDelta = CheckMouseMovement( m_mouseDelta, r );
  142. if ( Event.current.type == EventType.Repaint )
  143. {
  144. m_previewRenderUtility.BeginPreview( r, background );
  145. Texture resultRender = m_previewRenderUtility.EndPreview();
  146. m_previewRenderUtility.DrawMesh( m_previewMesh, Matrix4x4.identity, m_material, 0 );
  147. m_cameraTransform.rotation = Quaternion.Euler( new Vector3( -m_mouseDelta.y, -m_mouseDelta.x, 0 ) );
  148. m_cameraTransform.position = m_cameraTransform.forward * -8f;
  149. m_previewRenderUtility.camera.Render();
  150. GUI.DrawTexture( r, resultRender, ScaleMode.StretchToFill, false );
  151. }
  152. }
  153. void OnDestroy()
  154. {
  155. CleanUp();
  156. }
  157. public void OnDisable()
  158. {
  159. CleanUp();
  160. if( m_SrpCompatibilityCheckMaterial != null )
  161. {
  162. GameObject.DestroyImmediate( m_SrpCompatibilityCheckMaterial );
  163. }
  164. }
  165. void CleanUp()
  166. {
  167. if( m_previewRenderUtility != null )
  168. {
  169. m_previewRenderUtility.Cleanup();
  170. m_previewRenderUtility = null;
  171. }
  172. if( m_previewMesh != null )
  173. {
  174. Resources.UnloadAsset( m_previewMesh );
  175. m_previewMesh = null;
  176. }
  177. if( m_previewRenderUtility != null )
  178. {
  179. m_previewRenderUtility.Cleanup();
  180. m_previewRenderUtility = null;
  181. }
  182. m_material = null;
  183. }
  184. private Material m_SrpCompatibilityCheckMaterial = null;
  185. public Material srpCompatibilityCheckMaterial
  186. {
  187. get
  188. {
  189. if( m_SrpCompatibilityCheckMaterial == null )
  190. {
  191. m_SrpCompatibilityCheckMaterial = new Material( target as Shader );
  192. }
  193. return m_SrpCompatibilityCheckMaterial;
  194. }
  195. }
  196. public virtual void OnEnable()
  197. {
  198. Shader s = this.target as Shader;
  199. if( s!= null )
  200. ShaderUtilEx.FetchCachedErrors( s );
  201. m_allowOpenInCanvas = IOUtils.IsASEShader( s );
  202. }
  203. private static string GetPropertyType( Shader s, int index )
  204. {
  205. UnityEditor.ShaderUtil.ShaderPropertyType propertyType = UnityEditor.ShaderUtil.GetPropertyType( s, index );
  206. if ( propertyType == UnityEditor.ShaderUtil.ShaderPropertyType.TexEnv )
  207. {
  208. return CustomShaderInspector.kTextureTypes[ ( int ) UnityEditor.ShaderUtil.GetTexDim( s, index ) ];
  209. }
  210. return CustomShaderInspector.kPropertyTypes[ ( int ) propertyType ];
  211. }
  212. public override void OnInspectorGUI()
  213. {
  214. Shader shader = this.target as Shader;
  215. if ( shader == null )
  216. {
  217. return;
  218. }
  219. GUI.enabled = true;
  220. GUILayout.Space( 3 );
  221. GUILayout.BeginHorizontal();
  222. {
  223. GUI.enabled = m_allowOpenInCanvas;
  224. if ( GUILayout.Button( "Open in Shader Editor" ) )
  225. {
  226. ASEPackageManagerHelper.SetupLateShader( shader );
  227. }
  228. GUI.enabled = true;
  229. if ( GUILayout.Button( "Open in Text Editor" ) )
  230. {
  231. if( UIUtils.IsUnityNativeShader( shader ) )
  232. {
  233. Debug.LogWarningFormat( "Action not allowed. Attempting to load the native {0} shader into Text Editor", shader.name );
  234. }
  235. else
  236. {
  237. AssetDatabase.OpenAsset( shader, 1 );
  238. }
  239. }
  240. }
  241. GUILayout.EndHorizontal();
  242. GUILayout.Space( 5 );
  243. EditorGUI.indentLevel = 0;
  244. this.ShowShaderCodeArea( shader );
  245. if ( shader.isSupported )
  246. {
  247. EditorGUILayout.LabelField( "Cast shadows", ( !ShaderUtilEx.HasShadowCasterPass( shader ) ) ? "no" : "yes", new GUILayoutOption[ 0 ] );
  248. EditorGUILayout.LabelField( "Render queue", ShaderUtilEx.GetRenderQueue( shader ).ToString( System.Globalization.CultureInfo.InvariantCulture ), new GUILayoutOption[ 0 ] );
  249. EditorGUILayout.LabelField( "LOD", ShaderUtilEx.GetLOD( shader ).ToString( System.Globalization.CultureInfo.InvariantCulture ), new GUILayoutOption[ 0 ] );
  250. EditorGUILayout.LabelField( "Ignore projector", ( !ShaderUtilEx.DoesIgnoreProjector( shader ) ) ? "no" : "yes", new GUILayoutOption[ 0 ] );
  251. string label;
  252. switch ( ShaderEx.GetDisableBatching( shader ) )
  253. {
  254. case DisableBatchingType.False:
  255. label = "no";
  256. break;
  257. case DisableBatchingType.True:
  258. label = "yes";
  259. break;
  260. case DisableBatchingType.WhenLODFading:
  261. label = "when LOD fading is on";
  262. break;
  263. default:
  264. label = "unknown";
  265. break;
  266. }
  267. EditorGUILayout.LabelField( "Disable batching", label, new GUILayoutOption[ 0 ] );
  268. ShowKeywords( shader );
  269. srpCompatibilityCheckMaterial.SetPass( 0 );
  270. int shaderActiveSubshaderIndex = ShaderUtilEx.GetShaderActiveSubshaderIndex( shader );
  271. int sRPBatcherCompatibilityCode = ShaderUtilEx.GetSRPBatcherCompatibilityCode( shader, shaderActiveSubshaderIndex );
  272. string label2 = ( sRPBatcherCompatibilityCode != 0 ) ? "not compatible" : "compatible";
  273. EditorGUILayout.LabelField( "SRP Batcher", label2 );
  274. if( sRPBatcherCompatibilityCode != 0 )
  275. {
  276. EditorGUILayout.HelpBox( ShaderUtilEx.GetSRPBatcherCompatibilityIssueReason( shader, shaderActiveSubshaderIndex, sRPBatcherCompatibilityCode ), MessageType.Info );
  277. }
  278. CustomShaderInspector.ShowShaderProperties( shader );
  279. }
  280. }
  281. private void ShowKeywords( Shader s )
  282. {
  283. EditorGUILayout.BeginHorizontal();
  284. EditorGUILayout.PrefixLabel( "Keywords", EditorStyles.miniButton );
  285. Rect buttonRect = GUILayoutUtility.GetRect( Styles.arrayValuePopupButton, GUI.skin.button, GUILayout.MinWidth( kValueFieldWidth ) );
  286. buttonRect.width = kArrayValuePopupBtnWidth;
  287. if( GUI.Button( buttonRect, Styles.arrayValuePopupButton, EditorStyles.miniButton ) )
  288. {
  289. var globalKeywords = ShaderUtilEx.GetShaderGlobalKeywords( s );
  290. var localKeywords = ShaderUtilEx.GetShaderLocalKeywords( s );
  291. PopupWindow.Show( buttonRect, new KeywordsPopup( globalKeywords, localKeywords, 150.0f ) );
  292. }
  293. EditorGUILayout.EndHorizontal();
  294. }
  295. private void ShowShaderCodeArea( Shader s )
  296. {
  297. CustomShaderInspector.ShowSurfaceShaderButton( s );
  298. CustomShaderInspector.ShowFixedFunctionShaderButton( s );
  299. this.ShowCompiledCodeButton( s );
  300. this.ShowShaderErrors( s );
  301. }
  302. private static void ShowShaderProperties( Shader s )
  303. {
  304. GUILayout.Space( 5f );
  305. GUILayout.Label( "Properties:", EditorStyles.boldLabel, new GUILayoutOption[ 0 ] );
  306. int propertyCount = UnityEditor.ShaderUtil.GetPropertyCount( s );
  307. for ( int i = 0; i < propertyCount; i++ )
  308. {
  309. string propertyName = UnityEditor.ShaderUtil.GetPropertyName( s, i );
  310. string label = CustomShaderInspector.GetPropertyType( s, i ) + UnityEditor.ShaderUtil.GetPropertyDescription( s, i );
  311. EditorGUILayout.LabelField( propertyName, label, new GUILayoutOption[ 0 ] );
  312. }
  313. }
  314. internal static void ShaderErrorListUI( UnityEngine.Object shader, ShaderError[] errors, ref Vector2 scrollPosition )
  315. {
  316. int num = errors.Length;
  317. GUILayout.Space( 5f );
  318. GUILayout.Label( string.Format( "Errors ({0}):", num ), EditorStyles.boldLabel, new GUILayoutOption[ 0 ] );
  319. int controlID = GUIUtility.GetControlID( CustomShaderInspector.kErrorViewHash, FocusType.Passive );
  320. float minHeight = Mathf.Min( ( float ) num * 20f + 40f, 150f );
  321. scrollPosition = GUILayout.BeginScrollView( scrollPosition, GUISkinEx.GetCurrentSkin().box, new GUILayoutOption[]
  322. {
  323. GUILayout.MinHeight(minHeight)
  324. } );
  325. EditorGUIUtility.SetIconSize( new Vector2( 16f, 16f ) );
  326. float height = CustomShaderInspector.Styles.messageStyle.CalcHeight( EditorGUIUtilityEx.TempContent( CustomShaderInspector.Styles.errorIcon ), 100f );
  327. Event current = Event.current;
  328. for ( int i = 0; i < num; i++ )
  329. {
  330. Rect controlRect = EditorGUILayout.GetControlRect( false, height, new GUILayoutOption[ 0 ] );
  331. string message = errors[ i ].message;
  332. string platform = errors[ i ].platform;
  333. bool flag = errors[ i ].warning != 0;
  334. string lastPathNameComponent = FileUtilEx.GetLastPathNameComponent( errors[ i ].file );
  335. int line = errors[ i ].line;
  336. if ( current.type == EventType.MouseDown && current.button == 0 && controlRect.Contains( current.mousePosition ) )
  337. {
  338. GUIUtility.keyboardControl = controlID;
  339. if ( current.clickCount == 2 )
  340. {
  341. string file = errors[ i ].file;
  342. UnityEngine.Object @object = ( !string.IsNullOrEmpty( file ) ) ? AssetDatabase.LoadMainAssetAtPath( file ) : null;
  343. AssetDatabase.OpenAsset( @object ?? shader, line );
  344. GUIUtility.ExitGUI();
  345. }
  346. current.Use();
  347. }
  348. if ( current.type == EventType.ContextClick && controlRect.Contains( current.mousePosition ) )
  349. {
  350. current.Use();
  351. GenericMenu genericMenu = new GenericMenu();
  352. int errorIndex = i;
  353. genericMenu.AddItem( new GUIContent( "Copy error text" ), false, delegate
  354. {
  355. string text = errors[ errorIndex ].message;
  356. if ( !string.IsNullOrEmpty( errors[ errorIndex ].messageDetails ) )
  357. {
  358. text += '\n';
  359. text += errors[ errorIndex ].messageDetails;
  360. }
  361. EditorGUIUtility.systemCopyBuffer = text;
  362. } );
  363. genericMenu.ShowAsContext();
  364. }
  365. if ( current.type == EventType.Repaint && ( i & 1 ) == 0 )
  366. {
  367. GUIStyle evenBackground = CustomShaderInspector.Styles.evenBackground;
  368. evenBackground.Draw( controlRect, false, false, false, false );
  369. }
  370. Rect rect = controlRect;
  371. rect.xMin = rect.xMax;
  372. if ( line > 0 )
  373. {
  374. GUIContent content;
  375. if ( string.IsNullOrEmpty( lastPathNameComponent ) )
  376. {
  377. content = EditorGUIUtilityEx.TempContent( line.ToString( System.Globalization.CultureInfo.InvariantCulture ) );
  378. }
  379. else
  380. {
  381. content = EditorGUIUtilityEx.TempContent( lastPathNameComponent + ":" + line.ToString( System.Globalization.CultureInfo.InvariantCulture ) );
  382. }
  383. Vector2 vector = EditorStyles.miniLabel.CalcSize( content );
  384. rect.xMin -= vector.x;
  385. GUI.Label( rect, content, EditorStyles.miniLabel );
  386. rect.xMin -= 2f;
  387. if ( rect.width < 30f )
  388. {
  389. rect.xMin = rect.xMax - 30f;
  390. }
  391. }
  392. Rect position = rect;
  393. position.width = 0f;
  394. if ( platform.Length > 0 )
  395. {
  396. GUIContent content2 = EditorGUIUtilityEx.TempContent( platform );
  397. Vector2 vector2 = EditorStyles.miniLabel.CalcSize( content2 );
  398. position.xMin -= vector2.x;
  399. Color contentColor = GUI.contentColor;
  400. GUI.contentColor = new Color( 1f, 1f, 1f, 0.5f );
  401. GUI.Label( position, content2, EditorStyles.miniLabel );
  402. GUI.contentColor = contentColor;
  403. position.xMin -= 2f;
  404. }
  405. Rect position2 = controlRect;
  406. position2.xMax = position.xMin;
  407. GUI.Label( position2, EditorGUIUtilityEx.TempContent( message, ( !flag ) ? CustomShaderInspector.Styles.errorIcon : CustomShaderInspector.Styles.warningIcon ), CustomShaderInspector.Styles.messageStyle );
  408. }
  409. EditorGUIUtility.SetIconSize( Vector2.zero );
  410. GUILayout.EndScrollView();
  411. }
  412. ShaderMessage[] m_ShaderMessages;
  413. private void ShowShaderErrors( Shader s )
  414. {
  415. if( Event.current.type == EventType.Layout )
  416. {
  417. int n = ShaderUtil.GetShaderMessageCount( s );
  418. m_ShaderMessages = null;
  419. if( n >= 1 )
  420. {
  421. m_ShaderMessages = ShaderUtil.GetShaderMessages( s );
  422. }
  423. }
  424. if( m_ShaderMessages == null )
  425. return;
  426. ShaderInspectorEx.ShaderErrorListUI( s, m_ShaderMessages, ref this.m_ScrollPosition );
  427. }
  428. private void ShowCompiledCodeButton( Shader s )
  429. {
  430. #if UNITY_2020_1_OR_NEWER
  431. using( new EditorGUI.DisabledScope( !EditorSettings.cachingShaderPreprocessor ) )
  432. {
  433. s_PreprocessOnly = EditorGUILayout.Toggle( Styles.togglePreprocess, s_PreprocessOnly );
  434. #if UNITY_2020_2_OR_NEWER
  435. if( s_PreprocessOnly )
  436. {
  437. s_StripLineDirectives = EditorGUILayout.Toggle( Styles.toggleStripLineDirective, s_StripLineDirectives );
  438. }
  439. #endif
  440. }
  441. #endif
  442. EditorGUILayout.BeginHorizontal( new GUILayoutOption[ 0 ] );
  443. EditorGUILayout.PrefixLabel( "Compiled code", EditorStyles.miniButton );
  444. bool hasCode = ShaderUtilEx.HasShaderSnippets( s ) || ShaderUtilEx.HasSurfaceShaders( s ) || ShaderUtilEx.HasFixedFunctionShaders( s );
  445. if( hasCode )
  446. {
  447. GUIContent showCurrent = Styles.showCurrent;
  448. Rect rect = GUILayoutUtility.GetRect( showCurrent, EditorStyles.miniButton, new GUILayoutOption[]
  449. {
  450. GUILayout.ExpandWidth(false)
  451. } );
  452. Rect position = new Rect( rect.xMax - 16f, rect.y, 16f, rect.height );
  453. if( EditorGUIEx.ButtonMouseDown( position, GUIContent.none, FocusType.Passive, GUIStyle.none ) )
  454. {
  455. Rect last = GUILayoutUtilityEx.TopLevel_GetLast();
  456. PopupWindow.Show( last, (PopupWindowContent)Activator.CreateInstance( System.Type.GetType( "UnityEditor.ShaderInspectorPlatformsPopup, UnityEditor" ), new object[] { s } ) );
  457. GUIUtility.ExitGUI();
  458. }
  459. if( GUI.Button( rect, showCurrent, EditorStyles.miniButton ) )
  460. {
  461. #if UNITY_2020_1
  462. ShaderUtilEx.OpenCompiledShader( s, ShaderInspectorPlatformsPopupEx.GetCurrentMode(), ShaderInspectorPlatformsPopupEx.GetCurrentPlatformMask(), ShaderInspectorPlatformsPopupEx.GetCurrentVariantStripping() == 0, s_PreprocessOnly );
  463. #elif UNITY_2020_2_OR_NEWER
  464. ShaderUtilEx.OpenCompiledShader( s, ShaderInspectorPlatformsPopupEx.GetCurrentMode(), ShaderInspectorPlatformsPopupEx.GetCurrentPlatformMask(), ShaderInspectorPlatformsPopupEx.GetCurrentVariantStripping() == 0, s_PreprocessOnly, s_StripLineDirectives );
  465. #else
  466. ShaderUtilEx.OpenCompiledShader( s, ShaderInspectorPlatformsPopupEx.GetCurrentMode(), ShaderInspectorPlatformsPopupEx.GetCurrentPlatformMask(), ShaderInspectorPlatformsPopupEx.GetCurrentVariantStripping() == 0 );
  467. #endif
  468. GUIUtility.ExitGUI();
  469. }
  470. }
  471. else
  472. {
  473. GUILayout.Button( "none (precompiled shader)", GUI.skin.label, new GUILayoutOption[ 0 ] );
  474. }
  475. EditorGUILayout.EndHorizontal();
  476. }
  477. private static void ShowSurfaceShaderButton( Shader s )
  478. {
  479. bool flag = ShaderUtilEx.HasSurfaceShaders( s );
  480. EditorGUILayout.BeginHorizontal( new GUILayoutOption[ 0 ] );
  481. EditorGUILayout.PrefixLabel( "Surface shader", EditorStyles.miniButton );
  482. if ( flag )
  483. {
  484. if ( !( AssetImporter.GetAtPath( AssetDatabase.GetAssetPath( s ) ) == null ) )
  485. {
  486. if ( GUILayout.Button( CustomShaderInspector.Styles.showSurface, EditorStyles.miniButton, new GUILayoutOption[]
  487. {
  488. GUILayout.ExpandWidth(false)
  489. } ) )
  490. {
  491. ShaderUtilEx.OpenParsedSurfaceShader( s );
  492. GUIUtility.ExitGUI();
  493. }
  494. }
  495. else
  496. {
  497. GUILayout.Button( CustomShaderInspector.Styles.builtinShader, GUI.skin.label, new GUILayoutOption[ 0 ] );
  498. }
  499. }
  500. else
  501. {
  502. GUILayout.Button( CustomShaderInspector.Styles.no, GUI.skin.label, new GUILayoutOption[ 0 ] );
  503. }
  504. EditorGUILayout.EndHorizontal();
  505. }
  506. private static void ShowFixedFunctionShaderButton( Shader s )
  507. {
  508. bool flag = ShaderUtilEx.HasFixedFunctionShaders( s );
  509. EditorGUILayout.BeginHorizontal( new GUILayoutOption[ 0 ] );
  510. EditorGUILayout.PrefixLabel( "Fixed function", EditorStyles.miniButton );
  511. if ( flag )
  512. {
  513. if ( !( AssetImporter.GetAtPath( AssetDatabase.GetAssetPath( s ) ) == null ) )
  514. {
  515. if ( GUILayout.Button( CustomShaderInspector.Styles.showFF, EditorStyles.miniButton, new GUILayoutOption[]
  516. {
  517. GUILayout.ExpandWidth(false)
  518. } ) )
  519. {
  520. ShaderUtilEx.OpenGeneratedFixedFunctionShader( s );
  521. GUIUtility.ExitGUI();
  522. }
  523. }
  524. else
  525. {
  526. GUILayout.Button( CustomShaderInspector.Styles.builtinShader, GUI.skin.label, new GUILayoutOption[ 0 ] );
  527. }
  528. }
  529. else
  530. {
  531. GUILayout.Button( CustomShaderInspector.Styles.no, GUI.skin.label, new GUILayoutOption[ 0 ] );
  532. }
  533. EditorGUILayout.EndHorizontal();
  534. }
  535. }
  536. internal class KeywordsPopup : PopupWindowContent
  537. {
  538. private Vector2 m_ScrollPos = Vector2.zero;
  539. private string[] m_GlobalKeywords;
  540. private string[] m_LocalKeywords;
  541. private bool m_GlobalKeywordsExpended;
  542. private bool m_LocalKeywordsExpended;
  543. private float m_WindowWidth;
  544. private static readonly GUIStyle m_Style = EditorStyles.miniLabel;
  545. public KeywordsPopup( string[] globalKeywords, string[] localKeywords, float windowWidth )
  546. {
  547. m_GlobalKeywords = globalKeywords;
  548. m_LocalKeywords = localKeywords;
  549. m_GlobalKeywordsExpended = true;
  550. m_LocalKeywordsExpended = true;
  551. m_WindowWidth = windowWidth;
  552. }
  553. public override Vector2 GetWindowSize()
  554. {
  555. var numValues = m_GlobalKeywords.Length + m_LocalKeywords.Length + 2;
  556. var lineHeight = m_Style.lineHeight + m_Style.padding.vertical + m_Style.margin.top;
  557. return new Vector2( m_WindowWidth, Math.Min( lineHeight * numValues, 250.0f ) );
  558. }
  559. public override void OnGUI( Rect rect )
  560. {
  561. m_ScrollPos = EditorGUILayout.BeginScrollView( m_ScrollPos );
  562. m_GlobalKeywordsExpended = KeywordsFoldout( m_GlobalKeywordsExpended, "Global Keywords", m_GlobalKeywords );
  563. m_LocalKeywordsExpended = KeywordsFoldout( m_LocalKeywordsExpended, "Local Keywords", m_LocalKeywords );
  564. EditorGUILayout.EndScrollView();
  565. }
  566. private bool KeywordsFoldout( bool expended, string name, string[] values )
  567. {
  568. expended = EditorGUILayout.Foldout( expended, name, true, m_Style );
  569. if( expended )
  570. {
  571. EditorGUI.indentLevel++;
  572. for( int i = 0; i < values.Length; ++i )
  573. {
  574. EditorGUILayout.LabelField( values[ i ], m_Style );
  575. }
  576. EditorGUI.indentLevel--;
  577. }
  578. return expended;
  579. }
  580. }
  581. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  582. // UNITY EDITOR EXTENSIONS
  583. ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  584. public enum DisableBatchingType
  585. {
  586. False,
  587. True,
  588. WhenLODFading
  589. }
  590. public struct ShaderError
  591. {
  592. public string message;
  593. public string messageDetails;
  594. public string platform;
  595. public string file;
  596. public int line;
  597. public int warning;
  598. }
  599. public static class EditorGUIUtilityEx
  600. {
  601. private static System.Type type = null;
  602. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEditor.EditorGUIUtility, UnityEditor" ) : type; } }
  603. public static Texture2D LoadIcon( string icon )
  604. {
  605. return ( Texture2D ) EditorGUIUtilityEx.Type.InvokeMember( "LoadIcon", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { icon } );
  606. }
  607. public static GUIContent TextContent( string t )
  608. {
  609. return ( GUIContent ) EditorGUIUtilityEx.Type.InvokeMember( "TextContent", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { t } );
  610. }
  611. internal static GUIContent TempContent( string t )
  612. {
  613. return ( GUIContent ) EditorGUIUtilityEx.Type.InvokeMember( "TempContent", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { t } );
  614. }
  615. internal static GUIContent TempContent( Texture i )
  616. {
  617. return ( GUIContent ) EditorGUIUtilityEx.Type.InvokeMember( "TempContent", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { i } );
  618. }
  619. internal static GUIContent TempContent( string t, Texture i )
  620. {
  621. return ( GUIContent ) EditorGUIUtilityEx.Type.InvokeMember( "TempContent", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { t, i } );
  622. }
  623. }
  624. public static class GUILayoutUtilityEx
  625. {
  626. private static System.Type type = null;
  627. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEngine.GUILayoutUtility, UnityEngine" ) : type; } }
  628. public static Rect TopLevel_GetLast()
  629. {
  630. System.Type guiLayoutGroup = System.Type.GetType( "UnityEngine.GUILayoutGroup, UnityEngine" );
  631. var topLevel = GUILayoutUtilityEx.Type.GetProperty( "topLevel", BindingFlags.NonPublic | BindingFlags.Static ).GetValue( null, null );
  632. return ( Rect ) guiLayoutGroup.InvokeMember( "GetLast", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, topLevel, new object[] { } );
  633. }
  634. }
  635. public static class ShaderEx
  636. {
  637. private static System.Type type = null;
  638. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEngine.Shader, UnityEngine" ) : type; } }
  639. public static DisableBatchingType GetDisableBatching( Shader s )
  640. {
  641. return ( DisableBatchingType ) ShaderEx.Type.GetProperty( "disableBatching", BindingFlags.NonPublic | BindingFlags.Instance ).GetValue( s, new object[ 0 ] );
  642. }
  643. }
  644. public static class ShaderUtilEx
  645. {
  646. private static System.Type type = null;
  647. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEditor.ShaderUtil, UnityEditor" ) : type; } }
  648. public static void OpenParsedSurfaceShader( Shader s )
  649. {
  650. ShaderUtilEx.Type.InvokeMember( "OpenParsedSurfaceShader", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  651. }
  652. public static void OpenGeneratedFixedFunctionShader( Shader s )
  653. {
  654. ShaderUtilEx.Type.InvokeMember( "OpenGeneratedFixedFunctionShader", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  655. }
  656. #if UNITY_2020_1
  657. public static void OpenCompiledShader( Shader shader, int mode, int customPlatformsMask, bool includeAllVariants, bool preprocessOnly )
  658. {
  659. ShaderUtilEx.Type.InvokeMember( "OpenCompiledShader", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { shader, mode, customPlatformsMask, includeAllVariants, preprocessOnly } );
  660. }
  661. #elif UNITY_2020_2_OR_NEWER
  662. public static void OpenCompiledShader( Shader shader, int mode, int customPlatformsMask, bool includeAllVariants, bool preprocessOnly, bool stripLineDirectives )
  663. {
  664. ShaderUtilEx.Type.InvokeMember( "OpenCompiledShader", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { shader, mode, customPlatformsMask, includeAllVariants, preprocessOnly, stripLineDirectives } );
  665. }
  666. #else
  667. public static void OpenCompiledShader( Shader shader, int mode, int customPlatformsMask, bool includeAllVariants )
  668. {
  669. ShaderUtilEx.Type.InvokeMember( "OpenCompiledShader", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { shader, mode, customPlatformsMask, includeAllVariants } );
  670. }
  671. #endif
  672. public static void FetchCachedErrors( Shader s )
  673. {
  674. ShaderUtilEx.Type.InvokeMember( "FetchCachedMessages", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  675. }
  676. public static string[] GetShaderGlobalKeywords( Shader s )
  677. {
  678. return ShaderUtilEx.Type.InvokeMember( "GetShaderGlobalKeywords", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } ) as string[];
  679. }
  680. public static string[] GetShaderLocalKeywords( Shader s )
  681. {
  682. return ShaderUtilEx.Type.InvokeMember( "GetShaderLocalKeywords", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } ) as string[];
  683. }
  684. public static int GetShaderErrorCount( Shader s )
  685. {
  686. return ShaderUtil.GetShaderMessageCount( s );
  687. }
  688. public static int GetAvailableShaderCompilerPlatforms()
  689. {
  690. return (int)ShaderUtilEx.Type.InvokeMember( "GetAvailableShaderCompilerPlatforms", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { } );
  691. }
  692. public static ShaderError[] GetShaderErrors( Shader s )
  693. {
  694. System.Type shaderErrorType = System.Type.GetType( "UnityEditor.ShaderError, UnityEditor" );
  695. var errorList = ( System.Collections.IList ) ShaderUtilEx.Type.InvokeMember( "GetShaderErrors", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  696. FieldInfo messageField = shaderErrorType.GetField( "message", BindingFlags.Public | BindingFlags.Instance );
  697. FieldInfo messageDetailsField = shaderErrorType.GetField( "messageDetails", BindingFlags.Public | BindingFlags.Instance );
  698. FieldInfo platformField = shaderErrorType.GetField( "platform", BindingFlags.Public | BindingFlags.Instance );
  699. FieldInfo fileField = shaderErrorType.GetField( "file", BindingFlags.Public | BindingFlags.Instance );
  700. FieldInfo lineField = shaderErrorType.GetField( "line", BindingFlags.Public | BindingFlags.Instance );
  701. FieldInfo warningField = shaderErrorType.GetField( "warning", BindingFlags.Public | BindingFlags.Instance );
  702. ShaderError[] errors = new ShaderError[ errorList.Count ];
  703. for ( int i = 0; i < errorList.Count; i++ )
  704. {
  705. errors[ i ].message = ( string ) messageField.GetValue( errorList[ i ] );
  706. errors[ i ].messageDetails = ( string ) messageDetailsField.GetValue( errorList[ i ] );
  707. errors[ i ].platform = ( string ) platformField.GetValue( errorList[ i ] );
  708. errors[ i ].file = ( string ) fileField.GetValue( errorList[ i ] );
  709. errors[ i ].line = ( int ) lineField.GetValue( errorList[ i ] );
  710. errors[ i ].warning = ( int ) warningField.GetValue( errorList[ i ] );
  711. }
  712. return errors;
  713. }
  714. public static bool HasShaderSnippets( Shader s )
  715. {
  716. return ( bool ) ShaderUtilEx.Type.InvokeMember( "HasShaderSnippets", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  717. }
  718. public static bool HasSurfaceShaders( Shader s )
  719. {
  720. return ( bool ) ShaderUtilEx.Type.InvokeMember( "HasSurfaceShaders", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  721. }
  722. public static bool HasFixedFunctionShaders( Shader s )
  723. {
  724. return ( bool ) ShaderUtilEx.Type.InvokeMember( "HasFixedFunctionShaders", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  725. }
  726. public static bool HasShadowCasterPass( Shader s )
  727. {
  728. return ( bool ) ShaderUtilEx.Type.InvokeMember( "HasShadowCasterPass", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  729. }
  730. public static int GetRenderQueue( Shader s )
  731. {
  732. return ( int ) ShaderUtilEx.Type.InvokeMember( "GetRenderQueue", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  733. }
  734. public static int GetLOD( Shader s )
  735. {
  736. return ( int ) ShaderUtilEx.Type.InvokeMember( "GetLOD", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  737. }
  738. public static bool DoesIgnoreProjector( Shader s )
  739. {
  740. return ( bool ) ShaderUtilEx.Type.InvokeMember( "DoesIgnoreProjector", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  741. }
  742. public static int GetShaderActiveSubshaderIndex( Shader s )
  743. {
  744. return (int)ShaderUtilEx.Type.InvokeMember( "GetShaderActiveSubshaderIndex", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s } );
  745. }
  746. public static int GetSRPBatcherCompatibilityCode( Shader s, int subShaderIdx )
  747. {
  748. return (int)ShaderUtilEx.Type.InvokeMember( "GetSRPBatcherCompatibilityCode", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s, subShaderIdx } );
  749. }
  750. public static string GetSRPBatcherCompatibilityIssueReason( Shader s, int subShaderIdx, int err )
  751. {
  752. return (string)ShaderUtilEx.Type.InvokeMember( "GetSRPBatcherCompatibilityIssueReason", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { s, subShaderIdx, err } );
  753. }
  754. }
  755. public static class FileUtilEx
  756. {
  757. private static System.Type type = null;
  758. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEditor.FileUtil, UnityEditor" ) : type; } }
  759. public static string GetLastPathNameComponent( string path )
  760. {
  761. return ( string ) FileUtilEx.Type.InvokeMember( "GetLastPathNameComponent", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { path } );
  762. }
  763. }
  764. public static class ShaderInspectorEx
  765. {
  766. private static System.Type type = null;
  767. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEditor.ShaderInspector, UnityEditor" ) : type; } }
  768. public static void ShaderErrorListUI( UnityEngine.Object shader, ShaderMessage[] messages, ref Vector2 scrollPosition )
  769. {
  770. Type.InvokeMember( "ShaderErrorListUI", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, null, new object[] { shader, messages, scrollPosition } );
  771. }
  772. }
  773. public static class GUISkinEx
  774. {
  775. private static System.Type type = null;
  776. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEngine.GUISkin, UnityEngine" ) : type; } }
  777. public static GUISkin GetCurrentSkin()
  778. {
  779. return ( GUISkin ) GUISkinEx.Type.GetField( "current", BindingFlags.NonPublic | BindingFlags.Static ).GetValue( null );
  780. }
  781. }
  782. public static class EditorGUIEx
  783. {
  784. public static System.Type Type = typeof( EditorGUI );
  785. public static bool ButtonMouseDown( Rect position, GUIContent content, FocusType focusType, GUIStyle style )
  786. {
  787. return EditorGUI.DropdownButton( position, content, focusType, style );
  788. }
  789. public static float kObjectFieldMiniThumbnailHeight
  790. {
  791. get
  792. {
  793. return (float)EditorGUIEx.Type.InvokeMember( "kObjectFieldMiniThumbnailHeight", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetField, null, null, new object[] {} );
  794. }
  795. }
  796. public static float kSingleLineHeight
  797. {
  798. get
  799. {
  800. return (float)EditorGUIEx.Type.InvokeMember( "kSingleLineHeight", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetField, null, null, new object[] { } );
  801. }
  802. }
  803. public static Gradient GradientField( Rect position, Gradient gradient )
  804. {
  805. return EditorGUI.GradientField( position, gradient );
  806. }
  807. }
  808. internal static class EditorGUILayoutEx
  809. {
  810. public static System.Type Type = typeof( EditorGUILayout );
  811. public static Gradient GradientField( Gradient value, params GUILayoutOption[] options )
  812. {
  813. return EditorGUILayout.GradientField( value, options );
  814. }
  815. public static Gradient GradientField( string label, Gradient value, params GUILayoutOption[] options )
  816. {
  817. return EditorGUILayout.GradientField( label, value, options );
  818. }
  819. }
  820. public static class ShaderInspectorPlatformsPopupEx
  821. {
  822. private static System.Type type = null;
  823. public static System.Type Type { get { return ( type == null ) ? type = System.Type.GetType( "UnityEditor.ShaderInspectorPlatformsPopup, UnityEditor" ) : type; } }
  824. public static int GetCurrentMode()
  825. {
  826. return ( int ) ShaderInspectorPlatformsPopupEx.Type.GetProperty( "currentMode", BindingFlags.Public | BindingFlags.Static ).GetValue( null, null );
  827. }
  828. public static int GetCurrentPlatformMask()
  829. {
  830. return ( int ) ShaderInspectorPlatformsPopupEx.Type.GetProperty( "currentPlatformMask", BindingFlags.Public | BindingFlags.Static ).GetValue( null, null );
  831. }
  832. public static int GetCurrentVariantStripping()
  833. {
  834. return ( int ) ShaderInspectorPlatformsPopupEx.Type.GetProperty( "currentVariantStripping", BindingFlags.Public | BindingFlags.Static ).GetValue( null, null );
  835. }
  836. }
  837. }