From 5b509795471949a54015d49d7bb913bdeffe076f Mon Sep 17 00:00:00 2001 From: mob-sakai <12690315+mob-sakai@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:37:04 +0900 Subject: [PATCH] feat: automatically display a dialog to import TextMeshPro support --- .../Internal/Utilities/MaterialRepository.cs | 2 +- .../Utilities/ShaderVariantRegistry.cs | 72 +++++++++++++++++-- Packages/src/Runtime/UIEffectBase.cs | 21 ------ .../src/Runtime/UIEffectProjectSettings.cs | 44 ++++++++++++ 4 files changed, 113 insertions(+), 26 deletions(-) diff --git a/Packages/src/Runtime/Internal/Utilities/MaterialRepository.cs b/Packages/src/Runtime/Internal/Utilities/MaterialRepository.cs index ed15b950..29914267 100644 --- a/Packages/src/Runtime/Internal/Utilities/MaterialRepository.cs +++ b/Packages/src/Runtime/Internal/Utilities/MaterialRepository.cs @@ -15,7 +15,7 @@ internal static class MaterialRepository #if UNITY_EDITOR [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] - private static void Clear() + public static void Clear() { s_Repository.Clear(); } diff --git a/Packages/src/Runtime/Internal/Utilities/ShaderVariantRegistry.cs b/Packages/src/Runtime/Internal/Utilities/ShaderVariantRegistry.cs index 38c19f89..35a445e7 100644 --- a/Packages/src/Runtime/Internal/Utilities/ShaderVariantRegistry.cs +++ b/Packages/src/Runtime/Internal/Utilities/ShaderVariantRegistry.cs @@ -1,14 +1,17 @@ +using System; using System.Collections.Generic; using UnityEngine; -using System; +using UnityEngine.Profiling; #if UNITY_EDITOR using System.IO; -using Object = UnityEngine.Object; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using UnityEditor; +using UnityEditor.PackageManager.UI; using UnityEditorInternal; +using PackageInfo = UnityEditor.PackageManager.PackageInfo; +using Object = UnityEngine.Object; #endif namespace Coffee.UIEffectInternal @@ -75,7 +78,7 @@ public Shader FindOptionalShader(Shader shader, return Shader.Find(optionalShaderName); } - // Required shader. + // The shader has if (shader.name.Contains(requiredName)) { _cachedOptionalShaders[id] = shader.name; @@ -105,16 +108,70 @@ public Shader FindOptionalShader(Shader shader, return optionalShader; } +#if UNITY_EDITOR + ImportFromSample(optionalShaderName); +#endif + // Find default optional shader. _cachedOptionalShaders[id] = defaultOptionalShaderName; return Shader.Find(defaultOptionalShaderName); } #if UNITY_EDITOR - private HashSet _logVariants = new HashSet(); + private readonly HashSet _logVariants = new HashSet(); + private readonly Dictionary _sampleNames = new Dictionary(); + + /// + /// Import the sample containing the requested shader. + /// If choice 'Import' is selected, the sample is imported. + /// If choice 'Skip in this session' is selected, the sample is skipped in this session. + /// + public void ImportFromSample(string shaderName) + { + if (Misc.isBatchOrBuilding) return; + + // Find sample name. + if (_sampleNames.TryGetValue(shaderName, out var sampleName)) + { + // Find package info. + var pInfo = PackageInfo.FindForAssembly(typeof(ShaderVariantRegistry).Assembly); + if (pInfo == null) return; + + // Find sample. If not found (resolvedPath == null), skip. + var sample = Sample.FindByPackage(pInfo.name, pInfo.version) + .FirstOrDefault(x => x.displayName == sampleName); + if (sample.resolvedPath == null) return; + + // Import the sample if selected. + var importSelected = EditorUtility.DisplayDialog($"Import {sampleName}", + $"Import '{sampleName}' to use the shader '{shaderName}'", "Import", "Cancel"); + if (importSelected) + { + EditorApplication.delayCall += () => + { + sample.Import(); + }; + } + } + } + + public void ClearCache() + { + _cachedOptionalShaders.Clear(); + } + + public void RegisterSamples((string shaderName, string sampleName)[] samples) + { + foreach (var (shaderName, sampleName) in samples) + { + _sampleNames[shaderName] = sampleName; + } + } public void InitializeIfNeeded(Object owner, string optionalName) { + Profiler.BeginSample("(EDITOR/COF)[ShaderVariantRegistry] InitializeIfNeeded"); + // Register optional shader names by shader comment. if (!string.IsNullOrEmpty(optionalName)) { @@ -159,12 +216,16 @@ public void InitializeIfNeeded(Object owner, string optionalName) EditorUtility.SetDirty(owner); AssetDatabase.SaveAssets(); } + + ClearCache(); + Profiler.EndSample(); } internal void RegisterVariant(Material material, string path) { if (!material || !material.shader || !m_Asset) return; + Profiler.BeginSample("(EDITOR/COF)[ShaderVariantRegistry] RegisterVariant"); var shaderName = material.shader.name; var validKeywords = material.shaderKeywords .Where(x => !Regex.IsMatch(x, "(_EDITOR|EDITOR_)")) @@ -181,6 +242,7 @@ internal void RegisterVariant(Material material, string path) if (m_Asset.Contains(variant)) { m_UnregisteredVariants.Remove(pair); + Profiler.EndSample(); return; } @@ -199,11 +261,13 @@ internal void RegisterVariant(Material material, string path) $"Register it in 'ProjectSettings > {path}' to use it in player.", m_Asset); } + Profiler.EndSample(); return; } m_Asset.Add(variant); m_UnregisteredVariants.Remove(pair); + Profiler.EndSample(); } #endif } diff --git a/Packages/src/Runtime/UIEffectBase.cs b/Packages/src/Runtime/UIEffectBase.cs index 895ff96b..dfe6a406 100644 --- a/Packages/src/Runtime/UIEffectBase.cs +++ b/Packages/src/Runtime/UIEffectBase.cs @@ -1,5 +1,4 @@ using System.Collections.Generic; -using System.Linq; using System.Runtime.CompilerServices; using Coffee.UIEffectInternal; using UnityEngine; @@ -215,26 +214,6 @@ public virtual void ApplyContextToMaterial() } #if TMP_ENABLE -#if UNITY_EDITOR - private class Postprocessor : AssetPostprocessor - { - private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____) - { - if (Application.isBatchMode || BuildPipeline.isBuildingPlayer) return; - - foreach (var effect in Misc.FindObjectsOfType() - .Concat(Misc.GetAllComponentsInPrefabStage())) - { - if (!effect.isActiveAndEnabled) continue; - if (!(effect.graphic is TextMeshProUGUI tmp) || !tmp.isActiveAndEnabled) continue; - effect.SetMaterialDirty(); - } - - EditorApplication.QueuePlayerLoopUpdate(); - } - } -#endif - #if UNITY_EDITOR [InitializeOnLoadMethod] #else diff --git a/Packages/src/Runtime/UIEffectProjectSettings.cs b/Packages/src/Runtime/UIEffectProjectSettings.cs index 6f3901f0..60494136 100644 --- a/Packages/src/Runtime/UIEffectProjectSettings.cs +++ b/Packages/src/Runtime/UIEffectProjectSettings.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -82,6 +83,10 @@ protected override void OnEnable() { base.OnEnable(); SetPreferSamplingSize(); +#if UNITY_EDITOR + SetupSamplesForShaderVariantRegistry(); + m_ShaderVariantRegistry.ClearCache(); +#endif } private void SetPreferSamplingSize() @@ -117,6 +122,35 @@ private void OnValidate() SetPreferSamplingSize(); } + private void SetupSamplesForShaderVariantRegistry() + { +#if UNITY_2023_2_OR_NEWER + const string tmpSupport = "TextMeshPro Support (Unity 6)"; +#else + const string tmpSupport = "TextMeshPro Support"; +#endif + m_ShaderVariantRegistry.RegisterSamples(new[] + { + ("Hidden/TextMeshPro/Bitmap (UIEffect)", tmpSupport), + ("Hidden/TextMeshPro/Mobile/Bitmap (UIEffect)", tmpSupport), + ("Hidden/TextMeshPro/Distance Field (UIEffect)", tmpSupport), + ("Hidden/TextMeshPro/Mobile/Distance Field (UIEffect)", tmpSupport) + }); + } + + private void Refresh() + { + m_ShaderVariantRegistry.ClearCache(); + MaterialRepository.Clear(); + foreach (var c in Misc.FindObjectsOfType() + .Concat(Misc.GetAllComponentsInPrefabStage())) + { + c.SetMaterialDirty(); + } + + EditorApplication.QueuePlayerLoopUpdate(); + } + internal static UIEffect[] LoadEditorPresets() { var dirs = AssetDatabase.FindAssets(k_PresetDir + " t:folder") @@ -163,6 +197,16 @@ internal static string GetPresetPath(UIEffect preset) var m = Regex.Match(assetPath, k_PresetPathPattern); return m.Success ? m.Groups[1].Value : Path.GetFileNameWithoutExtension(assetPath); } + + private class Postprocessor : AssetPostprocessor + { + private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____) + { + if (Misc.isBatchOrBuilding) return; + + instance.Refresh(); + } + } #endif } }