SCWindow.Advanced.GUI.cs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. /*
  2. Shader Control - (C) Copyright 2016-2022 Ramiro Oliva (Kronnect)
  3. */
  4. using UnityEngine;
  5. using UnityEditor;
  6. using System.Text;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. using UnityEditorInternal;
  10. namespace ShaderControl {
  11. public class SCWindowAdvanced : EditorWindow {
  12. ShadersBuildInfo shadersBuildInfo;
  13. Vector2 scrollViewPosProject;
  14. GUIStyle titleStyle;
  15. public ShaderBuildInfo shader;
  16. public SCShader projectShader;
  17. StringBuilder sb = new StringBuilder();
  18. public static void ShowWindow(ShaderBuildInfo shader, SCShader projectShader) {
  19. SCWindowAdvanced window = GetWindow<SCWindowAdvanced>(true, "Advanced Build Options", true);
  20. window.shader = shader;
  21. window.projectShader = projectShader;
  22. }
  23. void OnGUI() {
  24. if (titleStyle == null) {
  25. titleStyle = new GUIStyle(GUI.skin.box);
  26. titleStyle.normal.textColor = EditorGUIUtility.isProSkin ? Color.white : Color.black;
  27. titleStyle.richText = true;
  28. titleStyle.alignment = TextAnchor.MiddleLeft;
  29. }
  30. if (shadersBuildInfo == null) {
  31. shadersBuildInfo = ShaderDebugBuildProcessor.CheckShadersBuildStore(shadersBuildInfo);
  32. }
  33. DrawAdvancedGUI();
  34. }
  35. void DrawAdvancedGUI() {
  36. GUILayout.Box(new GUIContent("This window let you specify which shader variants are allowed during build."), titleStyle, GUILayout.ExpandWidth(true));
  37. EditorGUILayout.Separator();
  38. if (shader == null) {
  39. Close();
  40. return;
  41. }
  42. EditorGUIUtility.labelWidth = 100;
  43. EditorGUILayout.Separator();
  44. EditorGUILayout.LabelField("Shader:", shader.name);
  45. EditorGUILayout.Separator();
  46. int kwCount = shader.keywords == null ? 0 : shader.keywords.Count;
  47. if (kwCount == 0) {
  48. EditorGUILayout.LabelField("No keywords.");
  49. return;
  50. }
  51. GUILayout.Label("Select keyword set (keywords in same group are mutually exclusive):");
  52. EditorGUI.indentLevel++;
  53. int prevGroup = 0;
  54. GUILayout.BeginVertical(GUI.skin.box);
  55. EditorGUILayout.BeginHorizontal();
  56. if (projectShader == null) {
  57. for (int j = 0; j < kwCount; j++) {
  58. KeywordBuildSettings kw = shader.keywords[j];
  59. if (kw == null) continue;
  60. kw.includeInVariant = EditorGUILayout.ToggleLeft(kw.keyword, kw.includeInVariant);
  61. }
  62. } else {
  63. for (int j = 0; j < kwCount; j++) {
  64. KeywordBuildSettings kw = shader.keywords[j];
  65. if (kw == null) continue;
  66. SCKeyword keyword = projectShader.GetKeyword(kw.keyword);
  67. if (keyword != null) {
  68. if (prevGroup == 0) {
  69. prevGroup = keyword.lineNumber;
  70. }
  71. if (keyword.lineNumber != prevGroup) {
  72. prevGroup = keyword.lineNumber;
  73. EditorGUILayout.EndHorizontal();
  74. GUILayout.EndVertical();
  75. GUILayout.BeginVertical(GUI.skin.box);
  76. EditorGUILayout.BeginHorizontal();
  77. }
  78. }
  79. EditorGUI.BeginChangeCheck();
  80. kw.includeInVariant = EditorGUILayout.ToggleLeft(kw.keyword, kw.includeInVariant);
  81. if (EditorGUI.EndChangeCheck() && kw.includeInVariant) {
  82. if (keyword.lineNumber > 0) {
  83. for (int i = 0; i < kwCount; i++) {
  84. if (i == j) continue;
  85. SCKeyword otherKeyword = projectShader.GetKeyword(shader.keywords[i].keyword);
  86. if (otherKeyword != null && otherKeyword.lineNumber == keyword.lineNumber) {
  87. shader.keywords[i].includeInVariant = false;
  88. }
  89. }
  90. }
  91. }
  92. }
  93. }
  94. EditorGUILayout.EndHorizontal();
  95. GUILayout.EndVertical();
  96. EditorGUI.indentLevel--;
  97. EditorGUILayout.BeginHorizontal();
  98. if (GUILayout.Button("Add Variant", GUILayout.Width(140))) {
  99. AddVariant(shader);
  100. GUIUtility.ExitGUI();
  101. }
  102. if (GUILayout.Button("Add Permutations", GUILayout.Width(140))) {
  103. AddPermutations(shader);
  104. GUIUtility.ExitGUI();
  105. }
  106. EditorGUILayout.EndHorizontal();
  107. GUI.enabled = shader.variants.Count > 0;
  108. if (GUILayout.Button("Create Shader Variant Collection Asset", GUILayout.Width(280))) {
  109. CreateShaderVariantCollection(shader);
  110. GUIUtility.ExitGUI();
  111. }
  112. GUI.enabled = true;
  113. EditorGUILayout.Separator();
  114. // Show current variants
  115. if (shader.variants != null) {
  116. int keywordSetsCount = shader.variants.Count;
  117. if (keywordSetsCount > 0) {
  118. GUILayout.Label("Current allowed keywords combinations:");
  119. }
  120. scrollViewPosProject = EditorGUILayout.BeginScrollView(scrollViewPosProject);
  121. for (int k = 0; k < keywordSetsCount; k++) {
  122. EditorGUILayout.Separator();
  123. KeywordSet keywordSet = shader.variants[k];
  124. sb.Length = 0;
  125. sb.Append("Variant ");
  126. sb.Append(k + 1);
  127. sb.Append(": ");
  128. foreach (string keyword in keywordSet.keywords) {
  129. sb.Append(keyword);
  130. sb.Append(" ");
  131. }
  132. GUILayout.Label(sb.ToString());
  133. EditorGUILayout.BeginHorizontal();
  134. GUILayout.Space(20);
  135. if (GUILayout.Button("Remove", GUILayout.Width(100))) {
  136. shader.variants.RemoveAt(k);
  137. RefreshShadersBuildInfo();
  138. GUIUtility.ExitGUI();
  139. }
  140. EditorGUILayout.EndHorizontal();
  141. }
  142. EditorGUILayout.EndScrollView();
  143. }
  144. }
  145. void AddVariant(ShaderBuildInfo shader) {
  146. int kwCount = shader.keywords.Count;
  147. int includedCount = 0;
  148. KeywordSet ks = new KeywordSet();
  149. for (int j = 0; j < kwCount; j++) {
  150. if (shader.keywords[j].includeInVariant) {
  151. includedCount++;
  152. ks.keywords.Add(shader.keywords[j].keyword);
  153. }
  154. }
  155. if (includedCount > 0) {
  156. AddKeywordSet(shader, ks);
  157. }
  158. }
  159. void AddPermutations(ShaderBuildInfo shader) {
  160. int kwCount = shader.keywords.Count;
  161. List<string> all = new List<string>();
  162. for (int j = 0; j < kwCount; j++) {
  163. if (shader.keywords[j].includeInVariant) all.Add(shader.keywords[j].keyword);
  164. }
  165. foreach (var variant in StringPerm.GetCombinations(all)) {
  166. KeywordSet ks = new KeywordSet();
  167. foreach (string keyword in variant) {
  168. ks.keywords.Add(keyword);
  169. }
  170. AddKeywordSet(shader, ks);
  171. }
  172. }
  173. void AddKeywordSet(ShaderBuildInfo shader, KeywordSet ks) {
  174. // check uniqueness
  175. bool repeated = false;
  176. foreach (var existingVariant in shader.variants) {
  177. if (ks.keywords.All(existingVariant.keywords.Contains) && ks.keywords.Count == existingVariant.keywords.Count) {
  178. repeated = true;
  179. break;
  180. }
  181. }
  182. if (!repeated) {
  183. shader.variants.Add(ks);
  184. RefreshShadersBuildInfo();
  185. }
  186. }
  187. void CreateShaderVariantCollection(ShaderBuildInfo shader) {
  188. Shader unityShader = Shader.Find(shader.name);
  189. if (unityShader == null) {
  190. Debug.LogError("Shader not found! " + shader.name);
  191. return;
  192. }
  193. ShaderVariantCollection svc = new ShaderVariantCollection();
  194. foreach (var variant in shader.variants) {
  195. ShaderVariantCollection.ShaderVariant sv = new ShaderVariantCollection.ShaderVariant();
  196. sv.shader = unityShader;
  197. sv.passType = UnityEngine.Rendering.PassType.Normal;
  198. sv.keywords = variant.keywords.ToArray();
  199. svc.Add(sv);
  200. }
  201. AssetDatabase.CreateAsset(svc, "Assets/ShaderVariantCollection.asset");
  202. AssetDatabase.Refresh();
  203. Selection.activeObject = svc;
  204. EditorGUIUtility.PingObject(svc);
  205. }
  206. void RefreshShadersBuildInfo() {
  207. EditorUtility.SetDirty(shadersBuildInfo);
  208. AssetDatabase.SaveAssets();
  209. AssetDatabase.Refresh();
  210. InternalEditorUtility.RepaintAllViews();
  211. }
  212. }
  213. }