diff --git a/CHANGELOG.md b/CHANGELOG.md index 96833b4..fd3c911 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,28 @@ # 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.3] - 2019-12-16 +## [2.1.0-preview.3] +### Changes +- Fixed potential issue with TMP Dropdown where calling Show() and Hide() in very short interval could result in additional Blockers. Case #1194114 +- Fixed potential issues that could occur when upgrading to version 1.5.0-preview.2 or newer of the TMP package without also updating the TMP Essential Resources in the project. +- Added check and warning when trying to create a font asset whose source font file has "Incl. Font Data" disabled in the Font Import Settings. Case #1198587 and #1198112 +- Fixed Ellipsis overflow mode issue when using small caps. Case #1198392 +- Fixed potential layout issue when adding a Layout Group to the text object itself. Case #1197614 +- Fixed Font Asset Creator issue where too many adjustment records with adjustment value of zero were added to the font asset. +- Added support for Line Separator \u2028 and Paragraph Separator \u2029. +- TMP shaders have been moved from "TextMesh Pro/Resources/Shaders" folder to "TextMesh Pro/Shaders" folder. See the following [post](https://forum.unity.com/threads/version-1-5-0-2-1-0-preview-2-now-available-for-testing.753587/#post-5206853) for details. +- Added new experimental SDF and Mobile SDF Shaders that use Screen Space Derivatives (SSD) where these shaders no longer require SDF Scale to be passed via Vertex Attributes. These shaders have higher performance overhead but are more flexible. This overhead should only be noticeable on mobile platforms. +- Fixed potential text alignment issue where upgrading from package version 1.4.1 to 1.5.0-preview.2 would result in incorrect alignment on prefabs. Case #1198833 +- Added \u061C Arabic Letter Mark, \u200E Left-to-Right Mark and \u200F Right-to-Left Mark to list of control and non renderable characters. +- Fixed Missing Reference Exception that would appear when expanding the Extra Settings of a TextMeshPro Preset asset. Case #1201072 +- Fixed Missing Reference Exception that would appear when editing the Vertex Color or Color Gradient of a TMP component Preset asset. Case #1201069 +- Fixed Inspector layout issue preventing enabling or disabling the Outline, Underlay, Lighting and Glow features when selecting a Preset asset material. Case #1196963 +- Revised the Create Material Preset context menu option to issue a warning and ignore materials outside the project. Case #1200109 +- Added experimental ITextPreprocessor interface to allow users to create custom components to handle text preprocessing and shaping. This interface includes a PreprocessText(string text) function that is called when the object contains a component that inherits from this interface. +- Added support for Unity Presets in the Editor for both and components. Case #1191793 +- Optimization to ensure the TMP Update Manager only rebuilds text objects once per frame regardless of the number of cameras in the scene. + ## [1.5.0-preview.2] - 2019-10-30 ## [2.1.0-preview.2] ### Changes diff --git a/Package Resources/TMP Essential Resources.unitypackage b/Package Resources/TMP Essential Resources.unitypackage index 002d7e2..018af48 100644 Binary files a/Package Resources/TMP Essential Resources.unitypackage and b/Package Resources/TMP Essential Resources.unitypackage differ diff --git a/Package Resources/TMP Examples & Extras.unitypackage b/Package Resources/TMP Examples & Extras.unitypackage index 8d2c960..ea4bda2 100644 Binary files a/Package Resources/TMP Examples & Extras.unitypackage and b/Package Resources/TMP Examples & Extras.unitypackage differ diff --git a/Scripts/Editor/TMP_BaseEditorPanel.cs b/Scripts/Editor/TMP_BaseEditorPanel.cs index dc4d128..0c420c7 100644 --- a/Scripts/Editor/TMP_BaseEditorPanel.cs +++ b/Scripts/Editor/TMP_BaseEditorPanel.cs @@ -395,6 +395,8 @@ protected void DrawTextInput() Rect rect = EditorGUILayout.GetControlRect(false, 22); GUI.Label(rect, new GUIContent("Text Input"), TMP_UIStyleManager.sectionHeader); + EditorGUI.indentLevel = 0; + // If the text component is linked, disable the text input box. if (m_ParentLinkedTextComponentProp.objectReferenceValue != null) { @@ -425,7 +427,7 @@ protected void DrawTextInput() } } - // Toggle showing Rich Tags + // Toggle showing RTL mode float labelWidth = EditorGUIUtility.labelWidth; EditorGUIUtility.labelWidth = 110f; m_IsRightToLeftProp.boolValue = EditorGUI.Toggle(new Rect(rect.width - 120, rect.y + 3, 130, 20), k_RtlToggleLabel, m_IsRightToLeftProp.boolValue); diff --git a/Scripts/Editor/TMP_BaseShaderGUI.cs b/Scripts/Editor/TMP_BaseShaderGUI.cs index 112d277..a36a01c 100644 --- a/Scripts/Editor/TMP_BaseShaderGUI.cs +++ b/Scripts/Editor/TMP_BaseShaderGUI.cs @@ -176,8 +176,9 @@ public override void OnGUI(MaterialEditor materialEditor, MaterialProperty[] pro protected bool BeginPanel(string panel, bool expanded) { + EditorGUI.indentLevel = 0; + EditorGUILayout.BeginVertical(EditorStyles.helpBox); - Rect r = EditorGUI.IndentedRect(GUILayoutUtility.GetRect(20, 18)); r.x += 20; r.width += 6; @@ -197,6 +198,8 @@ protected bool BeginPanel(string panel, bool expanded) protected bool BeginPanel(string panel, ShaderFeature feature, bool expanded, bool readState = true) { + EditorGUI.indentLevel = 0; + if (readState) { feature.ReadState(m_Material); diff --git a/Scripts/Editor/TMP_FontAsset_CreationMenu.cs b/Scripts/Editor/TMP_FontAsset_CreationMenu.cs index 7d5edfa..344965c 100644 --- a/Scripts/Editor/TMP_FontAsset_CreationMenu.cs +++ b/Scripts/Editor/TMP_FontAsset_CreationMenu.cs @@ -161,15 +161,22 @@ public static void CreateFontAsset() string newAssetFilePathWithName = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + assetName + " SDF.asset"); - //// Create new TM Font Asset. + // Initialize FontEngine + FontEngine.InitializeFontEngine(); + + // Load Font Face + if (FontEngine.LoadFontFace(sourceFont, 90) != FontEngineError.Success) + { + Debug.LogWarning("Unable to load font face for [" + sourceFont.name + "]. Make sure \"Include Font Data\" is enabled in the Font Import Settings.", sourceFont); + return; + } + + // Create new Font Asset TMP_FontAsset fontAsset = ScriptableObject.CreateInstance(); AssetDatabase.CreateAsset(fontAsset, newAssetFilePathWithName); fontAsset.version = "1.1.0"; - // Set face information - FontEngine.InitializeFontEngine(); - FontEngine.LoadFontFace(sourceFont, 90); fontAsset.faceInfo = FontEngine.GetFaceInfo(); // Set font reference and GUID diff --git a/Scripts/Editor/TMP_PackageUtilities.cs b/Scripts/Editor/TMP_PackageUtilities.cs index 21ca101..d0bf164 100644 --- a/Scripts/Editor/TMP_PackageUtilities.cs +++ b/Scripts/Editor/TMP_PackageUtilities.cs @@ -39,7 +39,7 @@ class AssetConversionData public class TMP_ProjectConversionUtility : EditorWindow { - // Create Sprite Asset Editor Window + // Create Project Files GUID Remapping Tool window [MenuItem("Window/TextMeshPro/Project Files GUID Remapping Tool", false, 2100)] static void ShowConverterWindow() { @@ -461,6 +461,57 @@ private static bool CheckProjectSerializationAndSourceControlModes() } + /* + public class TMP_ShaderRemappingTool : EditorWindow + { + // Create Shader Reference Upgrade Tool window + [MenuItem("Window/TextMeshPro/Shader Reference Remapping Tool", false, 2110)] + static void ShowShaderUpgradeWindow() + { + var window = GetWindow(); + window.titleContent = new GUIContent("Shader Upgrade Tool"); + window.Focus(); + } + + private static string k_ProjectMaterialScanReportDefaultText = "Project Scan Results\n"; + private static string m_ProjectMaterialScanResults = string.Empty; + + + void OnEnable() + { + // Set Editor Window Size + SetEditorWindowSize(); + + m_ProjectMaterialScanResults = k_ProjectMaterialScanReportDefaultText; + } + + + private void OnGUI() + { + + } + + + void OnInspectorUpdate() + { + Repaint(); + } + + + /// + /// Limits the minimum size of the editor window. + /// + void SetEditorWindowSize() + { + EditorWindow editorWindow = this; + + Vector2 currentWindowSize = editorWindow.minSize; + + editorWindow.minSize = new Vector2(Mathf.Max(640, currentWindowSize.x), Mathf.Max(420, currentWindowSize.y)); + } + } + */ + public class TMP_PackageUtilities : Editor { diff --git a/Scripts/Editor/TMPro_ContextMenus.cs b/Scripts/Editor/TMPro_ContextMenus.cs index 42fce2f..21410f4 100644 --- a/Scripts/Editor/TMPro_ContextMenus.cs +++ b/Scripts/Editor/TMPro_ContextMenus.cs @@ -46,13 +46,18 @@ static void DuplicateMaterial(MenuCommand command) Material source_Mat = (Material)command.context; if (!EditorUtility.IsPersistent(source_Mat)) { - Debug.LogWarning("Material is an instance and cannot be converted into a permanent asset."); + Debug.LogWarning("Material is an instance and cannot be converted into a persistent asset."); return; } + string assetPath = AssetDatabase.GetAssetPath(source_Mat).Split('.')[0]; - string assetPath = AssetDatabase.GetAssetPath(source_Mat).Split('.')[0]; - + if (assetPath.IndexOf("Assets/", System.StringComparison.InvariantCultureIgnoreCase) == -1) + { + Debug.LogWarning("Material Preset cannot be created from a material that is located outside the project."); + return; + } + Material duplicate = new Material(source_Mat); // Need to manually copy the shader keywords @@ -93,7 +98,7 @@ static void DuplicateMaterial(MenuCommand command) } - //[MenuItem("CONTEXT/MaterialComponent/Copy Material Properties", false)] + // COPY MATERIAL PROPERTIES [MenuItem("CONTEXT/Material/Copy Material Properties", false)] static void CopyMaterialProperties(MenuCommand command) { @@ -118,7 +123,6 @@ static void CopyMaterialProperties(MenuCommand command) [MenuItem("CONTEXT/Material/Paste Material Properties", false)] static void PasteMaterialProperties(MenuCommand command) { - if (m_copiedProperties == null) { Debug.LogWarning("No Material Properties to Paste. Use Copy Material Properties first."); @@ -159,7 +163,6 @@ static void PasteMaterialProperties(MenuCommand command) [MenuItem("CONTEXT/Material/Reset", false, 2100)] static void ResetSettings(MenuCommand command) { - Material mat = null; if (command.context.GetType() == typeof(Material)) mat = (Material)command.context; @@ -221,7 +224,6 @@ static void ResetSettings(MenuCommand command) } - //This function is used for debugging and fixing potentially broken font atlas links. [MenuItem("CONTEXT/Material/Copy Atlas", false, 2000)] static void CopyAtlas(MenuCommand command) @@ -320,7 +322,7 @@ static void ForceFontAssetUpgrade(MenuCommand command) /// - /// Clear Font Asset Data + /// Clear Dynamic Font Asset data such as glyph, character and font features. /// /// [MenuItem("CONTEXT/TMP_FontAsset/Reset", false, 100)] diff --git a/Scripts/Editor/TMPro_CreateObjectMenu.cs b/Scripts/Editor/TMPro_CreateObjectMenu.cs index 358333e..dc197e0 100644 --- a/Scripts/Editor/TMPro_CreateObjectMenu.cs +++ b/Scripts/Editor/TMPro_CreateObjectMenu.cs @@ -1,5 +1,6 @@ using UnityEngine; using UnityEditor; +using UnityEditor.Presets; using UnityEditor.SceneManagement; using UnityEditor.Experimental.SceneManagement; using UnityEngine.SceneManagement; @@ -19,18 +20,34 @@ public static class TMPro_CreateObjectMenu [MenuItem("GameObject/3D Object/Text - TextMeshPro", false, 30)] static void CreateTextMeshProObjectPerform(MenuCommand command) { - GameObject go = new GameObject("Text (TMP)"); + GameObject go = ObjectFactory.CreateGameObject("Text (TMP)"); // Add support for new prefab mode StageUtility.PlaceGameObjectInCurrentStage(go); - TextMeshPro textMeshPro = go.AddComponent(); - textMeshPro.text = "Sample text"; - textMeshPro.alignment = TextAlignmentOptions.TopLeft; + TextMeshPro textComponent = ObjectFactory.AddComponent(go); - + if (textComponent.m_isWaitingOnResourceLoad == false) + { + // Apply TMP Settings Defaults if no Preset is defined + if (Preset.GetDefaultForObject(textComponent) == null) + { + textComponent.text = "Sample text"; + textComponent.alignment = TextAlignmentOptions.TopLeft; + } + + if (TMP_Settings.autoSizeTextContainer) + { + Vector2 size = textComponent.GetPreferredValues(TMP_Math.FLOAT_MAX, TMP_Math.FLOAT_MAX); + textComponent.rectTransform.sizeDelta = size; + } + else + { + textComponent.rectTransform.sizeDelta = TMP_Settings.defaultTextMeshProTextContainerSize; + } + } - Undo.RegisterCreatedObjectUndo((Object)go, "Create " + go.name); + Undo.RegisterCreatedObjectUndo(go, "Create " + go.name); GameObject contextObject = command.context as GameObject; if (contextObject != null) @@ -53,10 +70,28 @@ static void CreateTextMeshProGuiObjectPerform(MenuCommand menuCommand) GameObject go = TMP_DefaultControls.CreateText(GetStandardResources()); // Override text color and font size - TMP_Text textComponent = go.GetComponent(); - textComponent.color = Color.white; + TextMeshProUGUI textComponent = go.GetComponent(); + if (textComponent.m_isWaitingOnResourceLoad == false) - textComponent.fontSize = TMP_Settings.defaultFontSize; + { + // Apply TMP Settings Defaults if no Preset is defined + if (Preset.GetDefaultForObject(textComponent) == null) + { + textComponent.fontSize = TMP_Settings.defaultFontSize; + textComponent.color = Color.white; + textComponent.text = "New Text"; + } + + if (TMP_Settings.autoSizeTextContainer) + { + Vector2 size = textComponent.GetPreferredValues(TMP_Math.FLOAT_MAX, TMP_Math.FLOAT_MAX); + textComponent.rectTransform.sizeDelta = size; + } + else + { + textComponent.rectTransform.sizeDelta = TMP_Settings.defaultTextMeshProUITextContainerSize; + } + } PlaceUIElementRoot(go, menuCommand); } diff --git a/Scripts/Editor/TMPro_FontAssetCreatorWindow.cs b/Scripts/Editor/TMPro_FontAssetCreatorWindow.cs index 7b7c54a..60e16be 100644 --- a/Scripts/Editor/TMPro_FontAssetCreatorWindow.cs +++ b/Scripts/Editor/TMPro_FontAssetCreatorWindow.cs @@ -1769,7 +1769,7 @@ public TMP_FontFeatureTable GetKerningTable() TMP_FontFeatureTable fontFeatureTable = new TMP_FontFeatureTable(); - for (int i = 0; i < adjustmentRecords.Length; i++) + for (int i = 0; i < adjustmentRecords.Length && adjustmentRecords[i].firstAdjustmentRecord.glyphIndex != 0; i++) { fontFeatureTable.glyphPairAdjustmentRecords.Add(new TMP_GlyphPairAdjustmentRecord(adjustmentRecords[i])); } diff --git a/Scripts/Runtime/ITextPreProcessor.cs b/Scripts/Runtime/ITextPreProcessor.cs new file mode 100644 index 0000000..5d3f57a --- /dev/null +++ b/Scripts/Runtime/ITextPreProcessor.cs @@ -0,0 +1,17 @@ + + +namespace TMPro +{ + /// + /// Interface used for preprocessing and shaping of text. + /// + public interface ITextPreprocessor + { + /// + /// Function used for preprocessing of text + /// + /// Source text to be processed + /// Processed text + string PreprocessText(string text); + } +} diff --git a/Scripts/Runtime/ITextPreProcessor.cs.meta b/Scripts/Runtime/ITextPreProcessor.cs.meta new file mode 100644 index 0000000..8dd7083 --- /dev/null +++ b/Scripts/Runtime/ITextPreProcessor.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: afc31ad767318c9488de260c166cd21d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Runtime/TMP_DefaultControls.cs b/Scripts/Runtime/TMP_DefaultControls.cs index 6d2b057..45eac33 100644 --- a/Scripts/Runtime/TMP_DefaultControls.cs +++ b/Scripts/Runtime/TMP_DefaultControls.cs @@ -2,6 +2,10 @@ using System.Collections; using UnityEngine.UI; +#if UNITY_EDITOR +using UnityEditor; +#endif + namespace TMPro { @@ -148,11 +152,19 @@ public static GameObject CreateButton(Resources resources) public static GameObject CreateText(Resources resources) { - GameObject go = CreateUIElementRoot("Text (TMP)", s_TextElementSize); - - TextMeshProUGUI lbl = go.AddComponent(); - lbl.text = "New Text"; - SetDefaultTextValues(lbl); + GameObject go = null; + #if UNITY_EDITOR + go = ObjectFactory.CreateGameObject("Text (TMP)"); + #else + go = CreateUIElementRoot("Text (TMP)", s_TextElementSize); + #endif + + TextMeshProUGUI textComponent = null; + #if UNITY_EDITOR + textComponent = ObjectFactory.AddComponent(go); + #else + textComponent = go.AddComponent(); + #endif return go; } diff --git a/Scripts/Runtime/TMP_Dropdown.cs b/Scripts/Runtime/TMP_Dropdown.cs index 1841d32..31efaa7 100644 --- a/Scripts/Runtime/TMP_Dropdown.cs +++ b/Scripts/Runtime/TMP_Dropdown.cs @@ -348,6 +348,7 @@ public List options private List m_Items = new List(); private TweenRunner m_AlphaTweenRunner; private bool validTemplate = false; + private Coroutine m_Coroutine = null; private static OptionData s_NoOptionData = new OptionData(); @@ -739,6 +740,12 @@ public virtual void OnCancel(BaseEventData eventData) /// public void Show() { + if (m_Coroutine != null) + { + StopCoroutine(m_Coroutine); + ImmediateDestroyDropdownList(); + } + if (!IsActive() || !IsInteractable() || m_Dropdown != null) return; @@ -1079,20 +1086,23 @@ private void SetAlpha(float alpha) /// public void Hide() { - if (m_Dropdown != null) + if (m_Coroutine == null) { - AlphaFadeList(m_AlphaFadeSpeed, 0f); + if (m_Dropdown != null) + { + AlphaFadeList(m_AlphaFadeSpeed, 0f); - // User could have disabled the dropdown during the OnValueChanged call. - if (IsActive()) - StartCoroutine(DelayedDestroyDropdownList(m_AlphaFadeSpeed)); - } + // User could have disabled the dropdown during the OnValueChanged call. + if (IsActive()) + m_Coroutine = StartCoroutine(DelayedDestroyDropdownList(m_AlphaFadeSpeed)); + } - if (m_Blocker != null) - DestroyBlocker(m_Blocker); + if (m_Blocker != null) + DestroyBlocker(m_Blocker); - m_Blocker = null; - Select(); + m_Blocker = null; + Select(); + } } private IEnumerator DelayedDestroyDropdownList(float delay) @@ -1114,7 +1124,11 @@ private void ImmediateDestroyDropdownList() if (m_Dropdown != null) DestroyDropdownList(m_Dropdown); + if (m_AlphaTweenRunner != null) + m_AlphaTweenRunner.StopTween(); + m_Dropdown = null; + m_Coroutine = null; } // Change the value and hide the dropdown. diff --git a/Scripts/Runtime/TMP_FontAsset.cs b/Scripts/Runtime/TMP_FontAsset.cs index 07740a6..c1710f3 100644 --- a/Scripts/Runtime/TMP_FontAsset.cs +++ b/Scripts/Runtime/TMP_FontAsset.cs @@ -427,14 +427,20 @@ public static TMP_FontAsset CreateFontAsset(Font font) /// public static TMP_FontAsset CreateFontAsset(Font font, 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(font, 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"; - - // Set face information - FontEngine.InitializeFontEngine(); - FontEngine.LoadFontFace(font, samplingPointSize); - fontAsset.faceInfo = FontEngine.GetFaceInfo(); // Set font reference and GUID @@ -646,6 +652,13 @@ public void ReadFontAssetDefinition() m_CharacterLookupDictionary.Add(3, new TMP_Character(3, glyph)); } + // Add Arabic Letter Mark (0x061C) + if (m_CharacterLookupDictionary.ContainsKey(0x061C) == false) + { + Glyph glyph = new Glyph(0, new GlyphMetrics(0, 0, 0, 0, 0), GlyphRect.zero, 1.0f, 0); + m_CharacterLookupDictionary.Add(0x061C, new TMP_Character(0x061C, glyph)); + } + // Add Zero Width Space 8203 (0x200B) if (m_CharacterLookupDictionary.ContainsKey(8203) == false) { @@ -653,6 +666,35 @@ public void ReadFontAssetDefinition() m_CharacterLookupDictionary.Add(8203, new TMP_Character(8203, glyph)); } + // Add Left-To-Right Mark (0x200E) + if (m_CharacterLookupDictionary.ContainsKey(0x200E) == false) + { + Glyph glyph = new Glyph(0, new GlyphMetrics(0, 0, 0, 0, 0), GlyphRect.zero, 1.0f, 0); + m_CharacterLookupDictionary.Add(0x200E, new TMP_Character(0x200E, glyph)); + } + + // Add Right-To-Left Mark (0x200F) + if (m_CharacterLookupDictionary.ContainsKey(0x200F) == false) + { + Glyph glyph = new Glyph(0, new GlyphMetrics(0, 0, 0, 0, 0), GlyphRect.zero, 1.0f, 0); + m_CharacterLookupDictionary.Add(0x200F, new TMP_Character(0x200F, glyph)); + } + + // Add Line Separator 0x2028 + if (m_CharacterLookupDictionary.ContainsKey(0x2028) == false) + { + Glyph glyph = new Glyph(0, new GlyphMetrics(0, 0, 0, 0, 0), GlyphRect.zero, 1.0f, 0); + m_CharacterLookupDictionary.Add(0x2028, new TMP_Character(0x2028, glyph)); + } + + // Add Line Separator 0x2029 + if (m_CharacterLookupDictionary.ContainsKey(0x2029) == false) + { + Glyph glyph = new Glyph(0, new GlyphMetrics(0, 0, 0, 0, 0), GlyphRect.zero, 1.0f, 0); + m_CharacterLookupDictionary.Add(0x2029, new TMP_Character(0x2029, glyph)); + } + + // Add Zero Width Non-Breaking Space 8288 (0x2060) if (m_CharacterLookupDictionary.ContainsKey(8288) == false) { diff --git a/Scripts/Runtime/TMP_SubMesh.cs b/Scripts/Runtime/TMP_SubMesh.cs index f7a3235..a0b2b81 100644 --- a/Scripts/Runtime/TMP_SubMesh.cs +++ b/Scripts/Runtime/TMP_SubMesh.cs @@ -311,8 +311,14 @@ void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat) int fallbackSourceMaterialID = m_fallbackSourceMaterial == null ? 0 : m_fallbackSourceMaterial.GetInstanceID(); // Sync culling with parent text object - float cullMode = textComponent.fontSharedMaterial.GetFloat(ShaderUtilities.ShaderTag_CullMode); - m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + bool hasCullModeProperty = m_sharedMaterial.HasProperty(ShaderUtilities.ShaderTag_CullMode); + float cullMode = 0; + + if (hasCullModeProperty) + { + cullMode = textComponent.fontSharedMaterial.GetFloat(ShaderUtilities.ShaderTag_CullMode); + m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + } // Filter events and return if the affected material is not this object's material. if (targetMaterialID != sharedMaterialID) @@ -323,7 +329,8 @@ void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat) TMP_MaterialManager.CopyMaterialPresetProperties(mat, m_fallbackMaterial); // Re-sync culling with parent text object - m_fallbackMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + if (hasCullModeProperty) + m_fallbackMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); } else return; @@ -573,16 +580,16 @@ protected void UpdateMaterial() { //Debug.Log("*** STO - UpdateMaterial() *** FRAME (" + Time.frameCount + ")"); - if (m_renderer == null) m_renderer = this.renderer; + if (renderer == null || m_sharedMaterial == null) return; m_renderer.sharedMaterial = m_sharedMaterial; - if (m_sharedMaterial == null) - return; - // Special handling to keep the Culling of the material in sync with parent text object - float cullMode = textComponent.fontSharedMaterial.GetFloat(ShaderUtilities.ShaderTag_CullMode); - m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + if (m_sharedMaterial.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + float cullMode = textComponent.fontSharedMaterial.GetFloat(ShaderUtilities.ShaderTag_CullMode); + m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + } #if UNITY_EDITOR if (m_sharedMaterial != null && gameObject.name != "TMP SubMesh [" + m_sharedMaterial.name + "]") diff --git a/Scripts/Runtime/TMP_SubMeshUI.cs b/Scripts/Runtime/TMP_SubMeshUI.cs index c45c747..f46ad9d 100644 --- a/Scripts/Runtime/TMP_SubMeshUI.cs +++ b/Scripts/Runtime/TMP_SubMeshUI.cs @@ -44,7 +44,6 @@ public override Texture mainTexture if (this.sharedMaterial != null) return this.sharedMaterial.GetTexture(ShaderUtilities.ID_MainTex); - return null; } } @@ -221,6 +220,9 @@ public static TMP_SubMeshUI AddSubTextObject(TextMeshProUGUI textComponent, Mate rectTransform.sizeDelta = Vector2.zero; rectTransform.pivot = textComponent.rectTransform.pivot; + LayoutElement layoutElement = go.AddComponent(); + layoutElement.ignoreLayout = true; + TMP_SubMeshUI subMesh = go.AddComponent(); //subMesh.canvasRenderer = subMesh.canvasRenderer; @@ -344,8 +346,14 @@ void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat) int fallbackSourceMaterialID = m_fallbackSourceMaterial == null ? 0 : m_fallbackSourceMaterial.GetInstanceID(); // Sync culling with parent text object - float cullMode = textComponent.fontSharedMaterial.GetFloat(ShaderUtilities.ShaderTag_CullMode); - m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + bool hasCullModeProperty = m_sharedMaterial.HasProperty(ShaderUtilities.ShaderTag_CullMode); + float cullMode = 0; + + if (hasCullModeProperty) + { + cullMode = textComponent.fontSharedMaterial.GetFloat(ShaderUtilities.ShaderTag_CullMode); + m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + } // Filter events and return if the affected material is not this object's material. if (m_fallbackMaterial != null && fallbackSourceMaterialID == targetMaterialID && TMP_Settings.matchMaterialPreset) @@ -395,7 +403,8 @@ void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat) } // Re-sync culling with parent text object - m_MaskMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + if (hasCullModeProperty) + m_MaskMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); } m_padding = GetPaddingForMaterial(); @@ -688,8 +697,11 @@ protected override void UpdateMaterial() //if (canvasRenderer == null) m_canvasRenderer = this.canvasRenderer; // Special handling to keep the Culling of the material in sync with parent text object - float cullMode = textComponent.fontSharedMaterial.GetFloat(ShaderUtilities.ShaderTag_CullMode); - m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + if (m_sharedMaterial.HasProperty(ShaderUtilities.ShaderTag_CullMode)) + { + float cullMode = textComponent.fontSharedMaterial.GetFloat(ShaderUtilities.ShaderTag_CullMode); + m_sharedMaterial.SetFloat(ShaderUtilities.ShaderTag_CullMode, cullMode); + } canvasRenderer.materialCount = 1; canvasRenderer.SetMaterial(materialForRendering, 0); diff --git a/Scripts/Runtime/TMP_Text.cs b/Scripts/Runtime/TMP_Text.cs index 349078f..9180168 100644 --- a/Scripts/Runtime/TMP_Text.cs +++ b/Scripts/Runtime/TMP_Text.cs @@ -131,7 +131,12 @@ public virtual string text [SerializeField] [TextArea(5, 10)] protected string m_text; - + + /// + /// Reference to potential text preprocessor component. + /// + [SerializeField] + protected ITextPreprocessor m_TextPreProcessor; /// /// @@ -1418,9 +1423,6 @@ protected LayoutElement layoutElement protected bool m_isCalculateSizeRequired = false; protected bool m_isLayoutDirty; - protected bool m_verticesAlreadyDirty; - protected bool m_layoutAlreadyDirty; - protected bool m_isAwake; internal bool m_isWaitingOnResourceLoad; @@ -1846,7 +1848,10 @@ protected void ParseInputText() { case TextInputSources.String: case TextInputSources.Text: - StringToCharArray(m_text, ref m_TextParsingBuffer); + if (m_TextPreProcessor != null) + StringToCharArray(m_TextPreProcessor.PreprocessText(m_text), ref m_TextParsingBuffer); + else + StringToCharArray(m_text, ref m_TextParsingBuffer); break; case TextInputSources.SetText: SetTextArrayToCharArray(m_input_CharArray, ref m_TextParsingBuffer); @@ -4505,7 +4510,7 @@ protected float GetPreferredWidth() } m_AutoSizeIterationCount = 0; - float preferredWidth = CalculatePreferredValues(fontSize, margin, true).x; + float preferredWidth = CalculatePreferredValues(fontSize, margin, true, false).x; m_isPreferredWidthDirty = false; @@ -4530,7 +4535,7 @@ protected float GetPreferredWidth(Vector2 margin) m_charWidthAdjDelta = 0; m_AutoSizeIterationCount = 0; - float preferredWidth = CalculatePreferredValues(fontSize, margin, true).x; + float preferredWidth = CalculatePreferredValues(fontSize, margin, true, false).x; //Debug.Log("GetPreferredWidth() Called. Returning width of " + preferredWidth); @@ -4562,7 +4567,7 @@ protected float GetPreferredHeight() } m_AutoSizeIterationCount = 0; - float preferredHeight = CalculatePreferredValues(fontSize, margin, !m_enableAutoSizing).y; + float preferredHeight = CalculatePreferredValues(fontSize, margin, !m_enableAutoSizing, true).y; m_isPreferredHeightDirty = false; @@ -4587,7 +4592,7 @@ protected float GetPreferredHeight(Vector2 margin) m_charWidthAdjDelta = 0; m_AutoSizeIterationCount = 0; - float preferredHeight = CalculatePreferredValues(fontSize, margin, true).y; + float preferredHeight = CalculatePreferredValues(fontSize, margin, true, true).y; //Debug.Log("GetPreferredHeight() Called. Returning height of " + preferredHeight); @@ -4656,7 +4661,7 @@ protected float GetRenderedHeight(bool onlyVisibleCharacters) /// Method to calculate the preferred width and height of the text object. /// /// - protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector2 marginSize, bool ignoreTextAutoSizing) + protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector2 marginSize, bool ignoreTextAutoSizing, bool isWordWrappingEnabled) { //Debug.Log("*** CalculatePreferredValues() ***"); // ***** Frame: " + Time.frameCount); @@ -5128,7 +5133,7 @@ protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector if (textWidth > widthOfTextArea * (isJustifiedOrFlush ? 1.05f : 1.0f)) { // Handle Line Breaking (if still possible) - if (m_enableWordWrapping && m_characterCount != m_firstCharacterOfLine) // && isFirstWord == false) + if (isWordWrappingEnabled && m_characterCount != m_firstCharacterOfLine) // && isFirstWord == false) { // Restore state to previous safe line breaking i = RestoreWordWrappingState(ref internalWordWrapState); @@ -5174,7 +5179,7 @@ protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector // Compute Preferred Width & Height renderedWidth += m_xAdvance; - if (m_enableWordWrapping) + if (isWordWrappingEnabled) renderedHeight = m_maxAscender - m_maxDescender; else renderedHeight = Mathf.Max(renderedHeight, lineAscender - lineDescender); @@ -5269,7 +5274,7 @@ protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector // Handle Line Spacing Adjustments + Word Wrapping & special case for last line. #region Check for Line Feed and Last Character - if (charCode == 10 || charCode == 11 || charCode == 0x03 || m_characterCount == totalCharacterCount - 1) + if (charCode == 10 || charCode == 11 || charCode == 0x03 || charCode == 0x2028 || charCode == 0x2029 || m_characterCount == totalCharacterCount - 1) { // Check if Line Spacing of previous line needs to be adjusted. if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && isDrivenLineSpacing == false && !m_isNewPage && isInjectingCharacter == false) @@ -5298,7 +5303,7 @@ protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector renderedHeight = m_maxAscender - m_maxDescender; // Add new line if not last lines or character. - if (charCode == 10 || charCode == 11 || charCode == 0x2D) + if (charCode == 10 || charCode == 11 || charCode == 0x2D || charCode == 0x2028 || charCode == 0x2029) { // Store the state of the line before starting on the new line. SaveWordWrappingState(ref internalLineState, i, m_characterCount); @@ -5311,13 +5316,13 @@ protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector // Apply Line Spacing with special handling for VT char(11) if (m_lineHeight == TMP_Math.FLOAT_UNSET) { - float lineOffsetDelta = 0 - m_maxLineDescender + elementAscender + (lineGap + m_lineSpacingDelta) * baseScale + (m_lineSpacing + (charCode == 10 ? m_paragraphSpacing : 0)) * currentEmScale; + float lineOffsetDelta = 0 - m_maxLineDescender + elementAscender + (lineGap + m_lineSpacingDelta) * baseScale + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale; m_lineOffset += lineOffsetDelta; isDrivenLineSpacing = false; } else { - m_lineOffset += m_lineHeight + (m_lineSpacing + (charCode == 10 ? m_paragraphSpacing : 0)) * currentEmScale; + m_lineOffset += m_lineHeight + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale; isDrivenLineSpacing = true; } @@ -5340,7 +5345,7 @@ protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector // Save State of Mesh Creation for handling of Word Wrapping #region Save Word Wrapping State - if (m_enableWordWrapping || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis) + if (isWordWrappingEnabled || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis) { if ((char.IsWhiteSpace((char)charCode) || charCode == 0x200B || charCode == 0x2D || charCode == 0xAD) && !m_isNonBreakingSpace && charCode != 0xA0 && charCode != 0x2007 && charCode != 0x2011 && charCode != 0x202F && charCode != 0x2060) { @@ -6088,9 +6093,9 @@ protected virtual void FillCharacterVertexBuffers(int i, int index_X4) int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex; index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount; - // Make sure buffers allocation are sufficient to hold the vertex data - //if (m_textInfo.meshInfo[materialIndex].vertices.Length < index_X4 + 4) - // m_textInfo.meshInfo[materialIndex].ResizeMeshInfo(Mathf.NextPowerOfTwo(index_X4 + 4)); + // Check to make sure our current mesh buffer allocations can hold these new Quads. + if (index_X4 >= m_textInfo.meshInfo[materialIndex].vertices.Length) + m_textInfo.meshInfo[materialIndex].ResizeMeshInfo(Mathf.NextPowerOfTwo((index_X4 + 4) / 4)); TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo; @@ -6139,6 +6144,10 @@ protected virtual void FillCharacterVertexBuffers(int i, int index_X4, bool isVo int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex; index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount; + // Check to make sure our current mesh buffer allocations can hold these new Quads. + if (index_X4 >= m_textInfo.meshInfo[materialIndex].vertices.Length) + m_textInfo.meshInfo[materialIndex].ResizeMeshInfo(Mathf.NextPowerOfTwo((index_X4 + (isVolumetric ? 8 : 4)) / 4)); + TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo; m_textInfo.characterInfo[i].vertexIndex = index_X4; @@ -6223,6 +6232,10 @@ protected virtual void FillSpriteVertexBuffers(int i, int index_X4) int materialIndex = m_textInfo.characterInfo[i].materialReferenceIndex; index_X4 = m_textInfo.meshInfo[materialIndex].vertexCount; + // Check to make sure our current mesh buffer allocations can hold these new Quads. + if (index_X4 >= m_textInfo.meshInfo[materialIndex].vertices.Length) + m_textInfo.meshInfo[materialIndex].ResizeMeshInfo(Mathf.NextPowerOfTwo((index_X4 + 4) / 4)); + TMP_CharacterInfo[] characterInfoArray = m_textInfo.characterInfo; m_textInfo.characterInfo[i].vertexIndex = index_X4; @@ -6509,7 +6522,9 @@ protected void LoadDefaultSettings() m_rectTransform = this.rectTransform; if (TMP_Settings.autoSizeTextContainer) + { autoSizeTextContainer = true; + } else { if (GetType() == typeof(TextMeshPro)) diff --git a/Scripts/Runtime/TMP_UpdateManager.cs b/Scripts/Runtime/TMP_UpdateManager.cs index 2b77411..ce41ba0 100644 --- a/Scripts/Runtime/TMP_UpdateManager.cs +++ b/Scripts/Runtime/TMP_UpdateManager.cs @@ -25,8 +25,7 @@ public class TMP_UpdateManager private readonly List m_InternalUpdateQueue = new List(); private HashSet m_InternalUpdateLookup = new HashSet(); - //private bool m_PerformingGraphicRebuild; - //private bool m_PerformingLayoutRebuild; + private int m_LastFrame = 0; /// /// Get a singleton instance of the registry @@ -136,12 +135,15 @@ void OnBeginFrameRendering(ScriptableRenderContext renderContext, Camera[] camer void OnBeginFrameRendering(Camera[] cameras) #endif { - // Exclude the PreRenderCamera - #if UNITY_EDITOR - if (cameras.Length == 1 && cameras[0].cameraType == CameraType.Preview) - return; - #endif - DoRebuilds(); + int currentFrame = Time.frameCount; + + // Make sure we only rebuild text objects once per frame regardless of number of cameras in the scene. + if (currentFrame < 2 || currentFrame != m_LastFrame) + { + DoRebuilds(); + + m_LastFrame = currentFrame; + } } /// @@ -150,14 +152,19 @@ void OnBeginFrameRendering(Camera[] cameras) /// void OnCameraPreCull(Camera cam) { - // Exclude the PreRenderCamera - #if UNITY_EDITOR - if (cam.cameraType == CameraType.Preview) - return; - #endif - DoRebuilds(); + int currentFrame = Time.frameCount; + + // Make sure we only rebuild text objects once per frame regardless of number of cameras in the scene. + if (currentFrame < 2 || currentFrame != m_LastFrame) + { + DoRebuilds(); + + m_LastFrame = currentFrame; + //Debug.Log("Updating text objects at frame:" + m_LastFrame); + } } - + + /// /// Process the rebuild requests in the rebuild queues. /// @@ -235,4 +242,4 @@ private void InternalUnRegisterTextObjectForUpdate(TMP_Text textObject) m_InternalUpdateLookup.Remove(id); } } -} \ No newline at end of file +} diff --git a/Scripts/Runtime/TMP_UpdateRegistery.cs b/Scripts/Runtime/TMP_UpdateRegistery.cs index dc1686b..7b66891 100644 --- a/Scripts/Runtime/TMP_UpdateRegistery.cs +++ b/Scripts/Runtime/TMP_UpdateRegistery.cs @@ -141,7 +141,6 @@ private void PerformUpdateForCanvasRendererObjects() private void PerformUpdateForMeshRendererObjects() { Debug.Log("Perform update of MeshRenderer objects."); - } diff --git a/Scripts/Runtime/TMPro_Private.cs b/Scripts/Runtime/TMPro_Private.cs index f2b099d..f2d64dc 100644 --- a/Scripts/Runtime/TMPro_Private.cs +++ b/Scripts/Runtime/TMPro_Private.cs @@ -1,4 +1,4 @@ -//#define TMP_PROFILE_ON +//#define TMP_PROFILE_ON using UnityEngine; @@ -169,6 +169,9 @@ protected override void OnEnable() m_isRegisteredForEvents = true; } + // Get reference to potential ITextPreprocessor components + m_TextPreProcessor = GetComponent(); + // Register text object for internal updates if (m_IsTextObjectScaleStatic == false) TMP_UpdateManager.RegisterTextObjectForUpdate(this); @@ -179,8 +182,6 @@ protected override void OnEnable() // Schedule potential text object update (if any of the properties have changed. ComputeMarginSize(); - m_verticesAlreadyDirty = false; - m_layoutAlreadyDirty = false; m_isInputParsingRequired = true; SetAllDirty(); @@ -254,6 +255,14 @@ protected override void OnValidate() { //Debug.Log("***** OnValidate() called on object ID " + GetInstanceID() + ". *****", this); + // Convert text alignment to independent horizontal and vertical alignment properties + if (m_textAlignment != TextAlignmentOptions.Converted) + { + m_HorizontalAlignment = (HorizontalAlignmentOptions)((int)m_textAlignment & 0xFF); + m_VerticalAlignment = (VerticalAlignmentOptions)((int)m_textAlignment & 0xFF00); + m_textAlignment = TextAlignmentOptions.Converted; + } + if (m_isAwake == false) return; @@ -353,6 +362,7 @@ void ON_MATERIAL_PROPERTY_CHANGED(bool isChanged, Material mat) UpdateMask(); UpdateEnvMapMatrix(); m_havePropertiesChanged = true; + SetVerticesDirty(); } @@ -385,6 +395,7 @@ void ON_TEXTMESHPRO_PROPERTY_CHANGED(bool isChanged, TextMeshPro obj) m_padding = GetPaddingForMaterial(); ComputeMarginSize(); // Verify this change + SetVerticesDirty(); } } @@ -409,6 +420,7 @@ void ON_DRAG_AND_DROP_MATERIAL(GameObject obj, Material currentMaterial, Materia m_padding = GetPaddingForMaterial(); m_havePropertiesChanged = true; + SetVerticesDirty(); SetMaterialDirty(); } @@ -420,6 +432,7 @@ void ON_TEXT_STYLE_CHANGED(bool isChanged) { m_havePropertiesChanged = true; m_isInputParsingRequired = true; + SetVerticesDirty(); } @@ -431,6 +444,7 @@ void ON_TEXT_STYLE_CHANGED(bool isChanged) void ON_COLOR_GRADIENT_CHANGED(TMP_ColorGradient gradient) { m_havePropertiesChanged = true; + SetVerticesDirty(); } @@ -443,6 +457,7 @@ void ON_TMP_SETTINGS_CHANGED() m_defaultSpriteAsset = null; m_havePropertiesChanged = true; m_isInputParsingRequired = true; + SetAllDirty(); } #endif @@ -1501,7 +1516,7 @@ internal override void InternalUpdate() /// void OnPreRenderObject() { - //Debug.Log("*** OnPreRenderObject() ***"); + //Debug.Log("*** OnPreRenderObject() called on object [" + this.name + "] ***"); if (!m_isAwake || (this.IsActive() == false && m_ignoreActiveState == false)) return; @@ -2905,7 +2920,7 @@ protected override void GenerateTextMesh() // This is white spacing / non visible characters. // Track # of spaces per line which is used for line justification. - if ((charCode == 10 || charCode == 11 || char.IsSeparator((char)charCode)) && charCode != 0xAD && charCode != 0x200B && charCode != 0x2060) + if ((charCode == 10 || charCode == 11 || charCode == 0x2028 || charCode == 0x2029 || char.IsSeparator((char)charCode)) && charCode != 0xAD && charCode != 0x200B && charCode != 0x2060) { m_textInfo.lineInfo[m_lineNumber].spaceCount += 1; m_textInfo.spaceCount += 1; @@ -2946,7 +2961,7 @@ protected override void GenerateTextMesh() #region Track Potential Insertion Location for Ellipsis if (m_overflowMode == TextOverflowModes.Ellipsis && isInjectingCharacter == false) { - float fontScale = m_currentFontSize * smallCapsMultiplier / m_fontAsset.m_FaceInfo.pointSize * m_fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); + float fontScale = m_currentFontSize / m_fontAsset.m_FaceInfo.pointSize * m_fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); float scale = fontScale * m_fontScaleMultiplier * m_cached_Ellipsis_Character.m_Scale * m_cached_Ellipsis_Character.m_Glyph.scale; float marginLeft = m_marginLeft; float marginRight = m_marginRight; @@ -2959,7 +2974,7 @@ protected override void GenerateTextMesh() marginRight = m_textInfo.lineInfo[m_lineNumber].marginRight; } - float descender = m_fontAsset.m_FaceInfo.descentLine * scale / smallCapsMultiplier + m_baselineOffset; + float descender = (m_fontAsset.m_FaceInfo.descentLine * scale) + m_baselineOffset; float textHeight = m_maxAscender - (descender - m_lineOffset); float textWidth = Mathf.Abs(m_xAdvance) + (!m_isRightToLeft ? m_cached_Ellipsis_Character.m_Glyph.metrics.horizontalAdvance : 0) * (1 - m_charWidthAdjDelta) * scale; @@ -3041,7 +3056,7 @@ protected override void GenerateTextMesh() // Handle Line Spacing Adjustments + Word Wrapping & special case for last line. #region Check for Line Feed and Last Character - if (charCode == 10 || charCode == 11 || charCode == 0x03 || (charCode == 0x2D && isInjectingCharacter) || m_characterCount == totalCharacterCount - 1) + if (charCode == 10 || charCode == 11 || charCode == 0x03 || charCode == 0x2028 || charCode == 0x2029 || (charCode == 0x2D && isInjectingCharacter) || m_characterCount == totalCharacterCount - 1) { #if TMP_PROFILE_ON Profiler.BeginSample("TMP - Handle Line & Text Termination"); @@ -3097,7 +3112,7 @@ protected override void GenerateTextMesh() m_textInfo.lineInfo[m_lineNumber].lineHeight = lineAscender - lineDescender + lineGap * baseScale; // Add new line if not last line or character. - if (charCode == 10 || charCode == 11 || charCode == 0x2D) + if (charCode == 10 || charCode == 11 || charCode == 0x2D || charCode == 0x2028 || charCode == 0x2029) { // Store the state of the line before starting on the new line. SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount); @@ -3119,13 +3134,13 @@ protected override void GenerateTextMesh() // Apply Line Spacing with special handling for VT char(11) if (m_lineHeight == TMP_Math.FLOAT_UNSET) { - float lineOffsetDelta = 0 - m_maxLineDescender + lastVisibleAscender + (lineGap + m_lineSpacingDelta) * baseScale + (m_lineSpacing + (charCode == 10 ? m_paragraphSpacing : 0)) * currentEmScale; + float lineOffsetDelta = 0 - m_maxLineDescender + lastVisibleAscender + (lineGap + m_lineSpacingDelta) * baseScale + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale; m_lineOffset += lineOffsetDelta; isDrivenLineSpacing = false; } else { - m_lineOffset += m_lineHeight + (m_lineSpacing + (charCode == 10 ? m_paragraphSpacing : 0)) * currentEmScale; + m_lineOffset += m_lineHeight + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale; isDrivenLineSpacing = true; } @@ -3180,7 +3195,7 @@ protected override void GenerateTextMesh() // Save pageInfo Data - if (m_overflowMode == TextOverflowModes.Page && charCode != 10 && charCode != 11 && charCode != 13) // && m_pageNumber < 16) + if (m_overflowMode == TextOverflowModes.Page && charCode != 10 && charCode != 11 && charCode != 13 && charCode != 0x2028 && charCode != 0x2029) // && m_pageNumber < 16) { // Check if we need to increase allocations for the pageInfo array. if (m_pageNumber + 1 > m_textInfo.pageInfo.Length) @@ -4386,4 +4401,4 @@ void UpdateSDFScale(float scaleDelta) } } -} \ No newline at end of file +} diff --git a/Scripts/Runtime/TMPro_UGUI_Private.cs b/Scripts/Runtime/TMPro_UGUI_Private.cs index 7bc1c63..6e1f58b 100644 --- a/Scripts/Runtime/TMPro_UGUI_Private.cs +++ b/Scripts/Runtime/TMPro_UGUI_Private.cs @@ -1,4 +1,4 @@ -//#define TMP_PROFILE_ON +//#define TMP_PROFILE_ON using UnityEngine; @@ -126,6 +126,9 @@ protected override void Awake() m_subTextObjects[i + 1] = subTextObjects[i]; } + // Get reference to potential text preprocessor component + m_TextPreProcessor = GetComponent(); + // Set flags to ensure our text is parsed and redrawn. m_isInputParsingRequired = true; m_havePropertiesChanged = true; @@ -176,8 +179,6 @@ protected override void OnEnable() ComputeMarginSize(); - m_verticesAlreadyDirty = false; - m_layoutAlreadyDirty = false; m_ShouldRecalculateStencil = true; m_isInputParsingRequired = true; SetAllDirty(); @@ -3010,7 +3011,7 @@ protected override void GenerateTextMesh() // This is white spacing / non visible characters. // Track # of spaces per line which is used for line justification. - if ((charCode == 10 || charCode == 11 || char.IsSeparator((char)charCode)) && charCode != 0xAD && charCode != 0x200B && charCode != 0x2060) + if ((charCode == 10 || charCode == 11 || charCode == 0x2028 || charCode == 0x2029 || char.IsSeparator((char)charCode)) && charCode != 0xAD && charCode != 0x200B && charCode != 0x2060) { m_textInfo.lineInfo[m_lineNumber].spaceCount += 1; m_textInfo.spaceCount += 1; @@ -3051,7 +3052,7 @@ protected override void GenerateTextMesh() #region Track Potential Insertion Location for Ellipsis if (m_overflowMode == TextOverflowModes.Ellipsis && isInjectingCharacter == false) { - float fontScale = m_currentFontSize * smallCapsMultiplier / m_fontAsset.m_FaceInfo.pointSize * m_fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); + float fontScale = m_currentFontSize / m_fontAsset.m_FaceInfo.pointSize * m_fontAsset.m_FaceInfo.scale * (m_isOrthographic ? 1 : 0.1f); float scale = fontScale * m_fontScaleMultiplier * m_cached_Ellipsis_Character.m_Scale * m_cached_Ellipsis_Character.m_Glyph.scale; float marginLeft = m_marginLeft; float marginRight = m_marginRight; @@ -3064,7 +3065,7 @@ protected override void GenerateTextMesh() marginRight = m_textInfo.lineInfo[m_lineNumber].marginRight; } - float descender = m_fontAsset.m_FaceInfo.descentLine * scale / smallCapsMultiplier + m_baselineOffset; + float descender = (m_fontAsset.m_FaceInfo.descentLine * scale) + m_baselineOffset; float textHeight = m_maxAscender - (descender - m_lineOffset); float textWidth = Mathf.Abs(m_xAdvance) + (!m_isRightToLeft ? m_cached_Ellipsis_Character.m_Glyph.metrics.horizontalAdvance : 0) * (1 - m_charWidthAdjDelta) * scale; @@ -3146,7 +3147,7 @@ protected override void GenerateTextMesh() // Handle Line Spacing Adjustments + Word Wrapping & special case for last line. #region Check for Line Feed and Last Character - if (charCode == 10 || charCode == 11 || charCode == 0x03 || (charCode == 0x2D && isInjectingCharacter) || m_characterCount == totalCharacterCount - 1) + if (charCode == 10 || charCode == 11 || charCode == 0x03 || charCode == 0x2028 || charCode == 0x2029 || (charCode == 0x2D && isInjectingCharacter) || m_characterCount == totalCharacterCount - 1) { #if TMP_PROFILE_ON Profiler.BeginSample("TMP - Handle Line & Text Termination"); @@ -3202,7 +3203,7 @@ protected override void GenerateTextMesh() m_textInfo.lineInfo[m_lineNumber].lineHeight = lineAscender - lineDescender + lineGap * baseScale; // Add new line if not last line or character. - if (charCode == 10 || charCode == 11 || charCode == 0x2D) + if (charCode == 10 || charCode == 11 || charCode == 0x2D || charCode == 0x2028 || charCode == 0x2029) { // Store the state of the line before starting on the new line. SaveWordWrappingState(ref m_SavedLineState, i, m_characterCount); @@ -3224,13 +3225,13 @@ protected override void GenerateTextMesh() // Apply Line Spacing with special handling for VT char(11) if (m_lineHeight == TMP_Math.FLOAT_UNSET) { - float lineOffsetDelta = 0 - m_maxLineDescender + lastVisibleAscender + (lineGap + m_lineSpacingDelta) * baseScale + (m_lineSpacing + (charCode == 10 ? m_paragraphSpacing : 0)) * currentEmScale; + float lineOffsetDelta = 0 - m_maxLineDescender + lastVisibleAscender + (lineGap + m_lineSpacingDelta) * baseScale + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale; m_lineOffset += lineOffsetDelta; isDrivenLineSpacing = false; } else { - m_lineOffset += m_lineHeight + (m_lineSpacing + (charCode == 10 ? m_paragraphSpacing : 0)) * currentEmScale; + m_lineOffset += m_lineHeight + (m_lineSpacing + (charCode == 10 || charCode == 0x2029 ? m_paragraphSpacing : 0)) * currentEmScale; isDrivenLineSpacing = true; } @@ -3285,7 +3286,7 @@ protected override void GenerateTextMesh() // Save pageInfo Data - if (m_overflowMode == TextOverflowModes.Page && charCode != 10 && charCode != 11 && charCode != 13) // && m_pageNumber < 16) + if (m_overflowMode == TextOverflowModes.Page && charCode != 10 && charCode != 11 && charCode != 13 && charCode != 0x2028 && charCode != 0x2029) // && m_pageNumber < 16) { // Check if we need to increase allocations for the pageInfo array. if (m_pageNumber + 1 > m_textInfo.pageInfo.Length) @@ -4523,4 +4524,4 @@ void UpdateSDFScale(float scaleDelta) } } -} \ No newline at end of file +} diff --git a/Scripts/Runtime/TextMeshPro.cs b/Scripts/Runtime/TextMeshPro.cs index 5a7eaf9..fd15b22 100644 --- a/Scripts/Runtime/TextMeshPro.cs +++ b/Scripts/Runtime/TextMeshPro.cs @@ -1,4 +1,4 @@ -using UnityEngine; +using UnityEngine; using System; using System.Collections; using System.Collections.Generic; @@ -21,8 +21,20 @@ public partial class TextMeshPro : TMP_Text, ILayoutElement /// public int sortingLayerID { - get { return m_renderer.sortingLayerID; } - set { m_renderer.sortingLayerID = value; } + get + { + if (renderer == null) + return 0; + + return m_renderer.sortingLayerID; + } + set + { + if (renderer == null) + return; + + m_renderer.sortingLayerID = value; + } } /// @@ -30,8 +42,20 @@ public int sortingLayerID /// public int sortingOrder { - get { return m_renderer.sortingOrder; } - set { m_renderer.sortingOrder = value; } + get + { + if (renderer == null) + return 0; + + return m_renderer.sortingOrder; + } + set + { + if (renderer == null) + return; + + m_renderer.sortingOrder = value; + } } /// @@ -164,13 +188,12 @@ public void SetMask(MaskingTypes type, Vector4 maskCoords, float softnessX, floa /// public override void SetVerticesDirty() { - if (m_verticesAlreadyDirty || this == null || !this.IsActive()) - return; + //Debug.Log("***** SetVerticesDirty() called on object [" + this.name + "] at frame [" + Time.frameCount + "] *****"); - //Debug.Log("***** SetVerticesDirty() called on object ID " + GetInstanceID() + ". ***** Dirty = " + m_verticesAlreadyDirty); + if (this == null || !this.IsActive()) + return; TMP_UpdateManager.RegisterTextElementForGraphicRebuild(this); - m_verticesAlreadyDirty = true; } @@ -182,10 +205,9 @@ public override void SetLayoutDirty() m_isPreferredWidthDirty = true; m_isPreferredHeightDirty = true; - if (m_layoutAlreadyDirty || this == null || !this.IsActive()) + if (this == null || !this.IsActive()) return; - m_layoutAlreadyDirty = true; m_isLayoutDirty = true; } @@ -237,8 +259,6 @@ public override void Rebuild(CanvasUpdate update) else if (update == CanvasUpdate.PreRender) { this.OnPreRenderObject(); - m_verticesAlreadyDirty = false; - m_layoutAlreadyDirty = false; if (!m_isMaterialDirty) return; @@ -258,13 +278,11 @@ protected override void UpdateMaterial() //if (!this.IsActive()) // return; - if (m_sharedMaterial == null) + if (renderer == null || m_sharedMaterial == null) return; - if (m_renderer == null) m_renderer = this.renderer; - // Only update the material if it has changed. - if (m_renderer.sharedMaterial.GetInstanceID() != m_sharedMaterial.GetInstanceID()) + if (m_renderer.sharedMaterial == null || m_renderer.sharedMaterial.GetInstanceID() != m_sharedMaterial.GetInstanceID()) m_renderer.sharedMaterial = m_sharedMaterial; } @@ -299,9 +317,6 @@ public override void ForceMeshUpdate(bool ignoreActiveState = false, bool forceT m_ignoreActiveState = ignoreActiveState; m_isInputParsingRequired = m_isInputParsingRequired ? true : forceTextReparsing; OnPreRenderObject(); - - m_verticesAlreadyDirty = false; - m_layoutAlreadyDirty = false; } diff --git a/Scripts/Runtime/TextMeshProUGUI.cs b/Scripts/Runtime/TextMeshProUGUI.cs index 1499e98..03d7e9a 100644 --- a/Scripts/Runtime/TextMeshProUGUI.cs +++ b/Scripts/Runtime/TextMeshProUGUI.cs @@ -1,18 +1,12 @@ -using UnityEngine; -using System; +using UnityEngine; using System.Collections; -using System.Collections.Generic; - using UnityEngine.UI; -using UnityEngine.EventSystems; -using UnityEngine.UI.CoroutineTween; - #pragma warning disable 0414 // Disabled a few warnings related to serialized variables not used in this script but used in the editor. + namespace TMPro { - [DisallowMultipleComponent] [RequireComponent(typeof(RectTransform))] [RequireComponent(typeof(CanvasRenderer))] @@ -28,6 +22,7 @@ public override Material materialForRendering get { return TMP_MaterialManager.GetMaterialForRendering(this, m_sharedMaterial); } } + /// /// Determines if the size of the text container will be adjusted to fit the text object when it is first created. /// @@ -39,7 +34,6 @@ public override bool autoSizeTextContainer } - /// /// Reference to the Mesh used by the text object. /// @@ -74,7 +68,8 @@ public override Mesh mesh private bool m_isRebuildingLayout = false; - //private bool m_isLayoutDirty = false; + private Coroutine m_DelayedGraphicRebuild; + private Coroutine m_DelayedMaterialRebuild; /// @@ -125,10 +120,17 @@ public void CalculateLayoutInputVertical() public override void SetVerticesDirty() { - if (m_verticesAlreadyDirty || this == null || !this.IsActive() || CanvasUpdateRegistry.IsRebuildingGraphics()) + if (this == null || !this.IsActive()) return; - m_verticesAlreadyDirty = true; + if (CanvasUpdateRegistry.IsRebuildingGraphics()) + { + if (m_DelayedGraphicRebuild == null) + m_DelayedGraphicRebuild = StartCoroutine(DelayedGraphicRebuild()); + + return; + } + CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild((ICanvasElement)this); if (m_OnDirtyVertsCallback != null) @@ -144,10 +146,9 @@ public override void SetLayoutDirty() m_isPreferredWidthDirty = true; m_isPreferredHeightDirty = true; - if ( m_layoutAlreadyDirty || this == null || !this.IsActive()) + if (this == null || !this.IsActive()) return; - m_layoutAlreadyDirty = true; LayoutRebuilder.MarkLayoutForRebuild(this.rectTransform); m_isLayoutDirty = true; @@ -162,10 +163,16 @@ public override void SetLayoutDirty() /// public override void SetMaterialDirty() { - //Debug.Log("SetMaterialDirty()"); + if (this == null || !this.IsActive()) + return; + + if (CanvasUpdateRegistry.IsRebuildingGraphics()) + { + if (m_DelayedMaterialRebuild == null) + m_DelayedMaterialRebuild = StartCoroutine(DelayedMaterialRebuild()); - if (this == null || !this.IsActive() || CanvasUpdateRegistry.IsRebuildingGraphics()) return; + } m_isMaterialDirty = true; CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild((ICanvasElement)this); @@ -188,6 +195,36 @@ public override void SetAllDirty() } + /// + /// Delay registration of text object for graphic rebuild by one frame. + /// + /// + IEnumerator DelayedGraphicRebuild() + { + yield return null; + + CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); + + if (m_OnDirtyVertsCallback != null) + m_OnDirtyVertsCallback(); + } + + + /// + /// Delay registration of text object for graphic rebuild by one frame. + /// + /// + IEnumerator DelayedMaterialRebuild() + { + yield return null; + + m_isMaterialDirty = true; + CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); + + if (m_OnDirtyMaterialCallback != null) + m_OnDirtyMaterialCallback(); + } + /// /// @@ -208,9 +245,6 @@ public override void Rebuild(CanvasUpdate update) { OnPreRenderCanvas(); - m_verticesAlreadyDirty = false; - m_layoutAlreadyDirty = false; - if (!m_isMaterialDirty) return; UpdateMaterial(); @@ -276,9 +310,7 @@ protected override void UpdateMaterial() //if (!this.IsActive()) // return; - if (m_sharedMaterial == null) return; - - if (m_canvasRenderer == null) m_canvasRenderer = this.canvasRenderer; + if (m_sharedMaterial == null || canvasRenderer == null) return; m_canvasRenderer.materialCount = 1; m_canvasRenderer.SetMaterial(materialForRendering, 0); @@ -337,6 +369,7 @@ public override void RecalculateClipping() base.RecalculateClipping(); } + // IMaskable Implementation /// /// Method called when Stencil Mask needs to be updated on this element and parents. @@ -349,6 +382,7 @@ public override void RecalculateMasking() SetMaterialDirty(); } + //public override void SetClipRect(Rect clipRect, bool validRect) //{ // //Debug.Log("***** SetClipRect (" + clipRect + ", " + validRect + ") *****"); @@ -356,6 +390,7 @@ public override void RecalculateMasking() // base.SetClipRect(clipRect, validRect); //} + /// /// Override of the Cull function to provide for the ability to override the culling of the text object. /// @@ -400,6 +435,7 @@ public MaskingTypes mask set { m_mask = value; havePropertiesChanged = true; isMaskUpdateRequired = true; } } + /// /// Set the masking offset mode (as percentage or pixels) /// @@ -411,7 +447,6 @@ public MaskingOffsetMode maskOffsetMode */ - /* /// /// Sets the softness of the mask @@ -422,6 +457,7 @@ public Vector2 maskSoftness set { m_maskSoftness = value; havePropertiesChanged = true; isMaskUpdateRequired = true; } } + /// /// Allows to move / offset the mesh vertices by a set amount /// @@ -498,9 +534,6 @@ public override void ForceMeshUpdate(bool ignoreActiveState = false, bool forceT m_ignoreActiveState = ignoreActiveState; m_isInputParsingRequired = m_isInputParsingRequired ? true : forceTextReparsing; OnPreRenderCanvas(); - - m_verticesAlreadyDirty = false; - m_layoutAlreadyDirty = false; } @@ -528,6 +561,7 @@ public override TMP_TextInfo GetTextInfo(string text) return this.textInfo; } + /// /// Function to clear the geometry of the Primary and Sub Text objects. /// @@ -661,4 +695,4 @@ public void UpdateFontAsset() } } -} \ No newline at end of file +} diff --git a/package.json b/package.json index 988302a..0bb9c26 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.unity.textmeshpro", "displayName": "TextMeshPro", - "version": "1.5.0-preview.2", + "version": "1.5.0-preview.3", "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": [ @@ -16,6 +16,6 @@ "repository": { "type": "git", "url": "git@github.cds.internal.unity3d.com:unity/com.unity.textmeshpro.git", - "revision": "e153502a1c6935e606ffc10027028d17769a1e5e" + "revision": "2ae6790fb8109f7d2f14332a54c58117b8f81dd3" } }