Skip to content

Commit f2df188

Browse files
committed
feat: automatically display a dialog to import TextMeshPro support
1 parent bbe57df commit f2df188

File tree

4 files changed

+118
-26
lines changed

4 files changed

+118
-26
lines changed

Packages/src/Runtime/Internal/Utilities/MaterialRepository.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ internal static class MaterialRepository
1515

1616
#if UNITY_EDITOR
1717
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
18-
private static void Clear()
18+
public static void Clear()
1919
{
2020
s_Repository.Clear();
2121
}

Packages/src/Runtime/Internal/Utilities/ShaderVariantRegistry.cs

+68-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1+
using System;
12
using System.Collections.Generic;
23
using UnityEngine;
3-
using System;
4+
using UnityEngine.Profiling;
45
#if UNITY_EDITOR
56
using System.IO;
6-
using Object = UnityEngine.Object;
77
using System.Linq;
88
using System.Reflection;
99
using System.Text.RegularExpressions;
1010
using UnityEditor;
11+
using UnityEditor.PackageManager.UI;
1112
using UnityEditorInternal;
13+
using PackageInfo = UnityEditor.PackageManager.PackageInfo;
14+
using Object = UnityEngine.Object;
1215
#endif
1316

1417
namespace Coffee.UIEffectInternal
@@ -75,7 +78,7 @@ public Shader FindOptionalShader(Shader shader,
7578
return Shader.Find(optionalShaderName);
7679
}
7780

78-
// Required shader.
81+
// The shader has
7982
if (shader.name.Contains(requiredName))
8083
{
8184
_cachedOptionalShaders[id] = shader.name;
@@ -105,16 +108,70 @@ public Shader FindOptionalShader(Shader shader,
105108
return optionalShader;
106109
}
107110

111+
#if UNITY_EDITOR
112+
ImportFromSample(optionalShaderName);
113+
#endif
114+
108115
// Find default optional shader.
109116
_cachedOptionalShaders[id] = defaultOptionalShaderName;
110117
return Shader.Find(defaultOptionalShaderName);
111118
}
112119

113120
#if UNITY_EDITOR
114-
private HashSet<StringPair> _logVariants = new HashSet<StringPair>();
121+
private readonly HashSet<StringPair> _logVariants = new HashSet<StringPair>();
122+
private readonly Dictionary<string, string> _sampleNames = new Dictionary<string, string>();
123+
124+
/// <summary>
125+
/// Import the sample containing the requested shader.
126+
/// If choice 'Import' is selected, the sample is imported.
127+
/// If choice 'Skip in this session' is selected, the sample is skipped in this session.
128+
/// </summary>
129+
public void ImportFromSample(string shaderName)
130+
{
131+
if (Misc.isBatchOrBuilding) return;
132+
133+
// Find sample name.
134+
if (_sampleNames.TryGetValue(shaderName, out var sampleName))
135+
{
136+
// Find package info.
137+
var pInfo = PackageInfo.FindForAssembly(typeof(ShaderVariantRegistry).Assembly);
138+
if (pInfo == null) return;
139+
140+
// Find sample. If not found (resolvedPath == null), skip.
141+
var sample = Sample.FindByPackage(pInfo.name, pInfo.version)
142+
.FirstOrDefault(x => x.displayName == sampleName);
143+
if (sample.resolvedPath == null) return;
144+
145+
// Import the sample if selected.
146+
var importSelected = EditorUtility.DisplayDialog($"Import {sampleName}",
147+
$"Import '{sampleName}' to use the shader '{shaderName}'", "Import", "Cancel");
148+
if (importSelected)
149+
{
150+
EditorApplication.delayCall += () =>
151+
{
152+
sample.Import();
153+
};
154+
}
155+
}
156+
}
157+
158+
public void ClearCache()
159+
{
160+
_cachedOptionalShaders.Clear();
161+
}
162+
163+
public void RegisterSamples((string shaderName, string sampleName)[] samples)
164+
{
165+
foreach (var (shaderName, sampleName) in samples)
166+
{
167+
_sampleNames[shaderName] = sampleName;
168+
}
169+
}
115170

116171
public void InitializeIfNeeded(Object owner, string optionalName)
117172
{
173+
Profiler.BeginSample("(EDITOR/COF)[ShaderVariantRegistry] InitializeIfNeeded");
174+
118175
// Register optional shader names by shader comment.
119176
if (!string.IsNullOrEmpty(optionalName))
120177
{
@@ -159,12 +216,16 @@ public void InitializeIfNeeded(Object owner, string optionalName)
159216
EditorUtility.SetDirty(owner);
160217
AssetDatabase.SaveAssets();
161218
}
219+
220+
ClearCache();
221+
Profiler.EndSample();
162222
}
163223

164224
internal void RegisterVariant(Material material, string path)
165225
{
166226
if (!material || !material.shader || !m_Asset) return;
167227

228+
Profiler.BeginSample("(EDITOR/COF)[ShaderVariantRegistry] RegisterVariant");
168229
var shaderName = material.shader.name;
169230
var validKeywords = material.shaderKeywords
170231
.Where(x => !Regex.IsMatch(x, "(_EDITOR|EDITOR_)"))
@@ -181,6 +242,7 @@ internal void RegisterVariant(Material material, string path)
181242
if (m_Asset.Contains(variant))
182243
{
183244
m_UnregisteredVariants.Remove(pair);
245+
Profiler.EndSample();
184246
return;
185247
}
186248

@@ -199,11 +261,13 @@ internal void RegisterVariant(Material material, string path)
199261
$"Register it in 'ProjectSettings > {path}' to use it in player.", m_Asset);
200262
}
201263

264+
Profiler.EndSample();
202265
return;
203266
}
204267

205268
m_Asset.Add(variant);
206269
m_UnregisteredVariants.Remove(pair);
270+
Profiler.EndSample();
207271
}
208272
#endif
209273
}

Packages/src/Runtime/UIEffectBase.cs

-21
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
using System.Collections.Generic;
2-
using System.Linq;
32
using System.Runtime.CompilerServices;
43
using Coffee.UIEffectInternal;
54
using UnityEngine;
@@ -215,26 +214,6 @@ public virtual void ApplyContextToMaterial()
215214
}
216215

217216
#if TMP_ENABLE
218-
#if UNITY_EDITOR
219-
private class Postprocessor : AssetPostprocessor
220-
{
221-
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
222-
{
223-
if (Application.isBatchMode || BuildPipeline.isBuildingPlayer) return;
224-
225-
foreach (var effect in Misc.FindObjectsOfType<UIEffectBase>()
226-
.Concat(Misc.GetAllComponentsInPrefabStage<UIEffectBase>()))
227-
{
228-
if (!effect.isActiveAndEnabled) continue;
229-
if (!(effect.graphic is TextMeshProUGUI tmp) || !tmp.isActiveAndEnabled) continue;
230-
effect.SetMaterialDirty();
231-
}
232-
233-
EditorApplication.QueuePlayerLoopUpdate();
234-
}
235-
}
236-
#endif
237-
238217
#if UNITY_EDITOR
239218
[InitializeOnLoadMethod]
240219
#else

Packages/src/Runtime/UIEffectProjectSettings.cs

+49
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using System;
12
using System.Collections.Generic;
23
using System.IO;
34
using System.Linq;
@@ -62,6 +63,15 @@ public static UIEffect LoadRuntimePreset(string presetName)
6263
return null;
6364
}
6465

66+
protected override void OnEnable()
67+
{
68+
base.OnEnable();
69+
#if UNITY_EDITOR
70+
SetupSamplesForShaderVariantRegistry();
71+
m_ShaderVariantRegistry.ClearCache();
72+
#endif
73+
}
74+
6575
#if UNITY_EDITOR
6676
private const string k_PresetDir = "UIEffectPresets";
6777
private const string k_PresetSaveDir = "Assets/ProjectSettings/" + k_PresetDir;
@@ -82,6 +92,35 @@ private void Reset()
8292
m_ShaderVariantRegistry.InitializeIfNeeded(this, "(UIEffect)");
8393
}
8494

95+
private void SetupSamplesForShaderVariantRegistry()
96+
{
97+
#if UNITY_2023_2_OR_NEWER
98+
const string tmpSupport = "TextMeshPro Support (Unity 6)";
99+
#else
100+
const string tmpSupport = "TextMeshPro Support";
101+
#endif
102+
m_ShaderVariantRegistry.RegisterSamples(new[]
103+
{
104+
("Hidden/TextMeshPro/Bitmap (UIEffect)", tmpSupport),
105+
("Hidden/TextMeshPro/Mobile/Bitmap (UIEffect)", tmpSupport),
106+
("Hidden/TextMeshPro/Distance Field (UIEffect)", tmpSupport),
107+
("Hidden/TextMeshPro/Mobile/Distance Field (UIEffect)", tmpSupport)
108+
});
109+
}
110+
111+
private void Refresh()
112+
{
113+
m_ShaderVariantRegistry.ClearCache();
114+
MaterialRepository.Clear();
115+
foreach (var c in Misc.FindObjectsOfType<UIEffectBase>()
116+
.Concat(Misc.GetAllComponentsInPrefabStage<UIEffectBase>()))
117+
{
118+
c.SetMaterialDirty();
119+
}
120+
121+
EditorApplication.QueuePlayerLoopUpdate();
122+
}
123+
85124
internal static UIEffect[] LoadEditorPresets()
86125
{
87126
var dirs = AssetDatabase.FindAssets(k_PresetDir + " t:folder")
@@ -128,6 +167,16 @@ internal static string GetPresetPath(UIEffect preset)
128167
var m = Regex.Match(assetPath, k_PresetPathPattern);
129168
return m.Success ? m.Groups[1].Value : Path.GetFileNameWithoutExtension(assetPath);
130169
}
170+
171+
private class Postprocessor : AssetPostprocessor
172+
{
173+
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
174+
{
175+
if (Misc.isBatchOrBuilding) return;
176+
177+
instance.Refresh();
178+
}
179+
}
131180
#endif
132181
}
133182
}

0 commit comments

Comments
 (0)