4 using System.Collections.Generic;
5 using System.Globalization;
6 using System.Threading;
14 [MenuItem(
"Window/TextMeshPro/Font Asset Creator",
false, 2025)]
15 public static void ShowFontAtlasCreatorWindow()
17 var window = GetWindow<TMPro_FontAssetCreatorWindow>();
18 window.titleContent =
new GUIContent(
"Font Asset Creator");
22 window.CheckEssentialResources();
26 public static void ShowFontAtlasCreatorWindow(Font sourceFontFile)
28 var window = GetWindow<TMPro_FontAssetCreatorWindow>();
30 window.titleContent =
new GUIContent(
"Font Asset Creator");
34 window.ClearGeneratedData();
35 window.m_SelectedFontAsset =
null;
36 window.m_LegacyFontAsset =
null;
37 window.m_SourceFontFile = sourceFontFile;
40 window.CheckEssentialResources();
44 public static void ShowFontAtlasCreatorWindow(
TMP_FontAsset fontAsset)
46 var window = GetWindow<TMPro_FontAssetCreatorWindow>();
48 window.titleContent =
new GUIContent(
"Font Creator");
52 window.ClearGeneratedData();
53 window.m_LegacyFontAsset =
null;
59 window.m_SavedFontAtlas = fontAsset.atlas;
63 window.m_WarningMessage =
"Font Asset [" + fontAsset.name +
"] does not contain any previous \"Font Asset Creation Settings\". This usually means [" + fontAsset.name +
"] was created before this new functionality was added.";
64 window.m_SourceFontFile =
null;
65 window.m_LegacyFontAsset = fontAsset;
69 window.m_SelectedFontAsset = fontAsset;
72 window.CheckEssentialResources();
78 public List<FontAssetCreationSettings> fontAssetCreationSettings;
84 int m_FontAssetCreationSettingsCurrentIndex = 0;
86 const string k_FontAssetCreationSettingsContainerKey =
"TextMeshPro.FontAssetCreator.RecentFontAssetCreationSettings.Container";
87 const string k_FontAssetCreationSettingsCurrentIndexKey =
"TextMeshPro.FontAssetCreator.RecentFontAssetCreationSettings.CurrentIndex";
88 const float k_TwoColumnControlsWidth = 335f;
91 System.Diagnostics.Stopwatch m_StopWatch;
93 string[] m_FontSizingOptions = {
"Auto Sizing",
"Custom Size" };
94 int m_PointSizeSamplingMode;
95 string[] m_FontResolutionLabels = {
"16",
"32",
"64",
"128",
"256",
"512",
"1024",
"2048",
"4096",
"8192" };
96 int[] m_FontAtlasResolutions = { 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
97 string[] m_FontCharacterSets = {
"ASCII",
"Extended ASCII",
"ASCII Lowercase",
"ASCII Uppercase",
"Numbers + Symbols",
"Custom Range",
"Unicode Range (Hex)",
"Custom Characters",
"Characters from File" };
98 enum FontPackingModes { Fast = 0, Optimum = 4 };
99 FontPackingModes m_PackingMode = FontPackingModes.Fast;
101 int m_CharacterSetSelectionMode;
103 string m_CharacterSequence =
"";
104 string m_OutputFeedback =
"";
105 string m_WarningMessage;
106 const string k_OutputNameLabel =
"Font: ";
107 const string k_OutputSizeLabel =
"Pt. Size: ";
108 const string k_OutputCountLabel =
"Characters packed: ";
109 int m_CharacterCount;
110 Vector2 m_ScrollPosition;
111 Vector2 m_OutputScrollPosition;
113 bool m_IsRepaintNeeded;
115 float m_RenderingProgress;
116 bool m_IsRenderingDone;
118 bool m_IsGenerationDisabled;
119 bool m_IsGenerationCancelled;
121 Object m_SourceFontFile;
122 TMP_FontAsset m_SelectedFontAsset;
123 TMP_FontAsset m_LegacyFontAsset;
124 TMP_FontAsset m_ReferencedFontAsset;
126 TextAsset m_CharacterList;
130 FaceStyles m_FontStyle = FaceStyles.Normal;
131 float m_FontStyleValue = 2;
132 RenderModes m_RenderMode = RenderModes.DistanceField16;
133 int m_AtlasWidth = 512;
134 int m_AtlasHeight = 512;
136 FT_FaceInfo m_FontFaceInfo;
137 FT_GlyphInfo[] m_FontGlyphInfo;
138 byte[] m_TextureBuffer;
139 Texture2D m_FontAtlas;
140 Texture2D m_SavedFontAtlas;
142 bool m_IncludeKerningPairs;
146 bool m_IsFontAtlasInvalid;
148 public void OnEnable()
150 minSize =
new Vector2(315, minSize.y);
153 m_StopWatch =
new System.Diagnostics.Stopwatch();
156 ShaderUtilities.GetShaderPropertyIDs();
159 if (EditorPrefs.HasKey(k_FontAssetCreationSettingsContainerKey))
161 if (m_FontAssetCreationSettingsContainer ==
null)
162 m_FontAssetCreationSettingsContainer = JsonUtility.FromJson<FontAssetCreationSettingsContainer>(EditorPrefs.GetString(k_FontAssetCreationSettingsContainerKey));
164 if (m_FontAssetCreationSettingsContainer.fontAssetCreationSettings !=
null && m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count > 0)
167 if (EditorPrefs.HasKey(k_FontAssetCreationSettingsCurrentIndexKey))
168 m_FontAssetCreationSettingsCurrentIndex = EditorPrefs.GetInt(k_FontAssetCreationSettingsCurrentIndexKey);
170 LoadFontCreationSettings(m_FontAssetCreationSettingsContainer.fontAssetCreationSettings[m_FontAssetCreationSettingsCurrentIndex]);
178 public void OnDisable()
183 TMPro_FontPlugin.SendCancellationRequest(CancellationRequestType.WindowClosed);
186 TMPro_FontPlugin.Destroy_FontEngine();
188 if (m_FontAtlas !=
null && EditorUtility.IsPersistent(m_FontAtlas) ==
false)
191 DestroyImmediate(m_FontAtlas);
194 if (File.Exists(
"Assets/TextMesh Pro/Glyph Report.txt"))
196 File.Delete(
"Assets/TextMesh Pro/Glyph Report.txt");
197 File.Delete(
"Assets/TextMesh Pro/Glyph Report.txt.meta");
199 AssetDatabase.Refresh();
204 EditorPrefs.SetInt(k_FontAssetCreationSettingsCurrentIndexKey, m_FontAssetCreationSettingsCurrentIndex);
207 TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
209 Resources.UnloadUnusedAssets();
214 void ON_RESOURCES_LOADED()
216 TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
218 m_IsGenerationDisabled =
false;
222 void CheckEssentialResources()
224 if (TMP_Settings.instance ==
null)
226 if (m_IsGenerationDisabled ==
false)
227 TMPro_EventManager.RESOURCE_LOAD_EVENT.Add(ON_RESOURCES_LOADED);
229 m_IsGenerationDisabled =
true;
236 GUILayout.BeginHorizontal();
238 if (position.width > position.height && position.width > k_TwoColumnControlsWidth)
242 GUILayout.EndHorizontal();
248 if (m_IsRepaintNeeded)
251 m_IsRepaintNeeded =
false;
258 m_RenderingProgress = TMPro_FontPlugin.Check_RenderProgress();
260 m_IsRepaintNeeded =
true;
264 if (m_IsRenderingDone)
268 Debug.Log(
"Font Atlas generation completed in: " + m_StopWatch.Elapsed.TotalMilliseconds.ToString(
"0.000 ms."));
271 m_IsProcessing =
false;
272 m_IsRenderingDone =
false;
274 if (m_IsGenerationCancelled ==
false)
291 List<int> unicodeList =
new List<int>();
292 string[] sequences = sequence.Split(
',');
294 foreach (
string seq
in sequences)
296 string[] s1 = seq.Split(
'-');
301 unicodeList.Add(
int.Parse(s1[0]));
305 Debug.Log(
"No characters selected or invalid format.");
309 for (
int j =
int.Parse(s1[0]); j <
int.Parse(s1[1]) + 1; j++)
316 return unicodeList.ToArray();
327 List<int> unicodeList =
new List<int>();
328 string[] sequences = sequence.Split(
',');
330 foreach (
string seq
in sequences)
332 string[] s1 = seq.Split(
'-');
337 unicodeList.Add(
int.Parse(s1[0], NumberStyles.AllowHexSpecifier));
341 Debug.Log(
"No characters selected or invalid format.");
345 for (
int j =
int.Parse(s1[0], NumberStyles.AllowHexSpecifier); j <
int.Parse(s1[1], NumberStyles.AllowHexSpecifier) + 1; j++)
352 return unicodeList.ToArray();
359 if (position.width > position.height && position.width > k_TwoColumnControlsWidth)
361 m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition, GUILayout.Width(315));
365 m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
370 GUILayout.Label(m_SelectedFontAsset !=
null ?
string.Format(
"Creation Settings ({0})", m_SelectedFontAsset.name) :
"Font Settings", EditorStyles.boldLabel);
372 EditorGUIUtility.labelWidth = 125f;
373 EditorGUIUtility.fieldWidth = 5f;
375 EditorGUI.BeginDisabledGroup(m_IsProcessing);
378 EditorGUI.BeginChangeCheck();
379 m_SourceFontFile = EditorGUILayout.ObjectField(
"Source Font File", m_SourceFontFile, typeof(Font),
false) as Font;
380 if (EditorGUI.EndChangeCheck())
382 m_SelectedFontAsset =
null;
383 m_IsFontAtlasInvalid =
true;
387 EditorGUI.BeginChangeCheck();
388 if (m_PointSizeSamplingMode == 0)
390 m_PointSizeSamplingMode = EditorGUILayout.Popup(
"Sampling Point Size", m_PointSizeSamplingMode, m_FontSizingOptions);
394 GUILayout.BeginHorizontal();
395 m_PointSizeSamplingMode = EditorGUILayout.Popup(
"Sampling Point Size", m_PointSizeSamplingMode, m_FontSizingOptions, GUILayout.Width(225));
396 m_PointSize = EditorGUILayout.IntField(m_PointSize);
397 GUILayout.EndHorizontal();
399 if (EditorGUI.EndChangeCheck())
401 m_IsFontAtlasInvalid =
true;
405 EditorGUI.BeginChangeCheck();
406 m_Padding = EditorGUILayout.IntField(
"Padding", m_Padding);
407 m_Padding = (int)Mathf.Clamp(m_Padding, 0f, 64f);
408 if (EditorGUI.EndChangeCheck())
410 m_IsFontAtlasInvalid =
true;
414 EditorGUI.BeginChangeCheck();
415 m_PackingMode = (FontPackingModes)EditorGUILayout.EnumPopup(
"Packing Method", m_PackingMode);
416 if (EditorGUI.EndChangeCheck())
418 m_IsFontAtlasInvalid =
true;
422 GUILayout.BeginHorizontal();
425 EditorGUI.BeginChangeCheck();
426 EditorGUILayout.PrefixLabel(
"Atlas Resolution");
427 m_AtlasWidth = EditorGUILayout.IntPopup(m_AtlasWidth, m_FontResolutionLabels, m_FontAtlasResolutions);
428 m_AtlasHeight = EditorGUILayout.IntPopup(m_AtlasHeight, m_FontResolutionLabels, m_FontAtlasResolutions);
429 if (EditorGUI.EndChangeCheck())
431 m_IsFontAtlasInvalid =
true;
434 GUILayout.EndHorizontal();
438 EditorGUI.BeginChangeCheck();
439 bool hasSelectionChanged =
false;
440 m_CharacterSetSelectionMode = EditorGUILayout.Popup(
"Character Set", m_CharacterSetSelectionMode, m_FontCharacterSets);
441 if (EditorGUI.EndChangeCheck())
443 m_CharacterSequence =
"";
444 hasSelectionChanged =
true;
445 m_IsFontAtlasInvalid =
true;
450 switch (m_CharacterSetSelectionMode)
454 m_CharacterSequence =
"32 - 126, 160, 8203, 8230, 9633";
458 m_CharacterSequence =
"32 - 126, 160 - 255, 8192 - 8303, 8364, 8482, 9633";
463 m_CharacterSequence =
"32 - 64, 91 - 126, 160";
467 m_CharacterSequence =
"32 - 96, 123 - 126, 160";
471 m_CharacterSequence =
"32 - 64, 91 - 96, 123 - 126, 160";
475 EditorGUILayout.BeginVertical(EditorStyles.helpBox);
476 GUILayout.Label(
"Enter a sequence of decimal values to define the characters to be included in the font asset or retrieve one from another font asset.", TMP_UIStyleManager.label);
477 GUILayout.Space(10f);
479 EditorGUI.BeginChangeCheck();
480 m_ReferencedFontAsset = EditorGUILayout.ObjectField(
"Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset),
false) as TMP_FontAsset;
481 if (EditorGUI.EndChangeCheck() || hasSelectionChanged)
483 if (m_ReferencedFontAsset !=
null)
484 m_CharacterSequence = TMP_EditorUtility.GetDecimalCharacterSequence(TMP_FontAsset.GetCharactersArray(m_ReferencedFontAsset));
485 m_IsFontAtlasInvalid =
true;
489 char chr = Event.current.character;
490 if ((chr < '0' || chr >
'9') && (chr < ',' || chr >
'-'))
492 Event.current.character =
'\0';
494 GUILayout.Label(
"Character Sequence (Decimal)", EditorStyles.boldLabel);
495 EditorGUI.BeginChangeCheck();
496 m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(
true));
497 if (EditorGUI.EndChangeCheck())
499 m_IsFontAtlasInvalid =
true;
502 EditorGUILayout.EndVertical();
506 EditorGUILayout.BeginVertical(EditorStyles.helpBox);
507 GUILayout.Label(
"Enter a sequence of Unicode (hex) values to define the characters to be included in the font asset or retrieve one from another font asset.", TMP_UIStyleManager.label);
508 GUILayout.Space(10f);
510 EditorGUI.BeginChangeCheck();
511 m_ReferencedFontAsset = EditorGUILayout.ObjectField(
"Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset),
false) as TMP_FontAsset;
512 if (EditorGUI.EndChangeCheck() || hasSelectionChanged)
514 if (m_ReferencedFontAsset !=
null)
515 m_CharacterSequence = TMP_EditorUtility.GetUnicodeCharacterSequence(TMP_FontAsset.GetCharactersArray(m_ReferencedFontAsset));
516 m_IsFontAtlasInvalid =
true;
520 chr = Event.current.character;
521 if ((chr < '0' || chr >
'9') && (chr < 'a' || chr >
'f') && (chr < 'A' || chr >
'F') && (chr < ',' || chr >
'-'))
523 Event.current.character =
'\0';
525 GUILayout.Label(
"Character Sequence (Hex)", EditorStyles.boldLabel);
526 EditorGUI.BeginChangeCheck();
527 m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(
true));
528 if (EditorGUI.EndChangeCheck())
530 m_IsFontAtlasInvalid =
true;
533 EditorGUILayout.EndVertical();
537 EditorGUILayout.BeginVertical(EditorStyles.helpBox);
538 GUILayout.Label(
"Type the characters to be included in the font asset or retrieve them from another font asset.", TMP_UIStyleManager.label);
539 GUILayout.Space(10f);
541 EditorGUI.BeginChangeCheck();
542 m_ReferencedFontAsset = EditorGUILayout.ObjectField(
"Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset),
false) as TMP_FontAsset;
543 if (EditorGUI.EndChangeCheck() || hasSelectionChanged)
545 if (m_ReferencedFontAsset !=
null)
546 m_CharacterSequence = TMP_FontAsset.GetCharacters(m_ReferencedFontAsset);
547 m_IsFontAtlasInvalid =
true;
550 EditorGUI.indentLevel = 0;
552 GUILayout.Label(
"Custom Character List", EditorStyles.boldLabel);
553 EditorGUI.BeginChangeCheck();
554 m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(
true));
555 if (EditorGUI.EndChangeCheck())
557 m_IsFontAtlasInvalid =
true;
559 EditorGUILayout.EndVertical();
563 EditorGUI.BeginChangeCheck();
564 m_CharacterList = EditorGUILayout.ObjectField(
"Character File", m_CharacterList, typeof(TextAsset),
false) as TextAsset;
565 if (EditorGUI.EndChangeCheck())
567 m_IsFontAtlasInvalid =
true;
569 if (m_CharacterList !=
null)
571 m_CharacterSequence = m_CharacterList.text;
577 GUILayout.BeginHorizontal();
578 EditorGUI.BeginChangeCheck();
579 m_FontStyle = (FaceStyles)EditorGUILayout.EnumPopup(
"Font Style", m_FontStyle, GUILayout.Width(225));
580 m_FontStyleValue = EditorGUILayout.IntField((
int)m_FontStyleValue);
581 if (EditorGUI.EndChangeCheck())
583 m_IsFontAtlasInvalid =
true;
585 GUILayout.EndHorizontal();
588 EditorGUI.BeginChangeCheck();
589 m_RenderMode = (RenderModes)EditorGUILayout.EnumPopup(
"Render Mode", m_RenderMode);
590 if (EditorGUI.EndChangeCheck())
593 m_IsFontAtlasInvalid =
true;
596 m_IncludeKerningPairs = EditorGUILayout.Toggle(
"Get Kerning Pairs", m_IncludeKerningPairs);
598 EditorGUILayout.Space();
601 EditorGUI.EndDisabledGroup();
603 if (!
string.IsNullOrEmpty(m_WarningMessage))
605 EditorGUILayout.HelpBox(m_WarningMessage, MessageType.Warning);
608 GUI.enabled = m_SourceFontFile !=
null && !m_IsProcessing && !m_IsGenerationDisabled;
609 if (GUILayout.Button(
"Generate Font Atlas") && m_CharacterSequence.Length != 0 && GUI.enabled)
611 if (!m_IsProcessing && m_SourceFontFile !=
null)
613 DestroyImmediate(m_FontAtlas);
615 m_OutputFeedback =
string.Empty;
616 m_SavedFontAtlas =
null;
619 errorCode = TMPro_FontPlugin.Initialize_FontEngine();
622 if (errorCode == 0xF0)
628 Debug.Log(
"Error Code: " + errorCode +
" occurred while Initializing the FreeType Library.");
631 string fontPath = AssetDatabase.GetAssetPath(m_SourceFontFile);
635 errorCode = TMPro_FontPlugin.Load_TrueType_Font(fontPath);
639 if (errorCode == 0xF1)
645 Debug.Log(
"Error Code: " + errorCode +
" occurred while Loading the [" + m_SourceFontFile.name +
"] font file. This typically results from the use of an incompatible or corrupted font file.");
651 if (m_PointSizeSamplingMode == 0) m_PointSize = 72;
653 errorCode = TMPro_FontPlugin.FT_Size_Font(m_PointSize);
655 Debug.Log(
"Error Code: " + errorCode +
" occurred while Sizing the font.");
662 if (m_CharacterSetSelectionMode == 7 || m_CharacterSetSelectionMode == 8)
664 List<int> charList =
new List<int>();
666 for (
int i = 0; i < m_CharacterSequence.Length; i++)
669 if (charList.FindIndex(item => item == m_CharacterSequence[i]) == -1)
670 charList.Add(m_CharacterSequence[i]);
677 characterSet = charList.ToArray();
679 else if (m_CharacterSetSelectionMode == 6)
688 m_CharacterCount = characterSet.Length;
690 m_TextureBuffer =
new byte[m_AtlasWidth * m_AtlasHeight];
692 m_FontFaceInfo =
new FT_FaceInfo();
694 m_FontGlyphInfo =
new FT_GlyphInfo[m_CharacterCount];
696 int padding = m_Padding;
698 bool autoSizing = m_PointSizeSamplingMode == 0;
700 float strokeSize = m_FontStyleValue;
701 if (m_RenderMode == RenderModes.DistanceField16) strokeSize = m_FontStyleValue * 16;
702 if (m_RenderMode == RenderModes.DistanceField32) strokeSize = m_FontStyleValue * 32;
704 m_IsProcessing =
true;
705 m_IsGenerationCancelled =
false;
708 m_StopWatch = System.Diagnostics.Stopwatch.StartNew();
710 ThreadPool.QueueUserWorkItem(someTask =>
712 m_IsRenderingDone =
false;
714 errorCode = TMPro_FontPlugin.Render_Characters(m_TextureBuffer, m_AtlasWidth, m_AtlasHeight, padding, characterSet, m_CharacterCount, m_FontStyle, strokeSize, autoSizing, m_RenderMode, (
int)m_PackingMode, ref m_FontFaceInfo, m_FontGlyphInfo);
715 m_IsRenderingDone =
true;
727 Rect progressRect = EditorGUILayout.GetControlRect(
false, 20);
729 bool isEnabled = GUI.enabled;
731 EditorGUI.ProgressBar(progressRect, m_IsProcessing ? m_RenderingProgress : 0,
"Generation Progress");
732 progressRect.x = progressRect.x + progressRect.width - 20;
734 progressRect.width = 20;
735 progressRect.height = 16;
737 GUI.enabled = m_IsProcessing;
738 if (GUI.Button(progressRect,
"X"))
740 TMPro_FontPlugin.SendCancellationRequest(CancellationRequestType.CancelInProgess);
741 m_RenderingProgress = 0;
742 m_IsProcessing =
false;
743 m_IsGenerationCancelled =
true;
745 GUI.enabled = isEnabled;
748 GUISkin skin = GUI.skin;
753 GUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Height(145));
754 m_OutputScrollPosition = EditorGUILayout.BeginScrollView(m_OutputScrollPosition);
755 EditorGUILayout.LabelField(m_OutputFeedback, TMP_UIStyleManager.label);
756 EditorGUILayout.EndScrollView();
757 GUILayout.EndVertical();
762 GUI.enabled = m_FontAtlas !=
null && !m_IsProcessing;
764 EditorGUILayout.BeginHorizontal();
766 if (GUILayout.Button(
"Save") && GUI.enabled)
768 if (m_SelectedFontAsset ==
null)
770 if (m_LegacyFontAsset !=
null)
778 string filePath = Path.GetFullPath(AssetDatabase.GetAssetPath(m_SelectedFontAsset)).Replace(
'\\',
'/');
780 if (m_RenderMode < RenderModes.DistanceField16)
781 Save_Normal_FontAsset(filePath);
783 Save_SDF_FontAsset(filePath);
786 if (GUILayout.Button(
"Save as...") && GUI.enabled)
788 if (m_SelectedFontAsset ==
null)
798 EditorGUILayout.EndHorizontal();
800 EditorGUILayout.Space();
806 if (position.height > position.width || position.width < k_TwoColumnControlsWidth)
812 EditorGUILayout.EndScrollView();
814 if (m_IsFontAtlasInvalid)
824 m_IsFontAtlasInvalid =
false;
826 if (m_FontAtlas !=
null)
828 DestroyImmediate(m_FontAtlas);
832 m_SavedFontAtlas =
null;
834 m_OutputFeedback =
string.Empty;
835 m_WarningMessage =
string.Empty;
844 m_PointSize = m_FontFaceInfo.pointSize;
846 string colorTag = m_FontFaceInfo.characterCount == m_CharacterCount ?
"<color=#C0ffff>" :
"<color=#ffff00>";
847 string colorTag2 =
"<color=#C0ffff>";
849 var missingGlyphReport = k_OutputNameLabel +
"<b>" + colorTag2 + m_FontFaceInfo.name +
"</color></b>";
851 if (missingGlyphReport.Length > 60)
852 missingGlyphReport +=
"\n" + k_OutputSizeLabel +
"<b>" + colorTag2 + m_FontFaceInfo.pointSize +
"</color></b>";
854 missingGlyphReport +=
" " + k_OutputSizeLabel +
"<b>" + colorTag2 + m_FontFaceInfo.pointSize +
"</color></b>";
856 missingGlyphReport +=
"\n" + k_OutputCountLabel +
"<b>" + colorTag + m_FontFaceInfo.characterCount +
"/" + m_CharacterCount +
"</color></b>";
859 missingGlyphReport +=
"\n\n<color=#ffff00><b>Missing Characters</b></color>";
860 missingGlyphReport +=
"\n----------------------------------------";
862 m_OutputFeedback = missingGlyphReport;
864 for (
int i = 0; i < m_CharacterCount; i++)
866 if (m_FontGlyphInfo[i].x == -1)
868 missingGlyphReport +=
"\nID: <color=#C0ffff>" + m_FontGlyphInfo[i].id +
"\t</color>Hex: <color=#C0ffff>" + m_FontGlyphInfo[i].id.ToString(
"X") +
"\t</color>Char [<color=#C0ffff>" + (char)m_FontGlyphInfo[i].
id +
"</color>]";
870 if (missingGlyphReport.Length < 16300)
871 m_OutputFeedback = missingGlyphReport;
875 if (missingGlyphReport.Length > 16300)
876 m_OutputFeedback +=
"\n\n<color=#ffff00>Report truncated.</color>\n<color=#c0ffff>See</color> \"TextMesh Pro\\Glyph Report.txt\"";
879 if (Directory.Exists(
"Assets/TextMesh Pro"))
881 missingGlyphReport = System.Text.RegularExpressions.Regex.Replace(missingGlyphReport,
@"<[^>]*>",
string.Empty);
882 File.WriteAllText(
"Assets/TextMesh Pro/Glyph Report.txt", missingGlyphReport);
883 AssetDatabase.Refresh();
888 void CreateFontTexture()
890 m_FontAtlas =
new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.Alpha8,
false,
true);
892 Color32[] colors =
new Color32[m_AtlasWidth * m_AtlasHeight];
894 for (
int i = 0; i < (m_AtlasWidth * m_AtlasHeight); i++)
896 byte c = m_TextureBuffer[i];
897 colors[i] =
new Color32(c, c, c, c);
900 m_TextureBuffer =
null;
902 if (m_RenderMode == RenderModes.Raster || m_RenderMode == RenderModes.RasterHinted)
903 m_FontAtlas.filterMode = FilterMode.Point;
905 m_FontAtlas.SetPixels32(colors, 0);
906 m_FontAtlas.Apply(
false,
true);
919 string saveDirectory =
new FileInfo(AssetDatabase.GetAssetPath(sourceObject)).DirectoryName;
921 if (m_RenderMode < RenderModes.DistanceField16)
923 filePath = EditorUtility.SaveFilePanel(
"Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name,
"asset");
925 if (filePath.Length == 0)
928 Save_Normal_FontAsset(filePath);
930 else if (m_RenderMode >= RenderModes.DistanceField16)
932 filePath = EditorUtility.SaveFilePanel(
"Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name +
" SDF",
"asset");
934 if (filePath.Length == 0)
937 Save_SDF_FontAsset(filePath);
951 string saveDirectory =
new FileInfo(AssetDatabase.GetAssetPath(sourceObject)).DirectoryName;
953 filePath = EditorUtility.SaveFilePanel(
"Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name,
"asset");
955 if (filePath.Length == 0)
958 if (m_RenderMode < RenderModes.DistanceField16)
960 Save_Normal_FontAsset(filePath);
962 else if (m_RenderMode >= RenderModes.DistanceField16)
964 Save_SDF_FontAsset(filePath);
969 void Save_Normal_FontAsset(
string filePath)
971 filePath = filePath.Substring(0, filePath.Length - 6);
973 string dataPath = Application.dataPath;
975 if (filePath.IndexOf(dataPath, System.StringComparison.InvariantCultureIgnoreCase) == -1)
977 Debug.LogError(
"You're saving the font asset in a directory outside of this project folder. This is not supported. Please select a directory under \"" + dataPath +
"\"");
981 string relativeAssetPath = filePath.Substring(dataPath.Length - 6);
982 string tex_DirName = Path.GetDirectoryName(relativeAssetPath);
983 string tex_FileName = Path.GetFileNameWithoutExtension(relativeAssetPath);
984 string tex_Path_NoExt = tex_DirName +
"/" + tex_FileName;
988 if (fontAsset ==
null)
991 fontAsset = ScriptableObject.CreateInstance<
TMP_FontAsset>();
992 AssetDatabase.CreateAsset(fontAsset, tex_Path_NoExt +
".asset");
995 fontAsset.fontAssetType =
TMP_FontAsset.FontAssetTypes.Bitmap;
1001 FaceInfo face = GetFaceInfo(m_FontFaceInfo, 1);
1005 TMP_Glyph[] glyphs = GetGlyphInfo(m_FontGlyphInfo, 1);
1009 if (m_IncludeKerningPairs)
1011 string fontFilePath = AssetDatabase.GetAssetPath(m_SourceFontFile);
1012 KerningTable kerningTable = GetKerningTable(fontFilePath, (
int)face.PointSize);
1018 fontAsset.atlas = m_FontAtlas;
1019 m_FontAtlas.name = tex_FileName +
" Atlas";
1021 AssetDatabase.AddObjectToAsset(m_FontAtlas, fontAsset);
1024 Shader default_Shader = Shader.Find(
"TextMeshPro/Bitmap");
1025 Material tmp_material =
new Material(default_Shader);
1026 tmp_material.name = tex_FileName +
" Material";
1027 tmp_material.SetTexture(ShaderUtilities.ID_MainTex, m_FontAtlas);
1030 AssetDatabase.AddObjectToAsset(tmp_material, fontAsset);
1036 Material[] material_references = TMP_EditorUtility.FindMaterialReferences(fontAsset);
1039 DestroyImmediate(fontAsset.atlas,
true);
1042 fontAsset.fontAssetType = TMP_FontAsset.FontAssetTypes.Bitmap;
1045 FaceInfo face = GetFaceInfo(m_FontFaceInfo, 1);
1049 TMP_Glyph[] glyphs = GetGlyphInfo(m_FontGlyphInfo, 1);
1053 if (m_IncludeKerningPairs)
1055 string fontFilePath = AssetDatabase.GetAssetPath(m_SourceFontFile);
1056 KerningTable kerningTable = GetKerningTable(fontFilePath, (
int)face.PointSize);
1061 fontAsset.atlas = m_FontAtlas;
1062 m_FontAtlas.name = tex_FileName +
" Atlas";
1065 m_FontAtlas.hideFlags = HideFlags.None;
1066 fontAsset.
material.hideFlags = HideFlags.None;
1068 AssetDatabase.AddObjectToAsset(m_FontAtlas, fontAsset);
1071 fontAsset.
material.SetTexture(ShaderUtilities.ID_MainTex, fontAsset.atlas);
1074 for (
int i = 0; i < material_references.Length; i++)
1076 material_references[i].SetTexture(ShaderUtilities.ID_MainTex, m_FontAtlas);
1081 m_SelectedFontAsset = fontAsset;
1082 m_LegacyFontAsset =
null;
1085 AssetDatabase.SaveAssets();
1087 AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(fontAsset));
1092 AssetDatabase.Refresh();
1097 TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(
true, fontAsset);
1101 void Save_SDF_FontAsset(
string filePath)
1103 filePath = filePath.Substring(0, filePath.Length - 6);
1105 string dataPath = Application.dataPath;
1107 if (filePath.IndexOf(dataPath, System.StringComparison.InvariantCultureIgnoreCase) == -1)
1109 Debug.LogError(
"You're saving the font asset in a directory outside of this project folder. This is not supported. Please select a directory under \"" + dataPath +
"\"");
1113 string relativeAssetPath = filePath.Substring(dataPath.Length - 6);
1114 string tex_DirName = Path.GetDirectoryName(relativeAssetPath);
1115 string tex_FileName = Path.GetFileNameWithoutExtension(relativeAssetPath);
1116 string tex_Path_NoExt = tex_DirName +
"/" + tex_FileName;
1120 TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(tex_Path_NoExt +
".asset");
1121 if (fontAsset ==
null)
1124 fontAsset = ScriptableObject.CreateInstance<TMP_FontAsset>();
1125 AssetDatabase.CreateAsset(fontAsset, tex_Path_NoExt +
".asset");
1131 fontAsset.fontAssetType = TMP_FontAsset.FontAssetTypes.SDF;
1137 int scaleDownFactor = 1;
1140 FaceInfo face = GetFaceInfo(m_FontFaceInfo, scaleDownFactor);
1141 fontAsset.AddFaceInfo(face);
1144 TMP_Glyph[] glyphs = GetGlyphInfo(m_FontGlyphInfo, scaleDownFactor);
1145 fontAsset.AddGlyphInfo(glyphs);
1148 if (m_IncludeKerningPairs)
1150 string fontFilePath = AssetDatabase.GetAssetPath(m_SourceFontFile);
1151 KerningTable kerningTable = GetKerningTable(fontFilePath, (
int)face.PointSize);
1152 fontAsset.AddKerningInfo(kerningTable);
1160 fontAsset.atlas = m_FontAtlas;
1161 m_FontAtlas.name = tex_FileName +
" Atlas";
1163 AssetDatabase.AddObjectToAsset(m_FontAtlas, fontAsset);
1166 Shader default_Shader = Shader.Find(
"TextMeshPro/Distance Field");
1167 Material tmp_material =
new Material(default_Shader);
1169 tmp_material.name = tex_FileName +
" Material";
1170 tmp_material.SetTexture(ShaderUtilities.ID_MainTex, m_FontAtlas);
1171 tmp_material.SetFloat(ShaderUtilities.ID_TextureWidth, m_FontAtlas.width);
1172 tmp_material.SetFloat(ShaderUtilities.ID_TextureHeight, m_FontAtlas.height);
1174 int spread = m_Padding + 1;
1175 tmp_material.SetFloat(ShaderUtilities.ID_GradientScale, spread);
1177 tmp_material.SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle);
1178 tmp_material.SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle);
1180 fontAsset.material = tmp_material;
1182 AssetDatabase.AddObjectToAsset(tmp_material, fontAsset);
1188 Material[] material_references = TMP_EditorUtility.FindMaterialReferences(fontAsset);
1191 DestroyImmediate(fontAsset.atlas,
true);
1194 fontAsset.fontAssetType = TMP_FontAsset.FontAssetTypes.SDF;
1196 int scaleDownFactor = 1;
1198 FaceInfo face = GetFaceInfo(m_FontFaceInfo, scaleDownFactor);
1199 fontAsset.AddFaceInfo(face);
1202 TMP_Glyph[] glyphs = GetGlyphInfo(m_FontGlyphInfo, scaleDownFactor);
1203 fontAsset.AddGlyphInfo(glyphs);
1206 if (m_IncludeKerningPairs)
1208 string fontFilePath = AssetDatabase.GetAssetPath(m_SourceFontFile);
1209 KerningTable kerningTable = GetKerningTable(fontFilePath, (
int)face.PointSize);
1210 fontAsset.AddKerningInfo(kerningTable);
1214 fontAsset.atlas = m_FontAtlas;
1215 m_FontAtlas.name = tex_FileName +
" Atlas";
1218 m_FontAtlas.hideFlags = HideFlags.None;
1219 fontAsset.material.hideFlags = HideFlags.None;
1221 AssetDatabase.AddObjectToAsset(m_FontAtlas, fontAsset);
1224 fontAsset.material.SetTexture(ShaderUtilities.ID_MainTex, fontAsset.atlas);
1227 for (
int i = 0; i < material_references.Length; i++)
1229 material_references[i].SetTexture(ShaderUtilities.ID_MainTex, m_FontAtlas);
1230 material_references[i].SetFloat(ShaderUtilities.ID_TextureWidth, m_FontAtlas.width);
1231 material_references[i].SetFloat(ShaderUtilities.ID_TextureHeight, m_FontAtlas.height);
1233 int spread = m_Padding + 1;
1234 material_references[i].SetFloat(ShaderUtilities.ID_GradientScale, spread);
1236 material_references[i].SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle);
1237 material_references[i].SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle);
1246 m_SelectedFontAsset = fontAsset;
1247 m_LegacyFontAsset =
null;
1250 AssetDatabase.SaveAssets();
1252 AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(fontAsset));
1254 fontAsset.ReadFontDefinition();
1256 AssetDatabase.Refresh();
1261 TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(
true, fontAsset);
1274 settings.sourceFontFileGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_SourceFontFile));
1275 settings.pointSizeSamplingMode = m_PointSizeSamplingMode;
1276 settings.pointSize = m_PointSize;
1277 settings.padding = m_Padding;
1278 settings.packingMode = (int)m_PackingMode;
1279 settings.atlasWidth = m_AtlasWidth;
1280 settings.atlasHeight = m_AtlasHeight;
1281 settings.characterSetSelectionMode = m_CharacterSetSelectionMode;
1282 settings.characterSequence = m_CharacterSequence;
1283 settings.referencedFontAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferencedFontAsset));
1284 settings.referencedTextAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_CharacterList));
1285 settings.fontStyle = (int)m_FontStyle;
1286 settings.fontStyleModifier = m_FontStyleValue;
1287 settings.renderMode = (int)m_RenderMode;
1288 settings.includeFontFeatures = m_IncludeKerningPairs;
1299 m_SourceFontFile = AssetDatabase.LoadAssetAtPath<Font>(AssetDatabase.GUIDToAssetPath(settings.sourceFontFileGUID));
1300 m_PointSizeSamplingMode = settings.pointSizeSamplingMode;
1301 m_PointSize = settings.pointSize;
1302 m_Padding = settings.padding;
1303 m_PackingMode = (FontPackingModes)settings.packingMode;
1304 m_AtlasWidth = settings.atlasWidth;
1305 m_AtlasHeight = settings.atlasHeight;
1306 m_CharacterSetSelectionMode = settings.characterSetSelectionMode;
1307 m_CharacterSequence = settings.characterSequence;
1308 m_ReferencedFontAsset = AssetDatabase.LoadAssetAtPath<
TMP_FontAsset>(AssetDatabase.GUIDToAssetPath(settings.referencedFontAssetGUID));
1309 m_CharacterList = AssetDatabase.LoadAssetAtPath<TextAsset>(AssetDatabase.GUIDToAssetPath(settings.referencedTextAssetGUID));
1310 m_FontStyle = (FaceStyles)settings.fontStyle;
1311 m_FontStyleValue = settings.fontStyleModifier;
1312 m_RenderMode = (RenderModes)settings.renderMode;
1313 m_IncludeKerningPairs = settings.includeFontFeatures;
1324 if (m_FontAssetCreationSettingsContainer ==
null)
1327 m_FontAssetCreationSettingsContainer.fontAssetCreationSettings =
new List<FontAssetCreationSettings>();
1331 m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Add(settings);
1334 if (m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count > 4)
1335 m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.RemoveAt(0);
1337 m_FontAssetCreationSettingsCurrentIndex = m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count - 1;
1340 string serializedSettings = JsonUtility.ToJson(m_FontAssetCreationSettingsContainer,
true);
1342 EditorPrefs.SetString(k_FontAssetCreationSettingsContainerKey, serializedSettings);
1348 if (position.width > position.height && position.width > k_TwoColumnControlsWidth)
1350 float minSide = Mathf.Min(position.height - 15f, position.width - k_TwoColumnControlsWidth);
1352 EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.MaxWidth(minSide));
1354 pixelRect = GUILayoutUtility.GetRect(minSide, minSide, GUILayout.ExpandHeight(
false), GUILayout.ExpandWidth(
false));
1358 EditorGUILayout.BeginVertical(EditorStyles.helpBox);
1360 pixelRect = GUILayoutUtility.GetAspectRect(1f);
1363 if (m_FontAtlas !=
null)
1365 EditorGUI.DrawTextureAlpha(pixelRect, m_FontAtlas, ScaleMode.StretchToFill);
1367 else if (m_SavedFontAtlas !=
null)
1369 EditorGUI.DrawTextureAlpha(pixelRect, m_SavedFontAtlas, ScaleMode.StretchToFill);
1372 EditorGUILayout.EndVertical();
1377 static FaceInfo GetFaceInfo(FT_FaceInfo ftFace,
int scaleFactor)
1379 FaceInfo face =
new FaceInfo();
1381 face.Name = ftFace.name;
1382 face.PointSize = (float)ftFace.pointSize / scaleFactor;
1383 face.Padding = ftFace.padding / scaleFactor;
1384 face.LineHeight = ftFace.lineHeight / scaleFactor;
1387 face.Ascender = ftFace.ascender / scaleFactor;
1388 face.Descender = ftFace.descender / scaleFactor;
1389 face.CenterLine = ftFace.centerLine / scaleFactor;
1390 face.Underline = ftFace.underline / scaleFactor;
1391 face.UnderlineThickness = ftFace.underlineThickness == 0 ? 5 : ftFace.underlineThickness / scaleFactor;
1392 face.strikethrough = (face.Ascender + face.Descender) / 2.75f;
1393 face.strikethroughThickness = face.UnderlineThickness;
1394 face.SuperscriptOffset = face.Ascender;
1395 face.SubscriptOffset = face.Underline;
1396 face.SubSize = 0.5f;
1398 face.AtlasWidth = ftFace.atlasWidth / scaleFactor;
1399 face.AtlasHeight = ftFace.atlasHeight / scaleFactor;
1406 TMP_Glyph[] GetGlyphInfo(FT_GlyphInfo[] ftGlyphs,
int scaleFactor)
1408 List<TMP_Glyph> glyphs =
new List<TMP_Glyph>();
1409 List<int> kerningSet =
new List<int>();
1411 for (
int i = 0; i < ftGlyphs.Length; i++)
1413 TMP_Glyph g =
new TMP_Glyph();
1415 g.id = ftGlyphs[i].id;
1416 g.x = ftGlyphs[i].x / scaleFactor;
1417 g.y = ftGlyphs[i].y / scaleFactor;
1418 g.width = ftGlyphs[i].width / scaleFactor;
1419 g.height = ftGlyphs[i].height / scaleFactor;
1420 g.xOffset = ftGlyphs[i].xOffset / scaleFactor;
1421 g.yOffset = ftGlyphs[i].yOffset / scaleFactor;
1422 g.xAdvance = ftGlyphs[i].xAdvance / scaleFactor;
1429 kerningSet.Add(g.id);
1432 m_KerningSet = kerningSet.ToArray();
1434 return glyphs.ToArray();
1439 public KerningTable GetKerningTable(
string fontFilePath,
int pointSize)
1441 KerningTable kerningInfo =
new KerningTable();
1442 kerningInfo.kerningPairs =
new List<KerningPair>();
1445 FT_KerningPair[] kerningPairs =
new FT_KerningPair[7500];
1447 int kpCount = TMPro_FontPlugin.FT_GetKerningPairs(fontFilePath, m_KerningSet, m_KerningSet.Length, kerningPairs);
1449 for (
int i = 0; i < kpCount; i++)
1452 KerningPair kp =
new KerningPair((uint)kerningPairs[i].ascII_Left, (uint)kerningPairs[i].ascII_Right, kerningPairs[i].xAdvanceOffset * pointSize);
1455 int index = kerningInfo.kerningPairs.FindIndex(item => item.firstGlyph == kp.firstGlyph && item.secondGlyph == kp.secondGlyph);
1458 kerningInfo.kerningPairs.Add(kp);
1460 if (!TMP_Settings.warningsDisabled) Debug.LogWarning(
"Kerning Key for [" + kp.firstGlyph +
"] and [" + kp.secondGlyph +
"] is a duplicate.");
void SaveNewFontAssetWithSameName(Object sourceObject)
Open Save Dialog to provide the option to save the font asset under the same name.
void AddKerningInfo(KerningTable kerningTable)
void SaveNewFontAsset(Object sourceObject)
Open Save Dialog to provide the option save the font asset using the name of the source font file....
static int [] ParseNumberSequence(string sequence)
Method which returns the character corresponding to a decimal value.
FontAssetCreationSettings SaveFontCreationSettings()
Internal method to save the Font Asset Creation Settings
void UpdateRenderFeedbackWindow()
Function to update the feedback window showing the results of the latest generation.
static int [] ParseHexNumberSequence(string sequence)
Method which returns the character (decimal value) from a hex sequence.
void SaveCreationSettingsToEditorPrefs(FontAssetCreationSettings settings)
Save the latest font asset creation settings to EditorPrefs.
void ReadFontDefinition()
void LoadFontCreationSettings(FontAssetCreationSettings settings)
Internal method to load the Font Asset Creation Settings
Material material
The material used by this asset.
void ClearGeneratedData()
Clear the previously generated data.
FontAssetCreationSettings creationSettings
The settings used in the Font Asset Creator when this font asset was created or edited.
void AddFaceInfo(FaceInfo faceInfo)
Class that contains the basic information about the font.
void AddGlyphInfo(TMP_Glyph[] glyphInfo)