From 5152b174a510cdc9431bdf6252f2f6a7c6f120d0 Mon Sep 17 00:00:00 2001 From: Unity Technologies <@unity> Date: Mon, 8 Jun 2020 00:00:00 +0000 Subject: [PATCH] com.unity.textmeshpro@1.5.0-preview.14 ## [1.5.0-preview.14] - 2020-06-08 ## [2.1.0-preview.14] ## [3.0.0-preview.14] ### Changes - Fixed sprite character and sprite glyph scale not being reflected in the text layout. See [forum post](https://forum.unity.com/threads/glyph-scale-dont-change-line-height.898817/) for details. - Fixed potential null reference exception in the CrossFadeColor or CrossFadeAlpha functions. See [forum post](https://forum.unity.com/threads/version-1-5-0-2-1-0-3-0-0-preview-13-now-available-for-testing.753587/page-4#post-5885075) for details. - Minor improvements to the Sprite Asset Importer to improve allocations and address potential error encountered when creating multiple sprite assets. - TMP GUID Remapping Tool - Removed "UnityEditor.Animations.AnimatorController" from the exclusion search list. - Fixed potential culling issue when dynamically updating the content of child text objects of RectMask2D components. Case #1253625 - Fixed InvalidOperationException that could occur when changing text Overflow linked components via code. Case #1251283 --- CHANGELOG.md | 11 ++ Scripts/Editor/TMP_PackageUtilities.cs | 1 - Scripts/Editor/TMP_SpriteAssetImporter.cs | 36 +++++-- Scripts/Runtime/TMP_Asset.cs | 7 +- Scripts/Runtime/TMP_ColorGradient.cs | 2 +- Scripts/Runtime/TMP_FontAsset.cs | 123 +++++++++++++++++++++- Scripts/Runtime/TMP_ResourcesManager.cs | 25 +++++ Scripts/Runtime/TMP_SpriteAsset.cs | 2 +- Scripts/Runtime/TMP_StyleSheet.cs | 10 +- Scripts/Runtime/TMP_SubMeshUI.cs | 15 +-- Scripts/Runtime/TMP_Text.cs | 42 ++++---- Scripts/Runtime/TMP_UpdateManager.cs | 99 ++++++++++++++--- Scripts/Runtime/TMPro_Private.cs | 11 +- Scripts/Runtime/TMPro_UGUI_Private.cs | 40 +------ Scripts/Runtime/TextMeshProUGUI.cs | 58 ++++++++-- package.json | 8 +- 16 files changed, 363 insertions(+), 127 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 456479a..5e6c91d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,17 @@ # 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.5.0-preview.14] - 2020-06-08 +## [2.1.0-preview.14] +## [3.0.0-preview.14] +### Changes +- Fixed sprite character and sprite glyph scale not being reflected in the text layout. See [forum post](https://forum.unity.com/threads/glyph-scale-dont-change-line-height.898817/) for details. +- Fixed potential null reference exception in the CrossFadeColor or CrossFadeAlpha functions. See [forum post](https://forum.unity.com/threads/version-1-5-0-2-1-0-3-0-0-preview-13-now-available-for-testing.753587/page-4#post-5885075) for details. +- Minor improvements to the Sprite Asset Importer to improve allocations and address potential error encountered when creating multiple sprite assets. +- TMP GUID Remapping Tool - Removed "UnityEditor.Animations.AnimatorController" from the exclusion search list. +- Fixed potential culling issue when dynamically updating the content of child text objects of RectMask2D components. Case #1253625 +- Fixed InvalidOperationException that could occur when changing text Overflow linked components via code. Case #1251283 + ## [1.5.0-preview.13] - 2020-05-22 ## [2.1.0-preview.13] ## [3.0.0-preview.13] diff --git a/Scripts/Editor/TMP_PackageUtilities.cs b/Scripts/Editor/TMP_PackageUtilities.cs index e082954..41b8932 100644 --- a/Scripts/Editor/TMP_PackageUtilities.cs +++ b/Scripts/Editor/TMP_PackageUtilities.cs @@ -72,7 +72,6 @@ static void ShowConverterWindow() typeof(Texture2D), typeof(Texture2DArray), typeof(Texture3D), - typeof(UnityEditor.Animations.AnimatorController), typeof(UnityEditorInternal.AssemblyDefinitionAsset), typeof(UnityEngine.AI.NavMeshData), typeof(UnityEngine.Tilemaps.Tile), diff --git a/Scripts/Editor/TMP_SpriteAssetImporter.cs b/Scripts/Editor/TMP_SpriteAssetImporter.cs index 5408c6f..89be4ad 100644 --- a/Scripts/Editor/TMP_SpriteAssetImporter.cs +++ b/Scripts/Editor/TMP_SpriteAssetImporter.cs @@ -1,4 +1,5 @@ -using UnityEngine; +using System; +using UnityEngine; using UnityEngine.TextCore; using UnityEditor; using System.IO; @@ -28,19 +29,36 @@ public static void ShowFontAtlasCreatorWindow() TMP_SpriteAsset m_SpriteAsset; List m_SpriteInfoList = new List(); - + /// + /// + /// void OnEnable() { // Set Editor Window Size SetEditorWindowSize(); } + /// + /// + /// public void OnGUI() { DrawEditorPanel(); } + /// + /// + /// + private void OnDisable() + { + // Clean up sprite asset object that may have been created and not saved. + if (m_SpriteAsset != null && !EditorUtility.IsPersistent(m_SpriteAsset)) + DestroyImmediate(m_SpriteAsset); + } + /// + /// + /// void DrawEditorPanel() { // label @@ -70,6 +88,10 @@ void DrawEditorPanel() { m_CreationFeedback = string.Empty; + // Clean up sprite asset object that may have been previously created. + if (m_SpriteAsset != null && !EditorUtility.IsPersistent(m_SpriteAsset)) + DestroyImmediate(m_SpriteAsset); + // Read json data file if (m_JsonFile != null) { @@ -94,9 +116,6 @@ void DrawEditorPanel() m_CreationFeedback = "Import Results\n--------------------\n"; m_CreationFeedback += "" + spriteCount + " Sprites were imported from file."; - if (m_SpriteAsset != null) - DestroyImmediate(m_SpriteAsset); - // Create new Sprite Asset m_SpriteAsset = CreateInstance(); @@ -122,7 +141,7 @@ void DrawEditorPanel() GUILayout.Space(5); GUILayout.BeginVertical(EditorStyles.helpBox, GUILayout.Height(60)); { - EditorGUILayout.LabelField(m_CreationFeedback, TMP_UIStyleManager.label); + EditorGUILayout.TextArea(m_CreationFeedback, TMP_UIStyleManager.label); } GUILayout.EndVertical(); @@ -140,7 +159,6 @@ void DrawEditorPanel() GUI.enabled = true; } - /// /// /// @@ -175,7 +193,6 @@ private static void PopulateSpriteTables(TexturePacker_JsonArray.SpriteDataObjec } } - /// /// /// @@ -210,7 +227,6 @@ void SaveSpriteAsset(string filePath) AddDefaultMaterial(m_SpriteAsset); } - /// /// Create and add new default material to sprite asset. /// @@ -226,7 +242,6 @@ static void AddDefaultMaterial(TMP_SpriteAsset spriteAsset) AssetDatabase.AddObjectToAsset(material, spriteAsset); } - /// /// Limits the minimum size of the editor window. /// @@ -238,6 +253,5 @@ void SetEditorWindowSize() editorWindow.minSize = new Vector2(Mathf.Max(230, currentWindowSize.x), Mathf.Max(300, currentWindowSize.y)); } - } } diff --git a/Scripts/Runtime/TMP_Asset.cs b/Scripts/Runtime/TMP_Asset.cs index e061958..60ed878 100644 --- a/Scripts/Runtime/TMP_Asset.cs +++ b/Scripts/Runtime/TMP_Asset.cs @@ -1,11 +1,12 @@ -using UnityEngine; +using System; +using UnityEngine; namespace TMPro { // Base class inherited by the various TextMeshPro Assets. - [System.Serializable] - public class TMP_Asset : ScriptableObject + [Serializable] + public abstract class TMP_Asset : ScriptableObject { /// /// Instance ID of the TMP Asset diff --git a/Scripts/Runtime/TMP_ColorGradient.cs b/Scripts/Runtime/TMP_ColorGradient.cs index 0730ada..8e8e38a 100644 --- a/Scripts/Runtime/TMP_ColorGradient.cs +++ b/Scripts/Runtime/TMP_ColorGradient.cs @@ -11,7 +11,7 @@ public enum ColorMode FourCornersGradient } - [System.Serializable] + [System.Serializable][ExcludeFromPresetAttribute] public class TMP_ColorGradient : ScriptableObject { public ColorMode colorMode = ColorMode.FourCornersGradient; diff --git a/Scripts/Runtime/TMP_FontAsset.cs b/Scripts/Runtime/TMP_FontAsset.cs index d9e8536..b849094 100644 --- a/Scripts/Runtime/TMP_FontAsset.cs +++ b/Scripts/Runtime/TMP_FontAsset.cs @@ -23,7 +23,7 @@ public enum AtlasPopulationMode } - [Serializable] + [Serializable][ExcludeFromPresetAttribute] public class TMP_FontAsset : TMP_Asset { /// @@ -524,6 +524,115 @@ public static TMP_FontAsset CreateFontAsset(Font font, int samplingPointSize, in } + /* + /// + /// Create new font asset using default settings from path to source font file. + /// + /// Path to source font file. + /// + public static TMP_FontAsset CreateFontAsset(string fontFilePath) + { + return CreateFontAsset(fontFilePath, 90, 9, GlyphRenderMode.SDFAA, 1024, 1024, AtlasPopulationMode.Dynamic); + } + + public static TMP_FontAsset CreateFontAsset(string fontFilePath, int samplingPointSize, int atlasPadding, GlyphRenderMode renderMode, int atlasWidth, int atlasHeight, AtlasPopulationMode atlasPopulationMode = AtlasPopulationMode.Dynamic, bool enableMultiAtlasSupport = true) + { + // Initialize FontEngine + FontEngine.InitializeFontEngine(); + + // Load Font Face + if (FontEngine.LoadFontFace(fontFilePath, samplingPointSize) != FontEngineError.Success) + { + //Debug.LogWarning("Unable to load font face for [" + font.name + "]. Make sure \"Include Font Data\" is enabled in the Font Import Settings.", font); + return null; + } + + // Create new font asset + TMP_FontAsset fontAsset = ScriptableObject.CreateInstance(); + + fontAsset.m_Version = "1.1.0"; + fontAsset.faceInfo = FontEngine.GetFaceInfo(); + + // Set font reference and GUID + if (atlasPopulationMode == AtlasPopulationMode.Dynamic) + fontAsset.sourceFontFile = font; + + // Set persistent reference to source font file in the Editor only. + #if UNITY_EDITOR + string guid; + long localID; + + UnityEditor.AssetDatabase.TryGetGUIDAndLocalFileIdentifier(font, out guid, out localID); + fontAsset.m_SourceFontFileGUID = guid; + fontAsset.m_SourceFontFile_EditorRef = font; + #endif + + fontAsset.atlasPopulationMode = atlasPopulationMode; + + fontAsset.atlasWidth = atlasWidth; + fontAsset.atlasHeight = atlasHeight; + fontAsset.atlasPadding = atlasPadding; + fontAsset.atlasRenderMode = renderMode; + + // Initialize array for the font atlas textures. + fontAsset.atlasTextures = new Texture2D[1]; + + // Create and add font atlas texture. + Texture2D texture = new Texture2D(0, 0, TextureFormat.Alpha8, false); + + //texture.name = assetName + " Atlas"; + fontAsset.atlasTextures[0] = texture; + + fontAsset.isMultiAtlasTexturesEnabled = enableMultiAtlasSupport; + + // Add free rectangle of the size of the texture. + int packingModifier; + if (((GlyphRasterModes)renderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP) + { + packingModifier = 0; + + // Optimize by adding static ref to shader. + Material tmp_material = new Material(ShaderUtilities.ShaderRef_MobileBitmap); + + //tmp_material.name = texture.name + " Material"; + tmp_material.SetTexture(ShaderUtilities.ID_MainTex, texture); + tmp_material.SetFloat(ShaderUtilities.ID_TextureWidth, atlasWidth); + tmp_material.SetFloat(ShaderUtilities.ID_TextureHeight, atlasHeight); + + fontAsset.material = tmp_material; + } + else + { + packingModifier = 1; + + // Optimize by adding static ref to shader. + Material tmp_material = new Material(ShaderUtilities.ShaderRef_MobileSDF); + + //tmp_material.name = texture.name + " Material"; + tmp_material.SetTexture(ShaderUtilities.ID_MainTex, texture); + tmp_material.SetFloat(ShaderUtilities.ID_TextureWidth, atlasWidth); + tmp_material.SetFloat(ShaderUtilities.ID_TextureHeight, atlasHeight); + + tmp_material.SetFloat(ShaderUtilities.ID_GradientScale, atlasPadding + packingModifier); + + tmp_material.SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle); + tmp_material.SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle); + + fontAsset.material = tmp_material; + } + + fontAsset.freeGlyphRects = new List(8) { new GlyphRect(0, 0, atlasWidth - packingModifier, atlasHeight - packingModifier) }; + fontAsset.usedGlyphRects = new List(8); + + // TODO: Consider adding support for extracting glyph positioning data + + fontAsset.ReadFontAssetDefinition(); + + return fontAsset; + } + */ + + void Awake() { //Debug.Log("TMP Font Asset [" + this.name + "] with Version #" + m_Version + " has been enabled!"); @@ -533,6 +642,13 @@ void Awake() UpgradeFontAsset(); } + #if UNITY_EDITOR + private void OnValidate() + { + if (m_CharacterLookupDictionary == null || m_GlyphLookupDictionary == null) + ReadFontAssetDefinition(); + } + #endif public void ReadFontAssetDefinition() { @@ -2722,8 +2838,9 @@ internal void UpdateFontAssetData() //TMP_ResourceManager.RebuildFontAssetCache(instanceID); - // Add glyphs - TryAddCharacters(unicodeCharacters, true); + // Add existing glyphs and characters back in the font asset (if any) + if (unicodeCharacters.Length > 0) + TryAddCharacters(unicodeCharacters, true); Profiler.EndSample(); } diff --git a/Scripts/Runtime/TMP_ResourcesManager.cs b/Scripts/Runtime/TMP_ResourcesManager.cs index 55f2f5d..b76fa39 100644 --- a/Scripts/Runtime/TMP_ResourcesManager.cs +++ b/Scripts/Runtime/TMP_ResourcesManager.cs @@ -14,6 +14,31 @@ public class TMP_ResourceManager static TMP_ResourceManager() { } + // ====================================================== + // TEXT SETTINGS MANAGEMENT + // ====================================================== + + private static TMP_Settings s_TextSettings; + + internal static TMP_Settings GetTextSettings() + { + if (s_TextSettings == null) + { + // Try loading the TMP Settings from a Resources folder in the user project. + s_TextSettings = Resources.Load("TextSettings"); // ?? ScriptableObject.CreateInstance(); + + #if UNITY_EDITOR + if (s_TextSettings == null) + { + // Open TMP Resources Importer to enable the user to import the TMP Essential Resources and option TMP Examples & Extras + TMP_PackageResourceImporterWindow.ShowPackageImporterWindow(); + } + #endif + } + + return s_TextSettings; + } + // ====================================================== // FONT ASSET MANAGEMENT - Fields, Properties and Functions // ====================================================== diff --git a/Scripts/Runtime/TMP_SpriteAsset.cs b/Scripts/Runtime/TMP_SpriteAsset.cs index 55b1b17..007ca42 100644 --- a/Scripts/Runtime/TMP_SpriteAsset.cs +++ b/Scripts/Runtime/TMP_SpriteAsset.cs @@ -6,7 +6,7 @@ namespace TMPro { - + [ExcludeFromPresetAttribute] public class TMP_SpriteAsset : TMP_Asset { internal Dictionary m_NameLookup; diff --git a/Scripts/Runtime/TMP_StyleSheet.cs b/Scripts/Runtime/TMP_StyleSheet.cs index 54ea5ff..89ad5a7 100644 --- a/Scripts/Runtime/TMP_StyleSheet.cs +++ b/Scripts/Runtime/TMP_StyleSheet.cs @@ -6,11 +6,11 @@ namespace TMPro { - [Serializable] + [Serializable][ExcludeFromPresetAttribute] public class TMP_StyleSheet : ScriptableObject { /// - /// + /// /// internal List styles { @@ -67,7 +67,7 @@ public void RefreshStyles() } /// - /// + /// /// private void LoadStyleDictionaryInternal() { @@ -80,7 +80,7 @@ private void LoadStyleDictionaryInternal() for (int i = 0; i < m_StyleList.Count; i++) { m_StyleList[i].RefreshStyle(); - + if (!m_StyleLookupDictionary.ContainsKey(m_StyleList[i].hashCode)) m_StyleLookupDictionary.Add(m_StyleList[i].hashCode, m_StyleList[i]); } @@ -92,4 +92,4 @@ private void LoadStyleDictionaryInternal() } } -} \ No newline at end of file +} diff --git a/Scripts/Runtime/TMP_SubMeshUI.cs b/Scripts/Runtime/TMP_SubMeshUI.cs index 2fb773d..850e73f 100644 --- a/Scripts/Runtime/TMP_SubMeshUI.cs +++ b/Scripts/Runtime/TMP_SubMeshUI.cs @@ -9,7 +9,7 @@ namespace TMPro { [ExecuteAlways] - public class TMP_SubMeshUI : MaskableGraphic, IClippable, IMaskable, IMaterialModifier + public class TMP_SubMeshUI : MaskableGraphic { /// /// The TMP Font Asset assigned to this sub text object. @@ -645,22 +645,13 @@ Transform GetRootCanvasTransform() private Transform m_RootCanvasTransform; /// - /// Override to Cull function of MaskableGraphic to prevent Culling. + /// Override Cull function as this is handled by the parent text object. /// /// /// public override void Cull(Rect clipRect, bool validRect) { - // Get compound rect for the text object and sub text objects in local canvas space. - Rect rect = m_TextComponent.GetCanvasSpaceClippingRect(); - - var cull = !validRect || !clipRect.Overlaps(rect, true); - if (canvasRenderer.cull != cull) - { - canvasRenderer.cull = cull; - onCullStateChanged.Invoke(cull); - OnCullingChanged(); - } + // Do nothing as this functionality is handled by the parent text object. } diff --git a/Scripts/Runtime/TMP_Text.cs b/Scripts/Runtime/TMP_Text.cs index d8b235a..ea9c738 100644 --- a/Scripts/Runtime/TMP_Text.cs +++ b/Scripts/Runtime/TMP_Text.cs @@ -1711,6 +1711,11 @@ protected virtual void SetShaderDepth() { } /// protected virtual void SetCulling() { } + /// + /// + /// + internal virtual void UpdateCulling() {} + /// /// Get the padding value for the currently assigned material /// @@ -5409,7 +5414,6 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m // Look up Character Data from Dictionary and cache it. #region Look up Character Data //float baselineOffset = 0; - float spriteScale = 1; float elementAscentLine = 0; float elementDescentLine = 0; if (m_textElementType == TMP_TextElementType.Sprite) @@ -5428,7 +5432,7 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m // The sprite scale calculations are based on the font asset assigned to the text object. if (m_currentSpriteAsset.faceInfo.pointSize > 0) { - spriteScale = (m_currentFontSize / m_currentSpriteAsset.faceInfo.pointSize * m_currentSpriteAsset.faceInfo.scale * (m_isOrthographic ? 1 : 0.1f)); + float spriteScale = (m_currentFontSize / m_currentSpriteAsset.faceInfo.pointSize * m_currentSpriteAsset.faceInfo.scale * (m_isOrthographic ? 1 : 0.1f)); currentElementScale = sprite.scale * sprite.glyph.scale * spriteScale; elementAscentLine = m_currentSpriteAsset.faceInfo.ascentLine; //baselineOffset = m_currentSpriteAsset.faceInfo.baseline * m_fontScale * m_fontScaleMultiplier * m_currentSpriteAsset.faceInfo.scale; @@ -5436,7 +5440,7 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m } else { - spriteScale = (m_currentFontSize / m_currentFontAsset.faceInfo.pointSize * m_currentFontAsset.faceInfo.scale * (m_isOrthographic ? 1 : 0.1f)); + float spriteScale = (m_currentFontSize / m_currentFontAsset.faceInfo.pointSize * m_currentFontAsset.faceInfo.scale * (m_isOrthographic ? 1 : 0.1f)); currentElementScale = m_currentFontAsset.faceInfo.ascentLine / sprite.glyph.metrics.height * sprite.scale * sprite.glyph.scale * spriteScale; elementAscentLine = m_currentFontAsset.faceInfo.ascentLine; //baselineOffset = m_currentFontAsset.faceInfo.baseline * m_fontScale * m_fontScaleMultiplier * m_currentFontAsset.faceInfo.scale; @@ -5446,7 +5450,7 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m m_cached_TextElement = sprite; m_internalCharacterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite; - m_internalCharacterInfo[m_characterCount].scale = spriteScale; + m_internalCharacterInfo[m_characterCount].scale = currentElementScale; m_currentMaterialIndex = prev_MaterialIndex; } @@ -5496,35 +5500,37 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m #region Handle Kerning TMP_GlyphValueRecord glyphAdjustments = new TMP_GlyphValueRecord(); float characterSpacingAdjustment = m_characterSpacing; + m_GlyphHorizontalAdvanceAdjustment = 0; if (m_enableKerning) { TMP_GlyphPairAdjustmentRecord adjustmentPair; + uint baseGlyphIndex = m_cached_TextElement.m_GlyphIndex; if (m_characterCount < totalCharacterCount - 1) { - uint firstGlyphIndex = m_cached_TextElement.glyphIndex; - uint secondGlyphIndex = m_textInfo.characterInfo[m_characterCount + 1].textElement.glyphIndex; - uint key = new GlyphPairKey(firstGlyphIndex, secondGlyphIndex).key; + uint nextGlyphIndex = m_textInfo.characterInfo[m_characterCount + 1].textElement.m_GlyphIndex; + uint key = nextGlyphIndex << 16 | baseGlyphIndex; - if (m_currentFontAsset.fontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out adjustmentPair)) + if (m_currentFontAsset.m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out adjustmentPair)) { - glyphAdjustments = adjustmentPair.firstAdjustmentRecord.glyphValueRecord; - characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; + glyphAdjustments = adjustmentPair.m_FirstAdjustmentRecord.m_GlyphValueRecord; + characterSpacingAdjustment = (adjustmentPair.m_FeatureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; } } if (m_characterCount >= 1) { - uint firstGlyphIndex = m_textInfo.characterInfo[m_characterCount - 1].textElement.glyphIndex; - uint secondGlyphIndex = m_cached_TextElement.glyphIndex; - uint key = new GlyphPairKey(firstGlyphIndex, secondGlyphIndex).key; + uint previousGlyphIndex = m_textInfo.characterInfo[m_characterCount - 1].textElement.m_GlyphIndex; + uint key = baseGlyphIndex << 16 | previousGlyphIndex; - if (m_currentFontAsset.fontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out adjustmentPair)) + if (m_currentFontAsset.m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out adjustmentPair)) { - glyphAdjustments += adjustmentPair.secondAdjustmentRecord.glyphValueRecord; - characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; + glyphAdjustments += adjustmentPair.m_SecondAdjustmentRecord.m_GlyphValueRecord; + characterSpacingAdjustment = (adjustmentPair.m_FeatureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; } } + + m_GlyphHorizontalAdvanceAdjustment = glyphAdjustments.m_XAdvance; } #endregion @@ -5566,12 +5572,12 @@ protected virtual Vector2 CalculatePreferredValues(ref float fontSize, Vector2 m // Element Ascender in line space float elementAscender = m_textElementType == TMP_TextElementType.Character ? elementAscentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset - : elementAscentLine * spriteScale + m_baselineOffset; + : elementAscentLine * currentElementScale + m_baselineOffset; // Element Descender in line space float elementDescender = m_textElementType == TMP_TextElementType.Character ? elementDescentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset - : elementDescentLine * spriteScale + m_baselineOffset; + : elementDescentLine * currentElementScale + m_baselineOffset; float adjustedAscender = elementAscender; float adjustedDescender = elementDescender; diff --git a/Scripts/Runtime/TMP_UpdateManager.cs b/Scripts/Runtime/TMP_UpdateManager.cs index 3fbcf8a..860420b 100644 --- a/Scripts/Runtime/TMP_UpdateManager.cs +++ b/Scripts/Runtime/TMP_UpdateManager.cs @@ -11,9 +11,17 @@ public class TMP_UpdateManager { private static TMP_UpdateManager s_Instance; - private readonly HashSet m_LayoutRebuildQueue = new HashSet(); - private readonly HashSet m_GraphicRebuildQueue = new HashSet(); - private readonly HashSet m_InternalUpdateQueue = new HashSet(); + private readonly HashSet m_LayoutQueueLookup = new HashSet(); + private readonly List m_LayoutRebuildQueue = new List(); + + private readonly HashSet m_GraphicQueueLookup = new HashSet(); + private readonly List m_GraphicRebuildQueue = new List(); + + private readonly HashSet m_InternalUpdateLookup = new HashSet(); + private readonly List m_InternalUpdateQueue = new List(); + + private readonly HashSet m_CullingUpdateLookup = new HashSet(); + private readonly List m_CullingUpdateQueue = new List(); /// @@ -53,9 +61,12 @@ internal static void RegisterTextObjectForUpdate(TMP_Text textObject) private void InternalRegisterTextObjectForUpdate(TMP_Text textObject) { - if (m_InternalUpdateQueue.Contains(textObject)) + int id = textObject.GetInstanceID(); + + if (m_InternalUpdateLookup.Contains(id)) return; + m_InternalUpdateLookup.Add(id); m_InternalUpdateQueue.Add(textObject); } @@ -70,9 +81,12 @@ public static void RegisterTextElementForLayoutRebuild(TMP_Text element) private void InternalRegisterTextElementForLayoutRebuild(TMP_Text element) { - if (m_LayoutRebuildQueue.Contains(element)) + int id = element.GetInstanceID(); + + if (m_LayoutQueueLookup.Contains(id)) return; + m_LayoutQueueLookup.Add(id); m_LayoutRebuildQueue.Add(element); } @@ -91,12 +105,35 @@ public static void RegisterTextElementForGraphicRebuild(TMP_Text element) private void InternalRegisterTextElementForGraphicRebuild(TMP_Text element) { - if (m_GraphicRebuildQueue.Contains(element)) + int id = element.GetInstanceID(); + + if (m_GraphicQueueLookup.Contains(id)) return; + m_GraphicQueueLookup.Add(id); m_GraphicRebuildQueue.Add(element); } + public static void RegisterTextElementForCullingUpdate(TMP_Text element) + { + Profiler.BeginSample("TMP.RegisterTextElementForCullingUpdate"); + + instance.InternalRegisterTextElementForCullingUpdate(element); + + Profiler.EndSample(); + } + + private void InternalRegisterTextElementForCullingUpdate(TMP_Text element) + { + int id = element.GetInstanceID(); + + if (m_CullingUpdateLookup.Contains(id)) + return; + + m_CullingUpdateLookup.Add(id); + m_CullingUpdateQueue.Add(element); + } + /// /// Callback which occurs just before the cam is rendered. /// @@ -110,28 +147,49 @@ void OnCameraPreCull() /// void DoRebuilds() { - Profiler.BeginSample("TMP.DoRebuilds"); - - // Handle text objects that require an update either as a result of scale changes or legacy animation. - foreach (var textObject in m_InternalUpdateQueue) - textObject.InternalUpdate(); + // Handle text objects the require an update either as a result of scale changes or legacy animation. + for (int i = 0; i < m_InternalUpdateQueue.Count; i++) + { + m_InternalUpdateQueue[i].InternalUpdate(); + } // Handle Layout Rebuild Phase - foreach (var textObject in m_LayoutRebuildQueue) - textObject.Rebuild(CanvasUpdate.Prelayout); + for (int i = 0; i < m_LayoutRebuildQueue.Count; i++) + { + m_LayoutRebuildQueue[i].Rebuild(CanvasUpdate.Prelayout); + } if (m_LayoutRebuildQueue.Count > 0) + { m_LayoutRebuildQueue.Clear(); + m_LayoutQueueLookup.Clear(); + } // Handle Graphic Rebuild Phase - foreach (var textObject in m_GraphicRebuildQueue) - textObject.Rebuild(CanvasUpdate.PreRender); + for (int i = 0; i < m_GraphicRebuildQueue.Count; i++) + { + m_GraphicRebuildQueue[i].Rebuild(CanvasUpdate.PreRender); + } // If there are no objects in the queue, we don't need to clear the lists again. if (m_GraphicRebuildQueue.Count > 0) + { m_GraphicRebuildQueue.Clear(); + m_GraphicQueueLookup.Clear(); + } - Profiler.EndSample(); + // Handle Culling Update + for (int i = 0; i < m_CullingUpdateQueue.Count; i++) + { + m_CullingUpdateQueue[i].UpdateCulling(); + } + + // If there are no objects in the queue, we don't need to clear the lists again. + if (m_CullingUpdateQueue.Count > 0) + { + m_CullingUpdateQueue.Clear(); + m_CullingUpdateLookup.Clear(); + } } internal static void UnRegisterTextObjectForUpdate(TMP_Text textObject) @@ -158,19 +216,28 @@ private void InternalUnRegisterTextElementForGraphicRebuild(TMP_Text element) { Profiler.BeginSample("TMP.InternalUnRegisterTextElementForGraphicRebuild"); + int id = element.GetInstanceID(); + m_GraphicRebuildQueue.Remove(element); + m_GraphicQueueLookup.Remove(id); Profiler.EndSample(); } private void InternalUnRegisterTextElementForLayoutRebuild(TMP_Text element) { + int id = element.GetInstanceID(); + m_LayoutRebuildQueue.Remove(element); + m_LayoutQueueLookup.Remove(id); } private void InternalUnRegisterTextObjectForUpdate(TMP_Text textObject) { + int id = textObject.GetInstanceID(); + m_InternalUpdateQueue.Remove(textObject); + m_InternalUpdateLookup.Remove(id); } } } diff --git a/Scripts/Runtime/TMPro_Private.cs b/Scripts/Runtime/TMPro_Private.cs index 79b8abb..2bfdbb7 100644 --- a/Scripts/Runtime/TMPro_Private.cs +++ b/Scripts/Runtime/TMPro_Private.cs @@ -1909,7 +1909,6 @@ protected override void GenerateTextMesh() Profiler.BeginSample("TMP - Lookup Character & Glyph Data"); #endif float baselineOffset = 0; - float spriteScale = 1; float elementAscentLine = 0; float elementDescentLine = 0; if (m_textElementType == TMP_TextElementType.Sprite) @@ -1930,7 +1929,7 @@ protected override void GenerateTextMesh() // The sprite scale calculations are based on the font asset assigned to the text object. if (m_currentSpriteAsset.m_FaceInfo.pointSize > 0) { - spriteScale = m_currentFontSize / m_currentSpriteAsset.m_FaceInfo.pointSize * m_currentSpriteAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); + float spriteScale = m_currentFontSize / m_currentSpriteAsset.m_FaceInfo.pointSize * m_currentSpriteAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); currentElementScale = sprite.m_Scale * sprite.m_Glyph.scale * spriteScale; elementAscentLine = m_currentSpriteAsset.m_FaceInfo.ascentLine; baselineOffset = m_currentSpriteAsset.m_FaceInfo.baseline * m_fontScale * m_fontScaleMultiplier * m_currentSpriteAsset.m_FaceInfo.scale; @@ -1938,7 +1937,7 @@ protected override void GenerateTextMesh() } else { - spriteScale = m_currentFontSize / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); + float spriteScale = m_currentFontSize / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); currentElementScale = m_currentFontAsset.m_FaceInfo.ascentLine / sprite.m_Glyph.metrics.height * sprite.m_Scale * sprite.m_Glyph.scale * spriteScale; elementAscentLine = m_currentFontAsset.m_FaceInfo.ascentLine; baselineOffset = m_currentFontAsset.m_FaceInfo.baseline * m_fontScale * m_fontScaleMultiplier * m_currentFontAsset.m_FaceInfo.scale; @@ -1948,7 +1947,7 @@ protected override void GenerateTextMesh() m_cached_TextElement = sprite; m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite; - m_textInfo.characterInfo[m_characterCount].scale = spriteScale; + m_textInfo.characterInfo[m_characterCount].scale = currentElementScale; m_textInfo.characterInfo[m_characterCount].spriteAsset = m_currentSpriteAsset; m_textInfo.characterInfo[m_characterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_characterCount].materialReferenceIndex = m_currentMaterialIndex; @@ -2213,12 +2212,12 @@ protected override void GenerateTextMesh() // Element Ascender in line space float elementAscender = m_textElementType == TMP_TextElementType.Character ? elementAscentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset - : elementAscentLine * spriteScale + m_baselineOffset; + : elementAscentLine * currentElementScale + m_baselineOffset; // Element Descender in line space float elementDescender = m_textElementType == TMP_TextElementType.Character ? elementDescentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset - : elementDescentLine * spriteScale + m_baselineOffset; + : elementDescentLine * currentElementScale + m_baselineOffset; float adjustedAscender = elementAscender; float adjustedDescender = elementDescender; diff --git a/Scripts/Runtime/TMPro_UGUI_Private.cs b/Scripts/Runtime/TMPro_UGUI_Private.cs index 777c202..20a854b 100644 --- a/Scripts/Runtime/TMPro_UGUI_Private.cs +++ b/Scripts/Runtime/TMPro_UGUI_Private.cs @@ -52,18 +52,6 @@ public partial class TextMeshProUGUI [NonSerialized] private bool m_isRegisteredForEvents; - // DEBUG Variables - //private System.Diagnostics.Stopwatch m_StopWatch; - //private int frame = 0; - //private int loopCountB = 0; - //private int loopCountC = 0; - //private int loopCountD = 0; - //private int loopCountE = 0; - - //[SerializeField] - //private new Material m_MaskMaterial; - - protected override void Awake() { //Debug.Log("***** Awake() called on object ID " + GetInstanceID() + ". *****"); @@ -1581,7 +1569,6 @@ internal override void InternalUpdate() } - // Called just before the Canvas is rendered. void OnPreRenderCanvas() { @@ -1600,22 +1587,6 @@ void OnPreRenderCanvas() return; } - // Debug Variables - //loopCountB = 0; - //loopCountC = 0; - //loopCountD = 0; - //loopCountE = 0; - - // Update Margins - //ComputeMarginSize(); - - // Update Mask - // if (m_isMaskingEnabled) - // { - // UpdateMask(); - // } - - if (m_havePropertiesChanged || m_isLayoutDirty) { //Debug.Log("Properties have changed!"); // Assigned Material is:" + m_sharedMaterial); // New Text is: " + m_text + "."); @@ -2022,7 +1993,6 @@ protected override void GenerateTextMesh() Profiler.BeginSample("TMP - Lookup Character & Glyph Data"); #endif float baselineOffset = 0; - float spriteScale = 1; float elementAscentLine = 0; float elementDescentLine = 0; if (m_textElementType == TMP_TextElementType.Sprite) @@ -2043,7 +2013,7 @@ protected override void GenerateTextMesh() // The sprite scale calculations are based on the font asset assigned to the text object. if (m_currentSpriteAsset.m_FaceInfo.pointSize > 0) { - spriteScale = m_currentFontSize / m_currentSpriteAsset.m_FaceInfo.pointSize * m_currentSpriteAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); + float spriteScale = m_currentFontSize / m_currentSpriteAsset.m_FaceInfo.pointSize * m_currentSpriteAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); currentElementScale = sprite.m_Scale * sprite.m_Glyph.scale * spriteScale; elementAscentLine = m_currentSpriteAsset.m_FaceInfo.ascentLine; baselineOffset = m_currentSpriteAsset.m_FaceInfo.baseline * m_fontScale * m_fontScaleMultiplier * m_currentSpriteAsset.m_FaceInfo.scale; @@ -2051,7 +2021,7 @@ protected override void GenerateTextMesh() } else { - spriteScale = m_currentFontSize / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); + float spriteScale = m_currentFontSize / m_currentFontAsset.m_FaceInfo.pointSize * m_currentFontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); currentElementScale = m_currentFontAsset.m_FaceInfo.ascentLine / sprite.m_Glyph.metrics.height * sprite.m_Scale * sprite.m_Glyph.scale * spriteScale; elementAscentLine = m_currentFontAsset.m_FaceInfo.ascentLine; baselineOffset = m_currentFontAsset.m_FaceInfo.baseline * m_fontScale * m_fontScaleMultiplier * m_currentFontAsset.m_FaceInfo.scale; @@ -2061,7 +2031,7 @@ protected override void GenerateTextMesh() m_cached_TextElement = sprite; m_textInfo.characterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite; - m_textInfo.characterInfo[m_characterCount].scale = spriteScale; + m_textInfo.characterInfo[m_characterCount].scale = currentElementScale; m_textInfo.characterInfo[m_characterCount].spriteAsset = m_currentSpriteAsset; m_textInfo.characterInfo[m_characterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_characterCount].materialReferenceIndex = m_currentMaterialIndex; @@ -2326,12 +2296,12 @@ protected override void GenerateTextMesh() // Element Ascender in line space float elementAscender = m_textElementType == TMP_TextElementType.Character ? elementAscentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset - : elementAscentLine * spriteScale + m_baselineOffset; + : elementAscentLine * currentElementScale + m_baselineOffset; // Element Descender in line space float elementDescender = m_textElementType == TMP_TextElementType.Character ? elementDescentLine * currentElementScale / smallCapsMultiplier + m_baselineOffset - : elementDescentLine * spriteScale + m_baselineOffset; + : elementDescentLine * currentElementScale + m_baselineOffset; float adjustedAscender = elementAscender; float adjustedDescender = elementDescender; diff --git a/Scripts/Runtime/TextMeshProUGUI.cs b/Scripts/Runtime/TextMeshProUGUI.cs index c2746cb..748effa 100644 --- a/Scripts/Runtime/TextMeshProUGUI.cs +++ b/Scripts/Runtime/TextMeshProUGUI.cs @@ -368,10 +368,18 @@ public override void RecalculateMasking() /// public override void Cull(Rect clipRect, bool validRect) { - //Debug.Log("***** Cull (" + clipRect + ", " + validRect + ") Cull: " + m_canvasRenderer.cull + " *****"); if (m_canvas == null || m_canvas.rootCanvas == null) return; + // Delay culling check until the geometry of the text has been updated. + if (m_isLayoutDirty) + { + TMP_UpdateManager.RegisterTextElementForCullingUpdate(this); + m_ClipRect = clipRect; + m_ValidRect = validRect; + return; + } + // Get compound rect for the text object and sub text objects in local canvas space. Rect rect = GetCanvasSpaceClippingRect(); @@ -385,22 +393,44 @@ public override void Cull(Rect clipRect, bool validRect) m_canvasRenderer.cull = cull; onCullStateChanged.Invoke(cull); OnCullingChanged(); + + // Update any potential sub mesh objects + for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++) + { + m_subTextObjects[i].canvasRenderer.cull = cull; + } } } + private Rect m_ClipRect; + private bool m_ValidRect; - //protected override void UpdateGeometry() - //{ - // //Debug.Log("UpdateGeometry"); - // //base.UpdateGeometry(); - //} + /// + /// Internal function to allow delay of culling until the text geometry has been updated. + /// + internal override void UpdateCulling() + { + // Get compound rect for the text object and sub text objects in local canvas space. + Rect rect = GetCanvasSpaceClippingRect(); + // No point culling if geometry bounds have no width or height. + if (rect.width == 0 || rect.height == 0) + return; - //protected override void UpdateMaterial() - //{ - // //Debug.Log("UpdateMaterial called."); - //// base.UpdateMaterial(); - //} + var cull = !m_ValidRect || !m_ClipRect.Overlaps(rect, true); + if (m_canvasRenderer.cull != cull) + { + m_canvasRenderer.cull = cull; + onCullStateChanged.Invoke(cull); + OnCullingChanged(); + + // Update any potential sub mesh objects + for (int i = 1; i < m_subTextObjects.Length && m_subTextObjects[i] != null; i++) + { + m_subTextObjects[i].canvasRenderer.cull = cull; + } + } + } /* @@ -475,6 +505,9 @@ public override void UpdateMeshPadding() /// Should also Tween the alpha channel? protected override void InternalCrossFadeColor(Color targetColor, float duration, bool ignoreTimeScale, bool useAlpha) { + if (m_textInfo == null) + return; + int materialCount = m_textInfo.materialCount; for (int i = 1; i < materialCount; i++) @@ -492,6 +525,9 @@ protected override void InternalCrossFadeColor(Color targetColor, float duration /// Should ignore Time.scale? protected override void InternalCrossFadeAlpha(float alpha, float duration, bool ignoreTimeScale) { + if (m_textInfo == null) + return; + int materialCount = m_textInfo.materialCount; for (int i = 1; i < materialCount; i++) diff --git a/package.json b/package.json index 486c0cd..f070502 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.unity.textmeshpro", "displayName": "TextMeshPro", - "version": "1.5.0-preview.13", + "version": "1.5.0-preview.14", "unity": "2018.3", "description": "TextMeshPro 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, TextMeshPro (also known as TMP) 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\nTextMeshPro 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 TextMeshPro uses two triangles per character just like Unity's text components, this improved visual quality and flexibility comes at no additional performance cost.", "keywords": [ @@ -14,11 +14,11 @@ "category": "Text Rendering", "dependencies": {}, "repository": { - "type": "git", "url": "https://github.cds.internal.unity3d.com/unity/com.unity.textmeshpro.git", - "revision": "1448aa571d4c804e4ff3209ae469eacc9387338d" + "type": "git", + "revision": "33d2f0042a34f9db89f35197e8e417c18cb120e1" }, "upmCi": { - "footprint": "458dc7747e3560202d6adcfe1ff6fa55499baad8" + "footprint": "e8d09b75d309884f5686f494199068be73ceef62" } }