No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TMPro_FontAssetCreatorWindow.cs 95KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136
  1. using System;
  2. using UnityEngine;
  3. using UnityEditor;
  4. using System.Collections.Generic;
  5. using System.Globalization;
  6. using System.Threading;
  7. using System.IO;
  8. using System.Text.RegularExpressions;
  9. using UnityEngine.TextCore;
  10. using UnityEngine.TextCore.LowLevel;
  11. using UnityEditor.TextCore.LowLevel;
  12. using Object = UnityEngine.Object;
  13. namespace TMPro.EditorUtilities
  14. {
  15. public class TMPro_FontAssetCreatorWindow : EditorWindow
  16. {
  17. [MenuItem("Window/TextMeshPro/Font Asset Creator", false, 2025)]
  18. public static void ShowFontAtlasCreatorWindow()
  19. {
  20. var window = GetWindow<TMPro_FontAssetCreatorWindow>();
  21. window.titleContent = new GUIContent("Font Asset Creator");
  22. window.Focus();
  23. // Make sure TMP Essential Resources have been imported.
  24. window.CheckEssentialResources();
  25. }
  26. public static void ShowFontAtlasCreatorWindow(Font font)
  27. {
  28. var window = GetWindow<TMPro_FontAssetCreatorWindow>();
  29. window.titleContent = new GUIContent("Font Asset Creator");
  30. window.Focus();
  31. window.ClearGeneratedData();
  32. window.m_LegacyFontAsset = null;
  33. window.m_SelectedFontAsset = null;
  34. // Override selected font asset
  35. window.m_SourceFont = font;
  36. // Make sure TMP Essential Resources have been imported.
  37. window.CheckEssentialResources();
  38. }
  39. public static void ShowFontAtlasCreatorWindow(TMP_FontAsset fontAsset)
  40. {
  41. var window = GetWindow<TMPro_FontAssetCreatorWindow>();
  42. window.titleContent = new GUIContent("Font Asset Creator");
  43. window.Focus();
  44. // Clear any previously generated data
  45. window.ClearGeneratedData();
  46. window.m_LegacyFontAsset = null;
  47. // Load font asset creation settings if we have valid settings
  48. if (string.IsNullOrEmpty(fontAsset.creationSettings.sourceFontFileGUID) == false)
  49. {
  50. window.LoadFontCreationSettings(fontAsset.creationSettings);
  51. // Override settings to inject character list from font asset
  52. //window.m_CharacterSetSelectionMode = 6;
  53. //window.m_CharacterSequence = TMP_EditorUtility.GetUnicodeCharacterSequence(TMP_FontAsset.GetCharactersArray(fontAsset));
  54. window.m_ReferencedFontAsset = fontAsset;
  55. window.m_SavedFontAtlas = fontAsset.atlasTexture;
  56. }
  57. else
  58. {
  59. 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.";
  60. window.m_SourceFont = null;
  61. window.m_LegacyFontAsset = fontAsset;
  62. }
  63. // Even if we don't have any saved generation settings, we still want to pre-select the source font file.
  64. window.m_SelectedFontAsset = fontAsset;
  65. // Make sure TMP Essential Resources have been imported.
  66. window.CheckEssentialResources();
  67. }
  68. [System.Serializable]
  69. class FontAssetCreationSettingsContainer
  70. {
  71. public List<FontAssetCreationSettings> fontAssetCreationSettings;
  72. }
  73. FontAssetCreationSettingsContainer m_FontAssetCreationSettingsContainer;
  74. //static readonly string[] m_FontCreationPresets = new string[] { "Recent 1", "Recent 2", "Recent 3", "Recent 4" };
  75. int m_FontAssetCreationSettingsCurrentIndex = 0;
  76. const string k_FontAssetCreationSettingsContainerKey = "TextMeshPro.FontAssetCreator.RecentFontAssetCreationSettings.Container";
  77. const string k_FontAssetCreationSettingsCurrentIndexKey = "TextMeshPro.FontAssetCreator.RecentFontAssetCreationSettings.CurrentIndex";
  78. const float k_TwoColumnControlsWidth = 335f;
  79. // Diagnostics
  80. System.Diagnostics.Stopwatch m_StopWatch;
  81. double m_GlyphPackingGenerationTime;
  82. double m_GlyphRenderingGenerationTime;
  83. string[] m_FontSizingOptions = { "Auto Sizing", "Custom Size" };
  84. int m_PointSizeSamplingMode;
  85. string[] m_FontResolutionLabels = { "8", "16", "32", "64", "128", "256", "512", "1024", "2048", "4096", "8192" };
  86. int[] m_FontAtlasResolutions = { 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192 };
  87. string[] m_FontCharacterSets = { "ASCII", "Extended ASCII", "ASCII Lowercase", "ASCII Uppercase", "Numbers + Symbols", "Custom Range", "Unicode Range (Hex)", "Custom Characters", "Characters from File" };
  88. enum FontPackingModes { Fast = 0, Optimum = 4 };
  89. FontPackingModes m_PackingMode = FontPackingModes.Fast;
  90. int m_CharacterSetSelectionMode;
  91. string m_CharacterSequence = "";
  92. string m_OutputFeedback = "";
  93. string m_WarningMessage;
  94. int m_CharacterCount;
  95. Vector2 m_ScrollPosition;
  96. Vector2 m_OutputScrollPosition;
  97. bool m_IsRepaintNeeded;
  98. float m_AtlasGenerationProgress;
  99. string m_AtlasGenerationProgressLabel = string.Empty;
  100. bool m_IsGlyphPackingDone;
  101. bool m_IsGlyphRenderingDone;
  102. bool m_IsRenderingDone;
  103. bool m_IsProcessing;
  104. bool m_IsGenerationDisabled;
  105. bool m_IsGenerationCancelled;
  106. bool m_IsFontAtlasInvalid;
  107. Font m_SourceFont;
  108. int m_SourceFontFaceIndex;
  109. private string[] m_SourceFontFaces = new string[0];
  110. TMP_FontAsset m_SelectedFontAsset;
  111. TMP_FontAsset m_LegacyFontAsset;
  112. TMP_FontAsset m_ReferencedFontAsset;
  113. TextAsset m_CharactersFromFile;
  114. int m_PointSize;
  115. float m_PaddingFieldValue = 10;
  116. int m_Padding;
  117. enum PaddingMode { Undefined = 0, Percentage = 1, Pixel = 2 };
  118. string[] k_PaddingOptionLabels = { "%", "px" };
  119. private PaddingMode m_PaddingMode = PaddingMode.Percentage;
  120. GlyphRenderMode m_GlyphRenderMode = GlyphRenderMode.SDFAA;
  121. int m_AtlasWidth = 512;
  122. int m_AtlasHeight = 512;
  123. byte[] m_AtlasTextureBuffer;
  124. Texture2D m_FontAtlasTexture;
  125. Texture2D m_GlyphRectPreviewTexture;
  126. Texture2D m_SavedFontAtlas;
  127. //
  128. List<Glyph> m_FontGlyphTable = new List<Glyph>();
  129. List<TMP_Character> m_FontCharacterTable = new List<TMP_Character>();
  130. Dictionary<uint, uint> m_CharacterLookupMap = new Dictionary<uint, uint>();
  131. Dictionary<uint, List<uint>> m_GlyphLookupMap = new Dictionary<uint, List<uint>>();
  132. List<Glyph> m_GlyphsToPack = new List<Glyph>();
  133. List<Glyph> m_GlyphsPacked = new List<Glyph>();
  134. List<GlyphRect> m_FreeGlyphRects = new List<GlyphRect>();
  135. List<GlyphRect> m_UsedGlyphRects = new List<GlyphRect>();
  136. List<Glyph> m_GlyphsToRender = new List<Glyph>();
  137. List<uint> m_AvailableGlyphsToAdd = new List<uint>();
  138. List<uint> m_MissingCharacters = new List<uint>();
  139. List<uint> m_ExcludedCharacters = new List<uint>();
  140. private FaceInfo m_FaceInfo;
  141. bool m_IncludeFontFeatures;
  142. public void OnEnable()
  143. {
  144. // Used for Diagnostics
  145. m_StopWatch = new System.Diagnostics.Stopwatch();
  146. // Set Editor window size.
  147. minSize = new Vector2(315, minSize.y);
  148. // Initialize & Get shader property IDs.
  149. ShaderUtilities.GetShaderPropertyIDs();
  150. // Load last selected preset if we are not already in the process of regenerating an existing font asset (via the Context menu)
  151. if (EditorPrefs.HasKey(k_FontAssetCreationSettingsContainerKey))
  152. {
  153. if (m_FontAssetCreationSettingsContainer == null)
  154. m_FontAssetCreationSettingsContainer = JsonUtility.FromJson<FontAssetCreationSettingsContainer>(EditorPrefs.GetString(k_FontAssetCreationSettingsContainerKey));
  155. if (m_FontAssetCreationSettingsContainer.fontAssetCreationSettings != null && m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count > 0)
  156. {
  157. // Load Font Asset Creation Settings preset.
  158. if (EditorPrefs.HasKey(k_FontAssetCreationSettingsCurrentIndexKey))
  159. m_FontAssetCreationSettingsCurrentIndex = EditorPrefs.GetInt(k_FontAssetCreationSettingsCurrentIndexKey);
  160. LoadFontCreationSettings(m_FontAssetCreationSettingsContainer.fontAssetCreationSettings[m_FontAssetCreationSettingsCurrentIndex]);
  161. }
  162. }
  163. // Get potential font face and styles for the current font.
  164. if (m_SourceFont != null)
  165. m_SourceFontFaces = GetFontFaces();
  166. ClearGeneratedData();
  167. }
  168. public void OnDisable()
  169. {
  170. //Debug.Log("TextMeshPro Editor Window has been disabled.");
  171. // Destroy Engine only if it has been initialized already
  172. FontEngine.DestroyFontEngine();
  173. ClearGeneratedData();
  174. // Remove Glyph Report if one was created.
  175. if (File.Exists("Assets/TextMesh Pro/Glyph Report.txt"))
  176. {
  177. File.Delete("Assets/TextMesh Pro/Glyph Report.txt");
  178. File.Delete("Assets/TextMesh Pro/Glyph Report.txt.meta");
  179. AssetDatabase.Refresh();
  180. }
  181. // Save Font Asset Creation Settings Index
  182. SaveCreationSettingsToEditorPrefs(SaveFontCreationSettings());
  183. EditorPrefs.SetInt(k_FontAssetCreationSettingsCurrentIndexKey, m_FontAssetCreationSettingsCurrentIndex);
  184. // Unregister to event
  185. TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
  186. Resources.UnloadUnusedAssets();
  187. }
  188. // Event received when TMP resources have been loaded.
  189. void ON_RESOURCES_LOADED()
  190. {
  191. TMPro_EventManager.RESOURCE_LOAD_EVENT.Remove(ON_RESOURCES_LOADED);
  192. m_IsGenerationDisabled = false;
  193. }
  194. // Make sure TMP Essential Resources have been imported.
  195. void CheckEssentialResources()
  196. {
  197. if (TMP_Settings.instance == null)
  198. {
  199. if (m_IsGenerationDisabled == false)
  200. TMPro_EventManager.RESOURCE_LOAD_EVENT.Add(ON_RESOURCES_LOADED);
  201. m_IsGenerationDisabled = true;
  202. }
  203. }
  204. public void OnGUI()
  205. {
  206. GUILayout.BeginHorizontal();
  207. DrawControls();
  208. if (position.width > position.height && position.width > k_TwoColumnControlsWidth)
  209. DrawPreview();
  210. GUILayout.EndHorizontal();
  211. }
  212. public void Update()
  213. {
  214. if (m_IsRepaintNeeded)
  215. {
  216. //Debug.Log("Repainting...");
  217. m_IsRepaintNeeded = false;
  218. Repaint();
  219. }
  220. // Update Progress bar is we are Rendering a Font.
  221. if (m_IsProcessing)
  222. {
  223. m_AtlasGenerationProgress = FontEngine.generationProgress;
  224. m_IsRepaintNeeded = true;
  225. }
  226. if (m_IsGlyphPackingDone)
  227. {
  228. UpdateRenderFeedbackWindow();
  229. if (m_IsGenerationCancelled == false)
  230. {
  231. DrawGlyphRectPreviewTexture();
  232. Debug.Log("Glyph packing completed in: " + m_GlyphPackingGenerationTime.ToString("0.000 ms."));
  233. }
  234. m_IsGlyphPackingDone = false;
  235. }
  236. if (m_IsGlyphRenderingDone)
  237. {
  238. Debug.Log("Font Atlas generation completed in: " + m_GlyphRenderingGenerationTime.ToString("0.000 ms."));
  239. m_IsGlyphRenderingDone = false;
  240. }
  241. // Update Feedback Window & Create Font Texture once Rendering is done.
  242. if (m_IsRenderingDone)
  243. {
  244. m_IsProcessing = false;
  245. m_IsRenderingDone = false;
  246. if (m_IsGenerationCancelled == false)
  247. {
  248. m_AtlasGenerationProgress = FontEngine.generationProgress;
  249. m_AtlasGenerationProgressLabel = "Generation completed in: " + (m_GlyphPackingGenerationTime + m_GlyphRenderingGenerationTime).ToString("0.00 ms.");
  250. UpdateRenderFeedbackWindow();
  251. CreateFontAtlasTexture();
  252. // If dynamic make readable ...
  253. m_FontAtlasTexture.Apply(false, false);
  254. }
  255. Repaint();
  256. }
  257. }
  258. /// <summary>
  259. /// Method which returns the character corresponding to a decimal value.
  260. /// </summary>
  261. /// <param name="sequence"></param>
  262. /// <returns></returns>
  263. static uint[] ParseNumberSequence(string sequence)
  264. {
  265. List<uint> unicodeList = new List<uint>();
  266. string[] sequences = sequence.Split(',');
  267. foreach (string seq in sequences)
  268. {
  269. string[] s1 = seq.Split('-');
  270. if (s1.Length == 1)
  271. try
  272. {
  273. unicodeList.Add(uint.Parse(s1[0]));
  274. }
  275. catch
  276. {
  277. Debug.Log("No characters selected or invalid format.");
  278. }
  279. else
  280. {
  281. for (uint j = uint.Parse(s1[0]); j < uint.Parse(s1[1]) + 1; j++)
  282. {
  283. unicodeList.Add(j);
  284. }
  285. }
  286. }
  287. return unicodeList.ToArray();
  288. }
  289. /// <summary>
  290. /// Method which returns the character (decimal value) from a hex sequence.
  291. /// </summary>
  292. /// <param name="sequence"></param>
  293. /// <returns></returns>
  294. static uint[] ParseHexNumberSequence(string sequence)
  295. {
  296. List<uint> unicodeList = new List<uint>();
  297. string[] sequences = sequence.Split(',');
  298. foreach (string seq in sequences)
  299. {
  300. string[] s1 = seq.Split('-');
  301. if (s1.Length == 1)
  302. try
  303. {
  304. unicodeList.Add(uint.Parse(s1[0], NumberStyles.AllowHexSpecifier));
  305. }
  306. catch
  307. {
  308. Debug.Log("No characters selected or invalid format.");
  309. }
  310. else
  311. {
  312. for (uint j = uint.Parse(s1[0], NumberStyles.AllowHexSpecifier); j < uint.Parse(s1[1], NumberStyles.AllowHexSpecifier) + 1; j++)
  313. {
  314. unicodeList.Add(j);
  315. }
  316. }
  317. }
  318. return unicodeList.ToArray();
  319. }
  320. void DrawControls()
  321. {
  322. GUILayout.Space(5f);
  323. if (position.width > position.height && position.width > k_TwoColumnControlsWidth)
  324. {
  325. m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition, GUILayout.Width(315));
  326. }
  327. else
  328. {
  329. m_ScrollPosition = EditorGUILayout.BeginScrollView(m_ScrollPosition);
  330. }
  331. GUILayout.Space(5f);
  332. GUILayout.Label(m_SelectedFontAsset != null ? string.Format("Font Settings [{0}]", m_SelectedFontAsset.name) : "Font Settings", EditorStyles.boldLabel);
  333. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  334. EditorGUIUtility.labelWidth = 125f;
  335. EditorGUIUtility.fieldWidth = 5f;
  336. // Disable Options if already generating a font atlas texture.
  337. EditorGUI.BeginDisabledGroup(m_IsProcessing);
  338. {
  339. // FONT SELECTION
  340. EditorGUI.BeginChangeCheck();
  341. m_SourceFont = EditorGUILayout.ObjectField("Source Font", m_SourceFont, typeof(Font), false) as Font;
  342. if (EditorGUI.EndChangeCheck())
  343. {
  344. m_SelectedFontAsset = null;
  345. m_IsFontAtlasInvalid = true;
  346. if (m_SourceFont != null)
  347. m_SourceFontFaces = GetFontFaces();
  348. m_SourceFontFaceIndex = 0;
  349. }
  350. // FONT FACE AND STYLE SELECTION
  351. EditorGUI.BeginChangeCheck();
  352. GUI.enabled = m_SourceFont != null;
  353. m_SourceFontFaceIndex = EditorGUILayout.Popup("Font Face", m_SourceFontFaceIndex, m_SourceFontFaces);
  354. if (EditorGUI.EndChangeCheck())
  355. {
  356. m_SelectedFontAsset = null;
  357. m_IsFontAtlasInvalid = true;
  358. }
  359. GUI.enabled = true;
  360. // FONT SIZING
  361. EditorGUI.BeginChangeCheck();
  362. if (m_PointSizeSamplingMode == 0)
  363. {
  364. m_PointSizeSamplingMode = EditorGUILayout.Popup("Sampling Point Size", m_PointSizeSamplingMode, m_FontSizingOptions);
  365. }
  366. else
  367. {
  368. GUILayout.BeginHorizontal();
  369. m_PointSizeSamplingMode = EditorGUILayout.Popup("Sampling Point Size", m_PointSizeSamplingMode, m_FontSizingOptions, GUILayout.Width(225));
  370. m_PointSize = EditorGUILayout.IntField(m_PointSize);
  371. GUILayout.EndHorizontal();
  372. }
  373. if (EditorGUI.EndChangeCheck())
  374. {
  375. m_IsFontAtlasInvalid = true;
  376. }
  377. // FONT PADDING
  378. GUILayout.BeginHorizontal();
  379. EditorGUI.BeginChangeCheck();
  380. m_PaddingFieldValue = EditorGUILayout.FloatField("Padding", m_PaddingFieldValue);
  381. int selection = m_PaddingMode == PaddingMode.Undefined || m_PaddingMode == PaddingMode.Pixel ? 1 : 0;
  382. selection = GUILayout.SelectionGrid(selection, k_PaddingOptionLabels, 2);
  383. if (m_PaddingMode == PaddingMode.Percentage)
  384. m_PaddingFieldValue = (int)(m_PaddingFieldValue + 0.5f);
  385. if (EditorGUI.EndChangeCheck())
  386. {
  387. m_PaddingMode = (PaddingMode)selection + 1;
  388. m_IsFontAtlasInvalid = true;
  389. }
  390. GUILayout.EndHorizontal();
  391. // FONT PACKING METHOD SELECTION
  392. EditorGUI.BeginChangeCheck();
  393. m_PackingMode = (FontPackingModes)EditorGUILayout.EnumPopup("Packing Method", m_PackingMode);
  394. if (EditorGUI.EndChangeCheck())
  395. {
  396. m_IsFontAtlasInvalid = true;
  397. }
  398. // FONT ATLAS RESOLUTION SELECTION
  399. GUILayout.BeginHorizontal();
  400. GUI.changed = false;
  401. EditorGUI.BeginChangeCheck();
  402. EditorGUILayout.PrefixLabel("Atlas Resolution");
  403. m_AtlasWidth = EditorGUILayout.IntPopup(m_AtlasWidth, m_FontResolutionLabels, m_FontAtlasResolutions);
  404. m_AtlasHeight = EditorGUILayout.IntPopup(m_AtlasHeight, m_FontResolutionLabels, m_FontAtlasResolutions);
  405. if (EditorGUI.EndChangeCheck())
  406. {
  407. m_IsFontAtlasInvalid = true;
  408. }
  409. GUILayout.EndHorizontal();
  410. // FONT CHARACTER SET SELECTION
  411. EditorGUI.BeginChangeCheck();
  412. bool hasSelectionChanged = false;
  413. m_CharacterSetSelectionMode = EditorGUILayout.Popup("Character Set", m_CharacterSetSelectionMode, m_FontCharacterSets);
  414. if (EditorGUI.EndChangeCheck())
  415. {
  416. m_CharacterSequence = "";
  417. hasSelectionChanged = true;
  418. m_IsFontAtlasInvalid = true;
  419. }
  420. switch (m_CharacterSetSelectionMode)
  421. {
  422. case 0: // ASCII
  423. //characterSequence = "32 - 126, 130, 132 - 135, 139, 145 - 151, 153, 155, 161, 166 - 167, 169 - 174, 176, 181 - 183, 186 - 187, 191, 8210 - 8226, 8230, 8240, 8242 - 8244, 8249 - 8250, 8252 - 8254, 8260, 8286";
  424. m_CharacterSequence = "32 - 126, 160, 8203, 8230, 9633";
  425. break;
  426. case 1: // EXTENDED ASCII
  427. m_CharacterSequence = "32 - 126, 160 - 255, 8192 - 8303, 8364, 8482, 9633";
  428. // Could add 9632 for missing glyph
  429. break;
  430. case 2: // Lowercase
  431. m_CharacterSequence = "32 - 64, 91 - 126, 160";
  432. break;
  433. case 3: // Uppercase
  434. m_CharacterSequence = "32 - 96, 123 - 126, 160";
  435. break;
  436. case 4: // Numbers & Symbols
  437. m_CharacterSequence = "32 - 64, 91 - 96, 123 - 126, 160";
  438. break;
  439. case 5: // Custom Range
  440. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  441. 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);
  442. GUILayout.Space(10f);
  443. EditorGUI.BeginChangeCheck();
  444. m_ReferencedFontAsset = EditorGUILayout.ObjectField("Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset), false) as TMP_FontAsset;
  445. if (EditorGUI.EndChangeCheck() || hasSelectionChanged)
  446. {
  447. if (m_ReferencedFontAsset != null)
  448. m_CharacterSequence = TMP_EditorUtility.GetDecimalCharacterSequence(TMP_FontAsset.GetCharactersArray(m_ReferencedFontAsset));
  449. m_IsFontAtlasInvalid = true;
  450. }
  451. // Filter out unwanted characters.
  452. char chr = Event.current.character;
  453. if ((chr < '0' || chr > '9') && (chr < ',' || chr > '-'))
  454. {
  455. Event.current.character = '\0';
  456. }
  457. GUILayout.Label("Character Sequence (Decimal)", EditorStyles.boldLabel);
  458. EditorGUI.BeginChangeCheck();
  459. m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(true));
  460. if (EditorGUI.EndChangeCheck())
  461. {
  462. m_IsFontAtlasInvalid = true;
  463. }
  464. EditorGUILayout.EndVertical();
  465. break;
  466. case 6: // Unicode HEX Range
  467. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  468. 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);
  469. GUILayout.Space(10f);
  470. EditorGUI.BeginChangeCheck();
  471. m_ReferencedFontAsset = EditorGUILayout.ObjectField("Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset), false) as TMP_FontAsset;
  472. if (EditorGUI.EndChangeCheck() || hasSelectionChanged)
  473. {
  474. if (m_ReferencedFontAsset != null)
  475. m_CharacterSequence = TMP_EditorUtility.GetUnicodeCharacterSequence(TMP_FontAsset.GetCharactersArray(m_ReferencedFontAsset));
  476. m_IsFontAtlasInvalid = true;
  477. }
  478. // Filter out unwanted characters.
  479. chr = Event.current.character;
  480. if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F') && (chr < ',' || chr > '-'))
  481. {
  482. Event.current.character = '\0';
  483. }
  484. GUILayout.Label("Character Sequence (Hex)", EditorStyles.boldLabel);
  485. EditorGUI.BeginChangeCheck();
  486. m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(true));
  487. if (EditorGUI.EndChangeCheck())
  488. {
  489. m_IsFontAtlasInvalid = true;
  490. }
  491. EditorGUILayout.EndVertical();
  492. break;
  493. case 7: // Characters from Font Asset
  494. EditorGUILayout.BeginVertical(EditorStyles.helpBox);
  495. GUILayout.Label("Type the characters to be included in the font asset or retrieve them from another font asset.", TMP_UIStyleManager.label);
  496. GUILayout.Space(10f);
  497. EditorGUI.BeginChangeCheck();
  498. m_ReferencedFontAsset = EditorGUILayout.ObjectField("Select Font Asset", m_ReferencedFontAsset, typeof(TMP_FontAsset), false) as TMP_FontAsset;
  499. if (EditorGUI.EndChangeCheck() || hasSelectionChanged)
  500. {
  501. if (m_ReferencedFontAsset != null)
  502. m_CharacterSequence = TMP_FontAsset.GetCharacters(m_ReferencedFontAsset);
  503. m_IsFontAtlasInvalid = true;
  504. }
  505. EditorGUI.indentLevel = 0;
  506. GUILayout.Label("Custom Character List", EditorStyles.boldLabel);
  507. EditorGUI.BeginChangeCheck();
  508. m_CharacterSequence = EditorGUILayout.TextArea(m_CharacterSequence, TMP_UIStyleManager.textAreaBoxWindow, GUILayout.Height(120), GUILayout.ExpandWidth(true));
  509. if (EditorGUI.EndChangeCheck())
  510. {
  511. m_IsFontAtlasInvalid = true;
  512. }
  513. EditorGUILayout.EndVertical();
  514. break;
  515. case 8: // Character List from File
  516. EditorGUI.BeginChangeCheck();
  517. m_CharactersFromFile = EditorGUILayout.ObjectField("Character File", m_CharactersFromFile, typeof(TextAsset), false) as TextAsset;
  518. if (EditorGUI.EndChangeCheck())
  519. {
  520. m_IsFontAtlasInvalid = true;
  521. }
  522. if (m_CharactersFromFile != null)
  523. {
  524. Regex rx = new Regex(@"(?<!\\)(?:\\u[0-9a-fA-F]{4}|\\U[0-9a-fA-F]{8})");
  525. m_CharacterSequence = rx.Replace(m_CharactersFromFile.text,
  526. match =>
  527. {
  528. if (match.Value.StartsWith("\\U"))
  529. return char.ConvertFromUtf32(int.Parse(match.Value.Replace("\\U", ""), NumberStyles.HexNumber));
  530. return char.ConvertFromUtf32(int.Parse(match.Value.Replace("\\u", ""), NumberStyles.HexNumber));
  531. });
  532. }
  533. break;
  534. }
  535. // FONT STYLE SELECTION
  536. //GUILayout.BeginHorizontal();
  537. //EditorGUI.BeginChangeCheck();
  538. ////m_FontStyle = (FaceStyles)EditorGUILayout.EnumPopup("Font Style", m_FontStyle, GUILayout.Width(225));
  539. ////m_FontStyleValue = EditorGUILayout.IntField((int)m_FontStyleValue);
  540. //if (EditorGUI.EndChangeCheck())
  541. //{
  542. // m_IsFontAtlasInvalid = true;
  543. //}
  544. //GUILayout.EndHorizontal();
  545. // Render Mode Selection
  546. CheckForLegacyGlyphRenderMode();
  547. EditorGUI.BeginChangeCheck();
  548. m_GlyphRenderMode = (GlyphRenderMode)EditorGUILayout.EnumPopup("Render Mode", m_GlyphRenderMode);
  549. if (EditorGUI.EndChangeCheck())
  550. {
  551. m_IsFontAtlasInvalid = true;
  552. }
  553. m_IncludeFontFeatures = EditorGUILayout.Toggle("Get Font Features", m_IncludeFontFeatures);
  554. EditorGUILayout.Space();
  555. }
  556. EditorGUI.EndDisabledGroup();
  557. if (!string.IsNullOrEmpty(m_WarningMessage))
  558. {
  559. EditorGUILayout.HelpBox(m_WarningMessage, MessageType.Warning);
  560. }
  561. GUI.enabled = m_SourceFont != null && !m_IsProcessing && !m_IsGenerationDisabled; // Enable Preview if we are not already rendering a font.
  562. if (GUILayout.Button("Generate Font Atlas") && GUI.enabled)
  563. {
  564. if (!m_IsProcessing && m_SourceFont != null)
  565. {
  566. DestroyImmediate(m_FontAtlasTexture);
  567. DestroyImmediate(m_GlyphRectPreviewTexture);
  568. m_FontAtlasTexture = null;
  569. m_SavedFontAtlas = null;
  570. m_OutputFeedback = string.Empty;
  571. // Initialize font engine
  572. FontEngineError errorCode = FontEngine.InitializeFontEngine();
  573. if (errorCode != FontEngineError.Success)
  574. {
  575. Debug.Log("Font Asset Creator - Error [" + errorCode + "] has occurred while Initializing the FreeType Library.");
  576. }
  577. if (errorCode == FontEngineError.Success)
  578. {
  579. errorCode = FontEngine.LoadFontFace(m_SourceFont, 0, m_SourceFontFaceIndex);
  580. if (errorCode != FontEngineError.Success)
  581. {
  582. Debug.Log("Font Asset Creator - Error Code [" + errorCode + "] has occurred trying to load the [" + m_SourceFont.name + "] font file. This typically results from the use of an incompatible or corrupted font file.", m_SourceFont);
  583. }
  584. }
  585. // Define an array containing the characters we will render.
  586. if (errorCode == FontEngineError.Success)
  587. {
  588. uint[] characterSet = null;
  589. // Get list of characters that need to be packed and rendered to the atlas texture.
  590. if (m_CharacterSetSelectionMode == 7 || m_CharacterSetSelectionMode == 8)
  591. {
  592. // Ensure these characters are always added
  593. List<uint> char_List = new List<uint>()
  594. {
  595. 0x09, // Tab
  596. 0x5F // Underline
  597. };
  598. for (int i = 0; i < m_CharacterSequence.Length; i++)
  599. {
  600. uint unicode = m_CharacterSequence[i];
  601. // Handle surrogate pairs
  602. if (i < m_CharacterSequence.Length - 1 && char.IsHighSurrogate((char)unicode) && char.IsLowSurrogate(m_CharacterSequence[i + 1]))
  603. {
  604. unicode = (uint)char.ConvertToUtf32(m_CharacterSequence[i], m_CharacterSequence[i + 1]);
  605. i += 1;
  606. }
  607. // Check to make sure we don't include duplicates
  608. if (char_List.FindIndex(item => item == unicode) == -1)
  609. char_List.Add(unicode);
  610. }
  611. characterSet = char_List.ToArray();
  612. }
  613. else if (m_CharacterSetSelectionMode == 6)
  614. {
  615. characterSet = ParseHexNumberSequence(m_CharacterSequence);
  616. }
  617. else
  618. {
  619. characterSet = ParseNumberSequence(m_CharacterSequence);
  620. }
  621. m_CharacterCount = characterSet.Length;
  622. m_AtlasGenerationProgress = 0;
  623. m_IsProcessing = true;
  624. m_IsGenerationCancelled = false;
  625. GlyphLoadFlags glyphLoadFlags = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_HINTED) == GlyphRasterModes.RASTER_MODE_HINTED
  626. ? GlyphLoadFlags.LOAD_RENDER
  627. : GlyphLoadFlags.LOAD_RENDER | GlyphLoadFlags.LOAD_NO_HINTING;
  628. glyphLoadFlags = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_MONO) == GlyphRasterModes.RASTER_MODE_MONO
  629. ? glyphLoadFlags | GlyphLoadFlags.LOAD_MONOCHROME
  630. : glyphLoadFlags;
  631. #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER
  632. glyphLoadFlags = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_COLOR) == GlyphRasterModes.RASTER_MODE_COLOR
  633. ? glyphLoadFlags | GlyphLoadFlags.LOAD_COLOR
  634. : glyphLoadFlags;
  635. #endif
  636. //
  637. AutoResetEvent autoEvent = new AutoResetEvent(false);
  638. // Worker thread to pack glyphs in the given texture space.
  639. ThreadPool.QueueUserWorkItem(PackGlyphs =>
  640. {
  641. // Start Stop Watch
  642. m_StopWatch = System.Diagnostics.Stopwatch.StartNew();
  643. // Clear the various lists used in the generation process.
  644. m_AvailableGlyphsToAdd.Clear();
  645. m_MissingCharacters.Clear();
  646. m_ExcludedCharacters.Clear();
  647. m_CharacterLookupMap.Clear();
  648. m_GlyphLookupMap.Clear();
  649. m_GlyphsToPack.Clear();
  650. m_GlyphsPacked.Clear();
  651. // Check if requested characters are available in the source font file.
  652. for (int i = 0; i < characterSet.Length; i++)
  653. {
  654. uint unicode = characterSet[i];
  655. uint glyphIndex;
  656. if (FontEngine.TryGetGlyphIndex(unicode, out glyphIndex))
  657. {
  658. // Skip over potential duplicate characters.
  659. if (m_CharacterLookupMap.ContainsKey(unicode))
  660. continue;
  661. // Add character to character lookup map.
  662. m_CharacterLookupMap.Add(unicode, glyphIndex);
  663. // Skip over potential duplicate glyph references.
  664. if (m_GlyphLookupMap.ContainsKey(glyphIndex))
  665. {
  666. // Add additional glyph reference for this character.
  667. m_GlyphLookupMap[glyphIndex].Add(unicode);
  668. continue;
  669. }
  670. // Add glyph reference to glyph lookup map.
  671. m_GlyphLookupMap.Add(glyphIndex, new List<uint>() { unicode });
  672. // Add glyph index to list of glyphs to add to texture.
  673. m_AvailableGlyphsToAdd.Add(glyphIndex);
  674. }
  675. else
  676. {
  677. // Add Unicode to list of missing characters.
  678. m_MissingCharacters.Add(unicode);
  679. }
  680. }
  681. // Pack available glyphs in the provided texture space.
  682. if (m_AvailableGlyphsToAdd.Count > 0)
  683. {
  684. int packingModifier = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP ? 0 : 1;
  685. if (m_PointSizeSamplingMode == 0) // Auto-Sizing Point Size Mode
  686. {
  687. // Estimate min / max range for auto sizing of point size.
  688. int minPointSize = 0;
  689. int maxPointSize = (int)Mathf.Sqrt((m_AtlasWidth * m_AtlasHeight) / m_AvailableGlyphsToAdd.Count) * 3;
  690. m_PointSize = (maxPointSize + minPointSize) / 2;
  691. bool optimumPointSizeFound = false;
  692. for (int iteration = 0; iteration < 15 && optimumPointSizeFound == false && m_PointSize > 0; iteration++)
  693. {
  694. m_AtlasGenerationProgressLabel = "Packing glyphs - Pass (" + iteration + ")";
  695. FontEngine.SetFaceSize(m_PointSize);
  696. m_Padding = (int)(m_PaddingMode == PaddingMode.Percentage ? m_PointSize * m_PaddingFieldValue / 100f : m_PaddingFieldValue);
  697. m_GlyphsToPack.Clear();
  698. m_GlyphsPacked.Clear();
  699. m_FreeGlyphRects.Clear();
  700. m_FreeGlyphRects.Add(new GlyphRect(0, 0, m_AtlasWidth - packingModifier, m_AtlasHeight - packingModifier));
  701. m_UsedGlyphRects.Clear();
  702. for (int i = 0; i < m_AvailableGlyphsToAdd.Count; i++)
  703. {
  704. uint glyphIndex = m_AvailableGlyphsToAdd[i];
  705. Glyph glyph;
  706. if (FontEngine.TryGetGlyphWithIndexValue(glyphIndex, glyphLoadFlags, out glyph))
  707. {
  708. if (glyph.glyphRect.width > 0 && glyph.glyphRect.height > 0)
  709. {
  710. m_GlyphsToPack.Add(glyph);
  711. }
  712. else
  713. {
  714. m_GlyphsPacked.Add(glyph);
  715. }
  716. }
  717. }
  718. FontEngine.TryPackGlyphsInAtlas(m_GlyphsToPack, m_GlyphsPacked, m_Padding, (GlyphPackingMode)m_PackingMode, m_GlyphRenderMode, m_AtlasWidth, m_AtlasHeight, m_FreeGlyphRects, m_UsedGlyphRects);
  719. if (m_IsGenerationCancelled)
  720. {
  721. DestroyImmediate(m_FontAtlasTexture);
  722. m_FontAtlasTexture = null;
  723. return;
  724. }
  725. //Debug.Log("Glyphs remaining to add [" + m_GlyphsToAdd.Count + "]. Glyphs added [" + m_GlyphsAdded.Count + "].");
  726. if (m_GlyphsToPack.Count > 0)
  727. {
  728. if (m_PointSize > minPointSize)
  729. {
  730. maxPointSize = m_PointSize;
  731. m_PointSize = (m_PointSize + minPointSize) / 2;
  732. //Debug.Log("Decreasing point size from [" + maxPointSize + "] to [" + m_PointSize + "].");
  733. }
  734. }
  735. else
  736. {
  737. if (maxPointSize - minPointSize > 1 && m_PointSize < maxPointSize)
  738. {
  739. minPointSize = m_PointSize;
  740. m_PointSize = (m_PointSize + maxPointSize) / 2;
  741. //Debug.Log("Increasing point size from [" + minPointSize + "] to [" + m_PointSize + "].");
  742. }
  743. else
  744. {
  745. //Debug.Log("[" + iteration + "] iterations to find the optimum point size of : [" + m_PointSize + "].");
  746. optimumPointSizeFound = true;
  747. }
  748. }
  749. }
  750. }
  751. else // Custom Point Size Mode
  752. {
  753. m_AtlasGenerationProgressLabel = "Packing glyphs...";
  754. // Set point size
  755. FontEngine.SetFaceSize(m_PointSize);
  756. m_Padding = (int)(m_PaddingMode == PaddingMode.Percentage ? m_PointSize * m_PaddingFieldValue / 100 : m_PaddingFieldValue);
  757. m_GlyphsToPack.Clear();
  758. m_GlyphsPacked.Clear();
  759. m_FreeGlyphRects.Clear();
  760. m_FreeGlyphRects.Add(new GlyphRect(0, 0, m_AtlasWidth - packingModifier, m_AtlasHeight - packingModifier));
  761. m_UsedGlyphRects.Clear();
  762. for (int i = 0; i < m_AvailableGlyphsToAdd.Count; i++)
  763. {
  764. uint glyphIndex = m_AvailableGlyphsToAdd[i];
  765. Glyph glyph;
  766. if (FontEngine.TryGetGlyphWithIndexValue(glyphIndex, glyphLoadFlags, out glyph))
  767. {
  768. if (glyph.glyphRect.width > 0 && glyph.glyphRect.height > 0)
  769. {
  770. m_GlyphsToPack.Add(glyph);
  771. }
  772. else
  773. {
  774. m_GlyphsPacked.Add(glyph);
  775. }
  776. }
  777. }
  778. FontEngine.TryPackGlyphsInAtlas(m_GlyphsToPack, m_GlyphsPacked, m_Padding, (GlyphPackingMode)m_PackingMode, m_GlyphRenderMode, m_AtlasWidth, m_AtlasHeight, m_FreeGlyphRects, m_UsedGlyphRects);
  779. if (m_IsGenerationCancelled)
  780. {
  781. DestroyImmediate(m_FontAtlasTexture);
  782. m_FontAtlasTexture = null;
  783. return;
  784. }
  785. //Debug.Log("Glyphs remaining to add [" + m_GlyphsToAdd.Count + "]. Glyphs added [" + m_GlyphsAdded.Count + "].");
  786. }
  787. }
  788. else
  789. {
  790. int packingModifier = ((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP ? 0 : 1;
  791. FontEngine.SetFaceSize(m_PointSize);
  792. m_Padding = (int)(m_PaddingMode == PaddingMode.Percentage ? m_PointSize * m_PaddingFieldValue / 100 : m_PaddingFieldValue);
  793. m_GlyphsToPack.Clear();
  794. m_GlyphsPacked.Clear();
  795. m_FreeGlyphRects.Clear();
  796. m_FreeGlyphRects.Add(new GlyphRect(0, 0, m_AtlasWidth - packingModifier, m_AtlasHeight - packingModifier));
  797. m_UsedGlyphRects.Clear();
  798. }
  799. //Stop StopWatch
  800. m_StopWatch.Stop();
  801. m_GlyphPackingGenerationTime = m_StopWatch.Elapsed.TotalMilliseconds;
  802. m_IsGlyphPackingDone = true;
  803. m_StopWatch.Reset();
  804. m_FontCharacterTable.Clear();
  805. m_FontGlyphTable.Clear();
  806. m_GlyphsToRender.Clear();
  807. // Handle Results and potential cancellation of glyph rendering
  808. if (m_GlyphRenderMode == GlyphRenderMode.SDF32 && m_PointSize > 512 || m_GlyphRenderMode == GlyphRenderMode.SDF16 && m_PointSize > 1024 || m_GlyphRenderMode == GlyphRenderMode.SDF8 && m_PointSize > 2048)
  809. {
  810. int upSampling = 1;
  811. switch (m_GlyphRenderMode)
  812. {
  813. case GlyphRenderMode.SDF8:
  814. upSampling = 8;
  815. break;
  816. case GlyphRenderMode.SDF16:
  817. upSampling = 16;
  818. break;
  819. case GlyphRenderMode.SDF32:
  820. upSampling = 32;
  821. break;
  822. }
  823. Debug.Log("Glyph rendering has been aborted due to sampling point size of [" + m_PointSize + "] x SDF [" + upSampling + "] up sampling exceeds 16,384 point size. Please revise your generation settings to make sure the sampling point size x SDF up sampling mode does not exceed 16,384.");
  824. m_IsRenderingDone = true;
  825. m_AtlasGenerationProgress = 0;
  826. m_IsGenerationCancelled = true;
  827. }
  828. // Add glyphs and characters successfully added to texture to their respective font tables.
  829. foreach (Glyph glyph in m_GlyphsPacked)
  830. {
  831. uint glyphIndex = glyph.index;
  832. m_FontGlyphTable.Add(glyph);
  833. // Add glyphs to list of glyphs that need to be rendered.
  834. if (glyph.glyphRect.width > 0 && glyph.glyphRect.height > 0)
  835. m_GlyphsToRender.Add(glyph);
  836. foreach (uint unicode in m_GlyphLookupMap[glyphIndex])
  837. {
  838. // Create new Character
  839. m_FontCharacterTable.Add(new TMP_Character(unicode, glyph));
  840. }
  841. }
  842. //
  843. foreach (Glyph glyph in m_GlyphsToPack)
  844. {
  845. foreach (uint unicode in m_GlyphLookupMap[glyph.index])
  846. {
  847. m_ExcludedCharacters.Add(unicode);
  848. }
  849. }
  850. // Get the face info for the current sampling point size.
  851. m_FaceInfo = FontEngine.GetFaceInfo();
  852. autoEvent.Set();
  853. });
  854. // Worker thread to render glyphs in texture buffer.
  855. ThreadPool.QueueUserWorkItem(RenderGlyphs =>
  856. {
  857. autoEvent.WaitOne();
  858. if (m_IsGenerationCancelled == false)
  859. {
  860. // Start Stop Watch
  861. m_StopWatch = System.Diagnostics.Stopwatch.StartNew();
  862. m_IsRenderingDone = false;
  863. // Allocate texture data
  864. #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER
  865. if (m_GlyphRenderMode == GlyphRenderMode.COLOR || m_GlyphRenderMode == GlyphRenderMode.COLOR_HINTED)
  866. m_AtlasTextureBuffer = new byte[m_AtlasWidth * m_AtlasHeight * 4];
  867. else
  868. m_AtlasTextureBuffer = new byte[m_AtlasWidth * m_AtlasHeight];
  869. #else
  870. m_AtlasTextureBuffer = new byte[m_AtlasWidth * m_AtlasHeight];
  871. #endif
  872. m_AtlasGenerationProgressLabel = "Rendering glyphs...";
  873. // Render and add glyphs to the given atlas texture.
  874. if (m_GlyphsToRender.Count > 0)
  875. {
  876. FontEngine.RenderGlyphsToTexture(m_GlyphsToRender, m_Padding, m_GlyphRenderMode, m_AtlasTextureBuffer, m_AtlasWidth, m_AtlasHeight);
  877. }
  878. m_IsRenderingDone = true;
  879. // Stop StopWatch
  880. m_StopWatch.Stop();
  881. m_GlyphRenderingGenerationTime = m_StopWatch.Elapsed.TotalMilliseconds;
  882. m_IsGlyphRenderingDone = true;
  883. m_StopWatch.Reset();
  884. }
  885. });
  886. }
  887. SaveCreationSettingsToEditorPrefs(SaveFontCreationSettings());
  888. }
  889. }
  890. // FONT RENDERING PROGRESS BAR
  891. GUILayout.Space(1);
  892. Rect progressRect = EditorGUILayout.GetControlRect(false, 20);
  893. GUI.enabled = true;
  894. progressRect.width -= 22;
  895. EditorGUI.ProgressBar(progressRect, Mathf.Max(0.01f, m_AtlasGenerationProgress), m_AtlasGenerationProgressLabel);
  896. progressRect.x = progressRect.x + progressRect.width + 2;
  897. progressRect.y -= 1;
  898. progressRect.width = 20;
  899. progressRect.height = 20;
  900. GUI.enabled = m_IsProcessing;
  901. if (GUI.Button(progressRect, "X"))
  902. {
  903. FontEngine.SendCancellationRequest();
  904. m_AtlasGenerationProgress = 0;
  905. m_IsProcessing = false;
  906. m_IsGenerationCancelled = true;
  907. }
  908. GUILayout.Space(5);
  909. // FONT STATUS & INFORMATION
  910. GUI.enabled = true;
  911. GUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Height(200));
  912. m_OutputScrollPosition = EditorGUILayout.BeginScrollView(m_OutputScrollPosition);
  913. EditorGUILayout.LabelField(m_OutputFeedback, TMP_UIStyleManager.label);
  914. EditorGUILayout.EndScrollView();
  915. GUILayout.EndVertical();
  916. // SAVE TEXTURE & CREATE and SAVE FONT XML FILE
  917. GUI.enabled = m_FontAtlasTexture != null && !m_IsProcessing; // Enable Save Button if font_Atlas is not Null.
  918. EditorGUILayout.BeginHorizontal();
  919. if (GUILayout.Button("Save") && GUI.enabled)
  920. {
  921. if (m_SelectedFontAsset == null)
  922. {
  923. if (m_LegacyFontAsset != null)
  924. SaveNewFontAssetWithSameName(m_LegacyFontAsset);
  925. else
  926. SaveNewFontAsset(m_SourceFont);
  927. }
  928. else
  929. {
  930. // Save over exiting Font Asset
  931. string filePath = Path.GetFullPath(AssetDatabase.GetAssetPath(m_SelectedFontAsset)).Replace('\\', '/');
  932. if (((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP)
  933. Save_Bitmap_FontAsset(filePath);
  934. else
  935. Save_SDF_FontAsset(filePath);
  936. }
  937. }
  938. if (GUILayout.Button("Save as...") && GUI.enabled)
  939. {
  940. if (m_SelectedFontAsset == null)
  941. {
  942. SaveNewFontAsset(m_SourceFont);
  943. }
  944. else
  945. {
  946. SaveNewFontAssetWithSameName(m_SelectedFontAsset);
  947. }
  948. }
  949. EditorGUILayout.EndHorizontal();
  950. EditorGUILayout.Space();
  951. EditorGUILayout.EndVertical();
  952. GUI.enabled = true; // Re-enable GUI
  953. if (position.height > position.width || position.width < k_TwoColumnControlsWidth)
  954. DrawPreview();
  955. EditorGUILayout.EndScrollView();
  956. if (m_IsFontAtlasInvalid)
  957. ClearGeneratedData();
  958. }
  959. /// <summary>
  960. /// Clear the previously generated data.
  961. /// </summary>
  962. void ClearGeneratedData()
  963. {
  964. m_IsFontAtlasInvalid = false;
  965. if (m_FontAtlasTexture != null && !EditorUtility.IsPersistent(m_FontAtlasTexture))
  966. {
  967. DestroyImmediate(m_FontAtlasTexture);
  968. m_FontAtlasTexture = null;
  969. }
  970. if (m_GlyphRectPreviewTexture != null)
  971. {
  972. DestroyImmediate(m_GlyphRectPreviewTexture);
  973. m_GlyphRectPreviewTexture = null;
  974. }
  975. m_AtlasGenerationProgressLabel = string.Empty;
  976. m_AtlasGenerationProgress = 0;
  977. m_SavedFontAtlas = null;
  978. m_OutputFeedback = string.Empty;
  979. m_WarningMessage = string.Empty;
  980. }
  981. /// <summary>
  982. ///
  983. /// </summary>
  984. /// <returns></returns>
  985. string[] GetFontFaces()
  986. {
  987. FontEngine.LoadFontFace(m_SourceFont, 0, 0);
  988. return FontEngine.GetFontFaces();
  989. }
  990. /// <summary>
  991. /// Function to update the feedback window showing the results of the latest generation.
  992. /// </summary>
  993. void UpdateRenderFeedbackWindow()
  994. {
  995. m_PointSize = (int)m_FaceInfo.pointSize;
  996. string missingGlyphReport = string.Empty;
  997. //string colorTag = m_FontCharacterTable.Count == m_CharacterCount ? "<color=#C0ffff>" : "<color=#ffff00>";
  998. string colorTag2 = "<color=#C0ffff>";
  999. missingGlyphReport = "Font: <b>" + colorTag2 + m_FaceInfo.familyName + "</color></b> Style: <b>" + colorTag2 + m_FaceInfo.styleName + "</color></b>";
  1000. missingGlyphReport += "\nPoint Size: <b>" + colorTag2 + m_FaceInfo.pointSize + "</color></b> Padding: <b>" + colorTag2 + m_Padding + "</color></b> SP/PD Ratio: <b>" + colorTag2 + ((float)m_Padding / m_FaceInfo.pointSize).ToString("0.0%" + "</color></b>");
  1001. missingGlyphReport += "\n\nCharacters included: <color=#ffff00><b>" + m_FontCharacterTable.Count + "/" + m_CharacterCount + "</b></color>";
  1002. missingGlyphReport += "\nMissing characters: <color=#ffff00><b>" + m_MissingCharacters.Count + "</b></color>";
  1003. missingGlyphReport += "\nExcluded characters: <color=#ffff00><b>" + m_ExcludedCharacters.Count + "</b></color>";
  1004. // Report characters missing from font file
  1005. missingGlyphReport += "\n\n<b><color=#ffff00>Characters missing from font file:</color></b>";
  1006. missingGlyphReport += "\n----------------------------------------";
  1007. m_OutputFeedback = missingGlyphReport;
  1008. for (int i = 0; i < m_MissingCharacters.Count; i++)
  1009. {
  1010. missingGlyphReport += "\nID: <color=#C0ffff>" + m_MissingCharacters[i] + "\t</color>Hex: <color=#C0ffff>" + m_MissingCharacters[i].ToString("X") + "\t</color>Char [<color=#C0ffff>" + (char)m_MissingCharacters[i] + "</color>]";
  1011. if (missingGlyphReport.Length < 16300)
  1012. m_OutputFeedback = missingGlyphReport;
  1013. }
  1014. // Report characters that did not fit in the atlas texture
  1015. missingGlyphReport += "\n\n<b><color=#ffff00>Characters excluded from packing:</color></b>";
  1016. missingGlyphReport += "\n----------------------------------------";
  1017. for (int i = 0; i < m_ExcludedCharacters.Count; i++)
  1018. {
  1019. missingGlyphReport += "\nID: <color=#C0ffff>" + m_ExcludedCharacters[i] + "\t</color>Hex: <color=#C0ffff>" + m_ExcludedCharacters[i].ToString("X") + "\t</color>Char [<color=#C0ffff>" + (char)m_ExcludedCharacters[i] + "</color>]";
  1020. if (missingGlyphReport.Length < 16300)
  1021. m_OutputFeedback = missingGlyphReport;
  1022. }
  1023. if (missingGlyphReport.Length > 16300)
  1024. m_OutputFeedback += "\n\n<color=#ffff00>Report truncated.</color>\n<color=#c0ffff>See</color> \"TextMesh Pro\\Glyph Report.txt\"";
  1025. // Save Missing Glyph Report file
  1026. if (Directory.Exists("Assets/TextMesh Pro"))
  1027. {
  1028. missingGlyphReport = System.Text.RegularExpressions.Regex.Replace(missingGlyphReport, @"<[^>]*>", string.Empty);
  1029. File.WriteAllText("Assets/TextMesh Pro/Glyph Report.txt", missingGlyphReport);
  1030. AssetDatabase.Refresh();
  1031. }
  1032. }
  1033. void DrawGlyphRectPreviewTexture()
  1034. {
  1035. if (m_GlyphRectPreviewTexture != null)
  1036. DestroyImmediate(m_GlyphRectPreviewTexture);
  1037. m_GlyphRectPreviewTexture = new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.RGBA32, false, true);
  1038. FontEngine.ResetAtlasTexture(m_GlyphRectPreviewTexture);
  1039. foreach (Glyph glyph in m_GlyphsPacked)
  1040. {
  1041. GlyphRect glyphRect = glyph.glyphRect;
  1042. Color c = UnityEngine.Random.ColorHSV(0f, 1f, 0.5f, 0.5f, 1.0f, 1.0f);
  1043. int x0 = glyphRect.x;
  1044. int x1 = x0 + glyphRect.width;
  1045. int y0 = glyphRect.y;
  1046. int y1 = y0 + glyphRect.height;
  1047. // Draw glyph rectangle.
  1048. for (int x = x0; x < x1; x++)
  1049. {
  1050. for (int y = y0; y < y1; y++)
  1051. m_GlyphRectPreviewTexture.SetPixel(x, y, c);
  1052. }
  1053. }
  1054. m_GlyphRectPreviewTexture.Apply(false);
  1055. }
  1056. void CreateFontAtlasTexture()
  1057. {
  1058. if (m_FontAtlasTexture != null)
  1059. DestroyImmediate(m_FontAtlasTexture);
  1060. Color32[] colors = new Color32[m_AtlasWidth * m_AtlasHeight];
  1061. #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER
  1062. switch (m_GlyphRenderMode)
  1063. {
  1064. case GlyphRenderMode.COLOR:
  1065. case GlyphRenderMode.COLOR_HINTED:
  1066. m_FontAtlasTexture = new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.RGBA32, false, true);
  1067. for (int i = 0; i < colors.Length; i++)
  1068. {
  1069. int readIndex = i * 4;
  1070. byte r = m_AtlasTextureBuffer[readIndex + 0];
  1071. byte g = m_AtlasTextureBuffer[readIndex + 1];
  1072. byte b = m_AtlasTextureBuffer[readIndex + 2];
  1073. byte a = m_AtlasTextureBuffer[readIndex + 3];
  1074. colors[i] = new Color32(r, g, b, a);
  1075. }
  1076. break;
  1077. default:
  1078. m_FontAtlasTexture = new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.Alpha8, false, true);
  1079. for (int i = 0; i < colors.Length; i++)
  1080. {
  1081. byte c = m_AtlasTextureBuffer[i];
  1082. colors[i] = new Color32(c, c, c, c);
  1083. }
  1084. break;
  1085. }
  1086. #else
  1087. m_FontAtlasTexture = new Texture2D(m_AtlasWidth, m_AtlasHeight, TextureFormat.Alpha8, false, true);
  1088. for (int i = 0; i < colors.Length; i++)
  1089. {
  1090. byte c = m_AtlasTextureBuffer[i];
  1091. colors[i] = new Color32(c, c, c, c);
  1092. }
  1093. #endif
  1094. // Clear allocation of
  1095. m_AtlasTextureBuffer = null;
  1096. if ((m_GlyphRenderMode & GlyphRenderMode.RASTER) == GlyphRenderMode.RASTER || (m_GlyphRenderMode & GlyphRenderMode.RASTER_HINTED) == GlyphRenderMode.RASTER_HINTED)
  1097. m_FontAtlasTexture.filterMode = FilterMode.Point;
  1098. m_FontAtlasTexture.SetPixels32(colors, 0);
  1099. m_FontAtlasTexture.Apply(false, false);
  1100. // Saving File for Debug
  1101. //var pngData = m_FontAtlasTexture.EncodeToPNG();
  1102. //File.WriteAllBytes("Assets/Textures/Debug Font Texture.png", pngData);
  1103. }
  1104. /// <summary>
  1105. /// Open Save Dialog to provide the option save the font asset using the name of the source font file. This also appends SDF to the name if using any of the SDF Font Asset creation modes.
  1106. /// </summary>
  1107. /// <param name="sourceObject"></param>
  1108. void SaveNewFontAsset(Object sourceObject)
  1109. {
  1110. string filePath;
  1111. // Save new Font Asset and open save file requester at Source Font File location.
  1112. string saveDirectory = new FileInfo(AssetDatabase.GetAssetPath(sourceObject)).DirectoryName;
  1113. if (((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP)
  1114. {
  1115. filePath = EditorUtility.SaveFilePanel("Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name, "asset");
  1116. if (filePath.Length == 0)
  1117. return;
  1118. Save_Bitmap_FontAsset(filePath);
  1119. }
  1120. else
  1121. {
  1122. filePath = EditorUtility.SaveFilePanel("Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name + " SDF", "asset");
  1123. if (filePath.Length == 0)
  1124. return;
  1125. Save_SDF_FontAsset(filePath);
  1126. }
  1127. }
  1128. /// <summary>
  1129. /// Open Save Dialog to provide the option to save the font asset under the same name.
  1130. /// </summary>
  1131. /// <param name="sourceObject"></param>
  1132. void SaveNewFontAssetWithSameName(Object sourceObject)
  1133. {
  1134. string filePath;
  1135. // Save new Font Asset and open save file requester at Source Font File location.
  1136. string saveDirectory = new FileInfo(AssetDatabase.GetAssetPath(sourceObject)).DirectoryName;
  1137. filePath = EditorUtility.SaveFilePanel("Save TextMesh Pro! Font Asset File", saveDirectory, sourceObject.name, "asset");
  1138. if (filePath.Length == 0)
  1139. return;
  1140. if (((GlyphRasterModes)m_GlyphRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP)
  1141. {
  1142. Save_Bitmap_FontAsset(filePath);
  1143. }
  1144. else
  1145. {
  1146. Save_SDF_FontAsset(filePath);
  1147. }
  1148. }
  1149. void Save_Bitmap_FontAsset(string filePath)
  1150. {
  1151. filePath = filePath.Substring(0, filePath.Length - 6); // Trim file extension from filePath.
  1152. string dataPath = Application.dataPath;
  1153. string relativeAssetPath = filePath.Substring(dataPath.Length - 6);
  1154. string tex_DirName = Path.GetDirectoryName(relativeAssetPath);
  1155. string tex_FileName = Path.GetFileNameWithoutExtension(relativeAssetPath);
  1156. string tex_Path_NoExt = tex_DirName + "/" + tex_FileName;
  1157. // Check if TextMeshPro font asset already exists. If not, create a new one. Otherwise update the existing one.
  1158. TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath(tex_Path_NoExt + ".asset", typeof(TMP_FontAsset)) as TMP_FontAsset;
  1159. if (fontAsset == null)
  1160. {
  1161. //Debug.Log("Creating TextMeshPro font asset!");
  1162. fontAsset = ScriptableObject.CreateInstance<TMP_FontAsset>(); // Create new TextMeshPro Font Asset.
  1163. AssetDatabase.CreateAsset(fontAsset, tex_Path_NoExt + ".asset");
  1164. // Set version number of font asset
  1165. fontAsset.version = "1.1.0";
  1166. //Set Font Asset Type
  1167. fontAsset.atlasRenderMode = m_GlyphRenderMode;
  1168. // Reference to the source font file GUID.
  1169. fontAsset.m_SourceFontFile_EditorRef = m_SourceFont;
  1170. fontAsset.m_SourceFontFileGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_SourceFont));
  1171. // Add FaceInfo to Font Asset
  1172. fontAsset.faceInfo = m_FaceInfo;
  1173. // Add GlyphInfo[] to Font Asset
  1174. fontAsset.glyphTable = m_FontGlyphTable;
  1175. // Add CharacterTable[] to font asset.
  1176. fontAsset.characterTable = m_FontCharacterTable;
  1177. // Sort glyph and character tables.
  1178. fontAsset.SortAllTables();
  1179. // Get and Add Kerning Pairs to Font Asset
  1180. if (m_IncludeFontFeatures)
  1181. fontAsset.fontFeatureTable = GetAllFontFeatures();
  1182. // Add Font Atlas as Sub-Asset
  1183. fontAsset.atlasTextures = new Texture2D[] { m_FontAtlasTexture };
  1184. m_FontAtlasTexture.name = tex_FileName + " Atlas";
  1185. fontAsset.atlasWidth = m_AtlasWidth;
  1186. fontAsset.atlasHeight = m_AtlasHeight;
  1187. fontAsset.atlasPadding = m_Padding;
  1188. AssetDatabase.AddObjectToAsset(m_FontAtlasTexture, fontAsset);
  1189. // Create new Material and Add it as Sub-Asset
  1190. Shader default_Shader = Shader.Find("TextMeshPro/Bitmap");
  1191. Material tmp_material = new Material(default_Shader);
  1192. tmp_material.name = tex_FileName + " Material";
  1193. tmp_material.SetTexture(ShaderUtilities.ID_MainTex, m_FontAtlasTexture);
  1194. fontAsset.material = tmp_material;
  1195. AssetDatabase.AddObjectToAsset(tmp_material, fontAsset);
  1196. }
  1197. else
  1198. {
  1199. // Find all Materials referencing this font atlas.
  1200. Material[] material_references = TMP_EditorUtility.FindMaterialReferences(fontAsset);
  1201. // Set version number of font asset
  1202. fontAsset.version = "1.1.0";
  1203. // Special handling to remove legacy font asset data
  1204. if (fontAsset.m_glyphInfoList != null && fontAsset.m_glyphInfoList.Count > 0)
  1205. fontAsset.m_glyphInfoList = null;
  1206. //Set Font Asset Type
  1207. fontAsset.atlasRenderMode = m_GlyphRenderMode;
  1208. // Add FaceInfo to Font Asset
  1209. fontAsset.faceInfo = m_FaceInfo;
  1210. // Add GlyphInfo[] to Font Asset
  1211. fontAsset.glyphTable = m_FontGlyphTable;
  1212. // Add CharacterTable[] to font asset.
  1213. fontAsset.characterTable = m_FontCharacterTable;
  1214. // Sort glyph and character tables.
  1215. fontAsset.SortAllTables();
  1216. // Get and Add Kerning Pairs to Font Asset
  1217. if (m_IncludeFontFeatures)
  1218. fontAsset.fontFeatureTable = GetAllFontFeatures();
  1219. // Destroy Assets that will be replaced.
  1220. if (fontAsset.atlasTextures != null && fontAsset.atlasTextures.Length > 0)
  1221. {
  1222. for (int i = 1; i < fontAsset.atlasTextures.Length; i++)
  1223. DestroyImmediate(fontAsset.atlasTextures[i], true);
  1224. }
  1225. fontAsset.m_AtlasTextureIndex = 0;
  1226. fontAsset.atlasWidth = m_AtlasWidth;
  1227. fontAsset.atlasHeight = m_AtlasHeight;
  1228. fontAsset.atlasPadding = m_Padding;
  1229. // Make sure remaining atlas texture is of the correct size
  1230. Texture2D tex = fontAsset.atlasTextures[0];
  1231. tex.name = tex_FileName + " Atlas";
  1232. // Make texture readable to allow resizing
  1233. bool isReadableState = tex.isReadable;
  1234. if (isReadableState == false)
  1235. FontEngineEditorUtilities.SetAtlasTextureIsReadable(tex, true);
  1236. if (tex.width != m_AtlasWidth || tex.height != m_AtlasHeight)
  1237. {
  1238. #if UNITY_2021_2_OR_NEWER
  1239. tex.Reinitialize(m_AtlasWidth, m_AtlasHeight);
  1240. #else
  1241. tex.Resize(m_AtlasWidth, m_AtlasHeight);
  1242. #endif
  1243. tex.Apply(false);
  1244. }
  1245. // Copy new texture data to existing texture
  1246. Graphics.CopyTexture(m_FontAtlasTexture, tex);
  1247. // Apply changes to the texture.
  1248. tex.Apply(false);
  1249. // Special handling due to a bug in earlier versions of Unity.
  1250. m_FontAtlasTexture.hideFlags = HideFlags.None;
  1251. fontAsset.material.hideFlags = HideFlags.None;
  1252. // Update the Texture reference on the Material
  1253. //for (int i = 0; i < material_references.Length; i++)
  1254. //{
  1255. // material_references[i].SetFloat(ShaderUtilities.ID_TextureWidth, tex.width);
  1256. // material_references[i].SetFloat(ShaderUtilities.ID_TextureHeight, tex.height);
  1257. // int spread = m_Padding;
  1258. // material_references[i].SetFloat(ShaderUtilities.ID_GradientScale, spread);
  1259. // material_references[i].SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle);
  1260. // material_references[i].SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle);
  1261. //}
  1262. }
  1263. // Set texture to non readable
  1264. if (fontAsset.atlasPopulationMode == AtlasPopulationMode.Static)
  1265. FontEngineEditorUtilities.SetAtlasTextureIsReadable(fontAsset.atlasTexture, false);
  1266. // Add list of GlyphRects to font asset.
  1267. fontAsset.freeGlyphRects = m_FreeGlyphRects;
  1268. fontAsset.usedGlyphRects = m_UsedGlyphRects;
  1269. // Save Font Asset creation settings
  1270. m_SelectedFontAsset = fontAsset;
  1271. m_LegacyFontAsset = null;
  1272. fontAsset.creationSettings = SaveFontCreationSettings();
  1273. AssetDatabase.SaveAssets();
  1274. AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(fontAsset)); // Re-import font asset to get the new updated version.
  1275. //EditorUtility.SetDirty(font_asset);
  1276. fontAsset.ReadFontAssetDefinition();
  1277. AssetDatabase.Refresh();
  1278. m_FontAtlasTexture = null;
  1279. // NEED TO GENERATE AN EVENT TO FORCE A REDRAW OF ANY TEXTMESHPRO INSTANCES THAT MIGHT BE USING THIS FONT ASSET
  1280. TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset);
  1281. }
  1282. void Save_SDF_FontAsset(string filePath)
  1283. {
  1284. filePath = filePath.Substring(0, filePath.Length - 6); // Trim file extension from filePath.
  1285. string dataPath = Application.dataPath;
  1286. string relativeAssetPath = filePath.Substring(dataPath.Length - 6);
  1287. string tex_DirName = Path.GetDirectoryName(relativeAssetPath);
  1288. string tex_FileName = Path.GetFileNameWithoutExtension(relativeAssetPath);
  1289. string tex_Path_NoExt = tex_DirName + "/" + tex_FileName;
  1290. // Check if TextMeshPro font asset already exists. If not, create a new one. Otherwise update the existing one.
  1291. TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(tex_Path_NoExt + ".asset");
  1292. if (fontAsset == null)
  1293. {
  1294. //Debug.Log("Creating TextMeshPro font asset!");
  1295. fontAsset = ScriptableObject.CreateInstance<TMP_FontAsset>(); // Create new TextMeshPro Font Asset.
  1296. AssetDatabase.CreateAsset(fontAsset, tex_Path_NoExt + ".asset");
  1297. // Set version number of font asset
  1298. fontAsset.version = "1.1.0";
  1299. // Reference to source font file GUID.
  1300. fontAsset.m_SourceFontFile_EditorRef = m_SourceFont;
  1301. fontAsset.m_SourceFontFileGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_SourceFont));
  1302. //Set Font Asset Type
  1303. fontAsset.atlasRenderMode = m_GlyphRenderMode;
  1304. // Add FaceInfo to Font Asset
  1305. fontAsset.faceInfo = m_FaceInfo;
  1306. // Add GlyphInfo[] to Font Asset
  1307. fontAsset.glyphTable = m_FontGlyphTable;
  1308. // Add CharacterTable[] to font asset.
  1309. fontAsset.characterTable = m_FontCharacterTable;
  1310. // Sort glyph and character tables.
  1311. fontAsset.SortAllTables();
  1312. // Get and Add Kerning Pairs to Font Asset
  1313. if (m_IncludeFontFeatures)
  1314. fontAsset.fontFeatureTable = GetAllFontFeatures();
  1315. // Add Font Atlas as Sub-Asset
  1316. fontAsset.atlasTextures = new Texture2D[] { m_FontAtlasTexture };
  1317. m_FontAtlasTexture.name = tex_FileName + " Atlas";
  1318. fontAsset.atlasWidth = m_AtlasWidth;
  1319. fontAsset.atlasHeight = m_AtlasHeight;
  1320. fontAsset.atlasPadding = m_Padding;
  1321. AssetDatabase.AddObjectToAsset(m_FontAtlasTexture, fontAsset);
  1322. // Create new Material and Add it as Sub-Asset
  1323. Shader default_Shader = Shader.Find("TextMeshPro/Distance Field");
  1324. Material tmp_material = new Material(default_Shader);
  1325. tmp_material.name = tex_FileName + " Material";
  1326. tmp_material.SetTexture(ShaderUtilities.ID_MainTex, m_FontAtlasTexture);
  1327. tmp_material.SetFloat(ShaderUtilities.ID_TextureWidth, m_FontAtlasTexture.width);
  1328. tmp_material.SetFloat(ShaderUtilities.ID_TextureHeight, m_FontAtlasTexture.height);
  1329. int spread = m_Padding + 1;
  1330. tmp_material.SetFloat(ShaderUtilities.ID_GradientScale, spread); // Spread = Padding for Brute Force SDF.
  1331. tmp_material.SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle);
  1332. tmp_material.SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle);
  1333. fontAsset.material = tmp_material;
  1334. AssetDatabase.AddObjectToAsset(tmp_material, fontAsset);
  1335. }
  1336. else
  1337. {
  1338. // Find all Materials referencing this font atlas.
  1339. Material[] material_references = TMP_EditorUtility.FindMaterialReferences(fontAsset);
  1340. // Set version number of font asset
  1341. fontAsset.version = "1.1.0";
  1342. // Special handling to remove legacy font asset data
  1343. if (fontAsset.m_glyphInfoList != null && fontAsset.m_glyphInfoList.Count > 0)
  1344. fontAsset.m_glyphInfoList = null;
  1345. //Set Font Asset Type
  1346. fontAsset.atlasRenderMode = m_GlyphRenderMode;
  1347. // Add FaceInfo to Font Asset
  1348. fontAsset.faceInfo = m_FaceInfo;
  1349. // Add GlyphInfo[] to Font Asset
  1350. fontAsset.glyphTable = m_FontGlyphTable;
  1351. // Add CharacterTable[] to font asset.
  1352. fontAsset.characterTable = m_FontCharacterTable;
  1353. // Sort glyph and character tables.
  1354. fontAsset.SortAllTables();
  1355. // Get and Add Kerning Pairs to Font Asset
  1356. // TODO: Check and preserve existing adjustment pairs.
  1357. if (m_IncludeFontFeatures)
  1358. fontAsset.fontFeatureTable = GetAllFontFeatures();
  1359. // Destroy Assets that will be replaced.
  1360. if (fontAsset.atlasTextures != null && fontAsset.atlasTextures.Length > 0)
  1361. {
  1362. for (int i = 1; i < fontAsset.atlasTextures.Length; i++)
  1363. DestroyImmediate(fontAsset.atlasTextures[i], true);
  1364. }
  1365. fontAsset.m_AtlasTextureIndex = 0;
  1366. fontAsset.atlasWidth = m_AtlasWidth;
  1367. fontAsset.atlasHeight = m_AtlasHeight;
  1368. fontAsset.atlasPadding = m_Padding;
  1369. // Make sure remaining atlas texture is of the correct size
  1370. Texture2D tex = fontAsset.atlasTextures[0];
  1371. tex.name = tex_FileName + " Atlas";
  1372. // Make texture readable to allow resizing
  1373. bool isReadableState = tex.isReadable;
  1374. if (isReadableState == false)
  1375. FontEngineEditorUtilities.SetAtlasTextureIsReadable(tex, true);
  1376. if (tex.width != m_AtlasWidth || tex.height != m_AtlasHeight)
  1377. {
  1378. #if UNITY_2021_2_OR_NEWER
  1379. tex.Reinitialize(m_AtlasWidth, m_AtlasHeight);
  1380. #else
  1381. tex.Resize(m_AtlasWidth, m_AtlasHeight);
  1382. #endif
  1383. tex.Apply(false);
  1384. }
  1385. // Copy new texture data to existing texture
  1386. Graphics.CopyTexture(m_FontAtlasTexture, tex);
  1387. // Apply changes to the texture.
  1388. tex.Apply(false);
  1389. // Special handling due to a bug in earlier versions of Unity.
  1390. m_FontAtlasTexture.hideFlags = HideFlags.None;
  1391. fontAsset.material.hideFlags = HideFlags.None;
  1392. // Update the Texture reference on the Material
  1393. for (int i = 0; i < material_references.Length; i++)
  1394. {
  1395. material_references[i].SetFloat(ShaderUtilities.ID_TextureWidth, tex.width);
  1396. material_references[i].SetFloat(ShaderUtilities.ID_TextureHeight, tex.height);
  1397. int spread = m_Padding + 1;
  1398. material_references[i].SetFloat(ShaderUtilities.ID_GradientScale, spread);
  1399. material_references[i].SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle);
  1400. material_references[i].SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle);
  1401. }
  1402. }
  1403. // Saving File for Debug
  1404. //var pngData = destination_Atlas.EncodeToPNG();
  1405. //File.WriteAllBytes("Assets/Textures/Debug Distance Field.png", pngData);
  1406. // Set texture to non readable
  1407. if (fontAsset.atlasPopulationMode == AtlasPopulationMode.Static)
  1408. FontEngineEditorUtilities.SetAtlasTextureIsReadable(fontAsset.atlasTexture, false);
  1409. // Add list of GlyphRects to font asset.
  1410. fontAsset.freeGlyphRects = m_FreeGlyphRects;
  1411. fontAsset.usedGlyphRects = m_UsedGlyphRects;
  1412. // Save Font Asset creation settings
  1413. m_SelectedFontAsset = fontAsset;
  1414. m_LegacyFontAsset = null;
  1415. fontAsset.creationSettings = SaveFontCreationSettings();
  1416. AssetDatabase.SaveAssets();
  1417. AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(fontAsset)); // Re-import font asset to get the new updated version.
  1418. fontAsset.ReadFontAssetDefinition();
  1419. AssetDatabase.Refresh();
  1420. m_FontAtlasTexture = null;
  1421. // NEED TO GENERATE AN EVENT TO FORCE A REDRAW OF ANY TEXTMESHPRO INSTANCES THAT MIGHT BE USING THIS FONT ASSET
  1422. TMPro_EventManager.ON_FONT_PROPERTY_CHANGED(true, fontAsset);
  1423. }
  1424. /// <summary>
  1425. /// Internal method to save the Font Asset Creation Settings
  1426. /// </summary>
  1427. /// <returns></returns>
  1428. FontAssetCreationSettings SaveFontCreationSettings()
  1429. {
  1430. FontAssetCreationSettings settings = new FontAssetCreationSettings();
  1431. //settings.sourceFontFileName = m_SourceFontFile.name;
  1432. settings.sourceFontFileGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_SourceFont));
  1433. settings.faceIndex = m_SourceFontFaceIndex;
  1434. settings.pointSizeSamplingMode = m_PointSizeSamplingMode;
  1435. settings.pointSize = m_PointSize;
  1436. settings.padding = m_Padding;
  1437. settings.paddingMode = (int)m_PaddingMode;
  1438. settings.packingMode = (int)m_PackingMode;
  1439. settings.atlasWidth = m_AtlasWidth;
  1440. settings.atlasHeight = m_AtlasHeight;
  1441. settings.characterSetSelectionMode = m_CharacterSetSelectionMode;
  1442. settings.characterSequence = m_CharacterSequence;
  1443. settings.referencedFontAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_ReferencedFontAsset));
  1444. settings.referencedTextAssetGUID = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(m_CharactersFromFile));
  1445. settings.renderMode = (int)m_GlyphRenderMode;
  1446. settings.includeFontFeatures = m_IncludeFontFeatures;
  1447. return settings;
  1448. }
  1449. /// <summary>
  1450. /// Internal method to load the Font Asset Creation Settings
  1451. /// </summary>
  1452. /// <param name="settings"></param>
  1453. void LoadFontCreationSettings(FontAssetCreationSettings settings)
  1454. {
  1455. m_SourceFont = AssetDatabase.LoadAssetAtPath<Font>(AssetDatabase.GUIDToAssetPath(settings.sourceFontFileGUID));
  1456. m_SourceFontFaceIndex = settings.faceIndex;
  1457. if (m_SourceFont != null)
  1458. m_SourceFontFaces = GetFontFaces();
  1459. m_PointSizeSamplingMode = settings.pointSizeSamplingMode;
  1460. m_PointSize = settings.pointSize;
  1461. m_Padding = settings.padding;
  1462. m_PaddingMode = settings.paddingMode == 0 ? PaddingMode.Pixel : (PaddingMode)settings.paddingMode;
  1463. m_PaddingFieldValue = m_PaddingMode == PaddingMode.Percentage ? (float)m_Padding / m_PointSize * 100 : m_Padding;
  1464. m_PackingMode = (FontPackingModes)settings.packingMode;
  1465. m_AtlasWidth = settings.atlasWidth;
  1466. m_AtlasHeight = settings.atlasHeight;
  1467. m_CharacterSetSelectionMode = settings.characterSetSelectionMode;
  1468. m_CharacterSequence = settings.characterSequence;
  1469. m_ReferencedFontAsset = AssetDatabase.LoadAssetAtPath<TMP_FontAsset>(AssetDatabase.GUIDToAssetPath(settings.referencedFontAssetGUID));
  1470. m_CharactersFromFile = AssetDatabase.LoadAssetAtPath<TextAsset>(AssetDatabase.GUIDToAssetPath(settings.referencedTextAssetGUID));
  1471. m_GlyphRenderMode = (GlyphRenderMode)settings.renderMode;
  1472. m_IncludeFontFeatures = settings.includeFontFeatures;
  1473. }
  1474. /// <summary>
  1475. /// Save the latest font asset creation settings to EditorPrefs.
  1476. /// </summary>
  1477. /// <param name="settings"></param>
  1478. void SaveCreationSettingsToEditorPrefs(FontAssetCreationSettings settings)
  1479. {
  1480. // Create new list if one does not already exist
  1481. if (m_FontAssetCreationSettingsContainer == null)
  1482. {
  1483. m_FontAssetCreationSettingsContainer = new FontAssetCreationSettingsContainer();
  1484. m_FontAssetCreationSettingsContainer.fontAssetCreationSettings = new List<FontAssetCreationSettings>();
  1485. }
  1486. // Add new creation settings to the list
  1487. m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Add(settings);
  1488. // Since list should only contain the most 4 recent settings, we remove the first element if list exceeds 4 elements.
  1489. if (m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count > 4)
  1490. m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.RemoveAt(0);
  1491. m_FontAssetCreationSettingsCurrentIndex = m_FontAssetCreationSettingsContainer.fontAssetCreationSettings.Count - 1;
  1492. // Serialize list to JSON
  1493. string serializedSettings = JsonUtility.ToJson(m_FontAssetCreationSettingsContainer, true);
  1494. EditorPrefs.SetString(k_FontAssetCreationSettingsContainerKey, serializedSettings);
  1495. }
  1496. void DrawPreview()
  1497. {
  1498. Rect pixelRect;
  1499. float ratioX = (position.width - k_TwoColumnControlsWidth) / m_AtlasWidth;
  1500. float ratioY = (position.height - 15) / m_AtlasHeight;
  1501. if (position.width < position.height)
  1502. {
  1503. ratioX = (position.width - 15) / m_AtlasWidth;
  1504. ratioY = (position.height - 485) / m_AtlasHeight;
  1505. }
  1506. if (ratioX < ratioY)
  1507. {
  1508. float width = m_AtlasWidth * ratioX;
  1509. float height = m_AtlasHeight * ratioX;
  1510. EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.MaxWidth(width), GUILayout.MaxHeight(height));
  1511. pixelRect = GUILayoutUtility.GetRect(width - 5, height, GUILayout.ExpandHeight(false), GUILayout.ExpandWidth(false));
  1512. }
  1513. else
  1514. {
  1515. float width = m_AtlasWidth * ratioY;
  1516. float height = m_AtlasHeight * ratioY;
  1517. EditorGUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.MaxWidth(width), GUILayout.MaxHeight(height));
  1518. pixelRect = GUILayoutUtility.GetRect(width - 5, height, GUILayout.ExpandHeight(false), GUILayout.ExpandWidth(false));
  1519. }
  1520. if (m_FontAtlasTexture != null)
  1521. {
  1522. if (m_FontAtlasTexture.format == TextureFormat.Alpha8)
  1523. EditorGUI.DrawTextureAlpha(pixelRect, m_FontAtlasTexture, ScaleMode.StretchToFill);
  1524. else
  1525. EditorGUI.DrawPreviewTexture(pixelRect, m_FontAtlasTexture, null, ScaleMode.StretchToFill);
  1526. // Destroy GlyphRect preview texture
  1527. if (m_GlyphRectPreviewTexture != null)
  1528. {
  1529. DestroyImmediate(m_GlyphRectPreviewTexture);
  1530. m_GlyphRectPreviewTexture = null;
  1531. }
  1532. }
  1533. else if (m_GlyphRectPreviewTexture != null)
  1534. {
  1535. EditorGUI.DrawPreviewTexture(pixelRect, m_GlyphRectPreviewTexture, null, ScaleMode.StretchToFill);
  1536. }
  1537. else if (m_SavedFontAtlas != null)
  1538. {
  1539. EditorGUI.DrawTextureAlpha(pixelRect, m_SavedFontAtlas, ScaleMode.StretchToFill);
  1540. }
  1541. EditorGUILayout.EndVertical();
  1542. }
  1543. void CheckForLegacyGlyphRenderMode()
  1544. {
  1545. // Special handling for legacy glyph render mode
  1546. if ((int)m_GlyphRenderMode < 0x100)
  1547. {
  1548. switch ((int)m_GlyphRenderMode)
  1549. {
  1550. case 0:
  1551. m_GlyphRenderMode = GlyphRenderMode.SMOOTH_HINTED;
  1552. break;
  1553. case 1:
  1554. m_GlyphRenderMode = GlyphRenderMode.SMOOTH;
  1555. break;
  1556. case 2:
  1557. m_GlyphRenderMode = GlyphRenderMode.RASTER_HINTED;
  1558. break;
  1559. case 3:
  1560. m_GlyphRenderMode = GlyphRenderMode.RASTER;
  1561. break;
  1562. case 6:
  1563. case 7:
  1564. m_GlyphRenderMode = GlyphRenderMode.SDFAA;
  1565. break;
  1566. }
  1567. }
  1568. }
  1569. /// <summary>
  1570. ///
  1571. /// </summary>
  1572. /// <returns></returns>
  1573. TMP_FontFeatureTable GetAllFontFeatures()
  1574. {
  1575. TMP_FontFeatureTable fontFeatureTable = new TMP_FontFeatureTable();
  1576. PopulateGlyphAdjustmentTable(fontFeatureTable);
  1577. #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER
  1578. PopulateLigatureTable(fontFeatureTable);
  1579. PopulateDiacriticalMarkAdjustmentTables(fontFeatureTable);
  1580. #endif
  1581. return fontFeatureTable;
  1582. }
  1583. #if TEXTCORE_FONT_ENGINE_1_5_OR_NEWER
  1584. void PopulateGlyphAdjustmentTable(TMP_FontFeatureTable fontFeatureTable)
  1585. {
  1586. GlyphPairAdjustmentRecord[] adjustmentRecords = FontEngine.GetPairAdjustmentRecords(m_AvailableGlyphsToAdd);
  1587. if (adjustmentRecords == null)
  1588. return;
  1589. float emScale = (float)m_FaceInfo.pointSize / m_FaceInfo.unitsPerEM;
  1590. for (int i = 0; i < adjustmentRecords.Length && adjustmentRecords[i].firstAdjustmentRecord.glyphIndex != 0; i++)
  1591. {
  1592. GlyphPairAdjustmentRecord record = adjustmentRecords[i];
  1593. // Adjust values currently in Units per EM to make them relative to Sampling Point Size.
  1594. GlyphValueRecord valueRecord = record.firstAdjustmentRecord.glyphValueRecord;
  1595. valueRecord.xAdvance *= emScale;
  1596. GlyphPairAdjustmentRecord newRecord = new GlyphPairAdjustmentRecord { firstAdjustmentRecord = new GlyphAdjustmentRecord { glyphIndex = record.firstAdjustmentRecord.glyphIndex, glyphValueRecord = valueRecord }, secondAdjustmentRecord = record.secondAdjustmentRecord };
  1597. fontFeatureTable.glyphPairAdjustmentRecords.Add(newRecord);
  1598. }
  1599. fontFeatureTable.SortGlyphPairAdjustmentRecords();
  1600. }
  1601. void PopulateLigatureTable(TMP_FontFeatureTable fontFeatureTable)
  1602. {
  1603. UnityEngine.TextCore.LowLevel.LigatureSubstitutionRecord[] ligatureRecords = FontEngine.GetLigatureSubstitutionRecords(m_AvailableGlyphsToAdd);
  1604. if (ligatureRecords != null)
  1605. AddLigatureRecords(fontFeatureTable, ligatureRecords);
  1606. }
  1607. void AddLigatureRecords(TMP_FontFeatureTable fontFeatureTable, UnityEngine.TextCore.LowLevel.LigatureSubstitutionRecord[] records)
  1608. {
  1609. for (int i = 0; i < records.Length; i++)
  1610. {
  1611. UnityEngine.TextCore.LowLevel.LigatureSubstitutionRecord record = records[i];
  1612. if (records[i].componentGlyphIDs == null || records[i].ligatureGlyphID == 0)
  1613. return;
  1614. uint firstComponentGlyphIndex = record.componentGlyphIDs[0];
  1615. LigatureSubstitutionRecord newRecord = new LigatureSubstitutionRecord() { componentGlyphIDs = record.componentGlyphIDs, ligatureGlyphID = record.ligatureGlyphID };
  1616. // Add new record to lookup
  1617. if (!fontFeatureTable.m_LigatureSubstitutionRecordLookup.ContainsKey(firstComponentGlyphIndex))
  1618. {
  1619. fontFeatureTable.m_LigatureSubstitutionRecordLookup.Add(firstComponentGlyphIndex, new List<LigatureSubstitutionRecord> { newRecord });
  1620. }
  1621. else
  1622. {
  1623. fontFeatureTable.m_LigatureSubstitutionRecordLookup[firstComponentGlyphIndex].Add(newRecord);
  1624. }
  1625. fontFeatureTable.m_LigatureSubstitutionRecords.Add(newRecord);
  1626. }
  1627. }
  1628. void PopulateDiacriticalMarkAdjustmentTables(TMP_FontFeatureTable fontFeatureTable)
  1629. {
  1630. UnityEngine.TextCore.LowLevel.MarkToBaseAdjustmentRecord[] markToBaseRecords = FontEngine.GetMarkToBaseAdjustmentRecords(m_AvailableGlyphsToAdd);
  1631. if (markToBaseRecords != null)
  1632. AddMarkToBaseAdjustmentRecords(fontFeatureTable, markToBaseRecords);
  1633. UnityEngine.TextCore.LowLevel.MarkToMarkAdjustmentRecord[] markToMarkRecords = FontEngine.GetMarkToMarkAdjustmentRecords(m_AvailableGlyphsToAdd);
  1634. if (markToMarkRecords != null)
  1635. AddMarkToMarkAdjustmentRecords(fontFeatureTable, markToMarkRecords);
  1636. }
  1637. void AddMarkToBaseAdjustmentRecords(TMP_FontFeatureTable fontFeatureTable, UnityEngine.TextCore.LowLevel.MarkToBaseAdjustmentRecord[] records)
  1638. {
  1639. float emScale = (float)m_FaceInfo.pointSize / m_FaceInfo.unitsPerEM;
  1640. for (int i = 0; i < records.Length; i++)
  1641. {
  1642. UnityEngine.TextCore.LowLevel.MarkToBaseAdjustmentRecord record = records[i];
  1643. uint key = record.markGlyphID << 16 | record.baseGlyphID;
  1644. if (fontFeatureTable.m_MarkToBaseAdjustmentRecordLookup.ContainsKey(key))
  1645. continue;
  1646. MarkToBaseAdjustmentRecord newRecord = new MarkToBaseAdjustmentRecord {
  1647. baseGlyphID = record.baseGlyphID,
  1648. baseGlyphAnchorPoint = new GlyphAnchorPoint { xCoordinate = record.baseGlyphAnchorPoint.xCoordinate * emScale, yCoordinate = record.baseGlyphAnchorPoint.yCoordinate * emScale },
  1649. markGlyphID = record.markGlyphID,
  1650. markPositionAdjustment = new MarkPositionAdjustment { xPositionAdjustment = record.markPositionAdjustment.xPositionAdjustment * emScale, yPositionAdjustment = record.markPositionAdjustment.yPositionAdjustment * emScale } };
  1651. fontFeatureTable.MarkToBaseAdjustmentRecords.Add(newRecord);
  1652. fontFeatureTable.m_MarkToBaseAdjustmentRecordLookup.Add(key, newRecord);
  1653. }
  1654. }
  1655. void AddMarkToMarkAdjustmentRecords(TMP_FontFeatureTable fontFeatureTable, UnityEngine.TextCore.LowLevel.MarkToMarkAdjustmentRecord[] records)
  1656. {
  1657. float emScale = (float)m_FaceInfo.pointSize / m_FaceInfo.unitsPerEM;
  1658. for (int i = 0; i < records.Length; i++)
  1659. {
  1660. UnityEngine.TextCore.LowLevel.MarkToMarkAdjustmentRecord record = records[i];
  1661. uint key = record.combiningMarkGlyphID << 16 | record.baseMarkGlyphID;
  1662. if (fontFeatureTable.m_MarkToMarkAdjustmentRecordLookup.ContainsKey(key))
  1663. continue;
  1664. MarkToMarkAdjustmentRecord newRecord = new MarkToMarkAdjustmentRecord {
  1665. baseMarkGlyphID = record.baseMarkGlyphID,
  1666. baseMarkGlyphAnchorPoint = new GlyphAnchorPoint { xCoordinate = record.baseMarkGlyphAnchorPoint.xCoordinate * emScale, yCoordinate = record.baseMarkGlyphAnchorPoint.yCoordinate * emScale},
  1667. combiningMarkGlyphID = record.combiningMarkGlyphID,
  1668. combiningMarkPositionAdjustment = new MarkPositionAdjustment { xPositionAdjustment = record.combiningMarkPositionAdjustment.xPositionAdjustment * emScale, yPositionAdjustment = record.combiningMarkPositionAdjustment.yPositionAdjustment * emScale } };
  1669. fontFeatureTable.MarkToMarkAdjustmentRecords.Add(newRecord);
  1670. fontFeatureTable.m_MarkToMarkAdjustmentRecordLookup.Add(key, newRecord);
  1671. }
  1672. }
  1673. #else
  1674. void PopulateGlyphAdjustmentTable(TMP_FontFeatureTable fontFeatureTable)
  1675. {
  1676. GlyphPairAdjustmentRecord[] adjustmentRecords = FontEngine.GetGlyphPairAdjustmentTable(m_AvailableGlyphsToAdd.ToArray());
  1677. if (adjustmentRecords == null)
  1678. return;
  1679. for (int i = 0; i < adjustmentRecords.Length && adjustmentRecords[i].firstAdjustmentRecord.glyphIndex != 0; i++)
  1680. {
  1681. fontFeatureTable.glyphPairAdjustmentRecords.Add(adjustmentRecords[i]);
  1682. }
  1683. fontFeatureTable.SortGlyphPairAdjustmentRecords();
  1684. }
  1685. #endif
  1686. }
  1687. }