예제 #1
0
        void UpdateShader(SCShader shader)
        {
            if (shader.isReadOnly)
            {
                EditorUtility.DisplayDialog("Locked file", "Shader file " + shader.name + " is read-only.", "Ok");
                return;
            }
            try {
                // Create backup
                MakeBackup(shader);

                if (shader.isShaderGraph)
                {
                    UpdateShaderGraph(shader);
                }
                else
                {
                    UpdateShaderNonGraph(shader);
                }

                // Also update materials
                CleanMaterials(shader);

                ScanShader(shader); // Rescan shader

                // do not include in build (sync with Build View)
                BuildUpdateShaderKeywordsState(shader);
            } catch (Exception ex) {
                Debug.LogError("Unexpected exception caught while updating shader: " + ex.Message);
            }
        }
 void PruneMaterials(string keywordName)
 {
     try {
         bool requiresSave = false;
         for (int s = 0; s < shaders.Count; s++)
         {
             SCShader shader        = shaders[s];
             int      materialCount = shader.materials.Count;
             for (int k = 0; k < materialCount; k++)
             {
                 SCMaterial material = shader.materials[k];
                 if (material.ContainsKeyword(keywordName))
                 {
                     Material theMaterial = AssetDatabase.LoadAssetAtPath <Material>(shader.materials[k].path);
                     if (theMaterial == null)
                     {
                         continue;
                     }
                     theMaterial.DisableKeyword(keywordName);
                     EditorUtility.SetDirty(theMaterial);
                     material.RemoveKeyword(keywordName);
                     shader.RemoveKeyword(keywordName);
                     requiresSave = true;
                 }
             }
         }
         if (requiresSave)
         {
             AssetDatabase.SaveAssets();
             AssetDatabase.Refresh();
         }
     } catch (Exception ex) {
         Debug.Log("Unexpected exception caught while pruning materials: " + ex.Message);
     }
 }
        void BuildUpdateShaderKeywordsState(SCShader shader)
        {
            if (shader == null || shader.keywords == null)
            {
                return;
            }
            if (shadersBuildInfo == null)
            {
                return;
            }
            int shadersCount = shadersBuildInfo.shaders.Count;

            for (int s = 0; s < shadersCount; s++)
            {
                ShaderBuildInfo sb = shadersBuildInfo.shaders[s];
                if (sb != null && sb.name.Equals(shader.fullName))
                {
                    for (int k = 0; k < shader.keywords.Count; k++)
                    {
                        SCKeyword keyword = shader.keywords[k];
                        sb.ToggleIncludeKeyword(keyword.name, keyword.enabled);
                    }
                }
            }
            shadersBuildInfo.requiresBuild = true;
        }
예제 #4
0
        void ConvertToLocalNonGraph(SCKeyword keyword, SCShader shader)
        {
            string path = shader.path;

            if (!File.Exists(path))
            {
                return;
            }
            string[] lines   = File.ReadAllLines(path);
            bool     changed = false;

            for (int k = 0; k < lines.Length; k++)
            {
                // Just convert to local shader_features for now since multi_compile global keywords can be nabled using the Shader global API
                if (lines[k].IndexOf(SCKeywordLine.PRAGMA_FEATURE_GLOBAL, StringComparison.InvariantCultureIgnoreCase) >= 0 && lines[k].IndexOf(keyword.name, StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    lines[k] = lines[k].Replace(SCKeywordLine.PRAGMA_FEATURE_GLOBAL, SCKeywordLine.PRAGMA_FEATURE_LOCAL);
                    lines[k] = lines[k].Replace(SCKeywordLine.PRAGMA_FEATURE_GLOBAL.ToUpper(), SCKeywordLine.PRAGMA_FEATURE_LOCAL);
                    changed  = true;
                }
            }
            if (changed)
            {
                MakeBackup(shader);
                File.WriteAllLines(path, lines, Encoding.UTF8);
            }
        }
예제 #5
0
        void ConvertToLocal(SCKeyword keyword, SCShader shader)
        {
            // Check total local keyword does not exceed 64 limit
            int potentialCount = 0;
            int kwCount        = shader.keywords.Count;

            for (int k = 0; k < kwCount; k++)
            {
                SCKeyword kw = shader.keywords[k];
                if (!kw.isMultiCompile)
                {
                    potentialCount++;
                }
            }
            if (potentialCount > 64)
            {
                return;
            }


            if (shader.isShaderGraph)
            {
                ConvertToLocalGraph(keyword, shader);
            }
            else
            {
                ConvertToLocalNonGraph(keyword, shader);
            }
        }
예제 #6
0
        void MakeBackup(SCShader shader)
        {
            string backupPath = shader.path + BACKUP_SUFFIX;

            if (!File.Exists(backupPath))
            {
                AssetDatabase.CopyAsset(shader.path, backupPath);
                shader.hasBackup = true;
            }
        }
        void ScanShaderGraph(SCShader shader)
        {
            shader.editedByShaderControl = File.Exists(shader.path + BACKUP_SUFFIX);

            // Reads shader
            string shaderContents = File.ReadAllText(shader.path, Encoding.UTF8);

            shaderContents = shaderContents.Replace("UnityEditor.ShaderGraph.ShaderKeyword", "ShaderControl.SCWindow.SerializedKeyword");
            ShaderGraphProxy graph = JsonUtility.FromJson <ShaderGraphProxy>(shaderContents);

            SCShaderPass currentPass = new SCShaderPass();

            if (graph.m_SerializedKeywords != null)
            {
                for (int k = 0; k < graph.m_SerializedKeywords.Length; k++)
                {
                    SerializedKeywordData skw = graph.m_SerializedKeywords[k];
                    if (string.IsNullOrEmpty(skw.JSONnodeData))
                    {
                        continue;
                    }

                    SerializedKeywordProxy kw = JsonUtility.FromJson <SerializedKeywordProxy>(skw.JSONnodeData);

                    PragmaType pragmaType = PragmaType.Unknown;
                    if (kw.m_KeywordDefinition == SHADER_GRAPH_KEYWORD_DEFINITION_MULTI_COMPILE && kw.m_KeywordScope == SHADER_GRAPH_KEYWORD_SCOPE_GLOBAL)
                    {
                        pragmaType = PragmaType.MultiCompileGlobal;
                    }
                    else if (kw.m_KeywordDefinition == SHADER_GRAPH_KEYWORD_DEFINITION_MULTI_COMPILE && kw.m_KeywordScope == SHADER_GRAPH_KEYWORD_SCOPE_LOCAL)
                    {
                        pragmaType = PragmaType.MultiCompileLocal;
                    }
                    else if (kw.m_KeywordDefinition == SHADER_GRAPH_KEYWORD_DEFINITION_SHADER_FEATURE && kw.m_KeywordScope == SHADER_GRAPH_KEYWORD_SCOPE_GLOBAL)
                    {
                        pragmaType = PragmaType.FeatureGlobal;
                    }
                    else if (kw.m_KeywordDefinition == SHADER_GRAPH_KEYWORD_DEFINITION_SHADER_FEATURE && kw.m_KeywordScope == SHADER_GRAPH_KEYWORD_SCOPE_LOCAL)
                    {
                        pragmaType = PragmaType.FeatureLocal;
                    }

                    SCKeywordLine keywordLine = new SCKeywordLine();
                    keywordLine.pragmaType = pragmaType;

                    SCKeyword keyword = new SCKeyword(kw.m_DefaultReferenceName, kw.m_Name);
                    keywordLine.Add(keyword);
                    currentPass.Add(keywordLine);
                }
            }
            shader.Add(currentPass);
            shader.UpdateVariantCount();
        }
예제 #8
0
        void ConvertToLocal(SCKeyword keyword, SCShader shader)
        {
            // Check total local keyword does not exceed 64 limit
            int potentialCount = 0;
            int kwCount        = shader.keywords.Count;

            for (int k = 0; k < kwCount; k++)
            {
                SCKeyword kw = shader.keywords[k];
                if (!kw.isMultiCompile)
                {
                    potentialCount++;
                }
            }
            if (potentialCount > 64)
            {
                return;
            }

            string path = shader.path;

            if (!File.Exists(path))
            {
                return;
            }
            string[] lines   = File.ReadAllLines(path);
            bool     changed = false;

            for (int k = 0; k < lines.Length; k++)
            {
                // Just convert to local shader_features for now since multi_compile global keywords can be nabled using the Shader global API
                if (lines[k].IndexOf(SCKeywordLine.PRAGMA_FEATURE_GLOBAL, StringComparison.InvariantCultureIgnoreCase) >= 0 && lines[k].IndexOf(keyword.name, StringComparison.InvariantCultureIgnoreCase) >= 0)
                {
                    lines[k] = lines[k].Replace(SCKeywordLine.PRAGMA_FEATURE_GLOBAL, SCKeywordLine.PRAGMA_FEATURE_LOCAL);
                    lines[k] = lines[k].Replace(SCKeywordLine.PRAGMA_FEATURE_GLOBAL.ToUpper(), SCKeywordLine.PRAGMA_FEATURE_LOCAL);
                    changed  = true;
                }
            }
            if (changed)
            {
                MakeBackup(shader);
                File.WriteAllLines(path, lines, Encoding.UTF8);
            }
        }
        void ConvertToLocalGraph(SCKeyword keyword, SCShader shader)
        {
            string contents = File.ReadAllText(shader.path, Encoding.UTF8);
            int    i        = contents.IndexOf("m_SerializedKeywords");

            if (i < 0)
            {
                return;
            }
            int j = contents.IndexOf("m_SerializedNodes");

            if (j < 0)
            {
                j = contents.Length - 1;
            }

            int  pos     = contents.IndexOf(keyword.name, i);
            bool changed = false;

            if (pos > i && pos < j)
            {
                int dataBlockPos = contents.LastIndexOf(JSON_NODE_DATA, pos);
                if (dataBlockPos > 0)
                {
                    int scopePos = contents.IndexOf(JSON_KEYWORD_SCOPE, dataBlockPos);
                    if (scopePos > dataBlockPos && scopePos < j)
                    {
                        scopePos += JSON_KEYWORD_SCOPE.Length + 2;
                        int valuePos  = contents.IndexOf("1", scopePos);
                        int safetyPos = contents.IndexOf("\"", scopePos);
                        if (valuePos > scopePos && valuePos < safetyPos && safetyPos > valuePos)
                        {
                            contents = contents.Substring(0, valuePos) + "0" + contents.Substring(valuePos + 1);
                            changed  = true;
                        }
                    }
                }
            }
            if (changed)
            {
                MakeBackup(shader);
                File.WriteAllText(shader.path, contents, Encoding.UTF8);
            }
        }
예제 #10
0
        void ScanShader(SCShader shader)
        {
            // Inits shader
            shader.passes.Clear();
            shader.keywords.Clear();
            shader.hasBackup             = File.Exists(shader.path + BACKUP_SUFFIX);
            shader.pendingChanges        = false;
            shader.editedByShaderControl = shader.hasBackup;

            if (shader.path.EndsWith(".shadergraph"))
            {
                shader.isShaderGraph = true;
                ScanShaderGraph(shader);
            }
            else
            {
                ScanShaderNonGraph(shader);
            }
        }
        void CleanMaterials(SCShader shader)
        {
            // Updates any material using this shader
            Shader shad = (Shader)AssetDatabase.LoadAssetAtPath <Shader>(shader.path);

            if (shad != null)
            {
                bool     requiresSave = false;
                string[] matGUIDs     = AssetDatabase.FindAssets("t:Material");
                foreach (string matGUID in matGUIDs)
                {
                    string   matPath = AssetDatabase.GUIDToAssetPath(matGUID);
                    Material mat     = (Material)AssetDatabase.LoadAssetAtPath <Material>(matPath);
                    if (mat != null && mat.shader.name.Equals(shad.name))
                    {
                        foreach (SCKeyword keyword in shader.keywords)
                        {
                            foreach (string matKeyword in mat.shaderKeywords)
                            {
                                if (matKeyword.Equals(keyword.name))
                                {
                                    if (!keyword.enabled && mat.IsKeywordEnabled(keyword.name))
                                    {
                                        mat.DisableKeyword(keyword.name);
                                        EditorUtility.SetDirty(mat);
                                        requiresSave = true;
                                    }
                                    break;
                                }
                            }
                        }
                    }
                }
                if (requiresSave)
                {
                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }
            }
        }
예제 #12
0
        void RestoreShader(SCShader shader)
        {
            try {
                string shaderBackupPath = shader.path + BACKUP_SUFFIX;
                if (!File.Exists(shaderBackupPath))
                {
                    EditorUtility.DisplayDialog("Restore shader", "Shader backup is missing!", "OK");
                    return;
                }
                File.Copy(shaderBackupPath, shader.path, true);
                File.Delete(shaderBackupPath);
                if (File.Exists(shaderBackupPath + ".meta"))
                {
                    File.Delete(shaderBackupPath + ".meta");
                }
                AssetDatabase.Refresh();

                ScanShader(shader); // Rescan shader
                UpdateProjectStats();
            } catch (Exception ex) {
                Debug.LogError("Unexpected exception caught while restoring shader: " + ex.Message);
            }
        }
 void UpdateShaderGraph(SCShader shader)
 {
     // Currently shader graph keywords cannot be disabled with Shader Control to avoid graph issues
     // Just click "Locate" and remove the keyword using the Shader Graph editor
 }
예제 #14
0
        public void OnProcessShader(
            Shader shader, ShaderSnippetData snippet, IList <ShaderCompilerData> shaderCompilerData)
        {
            bool skipCompilation = false;

            if (SCWindow.GetEditorPrefBool("QUICK_BUILD", false))
            {
                skipCompilation = true;
            }

            if (shadersBuildInfo == null)
            {
                string filename = GetStoredDataPath();
                shadersBuildInfo = AssetDatabase.LoadAssetAtPath <ShadersBuildInfo>(filename);
                if (shadersBuildInfo == null)
                {
                    shadersBuildInfo = ScriptableObject.CreateInstance <ShadersBuildInfo>();
                    Directory.CreateDirectory(Path.GetDirectoryName(filename));
                    AssetDatabase.CreateAsset(shadersBuildInfo, filename);
                    EditorUtility.SetDirty(shadersBuildInfo);
                }
            }

            ShaderBuildInfo sb = shadersBuildInfo.GetShader(shader.name);

            if (sb == null)
            {
                sb            = new ShaderBuildInfo();
                sb.name       = shader.name;
                sb.simpleName = SCShader.GetSimpleName(sb.name);
                sb.type       = snippet.shaderType;
                string path = AssetDatabase.GetAssetPath(shader);
                sb.isInternal = string.IsNullOrEmpty(path) || !File.Exists(path);
                shadersBuildInfo.Add(sb);
                EditorUtility.SetDirty(shadersBuildInfo);
            }
            else if (!sb.includeInBuild)
            {
                skipCompilation = true;
            }

            int count = shaderCompilerData.Count;

            for (int i = 0; i < count; ++i)
            {
                ShaderKeywordSet ks = shaderCompilerData[i].shaderKeywordSet;
                foreach (ShaderKeyword kw in ks.GetShaderKeywords())
                {
#if UNITY_2019_3_OR_NEWER
                    string kname = ShaderKeyword.GetKeywordName(shader, kw);
#else
                    string kname = kw.GetKeywordName();
#endif
                    if (string.IsNullOrEmpty(kname))
                    {
                        continue;
                    }
                    if (!sb.KeywordsIsIncluded(kname))
                    {
                        shaderCompilerData.RemoveAt(i);
                        count--;
                        i--;
                        break;
                    }
                    else
                    {
                        EditorUtility.SetDirty(shadersBuildInfo);
                    }
                }
            }

            if (skipCompilation)
            {
                shaderCompilerData.Clear();
            }
        }
        public void OnProcessShader(
            Shader shader, ShaderSnippetData snippet, IList <ShaderCompilerData> shaderCompilerData)
        {
            try {
                bool skipCompilation = false;
                if (SCWindow.GetEditorPrefBool("QUICK_BUILD", false))
                {
                    skipCompilation = true;
                }

                if (shadersBuildInfo == null)
                {
                    string filename = GetStoredDataPath();
                    shadersBuildInfo = AssetDatabase.LoadAssetAtPath <ShadersBuildInfo>(filename);
                    if (shadersBuildInfo == null)
                    {
                        return;
                    }
                }

                ShaderBuildInfo sb = shadersBuildInfo.GetShader(shader.name);
                if (sb == null)
                {
                    sb            = new ShaderBuildInfo();
                    sb.name       = shader.name;
                    sb.simpleName = SCShader.GetSimpleName(sb.name);
                    sb.type       = snippet.shaderType;
                    string path = AssetDatabase.GetAssetPath(shader);
                    sb.isInternal = string.IsNullOrEmpty(path) || !File.Exists(path);
                    shadersBuildInfo.Add(sb);
                    EditorUtility.SetDirty(shadersBuildInfo);
                }
                else if (!sb.includeInBuild)
                {
                    skipCompilation = true;
                }

                int count = shaderCompilerData.Count;
                for (int i = 0; i < count; ++i)
                {
                    ShaderKeywordSet ks = shaderCompilerData[i].shaderKeywordSet;
                    foreach (ShaderKeyword kw in ks.GetShaderKeywords())
                    {
#if UNITY_2019_3_OR_NEWER
                        string kname = ShaderKeyword.GetKeywordName(shader, kw);
#else
                        string kname = kw.GetName();
#endif
                        if (string.IsNullOrEmpty(kname))
                        {
                            continue;
                        }
                        if (!sb.KeywordsIsIncluded(kname))
                        {
                            shaderCompilerData.RemoveAt(i);
                            count--;
                            i--;
                            break;
                        }
                        else
                        {
                            EditorUtility.SetDirty(shadersBuildInfo);
                        }
                    }
                }

                if (skipCompilation)
                {
                    shaderCompilerData.Clear();
                    return;
                }
            } catch (Exception ex) {
                Debug.LogWarning("Shader Control detected an error during compilation of one shader: " + ex.ToString());
            }
        }
예제 #16
0
        void DrawSVCMgrGUI()
        {
            svcSettingsInfo = CheckSVCSettingsStore(svcSettingsInfo);
            if (null == svcSettingsInfo)
            {
                return;
            }

            GUILayout.Box(new GUIContent(" Set All Shader Variant Colletion Usage "), titleStyle, GUILayout.ExpandWidth(true));
            for (int i = 0; i < svcSettingsInfo.collection.Count; i++)
            {
                EditorGUILayout.BeginHorizontal();
                {
                    EditorGUILayout.LabelField(string.Format("Set SVC Usage {0}:", (i + 1)), GUILayout.Width(80));

                    EditorGUI.BeginChangeCheck();
                    {
                        svcSettingsInfo.collection[i] = (ShaderVariantCollection)EditorGUILayout.ObjectField(svcSettingsInfo.collection[i], typeof(ShaderVariantCollection), false);

                        ShaderVariantUsage usage = (ShaderVariantUsage)EditorGUILayout.EnumPopup("Usage", (ShaderVariantUsage)svcSettingsInfo.usage[i]);
                        svcSettingsInfo.usage[i] = (int)usage;

                        if (GUILayout.Button("¡ª", GUILayout.Width(30)))
                        {
                            //delete in loop
                            svcSettingsInfo.collection.RemoveAt(i);
                            svcSettingsInfo.usage.RemoveAt(i);
                            i--;
                        }
                    }
                    if (EditorGUI.EndChangeCheck())
                    {
                        EditorUtility.SetDirty(svcSettingsInfo);
                        AssetDatabase.SaveAssets();
                    }
                }
                EditorGUILayout.EndHorizontal();
            }

            EditorGUILayout.BeginHorizontal();
            {
                EditorGUI.BeginChangeCheck();
                {
                    if (GUILayout.Button(new GUIContent("Add Shader Variant Collection")))
                    {
                        svcSettingsInfo.collection.Add(null);
                        svcSettingsInfo.usage.Add(0);
                    }
                    if (EditorGUI.EndChangeCheck())
                    {
                        EditorUtility.SetDirty(svcSettingsInfo);
                        AssetDatabase.SaveAssets();
                    }
                }
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();
            EditorGUILayout.Separator();

            //if (GUILayout.Button(new GUIContent("Collect SVC in target Scenes", "Quickly scans the project and finds shaders that use keywords.")))
            //{
            //    LoadAllScenesCollectMaterial();
            //    GUIUtility.ExitGUI();
            //    return;
            //}
            if (shaders != null && shaders.Count > 0 && GUILayout.Button(new GUIContent("Clean All Materials", "Removes all disabled keywords in all materials.  This option is provided to ensure no existing materials are referencing a disabled shader keyword.\n\nTo disable keywords, first expand any shader from the list and uncheck the unwanted keywords (press 'Save' to modify the shader file and to clean any existing material that uses that specific shader)."), GUILayout.Width(130)))
            {
                CleanAllMaterials();
                GUIUtility.ExitGUI();
                return;
            }
            //if (GUILayout.Button("Help", GUILayout.Width(40))) {
            //    ShowHelpWindowProjectView();
            //}
            //EditorGUILayout.EndHorizontal();
            //EditorGUILayout.EndVertical();
            //EditorGUILayout.Separator();

            EditorGUILayout.BeginVertical(blackStyle);
            EditorGUILayout.BeginHorizontal();
            {
                if (GUILayout.Button(new GUIContent("Save Shader Variant Collection Settings", "save current shader variants")))
                {
                    string message   = "Save shader variant collection";
                    string assetPath = EditorUtility.SaveFilePanelInProject("Save Shader Variant Collection", "NewShaderVariants", "shadervariants", message);
                    if (!string.IsNullOrEmpty(assetPath))
                    {
                        SVCTool.ShaderUtils.SaveCurrentShaderVariantCollection(assetPath);
                        PostProcessSavedSVC(assetPath);
                    }

                    GUIUtility.ExitGUI();
                    return;
                }
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();
            EditorGUILayout.Separator();


            if (shaders != null)
            {
                string totalGlobalKeywordsTxt = totalGlobalKeywords != totalKeywords ? " (" + totalGlobalKeywords + " global) " : " ";
                string statsText;
                if (totalKeywords == totalUsedKeywords || totalKeywords == 0)
                {
                    statsText = "Shaders Found: " + totalShaderCount.ToString() + "  Shaders Using Keywords: " + shaders.Count.ToString() + "\nKeywords: " + totalKeywords.ToString() + totalGlobalKeywordsTxt + " Variants: " + totalVariants.ToString();
                }
                else
                {
                    int keywordsPerc = totalUsedKeywords * 100 / totalKeywords;
                    int variantsPerc = totalBuildVariants * 100 / totalVariants;
                    statsText = "Shaders Found: " + totalShaderCount.ToString() + "  Shaders Using Keywords: " + shaders.Count.ToString() + "\nUsed Keywords: " + totalUsedKeywords.ToString() + " of " + totalKeywords.ToString() + " (" + keywordsPerc.ToString() + "%) " + totalGlobalKeywordsTxt + " Actual Variants: " + totalBuildVariants.ToString() + " of " + totalVariants.ToString() + " (" + variantsPerc.ToString() + "%)";
                }
                if (totalBuildShaders == 0)
                {
                    statsText += "\nNote: Total keyword count maybe higher. Use 'Build View' tab to detect additional shaders/keywords used by Unity.";
                }
                else if (plusBuildKeywords > 0)
                {
                    statsText += "\n+ " + plusBuildKeywords + " additional keywords detected in last build.";
                }
                EditorGUILayout.HelpBox(statsText, MessageType.Info);
                EditorGUILayout.Separator();
                int shaderCount = shaders.Count;
                if (shaderCount > 0)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Sort By", GUILayout.Width(100));
                    SortType prevSortType = sortType;
                    sortType = (SortType)EditorGUILayout.EnumPopup(sortType);
                    if (sortType != prevSortType)
                    {
                        ScanProject();
                        GUIUtility.ExitGUI();
                        return;
                    }
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Name Filter", GUILayout.Width(100));
                    projectShaderNameFilter = EditorGUILayout.TextField(projectShaderNameFilter);
                    if (GUILayout.Button(new GUIContent("Clear", "Clear filter."), EditorStyles.miniButton, GUILayout.Width(60)))
                    {
                        projectShaderNameFilter    = "";
                        GUIUtility.keyboardControl = 0;
                    }
                    EditorGUILayout.EndHorizontal();

                    if (sortType != SortType.Keyword)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Keywords >=", GUILayout.Width(100));
                        minimumKeywordCount = EditorGUILayout.IntSlider(minimumKeywordCount, 0, maxKeywordsCountFound);
                        EditorGUILayout.EndHorizontal();
                    }

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Keyword Filter", GUILayout.Width(100));
                    keywordFilter = EditorGUILayout.TextField(keywordFilter);
                    if (GUILayout.Button(new GUIContent("Clear", "Clear filter."), EditorStyles.miniButton, GUILayout.Width(60)))
                    {
                        keywordFilter = "";
                        GUIUtility.keyboardControl = 0;
                    }
                    EditorGUILayout.EndHorizontal();

                    if (sortType != SortType.Material)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Keyword Scope", GUILayout.Width(100));
                        keywordScopeFilter = (KeywordScopeFilter)EditorGUILayout.EnumPopup(keywordScopeFilter);
                        EditorGUILayout.EndHorizontal();

                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Pragma Type", GUILayout.Width(100));
                        pragmaTypeFilter = (PragmaTypeFilter)EditorGUILayout.EnumPopup(pragmaTypeFilter);
                        EditorGUILayout.EndHorizontal();

                        if (sortType != SortType.Keyword)
                        {
                            EditorGUILayout.BeginHorizontal();
                            EditorGUILayout.LabelField("Modified", GUILayout.Width(100));
                            modifiedStatus = (ModifiedStatus)EditorGUILayout.EnumPopup(modifiedStatus);
                            EditorGUILayout.EndHorizontal();
                            notIncludedInBuild = EditorGUILayout.ToggleLeft("List Shaders Not Used In Build", notIncludedInBuild);
                            if (notIncludedInBuild)
                            {
                                if (totalBuildShaders == 0)
                                {
                                    EditorGUILayout.HelpBox("No build data yet. Perform a build to detect which shaders are being included in your build. Use 'Quick Build' from the Build View tab to make a fast build.", MessageType.Error);
                                }
                            }
                        }

                        if (keywordScopeFilter != KeywordScopeFilter.GlobalKeywords || pragmaTypeFilter != PragmaTypeFilter.ShaderFeature)
                        {
                            if (totalGlobalShaderFeatures > 0)
                            {
                                if (GUILayout.Button(new GUIContent("Click to show " + totalGlobalShaderFeatures + " global keyword(s) found of type 'shader_feature'", "Lists all shaders using global keywords that can be converted to local safely.")))
                                {
                                    sortType                   = SortType.Keyword;
                                    keywordScopeFilter         = KeywordScopeFilter.GlobalKeywords;
                                    pragmaTypeFilter           = PragmaTypeFilter.ShaderFeature;
                                    keywordFilter              = "";
                                    GUIUtility.keyboardControl = 0;
                                    minimumKeywordCount        = 0;
                                }
                            }
                        }
                        else
                        {
                            if (sortType == SortType.Keyword && totalGlobalShaderFeatures > 1)
                            {
                                if (GUILayout.Button(new GUIContent("Convert all these " + totalGlobalShaderFeatures + " keyword(s) to local", "Converts all global keywords of type Shader_Feature to local keywords, reducing the total keyword usage count.\n A local keyword does not count towards the limit of 256 total keywords in project.")))
                                {
                                    ConvertToLocalAll();
                                    EditorUtility.DisplayDialog("Process complete!", "All keywords of type shader_feature have been converted to local.\n\nPlease restart Unity to refresh keyword changes.", "Ok");
                                    ScanProject();
                                    GUIUtility.ExitGUI();
                                }
                            }
                        }
                    }
                    EditorGUILayout.Separator();
                }
                scrollViewPosProject = EditorGUILayout.BeginScrollView(scrollViewPosProject);
                if (sortType == SortType.Material)
                {
                    if (projectMaterials != null)
                    {
                        int matCount = projectMaterials.Count;
                        for (int s = 0; s < matCount; s++)
                        {
                            SCMaterial mat          = projectMaterials[s];
                            int        keywordCount = mat.keywords.Count;
                            if (keywordCount < minimumKeywordCount)
                            {
                                continue;
                            }
                            if (!string.IsNullOrEmpty(projectShaderNameFilter) && mat.unityMaterial.name.IndexOf(projectShaderNameFilter, StringComparison.InvariantCultureIgnoreCase) < 0)
                            {
                                continue;
                            }

                            mat.foldout = EditorGUILayout.Foldout(mat.foldout, new GUIContent("Material <b>" + mat.unityMaterial.name + "</b> referencing " + keywordCount + " keywords."), foldoutRTF);
                            if (mat.foldout)
                            {
                                for (int m = 0; m < keywordCount; m++)
                                {
                                    EditorGUILayout.BeginHorizontal();
                                    EditorGUILayout.LabelField("", GUILayout.Width(30));
                                    EditorGUILayout.LabelField(shaderIcon, GUILayout.Width(18));
                                    EditorGUILayout.LabelField(mat.keywords[m].name);
                                    if (GUILayout.Button(new GUIContent("Locate", "Locates material in project."), EditorStyles.miniButton, GUILayout.Width(60)))
                                    {
                                        Selection.activeObject = mat.unityMaterial;
                                        EditorGUIUtility.PingObject(mat.unityMaterial);
                                    }
                                    if (GUILayout.Button(new GUIContent("Prune", "Removes keyword from this material."), EditorStyles.miniButton, GUILayout.Width(60)))
                                    {
                                        if (EditorUtility.DisplayDialog("Prune Keyword", "Remove this keyword from the material?", "Yes", "No"))
                                        {
                                            mat.unityMaterial.DisableKeyword(mat.keywords[m].name);
                                            EditorUtility.SetDirty(mat.unityMaterial);
                                            mat.RemoveKeyword(mat.keywords[m].name);
                                            GUIUtility.ExitGUI();
                                            return;
                                        }
                                    }
                                    if (GUILayout.Button(new GUIContent("Prune All", "Removes this keyword from all materials."), EditorStyles.miniButton, GUILayout.Width(80)))
                                    {
                                        if (EditorUtility.DisplayDialog("Prune All", "Remove this keyword from all materials?", "Yes", "No"))
                                        {
                                            PruneMaterials(mat.keywords[m].name);
                                            UpdateProjectStats();
                                            GUIUtility.ExitGUI();
                                            return;
                                        }
                                    }
                                    EditorGUILayout.EndHorizontal();
                                }
                            }
                        }
                    }
                }
                else if (sortType == SortType.Keyword)
                {
                    if (keywordView != null)
                    {
                        int kvCount = keywordView.Count;
                        for (int s = 0; s < kvCount; s++)
                        {
                            SCKeyword keyword = keywordView[s].keyword;
                            if (keywordScopeFilter != KeywordScopeFilter.Any && ((keywordScopeFilter == KeywordScopeFilter.GlobalKeywords && !keyword.isGlobal) || (keywordScopeFilter == KeywordScopeFilter.LocalKeywords && keyword.isGlobal)))
                            {
                                continue;
                            }
                            if (pragmaTypeFilter != PragmaTypeFilter.Any && ((pragmaTypeFilter == PragmaTypeFilter.MultiCompile && !keyword.isMultiCompile) || (pragmaTypeFilter == PragmaTypeFilter.ShaderFeature && keyword.isMultiCompile)))
                            {
                                continue;
                            }
                            if (!string.IsNullOrEmpty(keywordFilter) && keyword.name.IndexOf(keywordFilter, StringComparison.InvariantCultureIgnoreCase) < 0)
                            {
                                continue;
                            }
                            EditorGUILayout.BeginHorizontal();
                            keywordView[s].foldout = EditorGUILayout.Foldout(keywordView[s].foldout, new GUIContent("Keyword <b>" + keywordView[s].keyword + "</b> found in " + keywordView[s].shaders.Count + " shader(s)"), foldoutRTF);
                            GUILayout.FlexibleSpace();
                            if (!keyword.isMultiCompile && keyword.isGlobal)
                            {
                                if (GUILayout.Button("Convert To Local Keyword", EditorStyles.miniButtonRight, GUILayout.Width(190)))
                                {
                                    if (EditorUtility.DisplayDialog("Convert global keyword to local", "Keyword " + keyword.name + " will be converted to local. This means the keyword won't count toward the maximum global keyword limit (256). Continue?", "Ok", "Cancel"))
                                    {
                                        ConvertToLocal(keyword);
                                        ScanProject();
                                        GUIUtility.ExitGUI();
                                    }
                                }
                            }
                            else if (!keyword.isGlobal)
                            {
                                GUILayout.Label("(Local keyword)");
                            }
                            EditorGUILayout.EndHorizontal();
                            if (keywordView[s].foldout)
                            {
                                int kvShadersCount = keywordView[s].shaders.Count;
                                for (int m = 0; m < kvShadersCount; m++)
                                {
                                    EditorGUILayout.BeginHorizontal();
                                    EditorGUILayout.LabelField("", GUILayout.Width(30));
                                    EditorGUILayout.LabelField(shaderIcon, GUILayout.Width(18));
                                    EditorGUILayout.LabelField(keywordView[s].shaders[m].name);
                                    SCShader shader = keywordView[s].shaders[m];
                                    GUI.enabled = shader.hasSource;
                                    if (GUILayout.Button(new GUIContent("Locate", "Locates the shader in the shader view."), EditorStyles.miniButton, GUILayout.Width(60)))
                                    {
                                        Shader theShader = AssetDatabase.LoadAssetAtPath <Shader>(shader.path);
                                        Selection.activeObject = theShader;
                                        EditorGUIUtility.PingObject(theShader);
                                    }
                                    GUI.enabled = true;
                                    if (GUILayout.Button(new GUIContent("Filter", "Show shaders using this keyword."), EditorStyles.miniButton, GUILayout.Width(60)))
                                    {
                                        keywordFilter = keywordView[s].keyword.name;
                                        sortType      = SortType.VariantsCount;
                                        GUIUtility.ExitGUI();
                                        return;
                                    }
                                    if (!shader.hasBackup)
                                    {
                                        GUI.enabled = false;
                                    }
                                    if (GUILayout.Button(new GUIContent("Restore", "Restores shader from the backup copy."), EditorStyles.miniButton))
                                    {
                                        RestoreShader(shader);
                                        GUIUtility.ExitGUI();
                                        return;
                                    }
                                    GUI.enabled = true;
                                    EditorGUILayout.EndHorizontal();
                                }
                            }
                        }
                    }
                }
                else
                {
                    int shadersListedCount = 0;

                    for (int s = 0; s < shaderCount; s++)
                    {
                        SCShader shader = shaders[s];
                        if (shader.keywordEnabledCount < minimumKeywordCount)
                        {
                            continue;
                        }
                        if (modifiedStatus == ModifiedStatus.OnlyModified && !shader.editedByShaderControl)
                        {
                            continue;
                        }
                        if (modifiedStatus == ModifiedStatus.NonModified && shader.editedByShaderControl)
                        {
                            continue;
                        }
                        bool filterByKeywordName = !string.IsNullOrEmpty(keywordFilter);
                        if (filterByKeywordName || keywordScopeFilter != KeywordScopeFilter.Any || pragmaTypeFilter != PragmaTypeFilter.Any)
                        {
                            int  kwCount = shader.keywords.Count;
                            bool found   = false;
                            for (int w = 0; w < kwCount; w++)
                            {
                                found = true;
                                SCKeyword keyword = shader.keywords[w];
                                if (filterByKeywordName)
                                {
                                    if (keyword.name.IndexOf(keywordFilter, StringComparison.InvariantCultureIgnoreCase) < 0)
                                    {
                                        found = false;
                                    }
                                }
                                if (keywordScopeFilter != KeywordScopeFilter.Any && ((keywordScopeFilter == KeywordScopeFilter.GlobalKeywords && !keyword.isGlobal) || (keywordScopeFilter == KeywordScopeFilter.LocalKeywords && keyword.isGlobal)))
                                {
                                    found = false;
                                }
                                if (pragmaTypeFilter != PragmaTypeFilter.Any && ((pragmaTypeFilter == PragmaTypeFilter.MultiCompile && !keyword.isMultiCompile) || (pragmaTypeFilter == PragmaTypeFilter.ShaderFeature && keyword.isMultiCompile)))
                                {
                                    found = false;
                                }
                                if (found)
                                {
                                    break;
                                }
                            }
                            if (!found)
                            {
                                continue;
                            }
                        }
                        if (!string.IsNullOrEmpty(projectShaderNameFilter) && shader.name.IndexOf(projectShaderNameFilter, StringComparison.InvariantCultureIgnoreCase) < 0)
                        {
                            continue;
                        }
                        if (notIncludedInBuild && totalBuildShaders > 0)
                        {
                            bool included = false;
                            for (int sb = 0; sb < totalBuildShaders; sb++)
                            {
                                if (shadersBuildInfo.shaders[sb].name.Equals(shader.fullName))
                                {
                                    included = true;
                                    break;
                                }
                            }
                            if (included)
                            {
                                continue;
                            }
                        }

                        shadersListedCount++;
                        EditorGUILayout.BeginHorizontal();
                        string shaderName = shader.isReadOnly ? shader.name + " (readonly)" : shader.name;
                        if (shader.hasSource)
                        {
                            shader.foldout = EditorGUILayout.Foldout(shader.foldout, new GUIContent(shaderName + " (" + shader.keywords.Count + " keywords, " + shader.keywordEnabledCount + " used, " + shader.actualBuildVariantCount + " variants)"), shader.editedByShaderControl ? foldoutBold : foldoutNormal);
                        }
                        else
                        {
                            shader.foldout = EditorGUILayout.Foldout(shader.foldout, new GUIContent(shaderName + " (" + shader.keywordEnabledCount + " keywords used by materials)"), foldoutDim);
                        }
                        EditorGUILayout.EndHorizontal();
                        if (shader.foldout)
                        {
                            EditorGUILayout.BeginHorizontal();
                            EditorGUILayout.LabelField("", GUILayout.Width(15));
                            if (shader.hasSource)
                            {
                                if (GUILayout.Button(new GUIContent("Locate", "Locate the shader in the project panel."), EditorStyles.miniButton))
                                {
                                    Shader theShader = AssetDatabase.LoadAssetAtPath <Shader>(shader.path);
                                    Selection.activeObject = theShader;
                                    EditorGUIUtility.PingObject(theShader);
                                }
                                if (!shader.isShaderGraph)
                                {
                                    if (GUILayout.Button(new GUIContent("Open", "Open the shader with the system default editor."), EditorStyles.miniButton))
                                    {
                                        EditorUtility.OpenWithDefaultApp(shader.path);
                                    }
                                    if (!shader.pendingChanges)
                                    {
                                        GUI.enabled = false;
                                    }
                                    if (GUILayout.Button(new GUIContent("Save", "Saves any keyword change to the shader file (disable/enable the keywords just clicking on the toggle next to the keywords shown below). A backup is created in the same folder."), EditorStyles.miniButton))
                                    {
                                        UpdateShader(shader);
                                    }
                                    GUI.enabled = true;
                                }
                                if (!shader.hasBackup)
                                {
                                    GUI.enabled = false;
                                }
                                if (GUILayout.Button(new GUIContent("Restore", "Restores shader from the backup copy."), EditorStyles.miniButton))
                                {
                                    RestoreShader(shader);
                                    GUIUtility.ExitGUI();
                                    return;
                                }
                                GUI.enabled = true;
                            }
                            else
                            {
                                EditorGUILayout.LabelField("(Shader source not available)");
                            }
                            if (shader.materials.Count > 0)
                            {
                                if (GUILayout.Button(new GUIContent(shader.showMaterials ? "Hide Materials" : "List Materials", "Show or hide the materials that use these keywords."), EditorStyles.miniButton))
                                {
                                    shader.showMaterials = !shader.showMaterials;
                                    GUIUtility.ExitGUI();
                                    return;
                                }
                                if (shader.showMaterials)
                                {
                                    EditorGUILayout.EndHorizontal();
                                    EditorGUILayout.BeginHorizontal();
                                    EditorGUILayout.LabelField("", GUILayout.Width(15));
                                    if (GUILayout.Button("Select Materials In Project", EditorStyles.miniButton))
                                    {
                                        int             matCount     = shader.materials.Count;
                                        List <Material> allMaterials = new List <Material>();
                                        for (int m = 0; m < matCount; m++)
                                        {
                                            SCMaterial material = shader.materials[m];
                                            allMaterials.Add(material.unityMaterial);
                                        }
                                        if (allMaterials.Count > 0)
                                        {
                                            Selection.objects = allMaterials.ToArray();
                                            EditorGUIUtility.PingObject(allMaterials[0]);
                                        }
                                        else
                                        {
                                            EditorUtility.DisplayDialog("Select Materials In Project", "No matching materials found in project.", "Ok");
                                        }
                                    }
                                    if (GUILayout.Button("Select Materials In Scene", EditorStyles.miniButton))
                                    {
                                        int matCount          = shader.materials.Count;
                                        List <GameObject> gos = new List <GameObject>();
                                        Renderer[]        rr  = FindObjectsOfType <Renderer>();
                                        foreach (Renderer r in rr)
                                        {
                                            GameObject go = r.gameObject;
                                            if (go == null)
                                            {
                                                continue;
                                            }
                                            if ((go.hideFlags & HideFlags.NotEditable) != 0 || (go.hideFlags & HideFlags.HideAndDontSave) != 0)
                                            {
                                                continue;
                                            }

                                            Material[] mats = r.sharedMaterials;
                                            if (mats == null)
                                            {
                                                continue;
                                            }

                                            for (int m = 0; m < matCount; m++)
                                            {
                                                Material mat = shader.materials[m].unityMaterial;
                                                for (int sm = 0; sm < mats.Length; sm++)
                                                {
                                                    Debug.Log(mat.name + " " + mats[sm].name);
                                                    if (mats[sm] == mat)
                                                    {
                                                        gos.Add(go);
                                                        m = matCount;
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        if (gos.Count > 0)
                                        {
                                            Selection.objects = gos.ToArray();
                                        }
                                        else
                                        {
                                            EditorUtility.DisplayDialog("Select Materials In Scene", "No matching materials found in objects of this scene.", "Ok");
                                        }
                                    }
                                }
                            }
                            EditorGUILayout.EndHorizontal();

                            for (int k = 0; k < shader.keywords.Count; k++)
                            {
                                SCKeyword keyword = shader.keywords[k];
                                if (keyword.isUnderscoreKeyword)
                                {
                                    continue;
                                }
                                EditorGUILayout.BeginHorizontal();
                                EditorGUILayout.LabelField("", GUILayout.Width(15));
                                if (shader.hasSource && !shader.isShaderGraph)
                                {
                                    bool prevState = keyword.enabled;
                                    keyword.enabled = EditorGUILayout.Toggle(prevState, GUILayout.Width(18));
                                    if (prevState != keyword.enabled)
                                    {
                                        shader.pendingChanges = true;
                                        shader.UpdateVariantCount();
                                        UpdateProjectStats();
                                        GUIUtility.ExitGUI();
                                        return;
                                    }
                                }
                                else
                                {
                                    EditorGUILayout.Toggle(true, GUILayout.Width(18));
                                }
                                EditorGUILayout.LabelField(keyword.verboseName);
                                if (keyword.enabled)
                                {
                                    if (!shader.hasSource && GUILayout.Button(new GUIContent("Prune Keyword", "Removes the keyword from all materials that reference it."), EditorStyles.miniButton, GUILayout.Width(110)))
                                    {
                                        if (EditorUtility.DisplayDialog("Prune Keyword", "This option will disable the keyword " + keyword.name + " in all materials that use " + shader.name + " shader.\nDo you want to continue?", "Ok", "Cancel"))
                                        {
                                            PruneMaterials(keyword.name);
                                            UpdateProjectStats();
                                        }
                                    }
                                    if (!keyword.isMultiCompile && keyword.isGlobal)
                                    {
                                        if (GUILayout.Button("Convert To Local Keyword", EditorStyles.miniButtonRight, GUILayout.Width(190)))
                                        {
                                            if (EditorUtility.DisplayDialog("Convert global keyword to local", "Keyword " + keyword.name + " will be converted to local. This means the keyword won't count toward the maximum global keyword limit (256). Continue?", "Ok", "Cancel"))
                                            {
                                                ConvertToLocal(keyword);
                                                ScanProject();
                                                GUIUtility.ExitGUI();
                                            }
                                        }
                                    }
                                }
                                EditorGUILayout.EndHorizontal();
                                if (shader.showMaterials)
                                {
                                    // show materials using this shader
                                    int matCount = shader.materials.Count;
                                    for (int m = 0; m < matCount; m++)
                                    {
                                        SCMaterial material = shader.materials[m];
                                        if (material.ContainsKeyword(keyword.name))
                                        {
                                            EditorGUILayout.BeginHorizontal();
                                            EditorGUILayout.LabelField("", GUILayout.Width(30));
                                            EditorGUILayout.LabelField(matIcon, GUILayout.Width(18));
                                            EditorGUILayout.LabelField(material.unityMaterial.name);
                                            if (GUILayout.Button(new GUIContent("Locate", "Locates the material in the project panel."), EditorStyles.miniButton, GUILayout.Width(60)))
                                            {
                                                Material theMaterial = AssetDatabase.LoadAssetAtPath <Material>(material.path) as Material;
                                                Selection.activeObject = theMaterial;
                                                EditorGUIUtility.PingObject(theMaterial);
                                            }
                                            EditorGUILayout.EndHorizontal();
                                        }
                                    }
                                }
                            }

                            if (shader.showMaterials)
                            {
                                // show materials using this shader that does not use any keywords
                                bool first    = true;
                                int  matCount = shader.materials.Count;
                                for (int m = 0; m < matCount; m++)
                                {
                                    SCMaterial material = shader.materials[m];
                                    if (material.keywords.Count == 0)
                                    {
                                        if (first)
                                        {
                                            first = false;
                                            EditorGUILayout.BeginHorizontal();
                                            EditorGUILayout.LabelField("", GUILayout.Width(15));
                                            EditorGUILayout.LabelField("Materials using this shader and no keywords:");
                                            EditorGUILayout.EndHorizontal();
                                        }
                                        EditorGUILayout.BeginHorizontal();
                                        EditorGUILayout.LabelField("", GUILayout.Width(15));
                                        EditorGUILayout.LabelField(matIcon, GUILayout.Width(18));
                                        EditorGUILayout.LabelField(material.unityMaterial.name);
                                        if (GUILayout.Button(new GUIContent("Locate", "Locates the material in the project panel."), EditorStyles.miniButton, GUILayout.Width(60)))
                                        {
                                            Material theMaterial = AssetDatabase.LoadAssetAtPath <Material>(material.path) as Material;
                                            Selection.activeObject = theMaterial;
                                            EditorGUIUtility.PingObject(theMaterial);
                                        }
                                        EditorGUILayout.EndHorizontal();
                                    }
                                }
                            }
                        }
                        EditorGUILayout.Separator();
                    }
                    if (shadersListedCount == 0 && !string.IsNullOrEmpty(projectShaderNameFilter))
                    {
                        EditorGUILayout.HelpBox("No shader matching '" + projectShaderNameFilter + "' name found. Either the shader doesn't exist in the project as source file or the shader does not use explicit keywords.", MessageType.Info);
                    }
                }
                EditorGUILayout.EndScrollView();
            }
        }
예제 #17
0
        void UpdateProjectStats()
        {
            totalKeywords             = 0;
            totalGlobalKeywords       = 0;
            totalUsedKeywords         = 0;
            totalVariants             = 0;
            totalBuildVariants        = 0;
            totalGlobalShaderFeatures = 0;

            if (shaders == null)
            {
                return;
            }

            if (keywordsDict == null)
            {
                keywordsDict = new Dictionary <string, SCKeyword>();
            }
            else
            {
                keywordsDict.Clear();
            }
            if (uniqueKeywords == null)
            {
                uniqueKeywords = new Dictionary <string, List <SCShader> >();
            }
            else
            {
                uniqueKeywords.Clear();
            }
            if (uniqueEnabledKeywords == null)
            {
                uniqueEnabledKeywords = new Dictionary <string, List <SCShader> >();
            }
            else
            {
                uniqueEnabledKeywords.Clear();
            }

            int shadersCount = shaders.Count;

            for (int k = 0; k < shadersCount; k++)
            {
                SCShader shader        = shaders[k];
                int      keywordsCount = shader.keywords.Count;
                for (int w = 0; w < keywordsCount; w++)
                {
                    SCKeyword       keyword = shader.keywords[w];
                    List <SCShader> shadersWithThisKeyword;
                    if (!uniqueKeywords.TryGetValue(keyword.name, out shadersWithThisKeyword))
                    {
                        shadersWithThisKeyword       = new List <SCShader>();
                        uniqueKeywords[keyword.name] = shadersWithThisKeyword;
                        totalKeywords++;
                        if (keyword.isGlobal)
                        {
                            totalGlobalKeywords++;
                        }
                        if (keyword.isGlobal && !keyword.isMultiCompile && keyword.enabled)
                        {
                            totalGlobalShaderFeatures++;
                        }
                        keywordsDict[keyword.name] = keyword;
                    }
                    shadersWithThisKeyword.Add(shader);
                    if (keyword.enabled)
                    {
                        List <SCShader> shadersWithThisKeywordEnabled;
                        if (!uniqueEnabledKeywords.TryGetValue(keyword.name, out shadersWithThisKeywordEnabled))
                        {
                            shadersWithThisKeywordEnabled       = new List <SCShader>();
                            uniqueEnabledKeywords[keyword.name] = shadersWithThisKeywordEnabled;
                            totalUsedKeywords++;
                        }
                        shadersWithThisKeywordEnabled.Add(shader);
                    }
                }
                totalVariants      += shader.totalVariantCount;
                totalBuildVariants += shader.actualBuildVariantCount;
            }

            if (keywordView == null)
            {
                keywordView = new List <KeywordView>();
            }
            else
            {
                keywordView.Clear();
            }
            foreach (KeyValuePair <string, List <SCShader> > kvp in uniqueEnabledKeywords)
            {
                SCKeyword kw;
                if (!keywordsDict.TryGetValue(kvp.Key, out kw))
                {
                    continue;
                }
                KeywordView kv = new KeywordView {
                    keyword = kw, shaders = kvp.Value
                };
                keywordView.Add(kv);
            }
            keywordView.Sort(delegate(KeywordView x, KeywordView y) {
                return(y.shaders.Count.CompareTo(x.shaders.Count));
            });

            // Compute which keywords in build are not present in project
            plusBuildKeywords = 0;
            if (buildKeywordView != null)
            {
                int count = buildKeywordView.Count;
                for (int k = 0; k < count; k++)
                {
                    BuildKeywordView bkv = buildKeywordView[k];
                    if (!uniqueKeywords.ContainsKey(bkv.keyword))
                    {
                        plusBuildKeywords++;
                    }
                }
            }
        }
예제 #18
0
        void UpdateShaderNonGraph(SCShader shader)
        {
            // Reads and updates shader from disk
            string[]      shaderLines   = File.ReadAllLines(shader.path);
            string[]      separator     = new string[] { " " };
            StringBuilder sb            = new StringBuilder();
            int           pragmaControl = 0;

            shader.editedByShaderControl = false;
            SCKeywordLine keywordLine  = new SCKeywordLine();
            bool          blockComment = false;

            for (int k = 0; k < shaderLines.Length; k++)
            {
                int lineCommentIndex = shaderLines[k].IndexOf("//");
                int blocCommentIndex = shaderLines[k].IndexOf("/*");
                int endCommentIndex  = shaderLines[k].IndexOf("*/");
                if (blocCommentIndex > 0 && (lineCommentIndex > blocCommentIndex || lineCommentIndex < 0))
                {
                    blockComment = true;
                }
                if (endCommentIndex > blocCommentIndex && (lineCommentIndex > endCommentIndex || lineCommentIndex < 0))
                {
                    blockComment = false;
                }

                int        j          = -1;
                PragmaType pragmaType = PragmaType.Unknown;
                if (!blockComment)
                {
                    j = shaderLines[k].IndexOf(PRAGMA_COMMENT_MARK);
                    if (j >= 0)
                    {
                        pragmaControl = 1;
                    }
                    j = shaderLines[k].IndexOf(SCKeywordLine.PRAGMA_MULTICOMPILE_GLOBAL);
                    if (j >= 0)
                    {
                        pragmaType = PragmaType.MultiCompileGlobal;
                    }
                    else
                    {
                        j = shaderLines[k].IndexOf(SCKeywordLine.PRAGMA_FEATURE_GLOBAL);
                        if (j >= 0)
                        {
                            pragmaType = PragmaType.FeatureGlobal;
                        }
                        else
                        {
                            j = shaderLines[k].IndexOf(SCKeywordLine.PRAGMA_MULTICOMPILE_LOCAL);
                            if (j >= 0)
                            {
                                pragmaType = PragmaType.MultiCompileLocal;
                            }
                            else
                            {
                                j = shaderLines[k].IndexOf(SCKeywordLine.PRAGMA_FEATURE_LOCAL);
                                if (j >= 0)
                                {
                                    pragmaType = PragmaType.FeatureLocal;
                                }
                            }
                        }
                    }
                    if (pragmaControl != 1 && lineCommentIndex == 0 && shaderLines[k].IndexOf(PRAGMA_DISABLED_MARK) < 0)
                    {
                        // do not process a commented line
                        j = -1;
                    }
                }
                if (j >= 0)
                {
                    if (pragmaControl != 2)
                    {
                        keywordLine.Clear();
                    }
                    keywordLine.pragmaType = pragmaType;
                    j = shaderLines[k].IndexOf(' ', j + 20) + 1; // first space after pragma declaration
                    if (j >= shaderLines[k].Length)
                    {
                        continue;
                    }
                    // exclude potential comments inside the #pragma line
                    int lastStringPos = shaderLines[k].IndexOf("//", j);
                    if (lastStringPos < 0)
                    {
                        lastStringPos = shaderLines[k].Length;
                    }
                    int      length = lastStringPos - j;
                    string[] kk     = shaderLines[k].Substring(j, length).Split(separator, StringSplitOptions.RemoveEmptyEntries);
                    // Sanitize keywords
                    for (int i = 0; i < kk.Length; i++)
                    {
                        kk[i] = kk[i].Trim();
                    }
                    // Act on keywords
                    switch (pragmaControl)
                    {
                    case 1:
                        // Read original keywords
                        for (int s = 0; s < kk.Length; s++)
                        {
                            SCKeyword keyword = shader.GetKeyword(kk[s]);
                            keywordLine.Add(keyword);
                        }
                        pragmaControl = 2;
                        break;

                    case 0:
                    case 2:
                        if (pragmaControl == 0)
                        {
                            for (int s = 0; s < kk.Length; s++)
                            {
                                SCKeyword keyword = shader.GetKeyword(kk[s]);
                                keywordLine.Add(keyword);
                            }
                        }
                        int kCount        = keywordLine.keywordCount;
                        int kEnabledCount = keywordLine.keywordsEnabledCount;
                        if (kEnabledCount < kCount)
                        {
                            // write original keywords
                            if (kEnabledCount == 0)
                            {
                                sb.Append(PRAGMA_DISABLED_MARK);
                            }
                            else
                            {
                                sb.Append(PRAGMA_COMMENT_MARK);
                            }
                            shader.editedByShaderControl = true;
                            sb.Append(keywordLine.GetPragma());
                            if (keywordLine.hasUnderscoreVariant)
                            {
                                sb.Append(PRAGMA_UNDERSCORE);
                            }
                            for (int s = 0; s < kCount; s++)
                            {
                                SCKeyword keyword = keywordLine.keywords[s];
                                sb.Append(keyword.name);
                                if (s < kCount - 1)
                                {
                                    sb.Append(" ");
                                }
                            }
                            sb.AppendLine();
                        }

                        if (kEnabledCount > 0)
                        {
                            // Write actual keywords
                            sb.Append(keywordLine.GetPragma());
                            if (keywordLine.hasUnderscoreVariant)
                            {
                                sb.Append(PRAGMA_UNDERSCORE);
                            }
                            for (int s = 0; s < kCount; s++)
                            {
                                SCKeyword keyword = keywordLine.keywords[s];
                                if (keyword.enabled)
                                {
                                    sb.Append(keyword.name);
                                    if (s < kCount - 1)
                                    {
                                        sb.Append(" ");
                                    }
                                }
                            }
                            sb.AppendLine();
                        }
                        pragmaControl = 0;
                        break;
                    }
                }
                else
                {
                    sb.AppendLine(shaderLines[k]);
                }
            }

            // Writes modified shader
            File.WriteAllText(shader.path, sb.ToString());
            AssetDatabase.Refresh();
        }
예제 #19
0
        void ScanShaderNonGraph(SCShader shader)
        {
            // Reads shader
            string[]      shaderLines   = File.ReadAllLines(shader.path);
            string[]      separator     = new string[] { " " };
            SCShaderPass  currentPass   = new SCShaderPass();
            SCShaderPass  basePass      = null;
            int           pragmaControl = 0;
            int           pass          = -1;
            bool          blockComment  = false;
            SCKeywordLine keywordLine   = new SCKeywordLine();

            for (int k = 0; k < shaderLines.Length; k++)
            {
                string line = shaderLines[k].Trim();
                if (line.Length == 0)
                {
                    continue;
                }

                int lineCommentIndex = line.IndexOf("//");
                int blocCommentIndex = line.IndexOf("/*");
                int endCommentIndex  = line.IndexOf("*/");
                if (blocCommentIndex > 0 && (lineCommentIndex > blocCommentIndex || lineCommentIndex < 0))
                {
                    blockComment = true;
                }
                if (endCommentIndex > blocCommentIndex && (lineCommentIndex > endCommentIndex || lineCommentIndex < 0))
                {
                    blockComment = false;
                }
                if (blockComment)
                {
                    continue;
                }

                string lineUPPER = line.ToUpper();
                if (lineUPPER.Equals("PASS") || lineUPPER.StartsWith("PASS "))
                {
                    if (pass >= 0)
                    {
                        currentPass.pass = pass;
                        if (basePass != null)
                        {
                            currentPass.Add(basePass.keywordLines);
                        }
                        shader.Add(currentPass);
                    }
                    else if (currentPass.keywordCount > 0)
                    {
                        basePass = currentPass;
                    }
                    currentPass = new SCShaderPass();
                    pass++;
                    continue;
                }
                int j = line.IndexOf(PRAGMA_COMMENT_MARK);
                if (j >= 0)
                {
                    pragmaControl = 1;
                }
                else
                {
                    j = line.IndexOf(PRAGMA_DISABLED_MARK);
                    if (j >= 0)
                    {
                        pragmaControl = 3;
                    }
                }
                if (lineCommentIndex == 0 && pragmaControl != 1 && pragmaControl != 3)
                {
                    continue; // do not process lines commented by user
                }

                PragmaType pragmaType = PragmaType.Unknown;
                int        offset     = 0;
                j = line.IndexOf(SCKeywordLine.PRAGMA_MULTICOMPILE_GLOBAL);
                if (j >= 0)
                {
                    pragmaType = PragmaType.MultiCompileGlobal;
                    offset     = SCKeywordLine.PRAGMA_MULTICOMPILE_GLOBAL.Length;
                }
                else
                {
                    j = line.IndexOf(SCKeywordLine.PRAGMA_FEATURE_GLOBAL);
                    if (j >= 0)
                    {
                        pragmaType = PragmaType.FeatureGlobal;
                        offset     = SCKeywordLine.PRAGMA_FEATURE_GLOBAL.Length;
                    }
                    else
                    {
                        j = line.IndexOf(SCKeywordLine.PRAGMA_MULTICOMPILE_LOCAL);
                        if (j >= 0)
                        {
                            pragmaType = PragmaType.MultiCompileLocal;
                            offset     = SCKeywordLine.PRAGMA_MULTICOMPILE_LOCAL.Length;
                        }
                        else
                        {
                            j = line.IndexOf(SCKeywordLine.PRAGMA_FEATURE_LOCAL);
                            if (j >= 0)
                            {
                                pragmaType = PragmaType.FeatureLocal;
                                offset     = SCKeywordLine.PRAGMA_FEATURE_LOCAL.Length;
                            }
                        }
                    }
                }
                if (j >= 0)
                {
                    if (pragmaControl != 2)
                    {
                        keywordLine = new SCKeywordLine();
                    }
                    keywordLine.pragmaType = pragmaType;
                    // exclude potential comments inside the #pragma line
                    int lastStringPos = line.IndexOf("//", j + offset);
                    if (lastStringPos < 0)
                    {
                        lastStringPos = line.Length;
                    }
                    int      length = lastStringPos - j - offset;
                    string[] kk     = line.Substring(j + offset, length).Split(separator, StringSplitOptions.RemoveEmptyEntries);
                    // Sanitize keywords
                    for (int i = 0; i < kk.Length; i++)
                    {
                        kk[i] = kk[i].Trim();
                    }
                    // Act on keywords
                    switch (pragmaControl)
                    {
                    case 1:     // Edited by Shader Control line
                        shader.editedByShaderControl = true;
                        // Add original keywords to current line
                        for (int s = 0; s < kk.Length; s++)
                        {
                            keywordLine.Add(shader.GetKeyword(kk[s]));
                        }
                        pragmaControl = 2;
                        break;

                    case 2:
                        // check enabled keywords
                        keywordLine.DisableKeywords();
                        for (int s = 0; s < kk.Length; s++)
                        {
                            SCKeyword keyword = keywordLine.GetKeyword(kk[s]);
                            if (keyword != null)
                            {
                                keyword.enabled = true;
                            }
                        }
                        currentPass.Add(keywordLine);
                        pragmaControl = 0;
                        break;

                    case 3:     // disabled by Shader Control line
                        shader.editedByShaderControl = true;
                        // Add original keywords to current line
                        for (int s = 0; s < kk.Length; s++)
                        {
                            SCKeyword keyword = shader.GetKeyword(kk[s]);
                            keyword.enabled = false;
                            keywordLine.Add(keyword);
                        }
                        currentPass.Add(keywordLine);
                        pragmaControl = 0;
                        break;

                    case 0:
                        // Add keywords to current line
                        for (int s = 0; s < kk.Length; s++)
                        {
                            keywordLine.Add(shader.GetKeyword(kk[s]));
                        }
                        currentPass.Add(keywordLine);
                        break;
                    }
                }
            }
            currentPass.pass = Mathf.Max(pass, 0);
            if (basePass != null)
            {
                currentPass.Add(basePass.keywordLines);
            }
            shader.Add(currentPass);
            shader.UpdateVariantCount();
        }
예제 #20
0
        void DrawProjectGUI()
        {
            GUILayout.Box(new GUIContent("List of shader files in your project and modify their keywords.\nOnly shaders with source code or referenced by materials are included in this tab.\nUse the <color=orange><b>Build View</b></color> tab for a complete list of shaders, including hidden/internal Unity shaders."), titleStyle);
            EditorGUILayout.BeginHorizontal();
            GUILayout.FlexibleSpace();
            scanAllShaders = EditorGUILayout.Toggle(new GUIContent("Force scan all shaders", "Also includes shaders that are not located within a Resources folder"), scanAllShaders);
            EditorGUILayout.EndHorizontal();

            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button(new GUIContent("Scan Project Folders", "Quickly scans the project and finds shaders that use keywords.")))
            {
                ScanProject();
                GUIUtility.ExitGUI();
                return;
            }
            if (shaders != null && shaders.Count > 0 && GUILayout.Button(new GUIContent("Clean All Materials", "Removes all disabled keywords in all materials.  This option is provided to ensure no existing materials are referencing a disabled shader keyword.\n\nTo disable keywords, first expand any shader from the list and uncheck the unwanted keywords (press 'Save' to modify the shader file and to clean any existing material that uses that specific shader)."), GUILayout.Width(120)))
            {
                CleanAllMaterials();
                GUIUtility.ExitGUI();
                return;
            }
            if (GUILayout.Button("Help", GUILayout.Width(40)))
            {
                ShowHelpWindowProjectView();
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();

            if (shaders != null)
            {
                string totalGlobalKeywordsTxt = totalGlobalKeywords != totalKeywords ? " (" + totalGlobalKeywords + " global) " : " ";
                if (totalKeywords == totalUsedKeywords || totalKeywords == 0)
                {
                    EditorGUILayout.HelpBox("Shaders Found: " + totalShaderCount.ToString() + "  Shaders Using Keywords: " + shaders.Count.ToString() + "\nKeywords: " + totalKeywords.ToString() + totalGlobalKeywordsTxt + " Variants: " + totalVariants.ToString(), MessageType.Info);
                }
                else
                {
                    int keywordsPerc = totalUsedKeywords * 100 / totalKeywords;
                    int variantsPerc = totalBuildVariants * 100 / totalVariants;
                    EditorGUILayout.HelpBox("Shaders Found: " + totalShaderCount.ToString() + "  Shaders Using Keywords: " + shaders.Count.ToString() + "\nUsed Keywords: " + totalUsedKeywords.ToString() + " of " + totalKeywords.ToString() + " (" + keywordsPerc.ToString() + "%) " + totalGlobalKeywordsTxt + " Actual Variants: " + totalBuildVariants.ToString() + " of " + totalVariants.ToString() + " (" + variantsPerc.ToString() + "%)", MessageType.Info);
                }
                EditorGUILayout.Separator();
                int shaderCount = shaders.Count;
                if (shaderCount > 1)
                {
                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Sort By", GUILayout.Width(90));
                    SortType prevSortType = sortType;
                    sortType = (SortType)EditorGUILayout.EnumPopup(sortType);
                    if (sortType != prevSortType)
                    {
                        ScanProject();
                        EditorGUIUtility.ExitGUI();
                        return;
                    }
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Name Filter", GUILayout.Width(90));
                    projectShaderNameFilter = EditorGUILayout.TextField(projectShaderNameFilter);
                    if (GUILayout.Button(new GUIContent("Clear", "Clear filter."), EditorStyles.miniButton, GUILayout.Width(60)))
                    {
                        projectShaderNameFilter    = "";
                        GUIUtility.keyboardControl = 0;
                    }
                    EditorGUILayout.EndHorizontal();

                    if (sortType != SortType.Keyword)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Keywords >=", GUILayout.Width(90));
                        minimumKeywordCount = EditorGUILayout.IntSlider(minimumKeywordCount, 0, maxKeywordsCountFound);
                        EditorGUILayout.EndHorizontal();
                    }

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Keyword Filter", GUILayout.Width(90));
                    keywordFilter = EditorGUILayout.TextField(keywordFilter);
                    if (GUILayout.Button(new GUIContent("Clear", "Clear filter."), EditorStyles.miniButton, GUILayout.Width(60)))
                    {
                        keywordFilter = "";
                        GUIUtility.keyboardControl = 0;
                    }
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Keyword Scope", GUILayout.Width(90));
                    keywordScopeFilter = (KeywordScopeFilter)EditorGUILayout.EnumPopup(keywordScopeFilter);
                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();
                    EditorGUILayout.LabelField("Pragma Type", GUILayout.Width(90));
                    pragmaTypeFilter = (PragmaTypeFilter)EditorGUILayout.EnumPopup(pragmaTypeFilter);
                    EditorGUILayout.EndHorizontal();

                    if (sortType != SortType.Keyword)
                    {
                        EditorGUILayout.BeginHorizontal();
                        EditorGUILayout.LabelField("Modified", GUILayout.Width(90));
                        modifiedStatus = (ModifiedStatus)EditorGUILayout.EnumPopup(modifiedStatus);
                        EditorGUILayout.EndHorizontal();
                    }

                    if (keywordScopeFilter != KeywordScopeFilter.GlobalKeywords || pragmaTypeFilter != PragmaTypeFilter.ShaderFeature)
                    {
                        if (totalGlobalShaderFeatures > 0)
                        {
                            if (GUILayout.Button(new GUIContent("Click to show " + totalGlobalShaderFeatures + " global keyword(s) found of type 'shader_feature'", "Lists all shaders using global keywords that can be converted to local safely.")))
                            {
                                sortType                   = SortType.Keyword;
                                keywordScopeFilter         = KeywordScopeFilter.GlobalKeywords;
                                pragmaTypeFilter           = PragmaTypeFilter.ShaderFeature;
                                keywordFilter              = "";
                                GUIUtility.keyboardControl = 0;
                                minimumKeywordCount        = 0;
                            }
                        }
                    }
                    else
                    {
                        if (sortType == SortType.Keyword && totalGlobalShaderFeatures > 1)
                        {
                            if (GUILayout.Button(new GUIContent("Convert all these " + totalGlobalShaderFeatures + " keyword(s) to local", "Converts all global keywords of type Shader_Feature to local keywords, reducing the total keyword usage count.\n A local keyword does not count towards the limit of 256 total keywords in project.")))
                            {
                                ConvertToLocalAll();
                                EditorUtility.DisplayDialog("Process complete!", "All keywords of type shader_feature have been converted to local.\n\nPlease restart Unity to refresh keyword changes.", "Ok");
                                ScanProject();
                                GUIUtility.ExitGUI();
                            }
                        }
                    }
                    EditorGUILayout.Separator();
                }
                scrollViewPosProject = EditorGUILayout.BeginScrollView(scrollViewPosProject);
                if (sortType == SortType.Keyword)
                {
                    if (keywordView != null)
                    {
                        int kvCount = keywordView.Count;
                        for (int s = 0; s < kvCount; s++)
                        {
                            SCKeyword keyword = keywordView[s].keyword;
                            if (keywordScopeFilter != KeywordScopeFilter.Any && ((keywordScopeFilter == KeywordScopeFilter.GlobalKeywords && !keyword.isGlobal) || (keywordScopeFilter == KeywordScopeFilter.LocalKeywords && keyword.isGlobal)))
                            {
                                continue;
                            }
                            if (pragmaTypeFilter != PragmaTypeFilter.Any && ((pragmaTypeFilter == PragmaTypeFilter.MultiCompile && !keyword.isMultiCompile) || (pragmaTypeFilter == PragmaTypeFilter.ShaderFeature && keyword.isMultiCompile)))
                            {
                                continue;
                            }
                            if (!string.IsNullOrEmpty(keywordFilter) && keyword.name.IndexOf(keywordFilter, StringComparison.InvariantCultureIgnoreCase) < 0)
                            {
                                continue;
                            }
                            EditorGUILayout.BeginHorizontal();
                            keywordView[s].foldout = EditorGUILayout.Foldout(keywordView[s].foldout, new GUIContent("Keyword <b>" + keywordView[s].keyword + "</b> found in " + keywordView[s].shaders.Count + " shader(s)"), foldoutRTF);
                            GUILayout.FlexibleSpace();
                            if (!keyword.isMultiCompile && keyword.isGlobal)
                            {
                                if (GUILayout.Button("Convert To Local Keyword", EditorStyles.miniButtonRight))
                                {
                                    if (EditorUtility.DisplayDialog("Convert global keyword to local", "Keyword " + keyword.name + " will be converted to local. This means the keyword won't count toward the maximum global keyword limit (256). Continue?", "Ok", "Cancel"))
                                    {
                                        ConvertToLocal(keyword);
                                        ScanProject();
                                        GUIUtility.ExitGUI();
                                    }
                                }
                            }
                            else if (!keyword.isGlobal)
                            {
                                GUILayout.Label("(Local keyword)");
                            }
                            EditorGUILayout.EndHorizontal();
                            if (keywordView[s].foldout)
                            {
                                int kvShadersCount = keywordView[s].shaders.Count;
                                for (int m = 0; m < kvShadersCount; m++)
                                {
                                    EditorGUILayout.BeginHorizontal();
                                    EditorGUILayout.LabelField("", GUILayout.Width(30));
                                    EditorGUILayout.LabelField(shaderIcon, GUILayout.Width(18));
                                    EditorGUILayout.LabelField(keywordView[s].shaders[m].name);
                                    SCShader shader = keywordView[s].shaders[m];
                                    GUI.enabled = shader.hasSource;
                                    if (GUILayout.Button(new GUIContent("Locate", "Locates the shader in the shader view."), EditorStyles.miniButton, GUILayout.Width(60)))
                                    {
                                        Shader theShader = AssetDatabase.LoadAssetAtPath <Shader>(shader.path);
                                        Selection.activeObject = theShader;
                                        EditorGUIUtility.PingObject(theShader);
                                    }
                                    GUI.enabled = true;
                                    if (GUILayout.Button(new GUIContent("Filter", "Show shaders using this keyword."), EditorStyles.miniButton, GUILayout.Width(60)))
                                    {
                                        keywordFilter = keywordView[s].keyword.name;
                                        sortType      = SortType.VariantsCount;
                                        GUIUtility.ExitGUI();
                                        return;
                                    }
                                    if (!shader.hasBackup)
                                    {
                                        GUI.enabled = false;
                                    }
                                    if (GUILayout.Button(new GUIContent("Restore", "Restores shader from the backup copy."), EditorStyles.miniButton))
                                    {
                                        RestoreShader(shader);
                                        GUIUtility.ExitGUI();
                                        return;
                                    }
                                    GUI.enabled = true;
                                    EditorGUILayout.EndHorizontal();
                                }
                            }
                        }
                    }
                }
                else
                {
                    int shadersListedCount = 0;
                    for (int s = 0; s < shaderCount; s++)
                    {
                        SCShader shader = shaders[s];
                        if (shader.keywordEnabledCount < minimumKeywordCount)
                        {
                            continue;
                        }
                        if (modifiedStatus == ModifiedStatus.OnlyModified && !shader.editedByShaderControl)
                        {
                            continue;
                        }
                        if (modifiedStatus == ModifiedStatus.NonModified && shader.editedByShaderControl)
                        {
                            continue;
                        }
                        bool filterByKeywordName = !string.IsNullOrEmpty(keywordFilter);
                        if (filterByKeywordName || keywordScopeFilter != KeywordScopeFilter.Any || pragmaTypeFilter != PragmaTypeFilter.Any)
                        {
                            int  kwCount = shader.keywords.Count;
                            bool found   = false;
                            for (int w = 0; w < kwCount; w++)
                            {
                                found = true;
                                SCKeyword keyword = shader.keywords[w];
                                if (filterByKeywordName)
                                {
                                    if (keyword.name.IndexOf(keywordFilter, StringComparison.InvariantCultureIgnoreCase) < 0)
                                    {
                                        found = false;
                                    }
                                }
                                if (keywordScopeFilter != KeywordScopeFilter.Any && ((keywordScopeFilter == KeywordScopeFilter.GlobalKeywords && !keyword.isGlobal) || (keywordScopeFilter == KeywordScopeFilter.LocalKeywords && keyword.isGlobal)))
                                {
                                    found = false;
                                }
                                if (pragmaTypeFilter != PragmaTypeFilter.Any && ((pragmaTypeFilter == PragmaTypeFilter.MultiCompile && !keyword.isMultiCompile) || (pragmaTypeFilter == PragmaTypeFilter.ShaderFeature && keyword.isMultiCompile)))
                                {
                                    found = false;
                                }
                                if (found)
                                {
                                    break;
                                }
                            }
                            if (!found)
                            {
                                continue;
                            }
                        }
                        if (!string.IsNullOrEmpty(projectShaderNameFilter) && shader.name.IndexOf(projectShaderNameFilter, StringComparison.InvariantCultureIgnoreCase) < 0)
                        {
                            continue;
                        }

                        shadersListedCount++;
                        EditorGUILayout.BeginHorizontal();
                        string shaderName = shader.isReadOnly ? shader.name + " (readonly)" : shader.name;
                        if (shader.hasSource)
                        {
                            shader.foldout = EditorGUILayout.Foldout(shader.foldout, new GUIContent(shaderName + " (" + shader.keywords.Count + " keywords, " + shader.keywordEnabledCount + " used, " + shader.actualBuildVariantCount + " variants)"), shader.editedByShaderControl ? foldoutBold : foldoutNormal);
                        }
                        else
                        {
                            shader.foldout = EditorGUILayout.Foldout(shader.foldout, new GUIContent(shaderName + " (" + shader.keywordEnabledCount + " keywords used by materials)"), foldoutDim);
                        }
                        EditorGUILayout.EndHorizontal();
                        if (shader.foldout)
                        {
                            EditorGUILayout.BeginHorizontal();
                            EditorGUILayout.LabelField("", GUILayout.Width(15));
                            if (shader.hasSource)
                            {
                                if (GUILayout.Button(new GUIContent("Locate", "Locate the shader in the project panel."), EditorStyles.miniButton))
                                {
                                    Shader theShader = AssetDatabase.LoadAssetAtPath <Shader>(shader.path);
                                    Selection.activeObject = theShader;
                                    EditorGUIUtility.PingObject(theShader);
                                }
                                if (GUILayout.Button(new GUIContent("Open", "Open the shader with the system default editor."), EditorStyles.miniButton))
                                {
                                    EditorUtility.OpenWithDefaultApp(shader.path);
                                }
                                if (!shader.pendingChanges)
                                {
                                    GUI.enabled = false;
                                }
                                if (GUILayout.Button(new GUIContent("Save", "Saves any keyword change to the shader file (disable/enable the keywords just clicking on the toggle next to the keywords shown below). A backup is created in the same folder."), EditorStyles.miniButton))
                                {
                                    UpdateShader(shader);
                                }
                                GUI.enabled = true;
                                if (!shader.hasBackup)
                                {
                                    GUI.enabled = false;
                                }
                                if (GUILayout.Button(new GUIContent("Restore", "Restores shader from the backup copy."), EditorStyles.miniButton))
                                {
                                    RestoreShader(shader);
                                    GUIUtility.ExitGUI();
                                    return;
                                }
                                GUI.enabled = true;
                            }
                            else
                            {
                                EditorGUILayout.LabelField("(Shader source not available)");
                            }
                            if (shader.materials.Count > 0)
                            {
                                if (GUILayout.Button(new GUIContent(shader.showMaterials ? "Hide Materials" : "List Materials", "Show or hide the materials that use these keywords."), EditorStyles.miniButton))
                                {
                                    shader.showMaterials = !shader.showMaterials;
                                    GUIUtility.ExitGUI();
                                    return;
                                }
                                if (shader.showMaterials)
                                {
                                    EditorGUILayout.EndHorizontal();
                                    EditorGUILayout.BeginHorizontal();
                                    EditorGUILayout.LabelField("", GUILayout.Width(15));
                                    if (GUILayout.Button("Select Materials In Project", EditorStyles.miniButton))
                                    {
                                        int             matCount     = shader.materials.Count;
                                        List <Material> allMaterials = new List <Material>();
                                        for (int m = 0; m < matCount; m++)
                                        {
                                            SCMaterial material = shader.materials[m];
                                            allMaterials.Add(material.unityMaterial);
                                        }
                                        if (allMaterials.Count > 0)
                                        {
                                            Selection.objects = allMaterials.ToArray();
                                            EditorGUIUtility.PingObject(allMaterials[0]);
                                        }
                                        else
                                        {
                                            EditorUtility.DisplayDialog("Select Materials In Project", "No matching materials found in project.", "Ok");
                                        }
                                    }
                                    if (GUILayout.Button("Select Materials In Scene", EditorStyles.miniButton))
                                    {
                                        int matCount          = shader.materials.Count;
                                        List <GameObject> gos = new List <GameObject>();
                                        Renderer[]        rr  = FindObjectsOfType <Renderer>();
                                        foreach (Renderer r in rr)
                                        {
                                            GameObject go = r.gameObject;
                                            if (go == null)
                                            {
                                                continue;
                                            }
                                            if ((go.hideFlags & HideFlags.NotEditable) != 0 || (go.hideFlags & HideFlags.HideAndDontSave) != 0)
                                            {
                                                continue;
                                            }

                                            Material[] mats = r.sharedMaterials;
                                            if (mats == null)
                                            {
                                                continue;
                                            }

                                            for (int m = 0; m < matCount; m++)
                                            {
                                                Material mat = shader.materials[m].unityMaterial;
                                                for (int sm = 0; sm < mats.Length; sm++)
                                                {
                                                    Debug.Log(mat.name + " " + mats[sm].name);
                                                    if (mats[sm] == mat)
                                                    {
                                                        gos.Add(go);
                                                        m = matCount;
                                                        break;
                                                    }
                                                }
                                            }
                                        }
                                        if (gos.Count > 0)
                                        {
                                            Selection.objects = gos.ToArray();
                                        }
                                        else
                                        {
                                            EditorUtility.DisplayDialog("Select Materials In Scene", "No matching materials found in objects of this scene.", "Ok");
                                        }
                                    }
                                }
                            }
                            EditorGUILayout.EndHorizontal();

                            for (int k = 0; k < shader.keywords.Count; k++)
                            {
                                SCKeyword keyword = shader.keywords[k];
                                if (keyword.isUnderscoreKeyword)
                                {
                                    continue;
                                }
                                EditorGUILayout.BeginHorizontal();
                                EditorGUILayout.LabelField("", GUILayout.Width(15));
                                if (shader.hasSource)
                                {
                                    bool prevState = keyword.enabled;
                                    keyword.enabled = EditorGUILayout.Toggle(prevState, GUILayout.Width(18));
                                    if (prevState != keyword.enabled)
                                    {
                                        shader.pendingChanges = true;
                                        shader.UpdateVariantCount();
                                        UpdateProjectStats();
                                        GUIUtility.ExitGUI();
                                        return;
                                    }
                                }
                                else
                                {
                                    EditorGUILayout.Toggle(true, GUILayout.Width(18));
                                }
                                if (!keyword.enabled)
                                {
                                    EditorGUILayout.LabelField(keyword.verboseName);
                                }
                                else
                                {
                                    EditorGUILayout.LabelField(keyword.verboseName);
                                    if (!shader.hasSource && GUILayout.Button(new GUIContent("Prune Keyword", "Removes the keyword from all materials that reference it."), EditorStyles.miniButton, GUILayout.Width(110)))
                                    {
                                        if (EditorUtility.DisplayDialog("Prune Keyword", "This option will disable the keyword " + keyword.name + " in all materials that use " + shader.name + " shader.\nDo you want to continue?", "Ok", "Cancel"))
                                        {
                                            PruneMaterials(shader, keyword.name);
                                            UpdateProjectStats();
                                        }
                                    }
                                }
                                EditorGUILayout.EndHorizontal();
                                if (shader.showMaterials)
                                {
                                    // show materials using this shader
                                    int matCount = shader.materials.Count;
                                    for (int m = 0; m < matCount; m++)
                                    {
                                        SCMaterial material = shader.materials[m];
                                        if (material.ContainsKeyword(keyword.name))
                                        {
                                            EditorGUILayout.BeginHorizontal();
                                            EditorGUILayout.LabelField("", GUILayout.Width(30));
                                            EditorGUILayout.LabelField(matIcon, GUILayout.Width(18));
                                            EditorGUILayout.LabelField(material.unityMaterial.name);
                                            if (GUILayout.Button(new GUIContent("Locate", "Locates the material in the project panel."), EditorStyles.miniButton, GUILayout.Width(60)))
                                            {
                                                Material theMaterial = AssetDatabase.LoadAssetAtPath <Material>(material.path) as Material;
                                                Selection.activeObject = theMaterial;
                                                EditorGUIUtility.PingObject(theMaterial);
                                            }
                                            EditorGUILayout.EndHorizontal();
                                        }
                                    }
                                }
                            }

                            if (shader.showMaterials)
                            {
                                // show materials using this shader that does not use any keywords
                                bool first    = true;
                                int  matCount = shader.materials.Count;
                                for (int m = 0; m < matCount; m++)
                                {
                                    SCMaterial material = shader.materials[m];
                                    if (material.keywords.Count == 0)
                                    {
                                        if (first)
                                        {
                                            first = false;
                                            EditorGUILayout.BeginHorizontal();
                                            EditorGUILayout.LabelField("", GUILayout.Width(15));
                                            EditorGUILayout.LabelField("Materials using this shader and no keywords:");
                                            EditorGUILayout.EndHorizontal();
                                        }
                                        EditorGUILayout.BeginHorizontal();
                                        EditorGUILayout.LabelField("", GUILayout.Width(15));
                                        EditorGUILayout.LabelField(matIcon, GUILayout.Width(18));
                                        EditorGUILayout.LabelField(material.unityMaterial.name);
                                        if (GUILayout.Button(new GUIContent("Locate", "Locates the material in the project panel."), EditorStyles.miniButton, GUILayout.Width(60)))
                                        {
                                            Material theMaterial = AssetDatabase.LoadAssetAtPath <Material>(material.path) as Material;
                                            Selection.activeObject = theMaterial;
                                            EditorGUIUtility.PingObject(theMaterial);
                                        }
                                        EditorGUILayout.EndHorizontal();
                                    }
                                }
                            }
                        }
                        EditorGUILayout.Separator();
                    }
                    if (shadersListedCount == 0 && !string.IsNullOrEmpty(projectShaderNameFilter))
                    {
                        EditorGUILayout.HelpBox("No shader matching '" + projectShaderNameFilter + "' name found. Either the shader doesn't exist in the project as source file or the shader does not use explicit keywords.", MessageType.Info);
                    }
                }
                EditorGUILayout.EndScrollView();
            }
        }
예제 #21
0
        void ScanProject()
        {
            try {
                if (shaders == null)
                {
                    shaders = new List <SCShader>();
                }
                else
                {
                    shaders.Clear();
                }
                // Add shaders from Resources folder
                string[] guids = AssetDatabase.FindAssets("t:Shader");
                totalShaderCount = guids.Length;
                for (int k = 0; k < totalShaderCount; k++)
                {
                    string guid = guids[k];
                    string path = AssetDatabase.GUIDToAssetPath(guid);
                    if (path != null)
                    {
                        string pathUpper = path.ToUpper();
                        if (scanAllShaders || pathUpper.Contains("\\RESOURCES\\") || pathUpper.Contains("/RESOURCES/"))     // this shader will be included in build
                        {
                            Shader unityShader = AssetDatabase.LoadAssetAtPath <Shader>(path);
                            if (unityShader != null)
                            {
                                SCShader shader = new SCShader();
                                shader.fullName = unityShader.name;
                                shader.name     = SCShader.GetSimpleName(shader.fullName); //  Path.GetFileNameWithoutExtension(path);
                                shader.path     = path;
                                string shaderGUID = path + "/" + unityShader.name;
                                shader.GUID = shaderGUID;
                                ScanShader(shader);
                                if (shader.keywords.Count > 0)
                                {
                                    shaders.Add(shader);
                                }
                            }
                        }
                    }
                }

                // Load and reference materials
                Dictionary <string, SCShader> shaderCache = new Dictionary <string, SCShader>(shaders.Count);
                shaders.ForEach(shader => {
                    shaderCache.Add(shader.GUID, shader);
                });
                string[] matGuids = AssetDatabase.FindAssets("t:Material");
                if (projectMaterials == null)
                {
                    projectMaterials = new List <SCMaterial>();
                }
                else
                {
                    projectMaterials.Clear();
                }

                for (int k = 0; k < matGuids.Length; k++)
                {
                    string   matGUID = matGuids[k];
                    string   matPath = AssetDatabase.GUIDToAssetPath(matGUID);
                    Material mat     = AssetDatabase.LoadAssetAtPath <Material>(matPath);
                    if (mat.shader == null)
                    {
                        continue;
                    }
                    SCMaterial scMat = new SCMaterial(mat, matPath, matGUID);
                    scMat.SetKeywords(mat.shaderKeywords);

                    if (mat.shaderKeywords != null && mat.shaderKeywords.Length > 0)
                    {
                        projectMaterials.Add(scMat);
                    }

                    string   path       = AssetDatabase.GetAssetPath(mat.shader);
                    string   shaderGUID = path + "/" + mat.shader.name;
                    SCShader shader;
                    if (!shaderCache.TryGetValue(shaderGUID, out shader))
                    {
                        if (mat.shaderKeywords == null || mat.shaderKeywords.Length == 0)
                        {
                            continue;
                        }
                        Shader shad = AssetDatabase.LoadAssetAtPath <Shader>(path);
                        // add non-sourced shader
                        shader            = new SCShader();
                        shader.isReadOnly = IsFileWritable(path);
                        shader.GUID       = shaderGUID;
                        if (shad != null)
                        {
                            shader.fullName = shad.name;
                            shader.name     = SCShader.GetSimpleName(shader.fullName);
                            shader.path     = path;
                            ScanShader(shader);
                        }
                        else
                        {
                            shader.fullName = mat.shader.name;
                            shader.name     = SCShader.GetSimpleName(shader.fullName);
                        }
                        shaders.Add(shader);
                        shaderCache.Add(shaderGUID, shader);
                        totalShaderCount++;
                    }
                    shader.materials.Add(scMat);
                    shader.AddKeywordsByName(mat.shaderKeywords);
                }

                // sort materials by name
                projectMaterials.Sort(CompareMaterialsName);

                // refresh variant and keywords count due to potential additional added keywords from materials (rogue keywords) and shader features count
                maxKeywordsCountFound = 0;
                shaders.ForEach((SCShader shader) => {
                    if (shader.keywordEnabledCount > maxKeywordsCountFound)
                    {
                        maxKeywordsCountFound = shader.keywordEnabledCount;
                    }
                    shader.UpdateVariantCount();
                });

                switch (sortType)
                {
                case SortType.VariantsCount:
                    shaders.Sort((SCShader x, SCShader y) => {
                        return(y.actualBuildVariantCount.CompareTo(x.actualBuildVariantCount));
                    });
                    break;

                case SortType.EnabledKeywordsCount:
                    shaders.Sort((SCShader x, SCShader y) => {
                        return(y.keywordEnabledCount.CompareTo(x.keywordEnabledCount));
                    });
                    break;

                case SortType.ShaderFileName:
                    shaders.Sort((SCShader x, SCShader y) => {
                        return(x.name.CompareTo(y.name));
                    });
                    break;
                }
                UpdateProjectStats();
            } catch (Exception ex) {
                Debug.LogError("Unexpected exception caught while scanning project: " + ex.Message);
            }
        }