diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d20a38..b37dec1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # Changelog These are the release notes for the TextMesh Pro UPM package which was first introduced with Unity 2018.1. Please see the following link for the Release Notes for prior versions of TextMesh Pro. http://digitalnativestudios.com/forum/index.php?topic=1363.0 +## [1.4.0-preview.3a] - 2019-02-28 +### Changes +- Improved performance of the Project Files GUID Remapping Tool. +- Fixed an issue with the TMP_FontAsset.TryAddCharacters() functions which was resulting in an error when added characters exceeded the capacity of the atlas texture. +- Updated TMP_FontAsset.TryAddCharacters functions to add new overloads returning list of characters that could not be added. +- Added function in OnEnable of FontAsset Editor's to clean up Fallback list to remove any null / empty entries. +- Added support for Stereo rendering to the TMP Distance Field and Mobile Distance Field shaders. + ## [1.4.0-preview.2a] - 2019-02-14 ### Changes - Fixed an issue with SDF Scale handling where the text object would not render correctly after the object scale had been set to zero. diff --git a/Package Resources/TMP Essential Resources.unitypackage b/Package Resources/TMP Essential Resources.unitypackage index 1643503..f813931 100644 Binary files a/Package Resources/TMP Essential Resources.unitypackage and b/Package Resources/TMP Essential Resources.unitypackage differ diff --git a/Scripts/Editor/TMP_FontAssetEditor.cs b/Scripts/Editor/TMP_FontAssetEditor.cs index 088bf05..0e44526 100644 --- a/Scripts/Editor/TMP_FontAssetEditor.cs +++ b/Scripts/Editor/TMP_FontAssetEditor.cs @@ -224,6 +224,9 @@ public void OnEnable() EditorGUI.LabelField(rect, "Fallback List"); }; + // Clean up fallback list in the event if contains null elements. + CleanFallbackFontAssetTable(); + font_normalStyle_prop = serializedObject.FindProperty("normalStyle"); font_normalSpacing_prop = serializedObject.FindProperty("normalSpacingOffset"); @@ -252,8 +255,6 @@ public void OnEnable() SerializedObject internalSerializedObject = new SerializedObject(m_SerializedPropertyHolder); m_EmptyGlyphPairAdjustmentRecord_prop = internalSerializedObject.FindProperty("glyphPairAdjustmentRecord"); - //m_EmptyGlyphPairAdjustmentRecord_prop = serializedObject.FindProperty("m_EmptyGlyphPairAdjustmentRecord"); - m_materialPresets = TMP_EditorUtility.FindMaterialReferences(m_fontAsset); m_GlyphSearchList = new List(); @@ -1275,6 +1276,34 @@ public override void OnInspectorGUI() } + void CleanFallbackFontAssetTable() + { + SerializedProperty m_FallbackFontAsseTable = serializedObject.FindProperty("m_FallbackFontAssetTable"); + + bool isListDirty = false; + + int elementCount = m_FallbackFontAsseTable.arraySize; + + for (int i = 0; i < elementCount; i++) + { + SerializedProperty element = m_FallbackFontAsseTable.GetArrayElementAtIndex(i); + if (element.objectReferenceValue == null) + { + m_FallbackFontAsseTable.DeleteArrayElementAtIndex(i); + elementCount -= 1; + i -= 1; + + isListDirty = true; + } + } + + if (isListDirty) + { + serializedObject.ApplyModifiedProperties(); + serializedObject.Update(); + } + } + void SavedAtlasGenerationSettings() { m_AtlasSettings.glyphRenderMode = (GlyphRenderMode)m_AtlasRenderMode_prop.intValue; diff --git a/Scripts/Editor/TMP_PackageUtilities.cs b/Scripts/Editor/TMP_PackageUtilities.cs index d2fc46d..5e50d76 100644 --- a/Scripts/Editor/TMP_PackageUtilities.cs +++ b/Scripts/Editor/TMP_PackageUtilities.cs @@ -1,9 +1,12 @@ using UnityEngine; using UnityEditor; +using System; using System.IO; using System.Linq; using System.Collections; using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using TMPro.EditorUtilities; @@ -43,6 +46,37 @@ static void ShowConverterWindow() window.Focus(); } + private static HashSet m_IgnoreAssetTypes = new HashSet() + { + typeof(AnimatorOverrideController), + typeof(AudioClip), + typeof(AvatarMask), + typeof(ComputeShader), + typeof(Cubemap), + typeof(DefaultAsset), + typeof(Flare), + typeof(Font), + typeof(GUISkin), + typeof(HumanTemplate), + typeof(LightingDataAsset), + typeof(Mesh), + typeof(MonoScript), + typeof(PhysicMaterial), + typeof(PhysicsMaterial2D), + typeof(RenderTexture), + typeof(Shader), + typeof(TerrainData), + typeof(TextAsset), + typeof(Texture2D), + typeof(Texture2DArray), + typeof(Texture3D), + typeof(UnityEditor.Animations.AnimatorController), + typeof(UnityEditorInternal.AssemblyDefinitionAsset), + typeof(UnityEngine.AI.NavMeshData), + typeof(UnityEngine.Tilemaps.Tile), + typeof(UnityEngine.U2D.SpriteAtlas), + typeof(UnityEngine.Video.VideoClip), + }; /// /// @@ -53,16 +87,35 @@ struct AssetModificationRecord public string assetDataFile; } + struct AssetFileRecord + { + public string assetFilePath; + public string assetMetaFilePath; + + public AssetFileRecord(string filePath, string metaFilePath) + { + this.assetFilePath = filePath; + this.assetMetaFilePath = metaFilePath; + } + } + + private static string m_ProjectPath; private static string m_ProjectFolderToScan; private static bool m_IsAlreadyScanningProject; private static bool m_CancelScanProcess; private static string k_ProjectScanReportDefaultText = "Project Scan Results\n"; + private static string k_ProjectScanLabelPrefix = "Scanning: "; private static string m_ProjectScanResults = string.Empty; private static Vector2 m_ProjectScanResultScrollPosition; private static float m_ProgressPercentage = 0; + private static int m_ScanningTotalFiles; + private static int m_RemainingFilesToScan; private static int m_ScanningCurrentFileIndex; private static string m_ScanningCurrentFileName; + + private static AssetConversionData m_ConversionData; + private static List m_ModifiedAssetList = new List(); @@ -97,6 +150,7 @@ void OnGUI() // Make sure Asset Serialization mode is set to ForceText and Version Control mode to Visible Meta Files. if (CheckProjectSerializationAndSourceControlModes() == true) { + m_ProjectPath = Path.GetFullPath("Assets/.."); TMP_EditorCoroutine.StartCoroutine(ScanProjectFiles()); } else @@ -118,7 +172,7 @@ void OnGUI() { m_CancelScanProcess = true; } - GUILayout.Label("Scanning: " + m_ScanningCurrentFileName); + GUILayout.Label(k_ProjectScanLabelPrefix + m_ScanningCurrentFileName, TMP_UIStyleManager.label); } else GUILayout.Label(string.Empty); @@ -139,7 +193,7 @@ void OnGUI() // Scan project files and resources GUILayout.BeginVertical(EditorStyles.helpBox); - { + { GUILayout.Label("Save Modified Project Files", EditorStyles.boldLabel); GUILayout.Label("Pressing the Save Modified Project Files button will update the files in the Project Scan Results listed above. Please make sure that you have created a backup of your project first as these file modifications are permanent and cannot be undone.", TMP_UIStyleManager.label); GUILayout.Space(5f); @@ -177,180 +231,169 @@ void SetEditorWindowSize() } + /// + /// + /// + /// + /// + private static bool ShouldIgnoreFile(string filePath) + { + string fileExtension = Path.GetExtension(filePath); + Type fileType = AssetDatabase.GetMainAssetTypeAtPath(filePath); + + if (m_IgnoreAssetTypes.Contains(fileType)) + return true; + + // Exclude FBX + if (fileType == typeof(GameObject) && fileExtension.ToLower() == ".fbx") { return true; } + return false; + } + + private IEnumerator ScanProjectFiles() { m_IsAlreadyScanningProject = true; - string projectPath = Path.GetFullPath("Assets/.."); string packageFullPath = EditorUtilities.TMP_EditorUtility.packageFullPath; // List containing assets that have been modified. - string scanResults = k_ProjectScanReportDefaultText; + m_ProjectScanResults = k_ProjectScanReportDefaultText; m_ModifiedAssetList.Clear(); m_ProgressPercentage = 0; // Read Conversion Data from Json file. - AssetConversionData conversionData = JsonUtility.FromJson(File.ReadAllText(packageFullPath + "/PackageConversionData.json")); - AssetConversionData conversionData_Assets = JsonUtility.FromJson(File.ReadAllText(packageFullPath + "/PackageConversionData_Assets.json")); + if (m_ConversionData == null) + m_ConversionData = JsonUtility.FromJson(File.ReadAllText(packageFullPath + "/PackageConversionData.json")); // Get list of GUIDs for assets that might contain references to previous GUIDs that require updating. string searchFolder = string.IsNullOrEmpty(m_ProjectFolderToScan) ? "Assets" : ("Assets/" + m_ProjectFolderToScan); - string[] projectGUIDs = AssetDatabase.FindAssets("t:Object", new string[] { searchFolder }).Distinct().ToArray(); - m_ScanningTotalFiles = projectGUIDs.Length; + string[] guids = AssetDatabase.FindAssets("t:Object", new string[] { searchFolder }).Distinct().ToArray(); + + k_ProjectScanLabelPrefix = "Phase 1 - Filtering: "; + m_ScanningTotalFiles = guids.Length; + m_ScanningCurrentFileIndex = 0; - bool cancelScanning = false; + List projectFilesToScan = new List(); - // Iterate through projectGUIDs to search project assets of the types likely to reference GUIDs and FileIDs used by previous versions of TextMesh Pro. - for (int i = 0; i < projectGUIDs.Length && cancelScanning == false; i++) + foreach (var guid in guids) { if (m_CancelScanProcess) - { - cancelScanning = true; - ResetScanProcess(); - - continue; - } - - m_ScanningCurrentFileIndex = i + 1; + break; - string guid = projectGUIDs[i]; string assetFilePath = AssetDatabase.GUIDToAssetPath(guid); - string assetFileExtension = Path.GetExtension(assetFilePath); - System.Type assetType = AssetDatabase.GetMainAssetTypeAtPath(assetFilePath); - - // Filter out asset types that we can't read or have not interest in searching. - if (assetType == typeof(DefaultAsset) || assetType == typeof(MonoScript) || assetType == typeof(Texture2D) || assetType == typeof(Texture3D) || assetType == typeof(Cubemap) || - assetType == typeof(TextAsset) || assetType == typeof(Shader) || assetType == typeof(Font) || assetType == typeof(UnityEditorInternal.AssemblyDefinitionAsset) || - assetType == typeof(GUISkin) || assetType == typeof(PhysicsMaterial2D) || assetType == typeof(PhysicMaterial) || assetType == typeof(UnityEngine.U2D.SpriteAtlas) || assetType == typeof(UnityEngine.Tilemaps.Tile) || - assetType == typeof(AudioClip) || assetType == typeof(ComputeShader) || assetType == typeof(UnityEditor.Animations.AnimatorController) || assetType == typeof(UnityEngine.AI.NavMeshData) || - assetType == typeof(Mesh) || assetType == typeof(RenderTexture) || assetType == typeof(Texture2DArray) || assetType == typeof(LightingDataAsset) || assetType == typeof(AvatarMask) || - assetType == typeof(AnimatorOverrideController) || assetType == typeof(TerrainData) || assetType == typeof(HumanTemplate) || assetType == typeof(Flare) || assetType == typeof(UnityEngine.Video.VideoClip)) - continue; - - // Exclude FBX - if (assetType == typeof(GameObject) && (assetFileExtension == ".FBX" || assetFileExtension == ".fbx")) - continue; + m_ScanningCurrentFileIndex += 1; m_ScanningCurrentFileName = assetFilePath; - //Debug.Log("Searching Asset: [" + assetFilePath + "] with file extension [" + assetFileExtension + "] of type [" + assetType + "]"); + m_ProgressPercentage = (float)m_ScanningCurrentFileIndex / m_ScanningTotalFiles; - // Read the asset data file - string assetDataFile = string.Empty; - try - { - assetDataFile = File.ReadAllText(projectPath + "/" + assetFilePath); - } - catch - { - // Continue to the next asset if we can't read the current one. + // Filter out file types we have no interest in searching + if (ShouldIgnoreFile(assetFilePath)) continue; - } - bool hasFileChanged = false; + string assetMetaFilePath = AssetDatabase.GetTextMetaFilePathFromAssetPath(assetFilePath); - // Special handling / optimization if assetType is null - if (assetType == null) - { - foreach (AssetConversionRecord record in conversionData_Assets.assetRecords) - { - if (assetDataFile.Contains(record.target)) - { - hasFileChanged = true; + projectFilesToScan.Add(new AssetFileRecord(assetFilePath, assetMetaFilePath)); - assetDataFile = assetDataFile.Replace(record.target, record.replacement); + yield return null; + } - //Debug.Log("Replacing Reference to [" + record.referencedResource + "] using [" + record.target + "] with [" + record.replacement + "] in asset file: [" + assetFilePath + "]."); - } - } - } - else - { - foreach (AssetConversionRecord record in conversionData.assetRecords) - { - if (assetDataFile.Contains(record.target)) - { - hasFileChanged = true; + m_RemainingFilesToScan = m_ScanningTotalFiles = projectFilesToScan.Count; - assetDataFile = assetDataFile.Replace(record.target, record.replacement); + k_ProjectScanLabelPrefix = "Phase 2 - Scanning: "; - //Debug.Log("Replacing Reference to [" + record.referencedResource + "] using [" + record.target + "] with [" + record.replacement + "] in asset file: [" + assetFilePath + "]."); - } - } - } + for (int i = 0; i < m_ScanningTotalFiles; i++) + { + if (m_CancelScanProcess) + break; - if (hasFileChanged) + AssetFileRecord fileRecord = projectFilesToScan[i]; + + Task.Run(() => { - //Debug.Log("Adding [" + assetFilePath + "] to list of assets to be modified."); + ScanProjectFileAsync(fileRecord); - AssetModificationRecord modifiedAsset; - modifiedAsset.assetFilePath = assetFilePath; - modifiedAsset.assetDataFile = assetDataFile; + m_ScanningCurrentFileName = fileRecord.assetFilePath; - m_ModifiedAssetList.Add(modifiedAsset); + int completedScans = m_ScanningTotalFiles - Interlocked.Decrement(ref m_RemainingFilesToScan); - scanResults += assetFilePath + "\n"; - } + m_ScanningCurrentFileIndex = completedScans; + m_ProgressPercentage = (float)completedScans / m_ScanningTotalFiles; + }); - m_ProjectScanResults = scanResults; - m_ProgressPercentage = (float)i / (projectGUIDs.Length * 2); + if (i % 64 == 0) + yield return new WaitForSeconds(2.0f); - yield return null; } - // Iterate through projectGUIDs (again) to search project meta files which reference GUIDs used by previous versions of TextMesh Pro. - for (int i = 0; i < projectGUIDs.Length && cancelScanning == false; i++) - { - if (m_CancelScanProcess) - { - cancelScanning = true; - ResetScanProcess(); + while (m_RemainingFilesToScan > 0 && !m_CancelScanProcess) + yield return null; - continue; - } + m_IsAlreadyScanningProject = false; + m_ScanningCurrentFileName = string.Empty; + } - string guid = projectGUIDs[i]; - string assetFilePath = AssetDatabase.GUIDToAssetPath(guid); - string assetMetaFilePath = AssetDatabase.GetTextMetaFilePathFromAssetPath(assetFilePath); - // Read the asset meta data file - string assetMetaFile = File.ReadAllText(projectPath + "/" + assetMetaFilePath); + static void ScanProjectFileAsync(AssetFileRecord fileRecord) + { + if (m_CancelScanProcess) + return; - bool hasFileChanged = false; + // Read the asset data file + string assetDataFile = string.Empty; + bool hasFileChanged = false; + + try + { + assetDataFile = File.ReadAllText(m_ProjectPath + "/" + fileRecord.assetFilePath); + } + catch + { + // Continue to the next asset if we can't read the current one. + return; + } - m_ScanningCurrentFileName = assetMetaFilePath; + // Read the asset meta data file + string assetMetaFile = File.ReadAllText(m_ProjectPath + "/" + fileRecord.assetMetaFilePath); + bool hasMetaFileChanges = false; - foreach (AssetConversionRecord record in conversionData.assetRecords) + foreach (AssetConversionRecord record in m_ConversionData.assetRecords) + { + if (assetDataFile.Contains(record.target)) { - if (assetMetaFile.Contains(record.target)) - { - hasFileChanged = true; + hasFileChanged = true; - assetMetaFile = assetMetaFile.Replace(record.target, record.replacement); - - //Debug.Log("Replacing Reference to [" + record.referencedResource + "] using [" + record.target + "] with [" + record.replacement + "] in asset file: [" + assetMetaFilePath + "]."); - } + assetDataFile = assetDataFile.Replace(record.target, record.replacement); } - if (hasFileChanged) + //// Check meta file + if (assetMetaFile.Contains(record.target)) { - //Debug.Log("Adding [" + assetMetaFilePath + "] to list of meta files to be modified."); - - AssetModificationRecord modifiedAsset; - modifiedAsset.assetFilePath = assetMetaFilePath; - modifiedAsset.assetDataFile = assetMetaFile; - - m_ModifiedAssetList.Add(modifiedAsset); + hasMetaFileChanges = true; - scanResults += assetMetaFilePath + "\n"; + assetMetaFile = assetMetaFile.Replace(record.target, record.replacement); } + } + + if (hasFileChanged) + { + AssetModificationRecord modifiedAsset; + modifiedAsset.assetFilePath = fileRecord.assetFilePath; + modifiedAsset.assetDataFile = assetDataFile; - m_ProjectScanResults = scanResults; - m_ProgressPercentage = 0.5f + ((float)i / (projectGUIDs.Length * 2)); + m_ModifiedAssetList.Add(modifiedAsset); - yield return null; + m_ProjectScanResults += fileRecord.assetFilePath + "\n"; } - m_IsAlreadyScanningProject = false; - m_ScanningCurrentFileName = string.Empty; + if (hasMetaFileChanges) + { + AssetModificationRecord modifiedAsset; + modifiedAsset.assetFilePath = fileRecord.assetMetaFilePath; + modifiedAsset.assetDataFile = assetMetaFile; + + m_ModifiedAssetList.Add(modifiedAsset); + + m_ProjectScanResults += fileRecord.assetMetaFilePath + "\n"; + } } @@ -443,8 +486,8 @@ public static void GenerateNewPackageGUIDs_Menu() GenerateNewPackageGUIDs(); } - - /// + + /// /// /// [MenuItem("Window/TextMeshPro/Import TMP Essential Resources", false, 2050)] @@ -453,7 +496,7 @@ public static void ImportProjectResourcesMenu() ImportProjectResources(); } - + /// /// /// diff --git a/Scripts/Runtime/TMP_FontAsset.cs b/Scripts/Runtime/TMP_FontAsset.cs index fc8fa2c..cdedfcf 100644 --- a/Scripts/Runtime/TMP_FontAsset.cs +++ b/Scripts/Runtime/TMP_FontAsset.cs @@ -971,6 +971,10 @@ public static int[] GetCharactersArray(TMP_FontAsset fontAsset) /// internal static uint[] s_GlyphIndexArray = new uint[16]; + /// + /// Internal static list used to track characters that could not be added to the font asset. + /// + internal static List s_MissingCharacterList = new List(16); /// /// Try adding the characters from the provided string to the font asset. @@ -979,6 +983,19 @@ public static int[] GetCharactersArray(TMP_FontAsset fontAsset) /// Returns true if all the characters were successfully added to the font asset. Return false otherwise. public bool TryAddCharacters(uint[] unicodes) { + return TryAddCharacters(unicodes, out uint[] missingUnicodes); + } + + /// + /// Try adding the characters from the provided string to the font asset. + /// + /// Array that contains the characters to add to the font asset. + /// Array containing the characters that could not be added to the font asset. + /// Returns true if all the characters were successfully added to the font asset. Return false otherwise. + public bool TryAddCharacters(uint[] unicodes, out uint[] missingUnicodes) + { + s_MissingCharacterList.Clear(); + // Make sure font asset is set to dynamic and that we have a valid list of characters. if (unicodes == null || unicodes.Length == 0 || m_AtlasPopulationMode == AtlasPopulationMode.Static) { @@ -989,6 +1006,7 @@ public bool TryAddCharacters(uint[] unicodes) Debug.LogWarning("Unable to add characters to font asset [" + this.name + "] because the provided Unicode list is Null or Empty.", this); } + missingUnicodes = unicodes.ToArray(); return false; } @@ -999,6 +1017,7 @@ public bool TryAddCharacters(uint[] unicodes) { Profiler.EndSample(); + missingUnicodes = unicodes.ToArray(); return false; } @@ -1047,6 +1066,7 @@ public bool TryAddCharacters(uint[] unicodes) //Debug.LogWarning("No characters will be added to font asset [" + this.name + "] either because they are already present in the font asset or missing from the font file."); Profiler.EndSample(); + missingUnicodes = unicodes.ToArray(); return false; } @@ -1075,7 +1095,13 @@ public bool TryAddCharacters(uint[] unicodes) for (int i = 0; i < m_CharactersToAdd.Count; i++) { TMP_Character character = m_CharactersToAdd[i]; - character.glyph = m_GlyphLookupDictionary[character.glyphIndex]; + if (m_GlyphLookupDictionary.TryGetValue(character.glyphIndex, out Glyph glyph) == false) + { + s_MissingCharacterList.Add(character.unicode); + continue; + } + + character.glyph = glyph; m_CharacterTable.Add(character); m_CharacterLookupDictionary.Add(character.unicode, character); } @@ -1087,16 +1113,32 @@ public bool TryAddCharacters(uint[] unicodes) Profiler.EndSample(); + missingUnicodes = null; + + if (s_MissingCharacterList.Count > 0) + missingUnicodes = s_MissingCharacterList.ToArray(); + return allCharactersAdded && !isMissingCharacters; } - /// /// Try adding the characters from the provided string to the font asset. /// /// String containing the characters to add to the font asset. /// Returns true if all the characters were successfully added to the font asset. Return false otherwise. public bool TryAddCharacters(string characters) + { + return TryAddCharacters(characters, out string missingCharacters); + } + + + /// + /// Try adding the characters from the provided string to the font asset. + /// + /// String containing the characters to add to the font asset. + /// String containing the characters that could not be added to the font asset. + /// Returns true if all the characters were successfully added to the font asset. Return false otherwise. + public bool TryAddCharacters(string characters, out string missingCharacters) { // Make sure font asset is set to dynamic and that we have a valid list of characters. if (string.IsNullOrEmpty(characters) || m_AtlasPopulationMode == AtlasPopulationMode.Static) @@ -1108,12 +1150,16 @@ public bool TryAddCharacters(string characters) Debug.LogWarning("Unable to add characters to font asset [" + this.name + "] because the provided character list is Null or Empty.", this); } + missingCharacters = characters; return false; } // Load font face. if (FontEngine.LoadFontFace(m_SourceFontFile, m_FaceInfo.pointSize) != FontEngineError.Success) + { + missingCharacters = characters; return false; + } // Clear data structures used to track which glyph needs to be added to atlas texture. m_GlyphIndexList.Clear(); @@ -1161,7 +1207,7 @@ public bool TryAddCharacters(string characters) if (m_GlyphIndexList.Count == 0) { - //Debug.LogWarning("No characters will be added to font asset [" + this.name + "] either because they are already present in the font asset or missing from the font file."); + missingCharacters = characters; return false; } @@ -1183,26 +1229,23 @@ public bool TryAddCharacters(string characters) // Add new glyph to glyph table. m_GlyphTable.Add(glyph); m_GlyphLookupDictionary.Add(glyphIndex, glyph); - - // Add new character(s) - //List unicodes = m_CharacterLookupMap[glyphIndex]; - //int unicodeCount = unicodes.Count; - - //for (int j = 0; j < unicodeCount; j++) - //{ - // uint unicode = unicodes[j]; - - // TMP_Character character = new TMP_Character(unicode, glyph); - // m_CharacterTable.Add(character); - // m_CharacterLookupDictionary.Add(unicode, character); - //} } + missingCharacters = string.Empty; + // Add new characters to relevant data structures. for (int i = 0; i < m_CharactersToAdd.Count; i++) { TMP_Character character = m_CharactersToAdd[i]; - character.glyph = m_GlyphLookupDictionary[character.glyphIndex]; + + if (m_GlyphLookupDictionary.TryGetValue(character.glyphIndex, out Glyph glyph) == false) + { + // TODO: Revise to avoid string concatenation. + missingCharacters += (char)character.unicode; + continue; + } + + character.glyph = glyph; m_CharacterTable.Add(character); m_CharacterLookupDictionary.Add(character.unicode, character); } diff --git a/package.json b/package.json index ff0af5c..d3943be 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.unity.textmeshpro", "displayName": "TextMesh Pro", - "version": "1.4.0-preview.2a", + "version": "1.4.0-preview.3a", "unity": "2018.3", "description": "TextMesh Pro is the ultimate text solution for Unity. It's the perfect replacement for Unity's UI Text and the legacy Text Mesh.\n\nPowerful and easy to use, TextMesh Pro uses Advanced Text Rendering techniques along with a set of custom shaders; delivering substantial visual quality improvements while giving users incredible flexibility when it comes to text styling and texturing.\n\nTextMesh Pro provides Improved Control over text formatting and layout with features like character, word, line and paragraph spacing, kerning, justified text, Links, over 30 Rich Text Tags available, support for Multi Font & Sprites, Custom Styles and more.\n\nGreat performance. Since the geometry created by TextMesh Pro uses two triangles per character just like Unity's text components, this improved visual quality and flexibility comes at no additional performance cost.", "keywords": [ @@ -15,6 +15,6 @@ "repository": { "type": "git", "url": "https://gitlab.cds.internal.unity3d.com/upm-packages/text/com.unity.textmeshpro.git", - "revision": "f10547e8" + "revision": "db71f1c9" } }