From 0f0fbf0f9a6e551476f42cdee850ca5b65924030 Mon Sep 17 00:00:00 2001 From: Unity Technologies <@unity.com> Date: Thu, 14 Feb 2019 00:00:00 +0100 Subject: [PATCH] com.unity.textmeshpro@1.4.0-preview.2a ## [1.4.0-preview.2a] - 2019-02-14 ### Changes - Fixed an issue with SDF Scale handling where the text object would not render correctly after the object scale had been set to zero. - Fixed an issue with the TMP_UpdateManager where text objects were not getting unregistered correctly. - Any changes to Font Asset Creation Settings' padding, atlas width and / or atlas height will now result in all Material Presets for the given font asset to also be updated. - Added new section in the TMP Settings related to the new Dynamic Font System. - Added new property in the Dynamic Font System section to determine if OpenType Font Features will be retrieved from source font files at runtime as new characters are added to font assets. Glyph Adjustment Data (Kerning) is the only feature currently supported. - Fix an issue where font assets created at runtime were not getting their asset version number set to "1.1.0". - Improved parsing of the text file used in the Font Asset Creator and "Characters from File" option to handle UTF16 "\u" and UTF32 "\U" escape character sequences. - Fixed a Null Reference Error (NRE) that could occur when using the <font> tag with an invalid font name followed by the <sprite> tag. - The Glyph Adjustment Table presentation and internal data structure has been changed to facilitate the future addition of OpenType font features. See https://forum.unity.com/threads/version-1-4-0-preview-with-dynamic-sdf-for-unity-2018-3-now-available.622420/#post-4206595 for more details. - Fixed an issue with the <rotate> tag incorrectly affecting character spacing. --- CHANGELOG.md | 15 +- Scripts/Editor/KerningPairDrawer.cs | 195 --------- Scripts/Editor/SpriteInfoDrawer.cs | 143 ------- ...torCoroutine.cs => TMP_EditorCoroutine.cs} | 8 +- ...ne.cs.meta => TMP_EditorCoroutine.cs.meta} | 0 Scripts/Editor/TMP_FontAssetEditor.cs | 174 +++++--- ...GlyphPairAdjustmentRecordPropertyDrawer.cs | 382 ++++++++++++++++++ ...airAdjustmentRecordPropertyDrawer.cs.meta} | 3 +- Scripts/Editor/TMP_GlyphPropertyDrawer.cs | 7 +- Scripts/Editor/TMP_PackageUtilities.cs | 2 +- .../Editor/TMP_SerializedPropertyHolder.cs | 14 + ...a => TMP_SerializedPropertyHolder.cs.meta} | 3 +- Scripts/Editor/TMP_SettingsEditor.cs | 15 +- ...ntDrawer.cs => TMP_TextAlignmentDrawer.cs} | 2 +- ...s.meta => TMP_TextAlignmentDrawer.cs.meta} | 0 .../Editor/TMPro_FontAssetCreatorWindow.cs | 79 ++-- Scripts/Runtime/TMP_Character.cs | 15 + Scripts/Runtime/TMP_CharacterInfo.cs | 2 +- Scripts/Runtime/TMP_FontAsset.cs | 337 ++++++++------- Scripts/Runtime/TMP_FontAssetCommon.cs | 31 +- Scripts/Runtime/TMP_FontFeatureTable.cs | 55 +++ Scripts/Runtime/TMP_FontFeatureTable.cs.meta | 11 + Scripts/Runtime/TMP_FontFeaturesCommon.cs | 223 ++++++++++ .../Runtime/TMP_FontFeaturesCommon.cs.meta | 11 + Scripts/Runtime/TMP_MeshInfo.cs | 5 +- Scripts/Runtime/TMP_Settings.cs | 10 + Scripts/Runtime/TMP_Text.cs | 32 +- Scripts/Runtime/TMP_UpdateManager.cs | 8 +- Scripts/Runtime/TMPro_Private.cs | 60 +-- Scripts/Runtime/TMPro_UGUI_Private.cs | 64 +-- package.json | 4 +- 31 files changed, 1205 insertions(+), 705 deletions(-) delete mode 100644 Scripts/Editor/KerningPairDrawer.cs delete mode 100644 Scripts/Editor/SpriteInfoDrawer.cs rename Scripts/Editor/{EditorCoroutine.cs => TMP_EditorCoroutine.cs} (90%) rename Scripts/Editor/{EditorCoroutine.cs.meta => TMP_EditorCoroutine.cs.meta} (100%) create mode 100644 Scripts/Editor/TMP_GlyphPairAdjustmentRecordPropertyDrawer.cs rename Scripts/Editor/{SpriteInfoDrawer.cs.meta => TMP_GlyphPairAdjustmentRecordPropertyDrawer.cs.meta} (74%) create mode 100644 Scripts/Editor/TMP_SerializedPropertyHolder.cs rename Scripts/Editor/{KerningPairDrawer.cs.meta => TMP_SerializedPropertyHolder.cs.meta} (74%) rename Scripts/Editor/{TextAlignmentDrawer.cs => TMP_TextAlignmentDrawer.cs} (98%) rename Scripts/Editor/{TextAlignmentDrawer.cs.meta => TMP_TextAlignmentDrawer.cs.meta} (100%) create mode 100644 Scripts/Runtime/TMP_FontFeatureTable.cs create mode 100644 Scripts/Runtime/TMP_FontFeatureTable.cs.meta create mode 100644 Scripts/Runtime/TMP_FontFeaturesCommon.cs create mode 100644 Scripts/Runtime/TMP_FontFeaturesCommon.cs.meta diff --git a/CHANGELOG.md b/CHANGELOG.md index 602ad95..1d20a38 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,20 @@ # Changelog These are the release notes for the TextMesh Pro UPM package which was first introduced with Unity 2018.1. Please see the following link for the Release Notes for prior versions of TextMesh Pro. http://digitalnativestudios.com/forum/index.php?topic=1363.0 -## [1.4.0] - 2018-09-10 +## [1.4.0-preview.2a] - 2019-02-14 +### Changes +- Fixed an issue with SDF Scale handling where the text object would not render correctly after the object scale had been set to zero. +- Fixed an issue with the TMP_UpdateManager where text objects were not getting unregistered correctly. +- Any changes to Font Asset Creation Settings' padding, atlas width and / or atlas height will now result in all Material Presets for the given font asset to also be updated. +- Added new section in the TMP Settings related to the new Dynamic Font System. +- Added new property in the Dynamic Font System section to determine if OpenType Font Features will be retrieved from source font files at runtime as new characters are added to font assets. Glyph Adjustment Data (Kerning) is the only feature currently supported. +- Fix an issue where font assets created at runtime were not getting their asset version number set to "1.1.0". +- Improved parsing of the text file used in the Font Asset Creator and "Characters from File" option to handle UTF16 "\u" and UTF32 "\U" escape character sequences. +- Fixed a Null Reference Error (NRE) that could occur when using the <font> tag with an invalid font name followed by the <sprite> tag. +- The Glyph Adjustment Table presentation and internal data structure has been changed to facilitate the future addition of OpenType font features. See https://forum.unity.com/threads/version-1-4-0-preview-with-dynamic-sdf-for-unity-2018-3-now-available.622420/#post-4206595 for more details. +- Fixed an issue with the <rotate> tag incorrectly affecting character spacing. + +## [1.4.0-preview.1] - 2019-01-30 ### Changes - Renamed TMPro_FontUtilities to TMP_FontAssetCommon to more accurately reflect the content of this file. - Accessing the TextMesh Pro Settings via the new Edit - Settings menu when TMP Essential Resources have not yet been imported in the project will no longer open a new window to provide the options to import these resources. diff --git a/Scripts/Editor/KerningPairDrawer.cs b/Scripts/Editor/KerningPairDrawer.cs deleted file mode 100644 index 8661903..0000000 --- a/Scripts/Editor/KerningPairDrawer.cs +++ /dev/null @@ -1,195 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System.Collections; - - -namespace TMPro.EditorUtilities -{ - - [CustomPropertyDrawer(typeof(KerningPair))] - public class KerningPairDrawer : PropertyDrawer - { - private bool isEditingEnabled = false; - private bool isSelectable = false; - - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - SerializedProperty prop_FirstGlyph = property.FindPropertyRelative("m_FirstGlyph"); - SerializedProperty prop_FirstGlyphAdjustment = property.FindPropertyRelative("m_FirstGlyphAdjustments"); - SerializedProperty prop_SecondGlyph = property.FindPropertyRelative("m_SecondGlyph"); - SerializedProperty prop_SecondGlyphAdjustment = property.FindPropertyRelative("m_SecondGlyphAdjustments"); - SerializedProperty prop_IgnoreCharacterSpacing = property.FindPropertyRelative("m_IgnoreSpacingAdjustments"); - - position.yMin += 2; - - float width = position.width / 2; - float padding = 5.0f; - - Rect rect; - - isEditingEnabled = GUI.enabled; - isSelectable = label.text == "Selectable" ? true : false; - - if (isSelectable) - GUILayoutUtility.GetRect(position.width, 65); - else - GUILayoutUtility.GetRect(position.width, 45); - - - // First Glyph - GUI.enabled = isEditingEnabled; - if (isSelectable) - { - bool prevGuiState = GUI.enabled; - GUI.enabled = true; - rect = new Rect(position.x, position.y, 40, 18); - EditorGUI.LabelField(rect, "Char:", TMP_UIStyleManager.label); - - rect = new Rect(position.x + 35f, position.y, 30, 18); - EditorGUI.LabelField(rect, "" + (char)prop_FirstGlyph.intValue + "", TMP_UIStyleManager.label); - - // Display ASCII decimal value - rect = new Rect(position.x + 60f, position.y, 30, 18); - EditorGUI.LabelField(rect, "ID:", TMP_UIStyleManager.label); - - rect = new Rect(position.x + 80f, position.y, 60, 18); - EditorGUI.LabelField(rect, "0x" + prop_FirstGlyph.intValue.ToString("X4") + "", TMP_UIStyleManager.label); - GUI.enabled = prevGuiState; - } - else - { - rect = new Rect(position.x, position.y, width / 2 * 0.8f - padding, 18); - - string glyph = EditorGUI.TextArea(rect, "" + (char)prop_FirstGlyph.intValue); - if (GUI.changed && glyph != "") - { - GUI.changed = false; - prop_FirstGlyph.intValue = glyph[0]; - } - - rect.x += width / 2 * 0.8f; - - GUI.SetNextControlName("Unicode 1"); - EditorGUI.BeginChangeCheck(); - string unicode = EditorGUI.TextField(rect, prop_FirstGlyph.intValue.ToString("X")); - - if (GUI.GetNameOfFocusedControl() == "Unicode 1") - { - //Filter out unwanted characters. - char chr = Event.current.character; - if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F')) - { - Event.current.character = '\0'; - } - } - - if (EditorGUI.EndChangeCheck()) - { - // Update Unicode value - prop_FirstGlyph.intValue = TMP_TextUtilities.StringHexToInt(unicode); - } - - } - - GUI.enabled = isEditingEnabled; - EditorGUIUtility.labelWidth = 25f; - - rect = new Rect(position.x, position.y + 20, width * 0.5f - padding, 18); - EditorGUI.PropertyField(rect, prop_FirstGlyphAdjustment.FindPropertyRelative("xPlacement"), new GUIContent("OX")); - - rect.x += width * 0.5f; - EditorGUI.PropertyField(rect, prop_FirstGlyphAdjustment.FindPropertyRelative("yPlacement"), new GUIContent("OY")); - - rect.x = position.x; - rect.y += 20; - EditorGUI.PropertyField(rect, prop_FirstGlyphAdjustment.FindPropertyRelative("xAdvance"), new GUIContent("AX")); - - //rect.x += width * 0.5f; - //EditorGUI.PropertyField(rect, prop_FirstGlyphAdjustment.FindPropertyRelative("yAdvance"), new GUIContent("AY")); - - // Second Glyph - GUI.enabled = isEditingEnabled; - if (isSelectable) - { - bool prevGuiState = GUI.enabled; - GUI.enabled = true; - rect = new Rect(position.width / 2 + 20, position.y, 40f, 18); - EditorGUI.LabelField(rect, "Char:", TMP_UIStyleManager.label); - - rect = new Rect(rect.x + 35f, position.y, 30, 18); - EditorGUI.LabelField(rect, "" + (char)prop_SecondGlyph.intValue + "", TMP_UIStyleManager.label); - - // Display ASCII decimal value - rect = new Rect(rect.x + 25f, position.y, 30, 18); - EditorGUI.LabelField(rect, "ID:", TMP_UIStyleManager.label); - - rect = new Rect(rect.x + 20f, position.y, 60, 18); - EditorGUI.LabelField(rect, "0x" + prop_SecondGlyph.intValue.ToString("X4") + "", TMP_UIStyleManager.label); - GUI.enabled = prevGuiState; - } - else - { - rect = new Rect(position.width / 2 + 20, position.y, width / 2 * 0.8f - padding, 18); - - string glyph = EditorGUI.TextArea(rect, "" + (char)prop_SecondGlyph.intValue); - if (GUI.changed && glyph != "") - { - GUI.changed = false; - prop_SecondGlyph.intValue = glyph[0]; - } - - rect.x += width / 2 * 0.8f; - - GUI.SetNextControlName("Unicode 2"); - EditorGUI.BeginChangeCheck(); - string unicode = EditorGUI.TextField(rect, prop_SecondGlyph.intValue.ToString("X")); - - if (GUI.GetNameOfFocusedControl() == "Unicode 2") - { - //Filter out unwanted characters. - char chr = Event.current.character; - if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F')) - { - Event.current.character = '\0'; - } - } - - if (EditorGUI.EndChangeCheck()) - { - // Update Unicode value - prop_SecondGlyph.intValue = TMP_TextUtilities.StringHexToInt(unicode); - } - } - - GUI.enabled = isEditingEnabled; - EditorGUIUtility.labelWidth = 25f; - - rect = new Rect(position.width / 2 + 20, position.y + 20, width * 0.5f - padding, 18); - EditorGUI.PropertyField(rect, prop_SecondGlyphAdjustment.FindPropertyRelative("xPlacement"), new GUIContent("OX")); - - rect.x += width * 0.5f; - EditorGUI.PropertyField(rect, prop_SecondGlyphAdjustment.FindPropertyRelative("yPlacement"), new GUIContent("OY")); - - rect.x = position.width / 2 + 20; - rect.y += 20; - EditorGUI.PropertyField(rect, prop_SecondGlyphAdjustment.FindPropertyRelative("xAdvance"), new GUIContent("AX")); - - //rect.x += width * 0.5f; - //EditorGUI.PropertyField(rect, prop_SecondGlyphAdjustment.FindPropertyRelative("yAdvance"), new GUIContent("AY")); - - // Ignore Character Spacing - if (isSelectable) - { - EditorGUIUtility.labelWidth = 160f; - - rect.x = position.x; - rect.y += 20; - rect.width = 180; - EditorGUI.PropertyField(rect, prop_IgnoreCharacterSpacing, new GUIContent("Ignore Character Spacing", "Adjustment Pair will ignore character spacing adjustments on text components.")); - } - - } - - - } -} \ No newline at end of file diff --git a/Scripts/Editor/SpriteInfoDrawer.cs b/Scripts/Editor/SpriteInfoDrawer.cs deleted file mode 100644 index f463527..0000000 --- a/Scripts/Editor/SpriteInfoDrawer.cs +++ /dev/null @@ -1,143 +0,0 @@ -using UnityEngine; -using UnityEditor; -using System.Collections; - - -namespace TMPro.EditorUtilities -{ - - [CustomPropertyDrawer(typeof(TMP_Sprite))] - public class SpriteInfoDrawer : PropertyDrawer - { - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) - { - //SerializedProperty prop_fileID = property.FindPropertyRelative("fileID"); - SerializedProperty prop_id = property.FindPropertyRelative("id"); - SerializedProperty prop_name = property.FindPropertyRelative("name"); - SerializedProperty prop_hashCode = property.FindPropertyRelative("hashCode"); - SerializedProperty prop_unicode = property.FindPropertyRelative("unicode"); - SerializedProperty prop_x = property.FindPropertyRelative("x"); - SerializedProperty prop_y = property.FindPropertyRelative("y"); - SerializedProperty prop_width = property.FindPropertyRelative("width"); - SerializedProperty prop_height = property.FindPropertyRelative("height"); - SerializedProperty prop_xOffset = property.FindPropertyRelative("xOffset"); - SerializedProperty prop_yOffset = property.FindPropertyRelative("yOffset"); - SerializedProperty prop_xAdvance = property.FindPropertyRelative("xAdvance"); - SerializedProperty prop_scale = property.FindPropertyRelative("scale"); - SerializedProperty prop_sprite = property.FindPropertyRelative("sprite"); - - // Get a reference to the sprite texture - Texture tex = (property.serializedObject.targetObject as TMP_SpriteAsset).spriteSheet; - - // Return if we don't have a texture assigned to the sprite asset. - if (tex == null) - { - Debug.LogWarning("Please assign a valid Sprite Atlas texture to the [" + property.serializedObject.targetObject.name + "] Sprite Asset.", property.serializedObject.targetObject); - return; - } - - Vector2 spriteTexPosition = new Vector2(position.x, position.y); - Vector2 spriteSize = new Vector2(65, 65); - if (prop_width.floatValue >= prop_height.floatValue) - { - spriteSize.y = prop_height.floatValue * spriteSize.x / prop_width.floatValue; - spriteTexPosition.y += (spriteSize.x - spriteSize.y) / 2; - } - else - { - spriteSize.x = prop_width.floatValue * spriteSize.y / prop_height.floatValue; - spriteTexPosition.x += (spriteSize.y - spriteSize.x) / 2; - } - - // Compute the normalized texture coordinates - Rect texCoords = new Rect(prop_x.floatValue / tex.width, prop_y.floatValue / tex.height, prop_width.floatValue / tex.width, prop_height.floatValue / tex.height); - GUI.DrawTextureWithTexCoords(new Rect(spriteTexPosition.x + 5, spriteTexPosition.y + 2.5f, spriteSize.x, spriteSize.y), tex, texCoords, true); - - // We get Rect since a valid position may not be provided by the caller. - Rect rect = new Rect(position.x, position.y, position.width, 49); - rect.x += 70; - - bool isEnabled = GUI.enabled; - GUI.enabled = true; - EditorGUIUtility.labelWidth = 30f; - EditorGUI.LabelField(new Rect(rect.x + 5f, rect.y, 65f, 18), new GUIContent("ID:"), new GUIContent(prop_id.intValue.ToString())); - - GUI.enabled = isEnabled; - EditorGUI.BeginChangeCheck(); - EditorGUIUtility.labelWidth = 55f; - GUI.SetNextControlName("Unicode Input"); - string unicode = EditorGUI.TextField(new Rect(rect.x + 75f, rect.y, 105, 18), "Unicode:", prop_unicode.intValue.ToString("X")); - - if (GUI.GetNameOfFocusedControl() == "Unicode Input") - { - //Filter out unwanted characters. - char chr = Event.current.character; - if ((chr < '0' || chr > '9') && (chr < 'a' || chr > 'f') && (chr < 'A' || chr > 'F')) - { - Event.current.character = '\0'; - } - - if (EditorGUI.EndChangeCheck()) - { - prop_unicode.intValue = TMP_TextUtilities.StringHexToInt(unicode); - - property.serializedObject.ApplyModifiedProperties(); - - TMP_SpriteAsset spriteAsset = property.serializedObject.targetObject as TMP_SpriteAsset; - spriteAsset.UpdateLookupTables(); - } - } - - - EditorGUIUtility.labelWidth = 45f; - EditorGUI.BeginChangeCheck(); - EditorGUI.PropertyField(new Rect(rect.x + 185f, rect.y, rect.width - 260, 18), prop_name, new GUIContent("Name: " + prop_name.stringValue)); - if (EditorGUI.EndChangeCheck()) - { - Sprite sprite = prop_sprite.objectReferenceValue as Sprite; - if (sprite != null) - sprite.name = prop_name.stringValue; - - // Recompute hashCode for new name - prop_hashCode.intValue = TMP_TextUtilities.GetSimpleHashCode(prop_name.stringValue); - // Check to make sure for duplicates - property.serializedObject.ApplyModifiedProperties(); - // Dictionary needs to be updated since HashCode has changed. - //TMP_StyleSheet.Instance.LoadStyleDictionary(); - } - - EditorGUIUtility.labelWidth = 30f; - EditorGUIUtility.fieldWidth = 10f; - - //GUI.enabled = false; - float width = (rect.width - 75f) / 4; - EditorGUI.PropertyField(new Rect(rect.x + 5f + width * 0, rect.y + 22, width - 5f, 18), prop_x, new GUIContent("X:")); - EditorGUI.PropertyField(new Rect(rect.x + 5f + width * 1, rect.y + 22, width - 5f, 18), prop_y, new GUIContent("Y:")); - EditorGUI.PropertyField(new Rect(rect.x + 5f + width * 2, rect.y + 22, width - 5f, 18), prop_width, new GUIContent("W:")); - EditorGUI.PropertyField(new Rect(rect.x + 5f + width * 3, rect.y + 22, width - 5f, 18), prop_height, new GUIContent("H:")); - - //GUI.enabled = true; - - EditorGUI.BeginChangeCheck(); - EditorGUI.PropertyField(new Rect(rect.x + 5f + width * 0, rect.y + 44, width - 5f, 18), prop_xOffset, new GUIContent("OX:")); - EditorGUI.PropertyField(new Rect(rect.x + 5f + width * 1, rect.y + 44, width - 5f, 18), prop_yOffset, new GUIContent("OY:")); - EditorGUI.PropertyField(new Rect(rect.x + 5f + width * 2, rect.y + 44, width - 5f, 18), prop_xAdvance, new GUIContent("Adv.")); - EditorGUI.PropertyField(new Rect(rect.x + 5f + width * 3, rect.y + 44, width - 5f, 18), prop_scale, new GUIContent("SF.")); - if (EditorGUI.EndChangeCheck()) - { - //Sprite sprite = prop_sprite.objectReferenceValue as Sprite; - //sprite = Sprite.Create(sprite.texture, sprite.rect, new Vector2(0.1f, 0.8f)); - //prop_sprite.objectReferenceValue = sprite; - //Debug.Log(sprite.bounds); - } - } - - - //public override float GetPropertyHeight(SerializedProperty property, GUIContent label) - //{ - // return 40f; - //} - - - } -} diff --git a/Scripts/Editor/EditorCoroutine.cs b/Scripts/Editor/TMP_EditorCoroutine.cs similarity index 90% rename from Scripts/Editor/EditorCoroutine.cs rename to Scripts/Editor/TMP_EditorCoroutine.cs index e5c35fd..e005603 100644 --- a/Scripts/Editor/EditorCoroutine.cs +++ b/Scripts/Editor/TMP_EditorCoroutine.cs @@ -10,7 +10,7 @@ namespace TMPro.EditorUtilities /// /// Simple implementation of coroutine working in the Unity Editor. /// - public class EditorCoroutine + public class TMP_EditorCoroutine { //private static Dictionary s_ActiveCoroutines; @@ -20,7 +20,7 @@ public class EditorCoroutine /// Constructor /// /// - EditorCoroutine(IEnumerator routine) + TMP_EditorCoroutine(IEnumerator routine) { this.coroutine = routine; } @@ -31,9 +31,9 @@ public class EditorCoroutine /// /// Coroutine /// new EditorCoroutine - public static EditorCoroutine StartCoroutine(IEnumerator routine) + public static TMP_EditorCoroutine StartCoroutine(IEnumerator routine) { - EditorCoroutine coroutine = new EditorCoroutine(routine); + TMP_EditorCoroutine coroutine = new TMP_EditorCoroutine(routine); coroutine.Start(); // Add coroutine to tracking list diff --git a/Scripts/Editor/EditorCoroutine.cs.meta b/Scripts/Editor/TMP_EditorCoroutine.cs.meta similarity index 100% rename from Scripts/Editor/EditorCoroutine.cs.meta rename to Scripts/Editor/TMP_EditorCoroutine.cs.meta diff --git a/Scripts/Editor/TMP_FontAssetEditor.cs b/Scripts/Editor/TMP_FontAssetEditor.cs index 5383bd3..088bf05 100644 --- a/Scripts/Editor/TMP_FontAssetEditor.cs +++ b/Scripts/Editor/TMP_FontAssetEditor.cs @@ -40,7 +40,6 @@ public override void OnGUI(Rect position, SerializedProperty property, GUIConten } } - [CustomEditor(typeof(TMP_FontAsset))] public class TMP_FontAssetEditor : Editor { @@ -53,7 +52,7 @@ private struct UI_PanelState public static bool fallbackFontAssetPanel = true; public static bool glyphTablePanel = false; public static bool characterTablePanel = false; - public static bool kerningInfoPanel = false; + public static bool fontFeatureTablePanel = false; } private struct AtlasSettings @@ -134,6 +133,7 @@ private struct Warning private Warning m_AddCharacterWarning; private bool m_DisplayDestructiveChangeWarning; private AtlasSettings m_AtlasSettings; + private bool m_MaterialPresetsRequireUpdate; private string m_GlyphSearchPattern; private List m_GlyphSearchList; @@ -176,15 +176,12 @@ private struct Warning private SerializedProperty m_GlyphTable_prop; private SerializedProperty m_CharacterTable_prop; - private SerializedProperty m_KerningTable_prop; - private KerningTable m_kerningTable; - private SerializedProperty m_KerningPairs_prop; - - private SerializedObject m_DummySerializedObject; + private TMP_FontFeatureTable m_FontFeatureTable; + private SerializedProperty m_FontFeatureTable_prop; + private SerializedProperty m_GlyphPairAdjustmentRecords_prop; - [SerializeField] - private KerningPair m_EmptyKerningPair = new KerningPair(); - private SerializedProperty m_KerningPair_prop; + private TMP_SerializedPropertyHolder m_SerializedPropertyHolder; + private SerializedProperty m_EmptyGlyphPairAdjustmentRecord_prop; private TMP_FontAsset m_fontAsset; @@ -239,16 +236,23 @@ public void OnEnable() m_CharacterTable_prop = serializedObject.FindProperty("m_CharacterTable"); m_GlyphTable_prop = serializedObject.FindProperty("m_GlyphTable"); - m_KerningTable_prop = serializedObject.FindProperty("m_KerningTable"); - m_KerningPairs_prop = m_KerningTable_prop.FindPropertyRelative("kerningPairs"); - - // Create serialized object to allow us to use a serialized property of an empty kerning pair. - m_DummySerializedObject = new SerializedObject(this); - m_KerningPair_prop = m_DummySerializedObject.FindProperty("m_EmptyKerningPair"); + m_FontFeatureTable_prop = serializedObject.FindProperty("m_FontFeatureTable"); + m_GlyphPairAdjustmentRecords_prop = m_FontFeatureTable_prop.FindPropertyRelative("m_GlyphPairAdjustmentRecords"); m_fontAsset = target as TMP_FontAsset; + m_FontFeatureTable = m_fontAsset.fontFeatureTable; - m_kerningTable = m_fontAsset.kerningTable; + // Upgrade Font Feature Table if necessary + if (m_fontAsset.m_KerningTable != null && m_fontAsset.m_KerningTable.kerningPairs != null && m_fontAsset.m_KerningTable.kerningPairs.Count > 0) + m_fontAsset.ReadFontAssetDefinition(); + + // Create serialized object to allow us to use a serialized property of an empty kerning pair. + m_SerializedPropertyHolder = CreateInstance(); + m_SerializedPropertyHolder.fontAsset = m_fontAsset; + SerializedObject internalSerializedObject = new SerializedObject(m_SerializedPropertyHolder); + m_EmptyGlyphPairAdjustmentRecord_prop = internalSerializedObject.FindProperty("glyphPairAdjustmentRecord"); + + //m_EmptyGlyphPairAdjustmentRecord_prop = serializedObject.FindProperty("m_EmptyGlyphPairAdjustmentRecord"); m_materialPresets = TMP_EditorUtility.FindMaterialReferences(m_fontAsset); @@ -439,11 +443,19 @@ public override void OnInspectorGUI() // TODO: Switch shaders depending on GlyphRenderMode. EditorGUILayout.PropertyField(m_AtlasRenderMode_prop); EditorGUILayout.PropertyField(m_SamplingPointSize_prop, new GUIContent("Sampling Point Size")); + if (EditorGUI.EndChangeCheck()) + { + m_DisplayDestructiveChangeWarning = true; + } + + // Changes to these properties require updating Material Presets for this font asset. + EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(m_AtlasPadding_prop, new GUIContent("Padding")); EditorGUILayout.IntPopup(m_AtlasWidth_prop, m_AtlasResolutionLabels, m_AtlasResolutions, new GUIContent("Atlas Width")); EditorGUILayout.IntPopup(m_AtlasHeight_prop, m_AtlasResolutionLabels, m_AtlasResolutions, new GUIContent("Atlas Height")); if (EditorGUI.EndChangeCheck()) { + m_MaterialPresetsRequireUpdate = true; m_DisplayDestructiveChangeWarning = true; } @@ -471,6 +483,22 @@ public override void OnInspectorGUI() m_fontAsset.material.SetFloat(ShaderUtilities.ID_TextureHeight, m_AtlasHeight_prop.intValue); m_fontAsset.material.SetFloat(ShaderUtilities.ID_GradientScale, m_AtlasPadding_prop.intValue + 1); + // Update material presets if any of the relevant properties have been changed. + if (m_MaterialPresetsRequireUpdate) + { + m_MaterialPresetsRequireUpdate = false; + + Material[] materialPresets = TMP_EditorUtility.FindMaterialReferences(m_fontAsset); + for (int i = 0; i < materialPresets.Length; i++) + { + Material mat = materialPresets[i]; + + mat.SetFloat(ShaderUtilities.ID_TextureWidth, m_AtlasWidth_prop.intValue); + mat.SetFloat(ShaderUtilities.ID_TextureHeight, m_AtlasHeight_prop.intValue); + mat.SetFloat(ShaderUtilities.ID_GradientScale, m_AtlasPadding_prop.intValue + 1); + } + } + m_fontAsset.ClearFontAssetData(); GUIUtility.keyboardControl = 0; isAssetDirty = true; @@ -907,12 +935,11 @@ public override void OnInspectorGUI() SerializedProperty glyphProperty = m_GlyphTable_prop.GetArrayElementAtIndex(elementIndex); EditorGUILayout.BeginVertical(glyphPanelStyle); - - EditorGUI.BeginDisabledGroup(i != m_SelectedGlyphRecord); + + using (new EditorGUI.DisabledScope(i != m_SelectedGlyphRecord)) { EditorGUILayout.PropertyField(glyphProperty); } - EditorGUI.EndDisabledGroup(); EditorGUILayout.EndVertical(); @@ -1025,21 +1052,21 @@ public override void OnInspectorGUI() } #endregion - // KERNING TABLE PANEL - #region Kerning Table + // FONT FEATURE TABLE + #region Font Feature Table EditorGUIUtility.labelWidth = labelWidth; EditorGUIUtility.fieldWidth = fieldWidth; EditorGUI.indentLevel = 0; rect = EditorGUILayout.GetControlRect(false, 24); if (GUI.Button(rect, new GUIContent("Glyph Adjustment Table", "List of glyph adjustment / advanced kerning pairs."), TMP_UIStyleManager.sectionHeader)) - UI_PanelState.kerningInfoPanel = !UI_PanelState.kerningInfoPanel; + UI_PanelState.fontFeatureTablePanel = !UI_PanelState.fontFeatureTablePanel; - GUI.Label(rect, (UI_PanelState.kerningInfoPanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); + GUI.Label(rect, (UI_PanelState.fontFeatureTablePanel ? "" : s_UiStateLabel[1]), TMP_UIStyleManager.rightLabel); - if (UI_PanelState.kerningInfoPanel) + if (UI_PanelState.fontFeatureTablePanel) { - int arraySize = m_KerningPairs_prop.arraySize; + int arraySize = m_GlyphPairAdjustmentRecords_prop.arraySize; int itemsPerPage = 20; // Display Kerning Pair Management Tools @@ -1097,15 +1124,14 @@ public override void OnInspectorGUI() if (!string.IsNullOrEmpty(m_KerningTableSearchPattern)) elementIndex = m_KerningTableSearchList[i]; - SerializedProperty kerningInfo = m_KerningPairs_prop.GetArrayElementAtIndex(elementIndex); - + SerializedProperty pairAdjustmentRecordProperty = m_GlyphPairAdjustmentRecords_prop.GetArrayElementAtIndex(elementIndex); + EditorGUILayout.BeginVertical(EditorStyles.helpBox); - EditorGUI.BeginDisabledGroup(i != m_SelectedAdjustmentRecord); + using (new EditorGUI.DisabledScope(i != m_SelectedAdjustmentRecord)) { - EditorGUILayout.PropertyField(kerningInfo, new GUIContent("Selectable")); + EditorGUILayout.PropertyField(pairAdjustmentRecordProperty, new GUIContent("Selectable")); } - EditorGUI.EndDisabledGroup(); EditorGUILayout.EndVertical(); @@ -1163,25 +1189,44 @@ public override void OnInspectorGUI() // Add new kerning pair EditorGUILayout.BeginVertical(EditorStyles.helpBox); { - EditorGUILayout.PropertyField(m_KerningPair_prop); + EditorGUILayout.PropertyField(m_EmptyGlyphPairAdjustmentRecord_prop); } EditorGUILayout.EndVertical(); - if (GUILayout.Button("Add New Kerning Pair")) + if (GUILayout.Button("Add New Glyph Adjustment Record")) { - int firstGlyph = m_KerningPair_prop.FindPropertyRelative("m_FirstGlyph").intValue; - int secondGlyph = m_KerningPair_prop.FindPropertyRelative("m_SecondGlyph").intValue; + SerializedProperty firstAdjustmentRecordProperty = m_EmptyGlyphPairAdjustmentRecord_prop.FindPropertyRelative("m_FirstAdjustmentRecord"); + SerializedProperty secondAdjustmentRecordProperty = m_EmptyGlyphPairAdjustmentRecord_prop.FindPropertyRelative("m_SecondAdjustmentRecord"); - GlyphValueRecord firstGlyphAdjustments = GetGlyphAdjustments(m_KerningPair_prop.FindPropertyRelative("m_FirstGlyphAdjustments")); - GlyphValueRecord secondGlyphAdjustments = GetGlyphAdjustments(m_KerningPair_prop.FindPropertyRelative("m_SecondGlyphAdjustments")); + uint firstGlyphIndex = (uint)firstAdjustmentRecordProperty.FindPropertyRelative("m_GlyphIndex").intValue; + uint secondGlyphIndex = (uint)secondAdjustmentRecordProperty.FindPropertyRelative("m_GlyphIndex").intValue; - errorCode = m_kerningTable.AddGlyphPairAdjustmentRecord((uint)firstGlyph, firstGlyphAdjustments, (uint)secondGlyph, secondGlyphAdjustments); + TMP_GlyphValueRecord firstValueRecord = GetValueRecord(firstAdjustmentRecordProperty.FindPropertyRelative("m_GlyphValueRecord")); + TMP_GlyphValueRecord secondValueRecord = GetValueRecord(secondAdjustmentRecordProperty.FindPropertyRelative("m_GlyphValueRecord")); + + errorCode = -1; + long pairKey = (long)secondGlyphIndex << 32 | firstGlyphIndex; + if (m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.ContainsKey(pairKey) == false) + { + TMP_GlyphPairAdjustmentRecord adjustmentRecord = new TMP_GlyphPairAdjustmentRecord(new TMP_GlyphAdjustmentRecord(firstGlyphIndex, firstValueRecord), new TMP_GlyphAdjustmentRecord(secondGlyphIndex, secondValueRecord)); + m_FontFeatureTable.m_GlyphPairAdjustmentRecords.Add(adjustmentRecord); + m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.Add(pairKey, adjustmentRecord); + errorCode = 0; + } + + // Add glyphs and characters + uint firstCharacter = m_SerializedPropertyHolder.firstCharacter; + if (!m_fontAsset.characterLookupTable.ContainsKey(firstCharacter)) + m_fontAsset.TryAddCharacterInternal(firstCharacter, out TMP_Character character); + + uint secondCharacter = m_SerializedPropertyHolder.secondCharacter; + if (!m_fontAsset.characterLookupTable.ContainsKey(secondCharacter)) + m_fontAsset.TryAddCharacterInternal(secondCharacter, out TMP_Character character); // Sort Kerning Pairs & Reload Font Asset if new kerning pair was added. if (errorCode != -1) { - m_kerningTable.SortKerningPairs(); - m_fontAsset.ReadFontAssetDefinition(); + m_FontFeatureTable.SortGlyphPairAdjustmentRecords(); serializedObject.ApplyModifiedProperties(); isAssetDirty = true; m_isSearchDirty = true; @@ -1461,30 +1506,29 @@ private bool DoSelectionCheck(Rect selectionArea) return false; } - GlyphValueRecord GetGlyphAdjustments (SerializedProperty property) + TMP_GlyphValueRecord GetValueRecord(SerializedProperty property) { - GlyphValueRecord record = new GlyphValueRecord(); - record.xPlacement = property.FindPropertyRelative("xPlacement").floatValue; - record.yPlacement = property.FindPropertyRelative("yPlacement").floatValue; - record.xAdvance = property.FindPropertyRelative("xAdvance").floatValue; - record.yAdvance = property.FindPropertyRelative("yAdvance").floatValue; + TMP_GlyphValueRecord record = new TMP_GlyphValueRecord(); + record.xPlacement = property.FindPropertyRelative("m_XPlacement").floatValue; + record.yPlacement = property.FindPropertyRelative("m_YPlacement").floatValue; + record.xAdvance = property.FindPropertyRelative("m_XAdvance").floatValue; + record.yAdvance = property.FindPropertyRelative("m_YAdvance").floatValue; return record; } void RemoveAdjustmentPairFromList(int index) { - if (index > m_KerningPairs_prop.arraySize) + if (index > m_GlyphPairAdjustmentRecords_prop.arraySize) return; - m_KerningPairs_prop.DeleteArrayElementAtIndex(index); + m_GlyphPairAdjustmentRecords_prop.DeleteArrayElementAtIndex(index); serializedObject.ApplyModifiedProperties(); m_fontAsset.ReadFontAssetDefinition(); } - /// /// /// @@ -1603,26 +1647,34 @@ void SearchKerningTable(string searchPattern, ref List searchResults) searchResults.Clear(); - int arraySize = m_KerningPairs_prop.arraySize; + // Lookup glyph index of potential characters contained in the search pattern. + uint firstGlyphIndex = 0; + if (searchPattern.Length > 0 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[0], out TMP_Character firstCharacterSearch)) + firstGlyphIndex = firstCharacterSearch.glyphIndex; + + uint secondGlyphIndex = 0; + if (searchPattern.Length > 1 && m_fontAsset.characterLookupTable.TryGetValue(searchPattern[1], out TMP_Character secondCharacterSearch)) + secondGlyphIndex = secondCharacterSearch.glyphIndex; + + int arraySize = m_GlyphPairAdjustmentRecords_prop.arraySize; for (int i = 0; i < arraySize; i++) { - SerializedProperty sourceGlyph = m_KerningPairs_prop.GetArrayElementAtIndex(i); + SerializedProperty record = m_GlyphPairAdjustmentRecords_prop.GetArrayElementAtIndex(i); + + SerializedProperty firstAdjustmentRecord = record.FindPropertyRelative("m_FirstAdjustmentRecord"); + SerializedProperty secondAdjustmentRecord = record.FindPropertyRelative("m_SecondAdjustmentRecord"); - int firstGlyph = sourceGlyph.FindPropertyRelative("m_FirstGlyph").intValue; - int secondGlyph = sourceGlyph.FindPropertyRelative("m_SecondGlyph").intValue; + int firstGlyph = firstAdjustmentRecord.FindPropertyRelative("m_GlyphIndex").intValue; + int secondGlyph = secondAdjustmentRecord.FindPropertyRelative("m_GlyphIndex").intValue; - if (searchPattern.Length == 1 && (firstGlyph == searchPattern[0] || secondGlyph == searchPattern[0])) - searchResults.Add(i); - else if (searchPattern.Length == 2 && firstGlyph == searchPattern[0] && secondGlyph == searchPattern[1]) - searchResults.Add(i); - else if (firstGlyph.ToString("x").Contains(searchPattern)) + if (firstGlyphIndex == firstGlyph && secondGlyphIndex == secondGlyph) searchResults.Add(i); - else if (firstGlyph.ToString("X").Contains(searchPattern)) + else if (searchPattern.Length == 1 && (firstGlyphIndex == firstGlyph || firstGlyphIndex == secondGlyph)) searchResults.Add(i); - else if (secondGlyph.ToString("x").Contains(searchPattern)) + else if (firstGlyph.ToString().Contains(searchPattern)) searchResults.Add(i); - else if (secondGlyph.ToString("X").Contains(searchPattern)) + else if (secondGlyph.ToString().Contains(searchPattern)) searchResults.Add(i); } } diff --git a/Scripts/Editor/TMP_GlyphPairAdjustmentRecordPropertyDrawer.cs b/Scripts/Editor/TMP_GlyphPairAdjustmentRecordPropertyDrawer.cs new file mode 100644 index 0000000..77268ba --- /dev/null +++ b/Scripts/Editor/TMP_GlyphPairAdjustmentRecordPropertyDrawer.cs @@ -0,0 +1,382 @@ +using UnityEngine; +using UnityEngine.TextCore; +using UnityEngine.TextCore.LowLevel; +using UnityEditor; +using System.Collections; +using System.Text.RegularExpressions; + + +namespace TMPro.EditorUtilities +{ + + [CustomPropertyDrawer(typeof(TMP_GlyphPairAdjustmentRecord))] + public class TMP_GlyphPairAdjustmentRecordPropertyDrawer : PropertyDrawer + { + private bool isEditingEnabled = false; + private bool isSelectable = false; + + private string m_FirstCharacter = string.Empty; + private string m_SecondCharacter = string.Empty; + private string m_PreviousInput; + + static GUIContent s_CharacterTextFieldLabel = new GUIContent("Char:", "Enter the character or its UTF16 or UTF32 Unicode character escape sequence. For UTF16 use \"\\uFF00\" and for UTF32 use \"\\UFF00FF00\" representation."); + + public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) + { + SerializedProperty prop_FirstAdjustmentRecord = property.FindPropertyRelative("m_FirstAdjustmentRecord"); + SerializedProperty prop_SecondAdjustmentRecord = property.FindPropertyRelative("m_SecondAdjustmentRecord"); + + SerializedProperty prop_FirstGlyphIndex = prop_FirstAdjustmentRecord.FindPropertyRelative("m_GlyphIndex"); + SerializedProperty prop_FirstGlyphValueRecord = prop_FirstAdjustmentRecord.FindPropertyRelative("m_GlyphValueRecord"); + + SerializedProperty prop_SecondGlyphIndex = prop_SecondAdjustmentRecord.FindPropertyRelative("m_GlyphIndex"); + SerializedProperty prop_SecondGlyphValueRecord = prop_SecondAdjustmentRecord.FindPropertyRelative("m_GlyphValueRecord"); + + SerializedProperty prop_FontFeatureLookupFlags = property.FindPropertyRelative("m_FeatureLookupFlags"); + + position.yMin += 2; + + float width = position.width / 2; + float padding = 5.0f; + + Rect rect; + + isEditingEnabled = GUI.enabled; + isSelectable = label.text == "Selectable" ? true : false; + + if (isSelectable) + GUILayoutUtility.GetRect(position.width, 75); + else + GUILayoutUtility.GetRect(position.width, 55); + + GUIStyle style = new GUIStyle(EditorStyles.label); + style.richText = true; + + // First Glyph + GUI.enabled = isEditingEnabled; + if (isSelectable) + { + rect = new Rect(position.x + 70, position.y, position.width, 49); + + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_FirstGlyphIndex.intValue)).x; + EditorGUI.LabelField(new Rect(position.x + (64 - labelWidth) / 2, position.y + 60, 64f, 18f), new GUIContent("ID: " + prop_FirstGlyphIndex.intValue + ""), style); + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 30f; + + rect = new Rect(position.x + 70, position.y + 10, (width - 70) - padding, 18); + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_XPlacement"), new GUIContent("OX:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_YPlacement"), new GUIContent("OY:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_XAdvance"), new GUIContent("AX:")); + + //rect.y += 20; + //EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_YAdvance"), new GUIContent("AY:")); + + DrawGlyph((uint)prop_FirstGlyphIndex.intValue, new Rect(position.x, position.y, position.width, position.height), property); + } + else + { + rect = new Rect(position.x, position.y, width / 2 * 0.8f - padding, 18); + EditorGUIUtility.labelWidth = 40f; + + // First Character Lookup + GUI.SetNextControlName("FirstCharacterField"); + EditorGUI.BeginChangeCheck(); + string firstCharacter = EditorGUI.TextField(rect, s_CharacterTextFieldLabel, m_FirstCharacter); + + if (GUI.GetNameOfFocusedControl() == "FirstCharacterField") + { + if (ValidateInput(firstCharacter)) + { + //Debug.Log("1st Unicode value: [" + firstCharacter + "]"); + + uint unicode = GetUnicodeCharacter(firstCharacter); + + // Lookup glyph index + TMP_SerializedPropertyHolder propertyHolder = property.serializedObject.targetObject as TMP_SerializedPropertyHolder; + TMP_FontAsset fontAsset = propertyHolder.fontAsset; + if (fontAsset != null) + { + prop_FirstGlyphIndex.intValue = (int)fontAsset.GetGlyphIndex(unicode); + propertyHolder.firstCharacter = unicode; + } + } + } + + if (EditorGUI.EndChangeCheck()) + m_FirstCharacter = firstCharacter; + + // First Glyph Index + rect.x += width / 2 * 0.8f; + + EditorGUIUtility.labelWidth = 25f; + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, prop_FirstGlyphIndex, new GUIContent("ID:")); + if (EditorGUI.EndChangeCheck()) + { + + } + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 25f; + + rect = new Rect(position.x, position.y + 20, width * 0.5f - padding, 18); + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_XPlacement"), new GUIContent("OX")); + + rect.x += width * 0.5f; + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_YPlacement"), new GUIContent("OY")); + + rect.x = position.x; + rect.y += 20; + EditorGUI.PropertyField(rect, prop_FirstGlyphValueRecord.FindPropertyRelative("m_XAdvance"), new GUIContent("AX")); + + //rect.x += width * 0.5f; + //EditorGUI.PropertyField(rect, prop_FirstGlyphAdjustment.FindPropertyRelative("m_YAdvance"), new GUIContent("AY")); + + } + + + // Second Glyph + GUI.enabled = isEditingEnabled; + if (isSelectable) + { + float labelWidth = GUI.skin.label.CalcSize(new GUIContent("ID: " + prop_SecondGlyphIndex.intValue)).x; + EditorGUI.LabelField(new Rect(position.width / 2 + 20 + (64 - labelWidth) / 2, position.y + 60, 64f, 18f), new GUIContent("ID: " + prop_SecondGlyphIndex.intValue + ""), style); + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 30f; + + rect = new Rect(position.width / 2 + 20 + 70, position.y + 10, (width - 70) - padding, 18); + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_XPlacement"), new GUIContent("OX:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_YPlacement"), new GUIContent("OY:")); + + rect.y += 20; + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_XAdvance"), new GUIContent("AX:")); + + //rect.y += 20; + //EditorGUI.PropertyField(rect, prop_SecondGlyphAdjustment.FindPropertyRelative("m_YAdvance"), new GUIContent("AY")); + + DrawGlyph((uint)prop_SecondGlyphIndex.intValue, new Rect(position.width / 2 + 20, position.y, position.width, position.height), property); + } + else + { + rect = new Rect(position.width / 2 + 20, position.y, width / 2 * 0.8f - padding, 18); + EditorGUIUtility.labelWidth = 40f; + + // Second Character Lookup + GUI.SetNextControlName("SecondCharacterField"); + EditorGUI.BeginChangeCheck(); + string secondCharacter = EditorGUI.TextField(rect, s_CharacterTextFieldLabel, m_SecondCharacter); + + if (GUI.GetNameOfFocusedControl() == "SecondCharacterField") + { + if (ValidateInput(secondCharacter)) + { + //Debug.Log("2nd Unicode value: [" + secondCharacter + "]"); + + uint unicode = GetUnicodeCharacter(secondCharacter); + + // Lookup glyph index + TMP_SerializedPropertyHolder propertyHolder = property.serializedObject.targetObject as TMP_SerializedPropertyHolder; + TMP_FontAsset fontAsset = propertyHolder.fontAsset; + if (fontAsset != null) + { + prop_SecondGlyphIndex.intValue = (int)fontAsset.GetGlyphIndex(unicode); + propertyHolder.secondCharacter = unicode; + } + } + } + + if (EditorGUI.EndChangeCheck()) + m_SecondCharacter = secondCharacter; + + // Second Glyph Index + rect.x += width / 2 * 0.8f; + + EditorGUIUtility.labelWidth = 25f; + EditorGUI.BeginChangeCheck(); + EditorGUI.PropertyField(rect, prop_SecondGlyphIndex, new GUIContent("ID:")); + if (EditorGUI.EndChangeCheck()) + { + + } + + GUI.enabled = isEditingEnabled; + EditorGUIUtility.labelWidth = 25f; + + rect = new Rect(position.width / 2 + 20, position.y + 20, width * 0.5f - padding, 18); + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_XPlacement"), new GUIContent("OX")); + + rect.x += width * 0.5f; + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_YPlacement"), new GUIContent("OY")); + + rect.x = position.width / 2 + 20; + rect.y += 20; + EditorGUI.PropertyField(rect, prop_SecondGlyphValueRecord.FindPropertyRelative("m_XAdvance"), new GUIContent("AX")); + + //rect.x += width * 0.5f; + //EditorGUI.PropertyField(rect, prop_SecondGlyphAdjustment.FindPropertyRelative("m_YAdvance"), new GUIContent("AY")); + } + + // Font Feature Lookup Flags + if (isSelectable) + { + EditorGUIUtility.labelWidth = 55f; + + rect.x = position.width - 255; + rect.y += 23; + rect.width = 270; // width - 70 - padding; + + FontFeatureLookupFlags flags = (FontFeatureLookupFlags)prop_FontFeatureLookupFlags.intValue; + + EditorGUI.BeginChangeCheck(); + flags = (FontFeatureLookupFlags)EditorGUI.EnumFlagsField(rect, new GUIContent("Options:"), flags); + if (EditorGUI.EndChangeCheck()) + { + prop_FontFeatureLookupFlags.intValue = (int)flags; + } + } + + } + + bool ValidateInput(string source) + { + int length = string.IsNullOrEmpty(source) ? 0 : source.Length; + + ////Filter out unwanted characters. + Event evt = Event.current; + + char c = evt.character; + + if (c != '\0') + { + switch (length) + { + case 0: + break; + case 1: + if (source != m_PreviousInput) + return true; + + if ((source[0] == '\\' && (c == 'u' || c == 'U')) == false) + evt.character = '\0'; + + break; + case 2: + case 3: + case 4: + case 5: + if ((c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) + evt.character = '\0'; + break; + case 6: + case 7: + case 8: + case 9: + if (source[1] == 'u' || (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F')) + evt.character = '\0'; + + // Validate input + if (length == 6 && source[1] == 'u' && source != m_PreviousInput) + return true; + break; + case 10: + if (source != m_PreviousInput) + return true; + + evt.character = '\0'; + break; + } + } + + m_PreviousInput = source; + + return false; + } + + uint GetUnicodeCharacter (string source) + { + uint unicode; + + if (source.Length == 1) + unicode = source[0]; + else if (source.Length == 6) + unicode = (uint)TMP_TextUtilities.StringHexToInt(source.Replace("\\u", "")); + else + unicode = (uint)TMP_TextUtilities.StringHexToInt(source.Replace("\\U", "")); + + return unicode; + } + + void DrawGlyph(uint glyphIndex, Rect position, SerializedProperty property) + { + // Get a reference to the sprite texture + TMP_FontAsset fontAsset = property.serializedObject.targetObject as TMP_FontAsset; + + if (fontAsset == null) + return; + + // Check if glyph currently exists in the atlas texture. + if (!fontAsset.glyphLookupTable.TryGetValue(glyphIndex, out Glyph glyph)) + return; + + // Get reference to atlas texture. + int atlasIndex = fontAsset.m_AtlasTextureIndex; + Texture2D atlasTexture = fontAsset.atlasTextures.Length > atlasIndex ? fontAsset.atlasTextures[atlasIndex] : null; + + if (atlasTexture == null) + return; + + Material mat; + if (((GlyphRasterModes)fontAsset.atlasRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP) + { + mat = TMP_FontAssetEditor.internalBitmapMaterial; + + if (mat == null) + return; + + mat.mainTexture = atlasTexture; + } + else + { + mat = TMP_FontAssetEditor.internalSDFMaterial; + + if (mat == null) + return; + + mat.mainTexture = atlasTexture; + mat.SetFloat(ShaderUtilities.ID_GradientScale, fontAsset.atlasPadding + 1); + } + + // Draw glyph from atlas texture. + Rect glyphDrawPosition = new Rect(position.x, position.y + 2, 64, 60); + + GlyphRect glyphRect = glyph.glyphRect; + + float normalizedHeight = fontAsset.faceInfo.ascentLine - fontAsset.faceInfo.descentLine; + float scale = glyphDrawPosition.width / normalizedHeight; + + // Compute the normalized texture coordinates + Rect texCoords = new Rect((float)glyphRect.x / atlasTexture.width, (float)glyphRect.y / atlasTexture.height, (float)glyphRect.width / atlasTexture.width, (float)glyphRect.height / atlasTexture.height); + + if (Event.current.type == EventType.Repaint) + { + glyphDrawPosition.x += (glyphDrawPosition.width - glyphRect.width * scale) / 2; + glyphDrawPosition.y += (glyphDrawPosition.height - glyphRect.height * scale) / 2; + glyphDrawPosition.width = glyphRect.width * scale; + glyphDrawPosition.height = glyphRect.height * scale; + + // Could switch to using the default material of the font asset which would require passing scale to the shader. + Graphics.DrawTexture(glyphDrawPosition, atlasTexture, texCoords, 0, 0, 0, 0, new Color(1f, 1f, 1f), mat); + } + } + + + } +} \ No newline at end of file diff --git a/Scripts/Editor/SpriteInfoDrawer.cs.meta b/Scripts/Editor/TMP_GlyphPairAdjustmentRecordPropertyDrawer.cs.meta similarity index 74% rename from Scripts/Editor/SpriteInfoDrawer.cs.meta rename to Scripts/Editor/TMP_GlyphPairAdjustmentRecordPropertyDrawer.cs.meta index 47f938b..b95203f 100644 --- a/Scripts/Editor/SpriteInfoDrawer.cs.meta +++ b/Scripts/Editor/TMP_GlyphPairAdjustmentRecordPropertyDrawer.cs.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 -guid: e87e16ece4884c3bb85cc0e02f133a9f +guid: d256fa541faf5d4409992c631adb98a1 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/Scripts/Editor/TMP_GlyphPropertyDrawer.cs b/Scripts/Editor/TMP_GlyphPropertyDrawer.cs index 85c03a0..b92dfd6 100644 --- a/Scripts/Editor/TMP_GlyphPropertyDrawer.cs +++ b/Scripts/Editor/TMP_GlyphPropertyDrawer.cs @@ -11,12 +11,6 @@ namespace TMPro.EditorUtilities [CustomPropertyDrawer(typeof(Glyph))] public class TMP_GlyphPropertyDrawer : PropertyDrawer { - //[SerializeField] - //static Material s_InternalSDFMaterial; - - //[SerializeField] - //static Material s_InternalBitmapMaterial; - public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { SerializedProperty prop_GlyphIndex = property.FindPropertyRelative("m_Index"); @@ -79,6 +73,7 @@ void DrawGlyph(Rect position, SerializedProperty property) return; mat.mainTexture = atlasTexture; + mat.SetColor("_Color", Color.white); } else { diff --git a/Scripts/Editor/TMP_PackageUtilities.cs b/Scripts/Editor/TMP_PackageUtilities.cs index bd8f437..d2fc46d 100644 --- a/Scripts/Editor/TMP_PackageUtilities.cs +++ b/Scripts/Editor/TMP_PackageUtilities.cs @@ -97,7 +97,7 @@ void OnGUI() // Make sure Asset Serialization mode is set to ForceText and Version Control mode to Visible Meta Files. if (CheckProjectSerializationAndSourceControlModes() == true) { - EditorCoroutine.StartCoroutine(ScanProjectFiles()); + TMP_EditorCoroutine.StartCoroutine(ScanProjectFiles()); } else { diff --git a/Scripts/Editor/TMP_SerializedPropertyHolder.cs b/Scripts/Editor/TMP_SerializedPropertyHolder.cs new file mode 100644 index 0000000..2ba34d6 --- /dev/null +++ b/Scripts/Editor/TMP_SerializedPropertyHolder.cs @@ -0,0 +1,14 @@ +using UnityEngine; +using UnityEditor; + +namespace TMPro +{ + class TMP_SerializedPropertyHolder : ScriptableObject + { + public TMP_FontAsset fontAsset; + public uint firstCharacter; + public uint secondCharacter; + + public TMP_GlyphPairAdjustmentRecord glyphPairAdjustmentRecord = new TMP_GlyphPairAdjustmentRecord(new TMP_GlyphAdjustmentRecord(), new TMP_GlyphAdjustmentRecord()); + } +} \ No newline at end of file diff --git a/Scripts/Editor/KerningPairDrawer.cs.meta b/Scripts/Editor/TMP_SerializedPropertyHolder.cs.meta similarity index 74% rename from Scripts/Editor/KerningPairDrawer.cs.meta rename to Scripts/Editor/TMP_SerializedPropertyHolder.cs.meta index 2f4a487..cde31db 100644 --- a/Scripts/Editor/KerningPairDrawer.cs.meta +++ b/Scripts/Editor/TMP_SerializedPropertyHolder.cs.meta @@ -1,6 +1,7 @@ fileFormatVersion: 2 -guid: 78b9ad527fe44d7cb05bbb77fbf351c0 +guid: 9c4a050f089abb04ebd4125e419f4548 MonoImporter: + externalObjects: {} serializedVersion: 2 defaultReferences: [] executionOrder: 0 diff --git a/Scripts/Editor/TMP_SettingsEditor.cs b/Scripts/Editor/TMP_SettingsEditor.cs index 4657eb1..571c9cd 100644 --- a/Scripts/Editor/TMP_SettingsEditor.cs +++ b/Scripts/Editor/TMP_SettingsEditor.cs @@ -40,9 +40,11 @@ internal class Styles public static readonly GUIContent tintAllSpritesLabel = new GUIContent("Tint All Sprites"); public static readonly GUIContent parseEscapeCharactersLabel = new GUIContent("Parse Escape Sequence"); - public static readonly GUIContent missingGlyphsTitleLabel = new GUIContent("Missing glyphs"); - public static readonly GUIContent missingGlyphLabel = new GUIContent("Replacement", "The glyph to be used as a replacement when a glyph can't be found in a font asset."); - public static readonly GUIContent disableWarningsLabel = new GUIContent("Disable warnings"); + public static readonly GUIContent dynamicFontSystemSettingsLabel = new GUIContent("Dynamic Font System Settings"); + public static readonly GUIContent getFontFeaturesAtRuntime = new GUIContent("Get Font Features at Runtime", "Determines if Glyph Adjustment Data will be retrieved from font files at runtime when new characters and glyphs are added to font assets."); + + public static readonly GUIContent missingGlyphLabel = new GUIContent("Replacement Character", "The character to be displayed when the requested character is not found in any font asset or fallbacks."); + public static readonly GUIContent disableWarningsLabel = new GUIContent("Disable warnings", "Disable warning messages in the Console."); public static readonly GUIContent defaultSpriteAssetLabel = new GUIContent("Default Sprite Asset", "The Sprite Asset that will be assigned by default when using the tag when no Sprite Asset is specified."); public static readonly GUIContent enableEmojiSupportLabel = new GUIContent("iOS Emoji Support", "Enables Emoji support for Touch Screen Keyboards on target devices."); @@ -82,6 +84,8 @@ internal class Styles SerializedProperty m_PropParseEscapeCharacters; SerializedProperty m_PropMissingGlyphCharacter; + SerializedProperty m_GetFontFeaturesAtRuntime; + SerializedProperty m_PropWarningsDisabled; SerializedProperty m_PropLeadingCharacters; @@ -133,6 +137,8 @@ public void OnEnable() m_PropWarningsDisabled = serializedObject.FindProperty("m_warningsDisabled"); + m_GetFontFeaturesAtRuntime = serializedObject.FindProperty("m_GetFontFeaturesAtRuntime"); + m_PropLeadingCharacters = serializedObject.FindProperty("m_leadingCharacters"); m_PropFollowingCharacters = serializedObject.FindProperty("m_followingCharacters"); } @@ -173,8 +179,9 @@ public override void OnInspectorGUI() // MISSING GLYPHS EditorGUILayout.BeginVertical(EditorStyles.helpBox); - GUILayout.Label(Styles.missingGlyphsTitleLabel, EditorStyles.boldLabel); + GUILayout.Label(Styles.dynamicFontSystemSettingsLabel, EditorStyles.boldLabel); EditorGUI.indentLevel = 1; + EditorGUILayout.PropertyField(m_GetFontFeaturesAtRuntime, Styles.getFontFeaturesAtRuntime); EditorGUILayout.PropertyField(m_PropMissingGlyphCharacter, Styles.missingGlyphLabel); EditorGUILayout.PropertyField(m_PropWarningsDisabled, Styles.disableWarningsLabel); EditorGUI.indentLevel = 0; diff --git a/Scripts/Editor/TextAlignmentDrawer.cs b/Scripts/Editor/TMP_TextAlignmentDrawer.cs similarity index 98% rename from Scripts/Editor/TextAlignmentDrawer.cs rename to Scripts/Editor/TMP_TextAlignmentDrawer.cs index e8caded..dbb271c 100644 --- a/Scripts/Editor/TextAlignmentDrawer.cs +++ b/Scripts/Editor/TMP_TextAlignmentDrawer.cs @@ -5,7 +5,7 @@ namespace TMPro.EditorUtilities { [CustomPropertyDrawer(typeof(TextAlignmentOptions))] - public class TextAlignmentDrawer : PropertyDrawer + public class TMP_TextAlignmentDrawer : PropertyDrawer { const int k_AlignmentButtonWidth = 24; const int k_AlignmentButtonHeight = 20; diff --git a/Scripts/Editor/TextAlignmentDrawer.cs.meta b/Scripts/Editor/TMP_TextAlignmentDrawer.cs.meta similarity index 100% rename from Scripts/Editor/TextAlignmentDrawer.cs.meta rename to Scripts/Editor/TMP_TextAlignmentDrawer.cs.meta diff --git a/Scripts/Editor/TMPro_FontAssetCreatorWindow.cs b/Scripts/Editor/TMPro_FontAssetCreatorWindow.cs index fd6d559..95be939 100644 --- a/Scripts/Editor/TMPro_FontAssetCreatorWindow.cs +++ b/Scripts/Editor/TMPro_FontAssetCreatorWindow.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Threading; using System.IO; +using System.Text.RegularExpressions; using UnityEngine.TextCore; using UnityEngine.TextCore.LowLevel; using Object = UnityEngine.Object; @@ -166,7 +167,7 @@ enum FontPackingModes { Fast = 0, Optimum = 4 }; private FaceInfo m_FaceInfo; - bool m_IncludeKerningPairs; + bool m_IncludeFontFeatures; public void OnEnable() @@ -593,7 +594,16 @@ void DrawControls() if (m_CharactersFromFile != null) { - m_CharacterSequence = m_CharactersFromFile.text; + Regex rx = new Regex(@"(? + { + if (match.Value.StartsWith("\\U")) + return char.ConvertFromUtf32(int.Parse(match.Value.Replace("\\U", ""), NumberStyles.HexNumber)); + + return char.ConvertFromUtf32(int.Parse(match.Value.Replace("\\u", ""), NumberStyles.HexNumber)); + }); } break; } @@ -619,7 +629,7 @@ void DrawControls() m_IsFontAtlasInvalid = true; } - m_IncludeKerningPairs = EditorGUILayout.Toggle("Get Kerning Pairs", m_IncludeKerningPairs); + m_IncludeFontFeatures = EditorGUILayout.Toggle("Get Kerning Pairs", m_IncludeFontFeatures); EditorGUILayout.Space(); } @@ -673,13 +683,18 @@ void DrawControls() for (int i = 0; i < m_CharacterSequence.Length; i++) { - // Check to make sure we don't include duplicates - if (char_List.FindIndex(item => item == m_CharacterSequence[i]) == -1) - char_List.Add(m_CharacterSequence[i]); - else + uint unicode = m_CharacterSequence[i]; + + // Handle surrogate pairs + if (i < m_CharacterSequence.Length - 1 && char.IsHighSurrogate((char)unicode) && char.IsLowSurrogate(m_CharacterSequence[i + 1])) { - //Debug.Log("Character [" + characterSequence[i] + "] is a duplicate."); + unicode = (uint)char.ConvertToUtf32(m_CharacterSequence[i], m_CharacterSequence[i + 1]); + i += 1; } + + // Check to make sure we don't include duplicates + if (char_List.FindIndex(item => item == unicode) == -1) + char_List.Add(unicode); } characterSet = char_List.ToArray(); @@ -1277,8 +1292,8 @@ void Save_Bitmap_FontAsset(string filePath) fontAsset.SortGlyphAndCharacterTables(); // Get and Add Kerning Pairs to Font Asset - if (m_IncludeKerningPairs) - fontAsset.kerningTable = GetKerningTable(); + if (m_IncludeFontFeatures) + fontAsset.fontFeatureTable = GetKerningTable(); // Add Font Atlas as Sub-Asset @@ -1332,8 +1347,8 @@ void Save_Bitmap_FontAsset(string filePath) fontAsset.SortGlyphAndCharacterTables(); // Get and Add Kerning Pairs to Font Asset - if (m_IncludeKerningPairs) - fontAsset.kerningTable = GetKerningTable(); + if (m_IncludeFontFeatures) + fontAsset.fontFeatureTable = GetKerningTable(); // Add Font Atlas as Sub-Asset fontAsset.atlasTextures = new Texture2D[] { m_FontAtlasTexture }; @@ -1431,8 +1446,8 @@ void Save_SDF_FontAsset(string filePath) fontAsset.SortGlyphAndCharacterTables(); // Get and Add Kerning Pairs to Font Asset - if (m_IncludeKerningPairs) - fontAsset.kerningTable = GetKerningTable(); + if (m_IncludeFontFeatures) + fontAsset.fontFeatureTable = GetKerningTable(); // Add Font Atlas as Sub-Asset fontAsset.atlasTextures = new Texture2D[] { m_FontAtlasTexture }; @@ -1496,8 +1511,8 @@ void Save_SDF_FontAsset(string filePath) // Get and Add Kerning Pairs to Font Asset // TODO: Check and preserve existing adjustment pairs. - if (m_IncludeKerningPairs) - fontAsset.kerningTable = GetKerningTable(); + if (m_IncludeFontFeatures) + fontAsset.fontFeatureTable = GetKerningTable(); // Add Font Atlas as Sub-Asset fontAsset.atlasTextures = new Texture2D[] { m_FontAtlasTexture }; @@ -1581,7 +1596,7 @@ FontAssetCreationSettings SaveFontCreationSettings() //settings.fontStyle = (int)m_FontStyle; //settings.fontStyleModifier = m_FontStyleValue; settings.renderMode = (int)m_GlyphRenderMode; - settings.includeFontFeatures = m_IncludeKerningPairs; + settings.includeFontFeatures = m_IncludeFontFeatures; return settings; } @@ -1607,7 +1622,7 @@ void LoadFontCreationSettings(FontAssetCreationSettings settings) //m_FontStyle = (FaceStyles)settings.fontStyle; //m_FontStyleValue = settings.fontStyleModifier; m_GlyphRenderMode = (GlyphRenderMode)settings.renderMode; - m_IncludeKerningPairs = settings.includeFontFeatures; + m_IncludeFontFeatures = settings.includeFontFeatures; } @@ -1699,41 +1714,23 @@ void CheckForLegacyGlyphRenderMode() // Get Kerning Pairs - public KerningTable GetKerningTable() + public TMP_FontFeatureTable GetKerningTable() { GlyphPairAdjustmentRecord[] adjustmentRecords = FontEngine.GetGlyphPairAdjustmentTable(m_AvailableGlyphsToAdd.ToArray()); if (adjustmentRecords == null) return null; - KerningTable kerningTable = new KerningTable(); + TMP_FontFeatureTable fontFeatureTable = new TMP_FontFeatureTable(); for (int i = 0; i < adjustmentRecords.Length; i++) { - GlyphAdjustmentRecord firstRecord = adjustmentRecords[i].firstAdjustmentRecord; - GlyphAdjustmentRecord secondRecord = adjustmentRecords[i].secondAdjustmentRecord; - - // Lookup Unicode for the referenced glyphs - List firstRecordUnicodeIndexes = m_GlyphLookupMap[firstRecord.glyphIndex]; - List secondRecordUnicodeIndexes = m_GlyphLookupMap[secondRecord.glyphIndex]; - - for (int first = 0; first < firstRecordUnicodeIndexes.Count; first++) - { - uint firstUnicode = firstRecordUnicodeIndexes[first]; - - for (int second = 0; second < secondRecordUnicodeIndexes.Count; second++) - { - uint secondUnicode = secondRecordUnicodeIndexes[second]; - - // Add kerning pair for the given unicode characters. - kerningTable.AddGlyphPairAdjustmentRecord(firstUnicode, new GlyphValueRecord(firstRecord.glyphValueRecord), secondUnicode, new GlyphValueRecord(secondRecord.glyphValueRecord)); - } - } + fontFeatureTable.glyphPairAdjustmentRecords.Add(new TMP_GlyphPairAdjustmentRecord(adjustmentRecords[i])); } - kerningTable.SortKerningPairs(); + fontFeatureTable.SortGlyphPairAdjustmentRecords(); - return kerningTable; + return fontFeatureTable; } } } \ No newline at end of file diff --git a/Scripts/Runtime/TMP_Character.cs b/Scripts/Runtime/TMP_Character.cs index 677c71a..8fc161e 100644 --- a/Scripts/Runtime/TMP_Character.cs +++ b/Scripts/Runtime/TMP_Character.cs @@ -32,5 +32,20 @@ public TMP_Character(uint unicode, Glyph glyph) this.glyphIndex = glyph.index; this.scale = 1.0f; } + + /// + /// Constructor for new character + /// + /// Unicode value. + /// Glyph index. + internal TMP_Character(uint unicode, uint glyphIndex) + { + m_ElementType = TextElementType.Character; + + this.unicode = unicode; + this.glyph = null; + this.glyphIndex = glyphIndex; + this.scale = 1.0f; + } } } diff --git a/Scripts/Runtime/TMP_CharacterInfo.cs b/Scripts/Runtime/TMP_CharacterInfo.cs index f9dc279..e15c46a 100644 --- a/Scripts/Runtime/TMP_CharacterInfo.cs +++ b/Scripts/Runtime/TMP_CharacterInfo.cs @@ -28,7 +28,7 @@ public struct TMP_CharacterInfo public int stringLength; public TMP_TextElementType elementType; - public TMP_Character textElement; + public TMP_TextElement textElement; public TMP_FontAsset fontAsset; public TMP_SpriteAsset spriteAsset; public int spriteIndex; diff --git a/Scripts/Runtime/TMP_FontAsset.cs b/Scripts/Runtime/TMP_FontAsset.cs index a1913a5..fc8fa2c 100644 --- a/Scripts/Runtime/TMP_FontAsset.cs +++ b/Scripts/Runtime/TMP_FontAsset.cs @@ -3,6 +3,7 @@ using UnityEngine.Serialization; using UnityEngine.TextCore; using UnityEngine.TextCore.LowLevel; +using UnityEngine.Profiling; using System.Collections; using System.Collections.Generic; using System.Linq; @@ -273,33 +274,24 @@ public GlyphRenderMode atlasRenderMode [SerializeField] private GlyphRenderMode m_AtlasRenderMode; - // Glyph Info + // Legacy field that will be removed. [SerializeField] internal List m_glyphInfoList; - /// - /// Dictionary containing the kerning data - /// - public Dictionary kerningLookupDictionary - { - get { return m_KerningLookupDictionary; } - } - private Dictionary m_KerningLookupDictionary; + [SerializeField] + [FormerlySerializedAs("m_kerningInfo")] + internal KerningTable m_KerningTable = new KerningTable(); /// - /// + /// Table containing the various font features of this font asset. /// - public KerningTable kerningTable + public TMP_FontFeatureTable fontFeatureTable { - get { return m_KerningTable; } - internal set { m_KerningTable = value; } + get { return m_FontFeatureTable; } + internal set { m_FontFeatureTable = value; } } - [SerializeField] - [FormerlySerializedAs("m_kerningInfo")] - private KerningTable m_KerningTable = new KerningTable(); - - private GlyphPairAdjustmentRecord[] m_GlyphPairAdjustmentRecords; + private TMP_FontFeatureTable m_FontFeatureTable = new TMP_FontFeatureTable(); /// /// List containing the Fallback font assets for this font. @@ -399,6 +391,8 @@ public static TMP_FontAsset CreateFontAsset(Font font, int samplingPointSize, in { TMP_FontAsset fontAsset = ScriptableObject.CreateInstance(); + fontAsset.m_Version = "1.1.0"; + // Set face information FontEngine.InitializeFontEngine(); FontEngine.LoadFontFace(font, samplingPointSize); @@ -516,8 +510,6 @@ void OnValidate() /// internal void InitializeDictionaryLookupTables() { - //Debug.Log("Reading [" + this.name + "] font definition."); - // Create new instance of the glyph lookup dictionary or clear the existing one. if (m_GlyphLookupDictionary == null) m_GlyphLookupDictionary = new Dictionary(); @@ -553,12 +545,6 @@ internal void InitializeDictionaryLookupTables() else m_CharacterLookupDictionary.Clear(); - // Allocated new character lookup map or clear the existing one. - if (m_CharacterLookupMap == null) - m_CharacterLookupMap = new Dictionary>(); - else - m_CharacterLookupMap.Clear(); - // Add the characters contained in the character table into the dictionary for faster lookup. for (int i = 0; i < m_CharacterTable.Count; i++) { @@ -574,49 +560,30 @@ internal void InitializeDictionaryLookupTables() { character.glyph = m_GlyphLookupDictionary[glyphIndex]; } - - // Fill character lookup map - if (m_CharacterLookupMap.TryGetValue(glyphIndex, out List unicodeList)) - unicodeList.Add(unicode); - else - m_CharacterLookupMap.Add(glyphIndex, new List { unicode }); - } - // Read Font Features which will include kerning data. - // TODO + // Upgrade Glyph Adjustment Table to the new Font Feature table and Glyph Pair Adjustment Records + if (m_KerningTable != null && m_KerningTable.kerningPairs != null && m_KerningTable.kerningPairs.Count > 0) + UpgradeGlyphAdjustmentTableToFontFeatureTable(); - // Read Kerning pairs and update Kerning pair dictionary for faster lookup. - if (m_KerningLookupDictionary == null) - m_KerningLookupDictionary = new Dictionary(); + // Read Font Features which will include kerning data. + if (m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary == null) + m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary = new Dictionary(); else - m_KerningLookupDictionary.Clear(); + m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.Clear(); - List glyphPairAdjustmentRecord = m_KerningTable.kerningPairs; - if (glyphPairAdjustmentRecord != null) + List glyphPairAdjustmentRecords = m_FontFeatureTable.m_GlyphPairAdjustmentRecords; + if (glyphPairAdjustmentRecords != null) { - for (int i = 0; i < glyphPairAdjustmentRecord.Count; i++) + for (int i = 0; i < glyphPairAdjustmentRecords.Count; i++) { - KerningPair pair = glyphPairAdjustmentRecord[i]; + TMP_GlyphPairAdjustmentRecord record = glyphPairAdjustmentRecords[i]; - // Convert legacy kerning data - if (pair.xOffset != 0) - glyphPairAdjustmentRecord[i].ConvertLegacyKerningData(); + long key = new GlyphPairKey(record).key; - KerningPairKey uniqueKey = new KerningPairKey(pair.firstGlyph, pair.secondGlyph); - - if (m_KerningLookupDictionary.ContainsKey((int)uniqueKey.key) == false) - { - m_KerningLookupDictionary.Add((int)uniqueKey.key, pair); - } - else - { - if (!TMP_Settings.warningsDisabled) - Debug.LogWarning("Kerning Key for [" + uniqueKey.ascii_Left + "] and [" + uniqueKey.ascii_Right + "] already exists."); - } + m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.Add(key, record); } } - } @@ -997,13 +964,12 @@ public static int[] GetCharactersArray(TMP_FontAsset fontAsset) /// List used in the process of adding new glyphs to the atlas texture. /// private List m_GlyphIndexList = new List(); - private Dictionary> m_CharacterLookupMap = new Dictionary>(); - //private Dictionary s_CharacterLookupMap = new Dictionary(); + private List m_CharactersToAdd = new List(); /// - /// Array used in the process of adding glyph adjustment pairs. + /// Internal static array used to avoid allocations when using the GetGlyphPairAdjustmentTable(). /// - private uint[] m_GlyphIndexes; + internal static uint[] s_GlyphIndexArray = new uint[16]; /// @@ -1026,13 +992,19 @@ public bool TryAddCharacters(uint[] unicodes) return false; } + Profiler.BeginSample("TMP.TryAddCharacter"); + // Load font face. if (FontEngine.LoadFontFace(m_SourceFontFile, m_FaceInfo.pointSize) != FontEngineError.Success) + { + Profiler.EndSample(); + return false; + } // Clear data structures used to track which glyph needs to be added to atlas texture. m_GlyphIndexList.Clear(); - m_CharacterLookupMap.Clear(); + m_CharactersToAdd.Clear(); bool isMissingCharacters = false; int unicodeCount = unicodes.Length; @@ -1054,31 +1026,27 @@ public bool TryAddCharacters(uint[] unicodes) continue; } + TMP_Character character = new TMP_Character(unicode, glyphIndex); + // Check if glyph is already contained in the font asset as the same glyph might be referenced by multiple characters. if (m_GlyphLookupDictionary.ContainsKey(glyphIndex)) { - TMP_Character character = new TMP_Character(unicode, m_GlyphLookupDictionary[glyphIndex]); + character.glyph = m_GlyphLookupDictionary[glyphIndex]; m_CharacterTable.Add(character); m_CharacterLookupDictionary.Add(unicode, character); continue; } - // Check if glyph is already on the list of glyphs to add - if (m_CharacterLookupMap.ContainsKey(glyphIndex)) - { - m_CharacterLookupMap[glyphIndex].Add(unicode); - continue; - } - - // TODO: Consider some alternative implementation that would be as efficient without resulting allocations. - m_CharacterLookupMap.Add(glyphIndex, new List { unicode }); m_GlyphIndexList.Add(glyphIndex); + m_CharactersToAdd.Add(character); } if (m_GlyphIndexList.Count == 0) { //Debug.LogWarning("No characters will be added to font asset [" + this.name + "] either because they are already present in the font asset or missing from the font file."); + Profiler.EndSample(); + return false; } @@ -1092,6 +1060,7 @@ public bool TryAddCharacters(uint[] unicodes) bool allCharactersAdded = FontEngine.TryAddGlyphsToTexture(m_GlyphIndexList, m_AtlasPadding, GlyphPackingMode.BestShortSideFit, m_FreeGlyphRects, m_UsedGlyphRects, m_AtlasRenderMode, m_AtlasTextures[m_AtlasTextureIndex], out Glyph[] glyphs); + // Add new glyphs to relevant data structures. for (int i = 0; i < glyphs.Length; i++) { Glyph glyph = glyphs[i]; @@ -1100,14 +1069,15 @@ public bool TryAddCharacters(uint[] unicodes) // Add new glyph to glyph table. m_GlyphTable.Add(glyph); m_GlyphLookupDictionary.Add(glyphIndex, glyph); + } - // Add new character(s) - foreach (uint unicode in m_CharacterLookupMap[glyphIndex]) - { - TMP_Character character = new TMP_Character(unicode, glyph); - m_CharacterTable.Add(character); - m_CharacterLookupDictionary.Add(unicode, character); - } + // Add new characters to relevant data structures. + for (int i = 0; i < m_CharactersToAdd.Count; i++) + { + TMP_Character character = m_CharactersToAdd[i]; + character.glyph = m_GlyphLookupDictionary[character.glyphIndex]; + m_CharacterTable.Add(character); + m_CharacterLookupDictionary.Add(character.unicode, character); } #if UNITY_EDITOR @@ -1115,6 +1085,8 @@ public bool TryAddCharacters(uint[] unicodes) UnityEditor.EditorUtility.SetDirty(this); #endif + Profiler.EndSample(); + return allCharactersAdded && !isMissingCharacters; } @@ -1145,7 +1117,7 @@ public bool TryAddCharacters(string characters) // Clear data structures used to track which glyph needs to be added to atlas texture. m_GlyphIndexList.Clear(); - m_CharacterLookupMap.Clear(); + m_CharactersToAdd.Clear(); bool isMissingCharacters = false; int characterCount = characters.Length; @@ -1170,30 +1142,21 @@ public bool TryAddCharacters(string characters) continue; } + TMP_Character character = new TMP_Character(unicode, glyphIndex); + // Check if glyph is already contained in the font asset as the same glyph might be referenced by multiple characters. if (m_GlyphLookupDictionary.ContainsKey(glyphIndex)) { - TMP_Character character = new TMP_Character(unicode, m_GlyphLookupDictionary[glyphIndex]); + character.glyph = m_GlyphLookupDictionary[glyphIndex]; m_CharacterTable.Add(character); m_CharacterLookupDictionary.Add(unicode, character); continue; } - // Check if glyph is already on the list of glyphs to added. - if (m_CharacterLookupMap.ContainsKey(glyphIndex)) - { - // Exclude duplicates. - if (m_CharacterLookupMap[glyphIndex].Contains(unicode)) - continue; - - m_CharacterLookupMap[glyphIndex].Add(unicode); - continue; - } - // Add glyph to list of glyphs to add and glyph lookup map. - m_CharacterLookupMap.Add(glyphIndex, new List { unicode } ); m_GlyphIndexList.Add(glyphIndex); + m_CharactersToAdd.Add(character); } if (m_GlyphIndexList.Count == 0) @@ -1222,17 +1185,26 @@ public bool TryAddCharacters(string characters) m_GlyphLookupDictionary.Add(glyphIndex, glyph); // Add new character(s) - List unicodes = m_CharacterLookupMap[glyphIndex]; - int unicodeCount = unicodes.Count; + //List unicodes = m_CharacterLookupMap[glyphIndex]; + //int unicodeCount = unicodes.Count; - for (int j = 0; j < unicodeCount; j++) - { - uint unicode = unicodes[j]; + //for (int j = 0; j < unicodeCount; j++) + //{ + // uint unicode = unicodes[j]; - TMP_Character character = new TMP_Character(unicode, glyph); - m_CharacterTable.Add(character); - m_CharacterLookupDictionary.Add(unicode, character); - } + // TMP_Character character = new TMP_Character(unicode, glyph); + // m_CharacterTable.Add(character); + // m_CharacterLookupDictionary.Add(unicode, character); + //} + } + + // Add new characters to relevant data structures. + for (int i = 0; i < m_CharactersToAdd.Count; i++) + { + TMP_Character character = m_CharactersToAdd[i]; + character.glyph = m_GlyphLookupDictionary[character.glyphIndex]; + m_CharacterTable.Add(character); + m_CharacterLookupDictionary.Add(character.unicode, character); } #if UNITY_EDITOR @@ -1256,10 +1228,7 @@ internal bool TryAddCharacter_Internal(uint unicode) // Check if character is already contained in the character table. if (m_CharacterLookupDictionary.ContainsKey(unicode)) - { - character = m_CharacterLookupDictionary[unicode]; return true; - } uint glyphIndex = FontEngine.GetGlyphIndex(unicode); if (glyphIndex == 0) @@ -1318,7 +1287,7 @@ internal bool TryAddCharacter_Internal(uint unicode) /// - /// + /// To be removed. /// /// /// @@ -1365,7 +1334,7 @@ internal TMP_Character AddCharacter_Internal(uint unicode, Glyph glyph) m_CharacterTable.Add(character); m_CharacterLookupDictionary.Add(unicode, character); - Debug.Log("Adding character [" + (char)unicode + "] with Unicode (" + unicode + ") to [" + this.name + "] font asset."); + //Debug.Log("Adding character [" + (char)unicode + "] with Unicode (" + unicode + ") to [" + this.name + "] font asset."); // Schedule glyph to be added to the font atlas texture //TM_FontAssetUpdateManager.RegisterFontAssetForUpdate(this); @@ -1402,6 +1371,8 @@ internal bool TryAddCharacterInternal(uint unicode, out TMP_Character character) if (glyphIndex == 0) return false; + Profiler.BeginSample("TMP.TryAddCharacter"); + // Check if glyph is already contained in the font asset as the same glyph might be referenced by multiple characters. if (m_GlyphLookupDictionary.ContainsKey(glyphIndex)) { @@ -1409,13 +1380,8 @@ internal bool TryAddCharacterInternal(uint unicode, out TMP_Character character) m_CharacterTable.Add(character); m_CharacterLookupDictionary.Add(unicode, character); - // Add new unicode to glyph lookup map. - if (m_CharacterLookupMap.ContainsKey(glyphIndex)) - m_CharacterLookupMap[glyphIndex].Add(unicode); - else - m_CharacterLookupMap.Add(glyphIndex, new List { unicode }); - - UpdateGlyphAdjustmentRecords(unicode, glyphIndex); + if (TMP_Settings.getFontFeaturesAtRuntime) + UpdateGlyphAdjustmentRecords(unicode, glyphIndex); #if UNITY_EDITOR // Makes the changes to the font asset persistent. @@ -1425,6 +1391,8 @@ internal bool TryAddCharacterInternal(uint unicode, out TMP_Character character) UnityEditor.EditorUtility.SetDirty(this); #endif + Profiler.EndSample(); + return true; } @@ -1435,6 +1403,8 @@ internal bool TryAddCharacterInternal(uint unicode, out TMP_Character character) if (m_AtlasTextures[m_AtlasTextureIndex].isReadable == false) { Debug.LogWarning("Unable to add the requested character to font asset [" + this.name + "]'s atlas texture. Please make the texture [" + m_AtlasTextures[m_AtlasTextureIndex].name + "] readable.", m_AtlasTextures[m_AtlasTextureIndex]); + + Profiler.EndSample(); return false; } @@ -1450,14 +1420,13 @@ internal bool TryAddCharacterInternal(uint unicode, out TMP_Character character) // Add new character character = new TMP_Character(unicode, glyph); - character.glyph = glyph; m_CharacterTable.Add(character); m_CharacterLookupDictionary.Add(unicode, character); m_GlyphIndexList.Add(glyphIndex); - m_CharacterLookupMap.Add(glyphIndex, new List { unicode }); - UpdateGlyphAdjustmentRecords(unicode, glyphIndex); + if (TMP_Settings.getFontFeaturesAtRuntime) + UpdateGlyphAdjustmentRecords(unicode, glyphIndex); #if UNITY_EDITOR // Makes the changes to the font asset persistent. @@ -1467,13 +1436,32 @@ internal bool TryAddCharacterInternal(uint unicode, out TMP_Character character) UnityEditor.EditorUtility.SetDirty(this); #endif + Profiler.EndSample(); + return true; } + Profiler.EndSample(); + return false; } + /// + /// Internal function used to get the glyph index for the given unicode. + /// + /// + /// + internal uint GetGlyphIndex(uint unicode) + { + // Load font face. + if (FontEngine.LoadFontFace(sourceFontFile, m_FaceInfo.pointSize) != FontEngineError.Success) + return 0; + + return FontEngine.GetGlyphIndex(unicode); + } + + internal void UpdateAtlasTexture() { // Return if we don't have any glyphs to add to atlas texture. @@ -1548,53 +1536,51 @@ internal void UpdateAtlasTexture() internal void UpdateGlyphAdjustmentRecords(uint unicode, uint glyphIndex) { - // Get glyph pair adjustment records from font file. - // TODO: Revise FontEngine bindings to use list instead of array to avoid allocations. - m_GlyphPairAdjustmentRecords = FontEngine.GetGlyphPairAdjustmentTable(m_GlyphIndexList.ToArray()); + Profiler.BeginSample("TMP.UpdateGlyphAdjustmentRecords"); - if (m_GlyphPairAdjustmentRecords == null) - return; + int glyphCount = m_GlyphIndexList.Count; - if (m_KerningTable == null) - m_KerningTable = new KerningTable(); + if (s_GlyphIndexArray.Length <= glyphCount) + s_GlyphIndexArray = new uint[Mathf.NextPowerOfTwo(glyphCount + 1)]; - for (int i = 0; i < m_GlyphPairAdjustmentRecords.Length; i++) - { - GlyphAdjustmentRecord firstRecord = m_GlyphPairAdjustmentRecords[i].firstAdjustmentRecord; - GlyphAdjustmentRecord secondRecord = m_GlyphPairAdjustmentRecords[i].secondAdjustmentRecord; + for (int i = 0; i < glyphCount; i++) + s_GlyphIndexArray[i] = m_GlyphIndexList[i]; - // Skip current glyph pair adjustment record if neither record match the new glyph index. - if (firstRecord.glyphIndex != glyphIndex && secondRecord.glyphIndex != glyphIndex) - continue; + // Clear unused array elements + Array.Clear(s_GlyphIndexArray, glyphCount, s_GlyphIndexArray.Length - glyphCount); - // Lookup Unicode for the referenced glyphs - List firstRecordUnicodeIndexes = m_CharacterLookupMap[firstRecord.glyphIndex]; - List secondRecordUnicodeIndexes = m_CharacterLookupMap[secondRecord.glyphIndex]; + // Get glyph pair adjustment records from font file. + // TODO: Revise FontEngine bindings to use a more efficient function where only the new glyph index is passed. + GlyphPairAdjustmentRecord[] pairAdjustmentRecords = FontEngine.GetGlyphPairAdjustmentTable(s_GlyphIndexArray); - for (int first = 0; first < firstRecordUnicodeIndexes.Count; first++) - { - uint firstUnicode = firstRecordUnicodeIndexes[first]; + if (pairAdjustmentRecords == null || pairAdjustmentRecords.Length == 0) + { + Profiler.EndSample(); + return; + } - for (int second = 0; second < secondRecordUnicodeIndexes.Count; second++) - { - uint secondUnicode = secondRecordUnicodeIndexes[second]; + if (m_FontFeatureTable == null) + m_FontFeatureTable = new TMP_FontFeatureTable(); + + for (int i = 0; i < pairAdjustmentRecords.Length && pairAdjustmentRecords[i].firstAdjustmentRecord.glyphIndex != 0; i++) + { + long pairKey = (long)pairAdjustmentRecords[i].secondAdjustmentRecord.glyphIndex << 32 | pairAdjustmentRecords[i].firstAdjustmentRecord.glyphIndex; - uint key = (secondUnicode << 16) + firstUnicode; + // Check if table already contains a pair adjustment record for this key. + if (m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.ContainsKey(pairKey)) + continue; - if (!m_KerningLookupDictionary.ContainsKey((int)key)) - { - KerningPair kerningPair = new KerningPair(firstUnicode, new GlyphValueRecord(firstRecord.glyphValueRecord), secondUnicode, new GlyphValueRecord(secondRecord.glyphValueRecord)); + TMP_GlyphPairAdjustmentRecord record = new TMP_GlyphPairAdjustmentRecord(pairAdjustmentRecords[i]); - m_KerningTable.kerningPairs.Add(kerningPair); - m_KerningLookupDictionary.Add((int)key, kerningPair); - } - } - } + m_FontFeatureTable.m_GlyphPairAdjustmentRecords.Add(record); + m_FontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.Add(pairKey, record); } #if UNITY_EDITOR - kerningTable.SortKerningPairs(); + m_FontFeatureTable.SortGlyphPairAdjustmentRecords(); #endif + + Profiler.EndSample(); } @@ -1607,7 +1593,7 @@ public void ClearFontAssetData(bool setAtlasSizeToZero = false) { #if UNITY_EDITOR // Record full object undo in the Editor. - UnityEditor.Undo.RecordObjects(new UnityEngine.Object[] { this, this.atlasTexture }, "Resetting Font Asset"); + //UnityEditor.Undo.RecordObjects(new UnityEngine.Object[] { this, this.atlasTexture }, "Resetting Font Asset"); #endif // Clear glyph and character tables @@ -1634,8 +1620,8 @@ public void ClearFontAssetData(bool setAtlasSizeToZero = false) m_GlyphsPacked.Clear(); // Clear Glyph Adjustment Table - if (m_KerningTable != null && m_KerningTable.kerningPairs != null) - m_KerningTable.kerningPairs.Clear(); + if (m_FontFeatureTable != null && m_FontFeatureTable.m_GlyphPairAdjustmentRecords != null) + m_FontFeatureTable.glyphPairAdjustmentRecords.Clear(); m_AtlasTextureIndex = 0; @@ -1825,5 +1811,48 @@ private void UpgradeFontAsset() #endif } + /// + /// + /// + void UpgradeGlyphAdjustmentTableToFontFeatureTable() + { + Debug.Log("Upgrading font asset [" + this.name + "] Glyph Adjustment Table.", this); + + if (m_FontFeatureTable == null) + m_FontFeatureTable = new TMP_FontFeatureTable(); + + int pairCount = m_KerningTable.kerningPairs.Count; + + m_FontFeatureTable.m_GlyphPairAdjustmentRecords = new List(pairCount); + + for (int i = 0; i < pairCount; i++) + { + KerningPair pair = m_KerningTable.kerningPairs[i]; + + uint firstGlyphIndex = 0; + if (m_CharacterLookupDictionary.TryGetValue(pair.firstGlyph, out TMP_Character firstCharacter)) + firstGlyphIndex = firstCharacter.glyphIndex; + + uint secondGlyphIndex = 0; + if (m_CharacterLookupDictionary.TryGetValue(pair.secondGlyph, out TMP_Character secondCharacter)) + secondGlyphIndex = secondCharacter.glyphIndex; + + TMP_GlyphAdjustmentRecord firstAdjustmentRecord = new TMP_GlyphAdjustmentRecord(firstGlyphIndex, new TMP_GlyphValueRecord(pair.firstGlyphAdjustments.xPlacement, pair.firstGlyphAdjustments.yPlacement, pair.firstGlyphAdjustments.xAdvance, pair.firstGlyphAdjustments.yAdvance)); + TMP_GlyphAdjustmentRecord secondAdjustmentRecord = new TMP_GlyphAdjustmentRecord(secondGlyphIndex, new TMP_GlyphValueRecord(pair.secondGlyphAdjustments.xPlacement, pair.secondGlyphAdjustments.yPlacement, pair.secondGlyphAdjustments.xAdvance, pair.secondGlyphAdjustments.yAdvance)); + TMP_GlyphPairAdjustmentRecord record = new TMP_GlyphPairAdjustmentRecord(firstAdjustmentRecord, secondAdjustmentRecord); + + m_FontFeatureTable.m_GlyphPairAdjustmentRecords.Add(record); + } + + // TODO: Should clear legacy kerning table. + m_KerningTable.kerningPairs = null; + m_KerningTable = null; + + #if UNITY_EDITOR + UnityEditor.EditorUtility.SetDirty(this); + //UnityEditor.AssetDatabase.SaveAssets(); + #endif + } + } } \ No newline at end of file diff --git a/Scripts/Runtime/TMP_FontAssetCommon.cs b/Scripts/Runtime/TMP_FontAssetCommon.cs index 855dfd2..0c092aa 100644 --- a/Scripts/Runtime/TMP_FontAssetCommon.cs +++ b/Scripts/Runtime/TMP_FontAssetCommon.cs @@ -147,14 +147,14 @@ public KerningPairKey(uint ascii_left, uint ascii_right) /// Positional adjustments of a glyph /// [Serializable] - public struct GlyphValueRecord + public struct GlyphValueRecord_Legacy { public float xPlacement; public float yPlacement; public float xAdvance; public float yAdvance; - internal GlyphValueRecord (UnityEngine.TextCore.LowLevel.GlyphValueRecord valueRecord) + internal GlyphValueRecord_Legacy(UnityEngine.TextCore.LowLevel.GlyphValueRecord valueRecord) { this.xPlacement = valueRecord.xPlacement; this.yPlacement = valueRecord.yPlacement; @@ -162,9 +162,9 @@ internal GlyphValueRecord (UnityEngine.TextCore.LowLevel.GlyphValueRecord valueR this.yAdvance = valueRecord.yAdvance; } - public static GlyphValueRecord operator +(GlyphValueRecord a, GlyphValueRecord b) + public static GlyphValueRecord_Legacy operator +(GlyphValueRecord_Legacy a, GlyphValueRecord_Legacy b) { - GlyphValueRecord c; + GlyphValueRecord_Legacy c; c.xPlacement = a.xPlacement + b.xPlacement; c.yPlacement = a.yPlacement + b.yPlacement; c.xAdvance = a.xAdvance + b.xAdvance; @@ -174,7 +174,6 @@ internal GlyphValueRecord (UnityEngine.TextCore.LowLevel.GlyphValueRecord valueR } } - [Serializable] public class KerningPair { @@ -193,12 +192,12 @@ public uint firstGlyph /// /// The positional adjustment of the first glyph. /// - public GlyphValueRecord firstGlyphAdjustments + public GlyphValueRecord_Legacy firstGlyphAdjustments { get { return m_FirstGlyphAdjustments; } } [SerializeField] - private GlyphValueRecord m_FirstGlyphAdjustments; + private GlyphValueRecord_Legacy m_FirstGlyphAdjustments; /// /// The second glyph part of a kerning pair. @@ -215,16 +214,18 @@ public uint secondGlyph /// /// The positional adjustment of the second glyph. /// - public GlyphValueRecord secondGlyphAdjustments + public GlyphValueRecord_Legacy secondGlyphAdjustments { get { return m_SecondGlyphAdjustments; } } [SerializeField] - private GlyphValueRecord m_SecondGlyphAdjustments; + private GlyphValueRecord_Legacy m_SecondGlyphAdjustments; [FormerlySerializedAs("XadvanceOffset")] public float xOffset; + internal static KerningPair empty = new KerningPair(0, new GlyphValueRecord_Legacy(), 0, new GlyphValueRecord_Legacy()); + /// /// Determines if the Character Spacing property of the text object will affect the kerning pair. /// This is mostly relevant when using Diacritical marks to prevent Character Spacing from altering the @@ -239,10 +240,10 @@ public bool ignoreSpacingAdjustments public KerningPair() { m_FirstGlyph = 0; - m_FirstGlyphAdjustments = new GlyphValueRecord(); + m_FirstGlyphAdjustments = new GlyphValueRecord_Legacy(); m_SecondGlyph = 0; - m_SecondGlyphAdjustments = new GlyphValueRecord(); + m_SecondGlyphAdjustments = new GlyphValueRecord_Legacy(); } public KerningPair(uint left, uint right, float offset) @@ -252,7 +253,7 @@ public KerningPair(uint left, uint right, float offset) xOffset = offset; } - public KerningPair(uint firstGlyph, GlyphValueRecord firstGlyphAdjustments, uint secondGlyph, GlyphValueRecord secondGlyphAdjustments) + public KerningPair(uint firstGlyph, GlyphValueRecord_Legacy firstGlyphAdjustments, uint secondGlyph, GlyphValueRecord_Legacy secondGlyphAdjustments) { m_FirstGlyph = firstGlyph; m_FirstGlyphAdjustments = firstGlyphAdjustments; @@ -268,7 +269,6 @@ internal void ConvertLegacyKerningData() } - [Serializable] public class KerningTable { @@ -326,7 +326,7 @@ public int AddKerningPair(uint first, uint second, float offset) /// The second glyph /// Adjustment record for the second glyph /// - public int AddGlyphPairAdjustmentRecord(uint first, GlyphValueRecord firstAdjustments, uint second, GlyphValueRecord secondAdjustments) + public int AddGlyphPairAdjustmentRecord(uint first, GlyphValueRecord_Legacy firstAdjustments, uint second, GlyphValueRecord_Legacy secondAdjustments) { int index = kerningPairs.FindIndex(item => item.firstGlyph == first && item.secondGlyph == second); @@ -453,7 +453,4 @@ private static TMP_FontAsset SearchForCharacterInternal(List font return null; } } - - - } \ No newline at end of file diff --git a/Scripts/Runtime/TMP_FontFeatureTable.cs b/Scripts/Runtime/TMP_FontFeatureTable.cs new file mode 100644 index 0000000..a56a4ff --- /dev/null +++ b/Scripts/Runtime/TMP_FontFeatureTable.cs @@ -0,0 +1,55 @@ +using System; +using System.Linq; +using System.Collections.Generic; +using UnityEngine; + + +namespace TMPro +{ + /// + /// Table that contains the various font features available for the given font asset. + /// + [Serializable] + public class TMP_FontFeatureTable + { + /// + /// List that contains the glyph pair adjustment records. + /// + internal List glyphPairAdjustmentRecords + { + get { return m_GlyphPairAdjustmentRecords; } + set { m_GlyphPairAdjustmentRecords = value; } + } + [SerializeField] + internal List m_GlyphPairAdjustmentRecords; + + /// + /// + /// + internal Dictionary m_GlyphPairAdjustmentRecordLookupDictionary; + + // ============================================= + // Constructor(s) + // ============================================= + + public TMP_FontFeatureTable() + { + m_GlyphPairAdjustmentRecords = new List(); + m_GlyphPairAdjustmentRecordLookupDictionary = new Dictionary(); + } + + // ============================================= + // Utility Functions + // ============================================= + + /// + /// Sort the glyph pair adjustment records by glyph index. + /// + public void SortGlyphPairAdjustmentRecords() + { + // Sort List of Kerning Info + if (m_GlyphPairAdjustmentRecords.Count > 0) + m_GlyphPairAdjustmentRecords = m_GlyphPairAdjustmentRecords.OrderBy(s => s.firstAdjustmentRecord.glyphIndex).ThenBy(s => s.secondAdjustmentRecord.glyphIndex).ToList(); + } + } +} \ No newline at end of file diff --git a/Scripts/Runtime/TMP_FontFeatureTable.cs.meta b/Scripts/Runtime/TMP_FontFeatureTable.cs.meta new file mode 100644 index 0000000..39f3111 --- /dev/null +++ b/Scripts/Runtime/TMP_FontFeatureTable.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 5ea9f573d4b800a49b9d83a1f61c0a88 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Runtime/TMP_FontFeaturesCommon.cs b/Scripts/Runtime/TMP_FontFeaturesCommon.cs new file mode 100644 index 0000000..b30a74a --- /dev/null +++ b/Scripts/Runtime/TMP_FontFeaturesCommon.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.TextCore.LowLevel; + + +namespace TMPro +{ + public enum FontFeatureLookupFlags + { + IgnoreLigatures = 0x004, + IgnoreSpacingAdjustments = 0x100, + } + + /// + /// The values used to adjust the position of a glyph or set of glyphs. + /// + [Serializable] + public struct TMP_GlyphValueRecord + { + /// + /// The positional adjustment affecting the horizontal bearing X of the glyph. + /// + public float xPlacement { get { return m_XPlacement; } set { m_XPlacement = value; } } + + /// + /// The positional adjustment affecting the horizontal bearing Y of the glyph. + /// + public float yPlacement { get { return m_YPlacement; } set { m_YPlacement = value; } } + + /// + /// The positional adjustment affecting the horizontal advance of the glyph. + /// + public float xAdvance { get { return m_XAdvance; } set { m_XAdvance = value; } } + + /// + /// The positional adjustment affecting the vertical advance of the glyph. + /// + public float yAdvance { get { return m_YAdvance; } set { m_YAdvance = value; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private float m_XPlacement; + + [SerializeField] + private float m_YPlacement; + + [SerializeField] + private float m_XAdvance; + + [SerializeField] + private float m_YAdvance; + + + /// + /// Constructor + /// + /// The positional adjustment affecting the horizontal bearing X of the glyph. + /// The positional adjustment affecting the horizontal bearing Y of the glyph. + /// The positional adjustment affecting the horizontal advance of the glyph. + /// The positional adjustment affecting the vertical advance of the glyph. + public TMP_GlyphValueRecord(float xPlacement, float yPlacement, float xAdvance, float yAdvance) + { + m_XPlacement = xPlacement; + m_YPlacement = yPlacement; + m_XAdvance = xAdvance; + m_YAdvance = yAdvance; + } + + internal TMP_GlyphValueRecord(GlyphValueRecord_Legacy valueRecord) + { + m_XPlacement = valueRecord.xPlacement; + m_YPlacement = valueRecord.yPlacement; + m_XAdvance = valueRecord.xAdvance; + m_YAdvance = valueRecord.yAdvance; + } + + internal TMP_GlyphValueRecord(GlyphValueRecord valueRecord) + { + m_XPlacement = valueRecord.xPlacement; + m_YPlacement = valueRecord.yPlacement; + m_XAdvance = valueRecord.xAdvance; + m_YAdvance = valueRecord.yAdvance; + } + + public static TMP_GlyphValueRecord operator +(TMP_GlyphValueRecord a, TMP_GlyphValueRecord b) + { + TMP_GlyphValueRecord c; + c.m_XPlacement = a.xPlacement + b.xPlacement; + c.m_YPlacement = a.yPlacement + b.yPlacement; + c.m_XAdvance = a.xAdvance + b.xAdvance; + c.m_YAdvance = a.yAdvance + b.yAdvance; + + return c; + } + } + + /// + /// The positional adjustment values of a glyph. + /// + [Serializable] + public struct TMP_GlyphAdjustmentRecord + { + /// + /// The index of the glyph in the source font file. + /// + public uint glyphIndex { get { return m_GlyphIndex; } set { m_GlyphIndex = value; } } + + /// + /// The GlyphValueRecord contains the positional adjustments of the glyph. + /// + public TMP_GlyphValueRecord glyphValueRecord { get { return m_GlyphValueRecord; } set { m_GlyphValueRecord = value; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private uint m_GlyphIndex; + + [SerializeField] + private TMP_GlyphValueRecord m_GlyphValueRecord; + + /// + /// Constructor + /// + /// The index of the glyph in the source font file. + /// The GlyphValueRecord contains the positional adjustments of the glyph. + public TMP_GlyphAdjustmentRecord(uint glyphIndex, TMP_GlyphValueRecord glyphValueRecord) + { + m_GlyphIndex = glyphIndex; + m_GlyphValueRecord = glyphValueRecord; + } + + internal TMP_GlyphAdjustmentRecord(GlyphAdjustmentRecord adjustmentRecord) + { + m_GlyphIndex = adjustmentRecord.glyphIndex; + m_GlyphValueRecord = new TMP_GlyphValueRecord(adjustmentRecord.glyphValueRecord); + } + } + + /// + /// The positional adjustment values for a pair of glyphs. + /// + [Serializable] + public class TMP_GlyphPairAdjustmentRecord + { + /// + /// Contains the positional adjustment values for the first glyph. + /// + public TMP_GlyphAdjustmentRecord firstAdjustmentRecord { get { return m_FirstAdjustmentRecord; } set { m_FirstAdjustmentRecord = value; } } + + /// + /// Contains the positional adjustment values for the second glyph. + /// + public TMP_GlyphAdjustmentRecord secondAdjustmentRecord { get { return m_SecondAdjustmentRecord; } set { m_SecondAdjustmentRecord = value; } } + + /// + /// + /// + public FontFeatureLookupFlags featureLookupFlags { get { return m_FeatureLookupFlags; } set { m_FeatureLookupFlags = value; } } + + // ============================================= + // Private backing fields for public properties. + // ============================================= + + [SerializeField] + private TMP_GlyphAdjustmentRecord m_FirstAdjustmentRecord; + + [SerializeField] + private TMP_GlyphAdjustmentRecord m_SecondAdjustmentRecord; + + [SerializeField] + private FontFeatureLookupFlags m_FeatureLookupFlags; + + /// + /// Constructor + /// + /// First glyph adjustment record. + /// Second glyph adjustment record. + public TMP_GlyphPairAdjustmentRecord(TMP_GlyphAdjustmentRecord firstAdjustmentRecord, TMP_GlyphAdjustmentRecord secondAdjustmentRecord) + { + m_FirstAdjustmentRecord = firstAdjustmentRecord; + m_SecondAdjustmentRecord = secondAdjustmentRecord; + } + + /// + /// Internal constructor + /// + /// + /// + internal TMP_GlyphPairAdjustmentRecord(GlyphPairAdjustmentRecord glyphPairAdjustmentRecord) + { + m_FirstAdjustmentRecord = new TMP_GlyphAdjustmentRecord(glyphPairAdjustmentRecord.firstAdjustmentRecord); + m_SecondAdjustmentRecord = new TMP_GlyphAdjustmentRecord(glyphPairAdjustmentRecord.secondAdjustmentRecord); + } + } + + public struct GlyphPairKey + { + public uint firstGlyphIndex; + public uint secondGlyphIndex; + public long key; + + public GlyphPairKey(uint firstGlyphIndex, uint secondGlyphIndex) + { + this.firstGlyphIndex = firstGlyphIndex; + this.secondGlyphIndex = secondGlyphIndex; + key = (long)secondGlyphIndex << 32 | firstGlyphIndex; + } + + internal GlyphPairKey(TMP_GlyphPairAdjustmentRecord record) + { + firstGlyphIndex = record.firstAdjustmentRecord.glyphIndex; + secondGlyphIndex = record.secondAdjustmentRecord.glyphIndex; + key = (long)secondGlyphIndex << 32 | firstGlyphIndex; + } + } +} diff --git a/Scripts/Runtime/TMP_FontFeaturesCommon.cs.meta b/Scripts/Runtime/TMP_FontFeaturesCommon.cs.meta new file mode 100644 index 0000000..ad2b502 --- /dev/null +++ b/Scripts/Runtime/TMP_FontFeaturesCommon.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 27df3b12f30d0b74a9b10a3968c402ff +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Scripts/Runtime/TMP_MeshInfo.cs b/Scripts/Runtime/TMP_MeshInfo.cs index 0605269..33dc81c 100644 --- a/Scripts/Runtime/TMP_MeshInfo.cs +++ b/Scripts/Runtime/TMP_MeshInfo.cs @@ -449,10 +449,11 @@ public void Clear(bool uploadChanges) Array.Clear(this.vertices, 0, this.vertices.Length); this.vertexCount = 0; - this.mesh.bounds = s_DefaultBounds; - if (uploadChanges && this.mesh != null) this.mesh.vertices = this.vertices; + + if (this.mesh != null) + this.mesh.bounds = s_DefaultBounds; } diff --git a/Scripts/Runtime/TMP_Settings.cs b/Scripts/Runtime/TMP_Settings.cs index 3461f71..43f1f7a 100644 --- a/Scripts/Runtime/TMP_Settings.cs +++ b/Scripts/Runtime/TMP_Settings.cs @@ -80,6 +80,16 @@ public static bool enableRaycastTarget [SerializeField] private bool m_EnableRaycastTarget = true; + /// + /// Determines if OpenType Font Features should be retrieved at runtime from the source font file. + /// + public static bool getFontFeaturesAtRuntime + { + get { return instance.m_GetFontFeaturesAtRuntime; } + } + [SerializeField] + private bool m_GetFontFeaturesAtRuntime = true; + /// /// The character that will be used as a replacement for missing glyphs in a font asset. /// diff --git a/Scripts/Runtime/TMP_Text.cs b/Scripts/Runtime/TMP_Text.cs index a25b6b4..7a0e5d5 100644 --- a/Scripts/Runtime/TMP_Text.cs +++ b/Scripts/Runtime/TMP_Text.cs @@ -3932,33 +3932,33 @@ protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector // Handle Kerning if Enabled. #region Handle Kerning - GlyphValueRecord glyphAdjustments = new GlyphValueRecord(); - float CharacterSpacingAdjustment = m_characterSpacing; + TMP_GlyphValueRecord glyphAdjustments = new TMP_GlyphValueRecord(); + float characterSpacingAdjustment = m_characterSpacing; if (m_enableKerning) { if (m_characterCount < totalCharacterCount - 1) { - uint nextGlyph = m_textInfo.characterInfo[m_characterCount + 1].character; - KerningPairKey keyValue = new KerningPairKey((uint)charCode, nextGlyph); + uint firstGlyphIndex = m_cached_TextElement.glyphIndex; + uint secondGlyphIndex = m_textInfo.characterInfo[m_characterCount + 1].textElement.glyphIndex; + long key = new GlyphPairKey(firstGlyphIndex, secondGlyphIndex).key; - m_currentFontAsset.kerningLookupDictionary.TryGetValue((int)keyValue.key, out KerningPair adjustmentPair); - if (adjustmentPair != null) + if (m_currentFontAsset.fontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out TMP_GlyphPairAdjustmentRecord adjustmentPair)) { - glyphAdjustments = adjustmentPair.firstGlyphAdjustments; - CharacterSpacingAdjustment = adjustmentPair.ignoreSpacingAdjustments ? 0 : CharacterSpacingAdjustment; + glyphAdjustments = adjustmentPair.firstAdjustmentRecord.glyphValueRecord; + characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; } } if (m_characterCount >= 1) { - uint previousGlyph = m_textInfo.characterInfo[m_characterCount - 1].character; - KerningPairKey keyValue = new KerningPairKey(previousGlyph, (uint)charCode); + uint firstGlyphIndex = m_textInfo.characterInfo[m_characterCount - 1].textElement.glyphIndex; + uint secondGlyphIndex = m_cached_TextElement.glyphIndex; + long key = new GlyphPairKey(firstGlyphIndex, secondGlyphIndex).key; - m_currentFontAsset.kerningLookupDictionary.TryGetValue((int)keyValue.key, out KerningPair adjustmentPair); - if (adjustmentPair != null) + if (m_currentFontAsset.fontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out TMP_GlyphPairAdjustmentRecord adjustmentPair)) { - glyphAdjustments += adjustmentPair.secondGlyphAdjustments; - CharacterSpacingAdjustment = adjustmentPair.ignoreSpacingAdjustments ? 0 : CharacterSpacingAdjustment; + glyphAdjustments += adjustmentPair.secondAdjustmentRecord.glyphValueRecord; + characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; } } } @@ -4263,14 +4263,14 @@ protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector } else if (m_monoSpacing != 0) { - m_xAdvance += (m_monoSpacing - monoAdvance + ((CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta); + m_xAdvance += (m_monoSpacing - monoAdvance + ((characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance += m_wordSpacing * currentElementScale; } else { - m_xAdvance += ((m_cached_TextElement.glyph.metrics.horizontalAdvance * bold_xAdvance_multiplier + CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); + m_xAdvance += ((m_cached_TextElement.glyph.metrics.horizontalAdvance * bold_xAdvance_multiplier + characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance += m_wordSpacing * currentElementScale; diff --git a/Scripts/Runtime/TMP_UpdateManager.cs b/Scripts/Runtime/TMP_UpdateManager.cs index 42aaef7..4f07cf1 100644 --- a/Scripts/Runtime/TMP_UpdateManager.cs +++ b/Scripts/Runtime/TMP_UpdateManager.cs @@ -130,10 +130,10 @@ private bool InternalRegisterTextElementForGraphicRebuild(TMP_Text element) /// Callback which occurs just before the Scriptable Render Pipeline (SRP) begins rendering. /// /// - #if UNITY_2018_1_OR_NEWER - void OnBeginFrameRendering(Camera[] cameras) - #elif UNITY_2019_1_OR_NEWER + #if UNITY_2019_1_OR_NEWER void OnBeginFrameRendering(ScriptableRenderContext renderContext, Camera[] cameras) + #elif UNITY_2018_1_OR_NEWER + void OnBeginFrameRendering(Camera[] cameras) #endif { // Exclude the PreRenderCamera @@ -232,7 +232,7 @@ private void InternalUnRegisterTextObjectForUpdate(TMP_Text textObject) int id = textObject.GetInstanceID(); TMP_UpdateManager.instance.m_InternalUpdateQueue.Remove(textObject); - m_LayoutQueueLookup.Remove(id); + m_InternalUpdateLookup.Remove(id); } } } \ No newline at end of file diff --git a/Scripts/Runtime/TMPro_Private.cs b/Scripts/Runtime/TMPro_Private.cs index 600da30..c3cf513 100644 --- a/Scripts/Runtime/TMPro_Private.cs +++ b/Scripts/Runtime/TMPro_Private.cs @@ -349,6 +349,8 @@ void ON_FONT_PROPERTY_CHANGED(bool isChanged, TMP_FontAsset font) m_isInputParsingRequired = true; m_havePropertiesChanged = true; + UpdateMeshPadding(); + SetMaterialDirty(); SetVerticesDirty(); } @@ -1030,6 +1032,7 @@ protected override int SetArraySizes(UnicodeChar[] chars) m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = m_currentSpriteAsset; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; + m_textInfo.characterInfo[m_totalCharacterCount].textElement = m_currentSpriteAsset.spriteCharacterTable[m_spriteIndex]; m_textInfo.characterInfo[m_totalCharacterCount].elementType = m_textElementType; m_textInfo.characterInfo[m_totalCharacterCount].index = tagStartIndex; m_textInfo.characterInfo[m_totalCharacterCount].stringLength = chars[i].stringIndex - tagStartIndex + 1; @@ -1119,6 +1122,7 @@ protected override int SetArraySizes(UnicodeChar[] chars) m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = spriteIndex; m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = spriteAsset; + m_textInfo.characterInfo[m_totalCharacterCount].textElement = spriteAsset.spriteCharacterTable[m_spriteIndex]; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; m_textInfo.characterInfo[m_totalCharacterCount].index = chars[i].stringIndex; m_textInfo.characterInfo[m_totalCharacterCount].stringLength = chars[i].length; @@ -1174,6 +1178,7 @@ protected override int SetArraySizes(UnicodeChar[] chars) m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = spriteIndex; m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = spriteAsset; + m_textInfo.characterInfo[m_totalCharacterCount].textElement = spriteAsset.spriteCharacterTable[m_spriteIndex]; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; m_textInfo.characterInfo[m_totalCharacterCount].index = chars[i].stringIndex; m_textInfo.characterInfo[m_totalCharacterCount].stringLength = chars[i].length; @@ -1885,33 +1890,33 @@ protected override void GenerateTextMesh() // Handle Kerning if Enabled. #region Handle Kerning - GlyphValueRecord glyphAdjustments = new GlyphValueRecord(); - float CharacterSpacingAdjustment = m_characterSpacing; + TMP_GlyphValueRecord glyphAdjustments = new TMP_GlyphValueRecord(); + float characterSpacingAdjustment = m_characterSpacing; if (m_enableKerning) { if (m_characterCount < totalCharacterCount - 1) { - uint nextGlyph = m_textInfo.characterInfo[m_characterCount + 1].character; - KerningPairKey keyValue = new KerningPairKey((uint)charCode, nextGlyph); + uint firstGlyphIndex = m_cached_TextElement.glyphIndex; + uint secondGlyphIndex = m_textInfo.characterInfo[m_characterCount + 1].textElement.glyphIndex; + long key = new GlyphPairKey(firstGlyphIndex, secondGlyphIndex).key; - m_currentFontAsset.kerningLookupDictionary.TryGetValue((int)keyValue.key, out KerningPair adjustmentPair); - if (adjustmentPair != null) + if (m_currentFontAsset.fontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out TMP_GlyphPairAdjustmentRecord adjustmentPair)) { - glyphAdjustments = adjustmentPair.firstGlyphAdjustments; - CharacterSpacingAdjustment = adjustmentPair.ignoreSpacingAdjustments ? 0 : CharacterSpacingAdjustment; + glyphAdjustments = adjustmentPair.firstAdjustmentRecord.glyphValueRecord; + characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; } } if (m_characterCount >= 1) { - uint previousGlyph = m_textInfo.characterInfo[m_characterCount - 1].character; - KerningPairKey keyValue = new KerningPairKey(previousGlyph, (uint)charCode); + uint firstGlyphIndex = m_textInfo.characterInfo[m_characterCount - 1].textElement.glyphIndex; + uint secondGlyphIndex = m_cached_TextElement.glyphIndex; + long key = new GlyphPairKey(firstGlyphIndex, secondGlyphIndex).key; - m_currentFontAsset.kerningLookupDictionary.TryGetValue((int)keyValue.key, out KerningPair adjustmentPair); - if (adjustmentPair != null) + if (m_currentFontAsset.fontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out TMP_GlyphPairAdjustmentRecord adjustmentPair)) { - glyphAdjustments += adjustmentPair.secondGlyphAdjustments; - CharacterSpacingAdjustment = adjustmentPair.ignoreSpacingAdjustments ? 0 : CharacterSpacingAdjustment; + glyphAdjustments += adjustmentPair.secondAdjustmentRecord.glyphValueRecord; + characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; } } } @@ -1922,7 +1927,7 @@ protected override void GenerateTextMesh() #region Handle Right-to-Left if (m_isRightToLeft) { - m_xAdvance -= ((m_cached_TextElement.glyph.metrics.horizontalAdvance * bold_xAdvance_multiplier + CharacterSpacingAdjustment + m_wordSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); + m_xAdvance -= ((m_cached_TextElement.glyph.metrics.horizontalAdvance * bold_xAdvance_multiplier + characterSpacingAdjustment + m_wordSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance -= m_wordSpacing * currentElementScale; @@ -2025,7 +2030,7 @@ protected override void GenerateTextMesh() if (m_isFXMatrixSet) { // Apply scale matrix when simulating Condensed text. - if (m_FXMatrix.m00 != 1) + if (m_FXMatrix.lossyScale.x != 1) { //top_left = m_FXMatrix.MultiplyPoint3x4(top_left); //bottom_left = m_FXMatrix.MultiplyPoint3x4(bottom_left); @@ -2252,7 +2257,7 @@ protected override void GenerateTextMesh() //m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification; - m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; + m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; m_textInfo.lineInfo[m_lineNumber].baseline = 0 - m_lineOffset; m_textInfo.lineInfo[m_lineNumber].ascender = lineAscender; @@ -2662,7 +2667,7 @@ protected override void GenerateTextMesh() } else if (m_monoSpacing != 0) { - m_xAdvance += (m_monoSpacing - monoAdvance + ((CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta); + m_xAdvance += (m_monoSpacing - monoAdvance + ((characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance += m_wordSpacing * currentElementScale; @@ -2670,9 +2675,9 @@ protected override void GenerateTextMesh() else if (!m_isRightToLeft) { float scaleFXMultiplier = 1; - if (m_isFXMatrixSet) scaleFXMultiplier = m_FXMatrix.m00; + if (m_isFXMatrixSet) scaleFXMultiplier = m_FXMatrix.lossyScale.x; - m_xAdvance += ((m_cached_TextElement.glyph.metrics.horizontalAdvance * scaleFXMultiplier * bold_xAdvance_multiplier + CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); + m_xAdvance += ((m_cached_TextElement.glyph.metrics.horizontalAdvance * scaleFXMultiplier * bold_xAdvance_multiplier + characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance += m_wordSpacing * currentElementScale; @@ -2742,9 +2747,9 @@ protected override void GenerateTextMesh() m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification; if (m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].isVisible) - m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; + m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; else - m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastCharacterOfLine].xAdvance - (CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; + m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastCharacterOfLine].xAdvance - (characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; m_textInfo.lineInfo[m_lineNumber].baseline = 0 - m_lineOffset; m_textInfo.lineInfo[m_lineNumber].ascender = lineAscender; @@ -3293,7 +3298,7 @@ protected override void GenerateTextMesh() // Pack UV's so that we can pass Xscale needed for Shader to maintain 1:1 ratio. #region Pack Scale into UV2 - xScale = characterInfos[i].scale * lossyScale * (1 - m_charWidthAdjDelta); + xScale = characterInfos[i].scale * Mathf.Abs(lossyScale) * (1 - m_charWidthAdjDelta); if (!characterInfos[i].isUsingAlternateTypeface && (characterInfos[i].style & FontStyles.Bold) == FontStyles.Bold) xScale *= -1; //int isBold = (m_textInfo.characterInfo[i].style & FontStyles.Bold) == FontStyles.Bold ? 1 : 0; @@ -3988,13 +3993,20 @@ protected override Bounds GetCompoundBounds() /// void UpdateSDFScale(float scaleDelta) { + if (scaleDelta == 0 || scaleDelta == float.PositiveInfinity) + { + m_havePropertiesChanged = true; + OnPreRenderObject(); + return; + } + for (int materialIndex = 0; materialIndex < m_textInfo.materialCount; materialIndex++) { TMP_MeshInfo meshInfo = m_textInfo.meshInfo[materialIndex]; for (int i = 0; i < meshInfo.uvs2.Length; i++) { - meshInfo.uvs2[i].y *= scaleDelta; + meshInfo.uvs2[i].y *= Mathf.Abs(scaleDelta); } } diff --git a/Scripts/Runtime/TMPro_UGUI_Private.cs b/Scripts/Runtime/TMPro_UGUI_Private.cs index 4f8ab33..21e55a8 100644 --- a/Scripts/Runtime/TMPro_UGUI_Private.cs +++ b/Scripts/Runtime/TMPro_UGUI_Private.cs @@ -419,6 +419,8 @@ void ON_FONT_PROPERTY_CHANGED(bool isChanged, TMP_FontAsset font) m_isInputParsingRequired = true; m_havePropertiesChanged = true; + UpdateMeshPadding(); + SetLayoutDirty(); SetVerticesDirty(); } @@ -1100,6 +1102,7 @@ protected override int SetArraySizes(UnicodeChar[] chars) m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = m_currentSpriteAsset; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; + m_textInfo.characterInfo[m_totalCharacterCount].textElement = m_currentSpriteAsset.spriteCharacterTable[m_spriteIndex]; m_textInfo.characterInfo[m_totalCharacterCount].elementType = m_textElementType; m_textInfo.characterInfo[m_totalCharacterCount].index = tagStartIndex; m_textInfo.characterInfo[m_totalCharacterCount].stringLength = chars[i].stringIndex - tagStartIndex + 1; @@ -1189,6 +1192,7 @@ protected override int SetArraySizes(UnicodeChar[] chars) m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = spriteIndex; m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = spriteAsset; + m_textInfo.characterInfo[m_totalCharacterCount].textElement = spriteAsset.spriteCharacterTable[m_spriteIndex]; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; m_textInfo.characterInfo[m_totalCharacterCount].index = chars[i].stringIndex; m_textInfo.characterInfo[m_totalCharacterCount].stringLength = chars[i].length; @@ -1244,6 +1248,7 @@ protected override int SetArraySizes(UnicodeChar[] chars) m_textInfo.characterInfo[m_totalCharacterCount].spriteIndex = spriteIndex; m_textInfo.characterInfo[m_totalCharacterCount].fontAsset = m_currentFontAsset; m_textInfo.characterInfo[m_totalCharacterCount].spriteAsset = spriteAsset; + m_textInfo.characterInfo[m_totalCharacterCount].textElement = spriteAsset.spriteCharacterTable[m_spriteIndex]; m_textInfo.characterInfo[m_totalCharacterCount].materialReferenceIndex = m_currentMaterialIndex; m_textInfo.characterInfo[m_totalCharacterCount].index = chars[i].stringIndex; m_textInfo.characterInfo[m_totalCharacterCount].stringLength = chars[i].length; @@ -2010,33 +2015,33 @@ protected override void GenerateTextMesh() // Handle Kerning if Enabled. #region Handle Kerning - GlyphValueRecord glyphAdjustments = new GlyphValueRecord(); - float CharacterSpacingAdjustment = m_characterSpacing; + TMP_GlyphValueRecord glyphAdjustments = new TMP_GlyphValueRecord(); + float characterSpacingAdjustment = m_characterSpacing; if (m_enableKerning) { if (m_characterCount < totalCharacterCount - 1) { - uint nextGlyph = m_textInfo.characterInfo[m_characterCount + 1].character; - KerningPairKey keyValue = new KerningPairKey((uint)charCode, nextGlyph); + uint firstGlyphIndex = m_cached_TextElement.glyphIndex; + uint secondGlyphIndex = m_textInfo.characterInfo[m_characterCount + 1].textElement.glyphIndex; + long key = new GlyphPairKey(firstGlyphIndex, secondGlyphIndex).key; - m_currentFontAsset.kerningLookupDictionary.TryGetValue((int)keyValue.key, out KerningPair adjustmentPair); - if (adjustmentPair != null) + if (m_currentFontAsset.fontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out TMP_GlyphPairAdjustmentRecord adjustmentPair)) { - glyphAdjustments = adjustmentPair.firstGlyphAdjustments; - CharacterSpacingAdjustment = adjustmentPair.ignoreSpacingAdjustments ? 0 : CharacterSpacingAdjustment; + glyphAdjustments = adjustmentPair.firstAdjustmentRecord.glyphValueRecord; + characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; } } if (m_characterCount >= 1) { - uint previousGlyph = m_textInfo.characterInfo[m_characterCount - 1].character; - KerningPairKey keyValue = new KerningPairKey(previousGlyph, (uint)charCode); + uint firstGlyphIndex = m_textInfo.characterInfo[m_characterCount - 1].textElement.glyphIndex; + uint secondGlyphIndex = m_cached_TextElement.glyphIndex; + long key = new GlyphPairKey(firstGlyphIndex, secondGlyphIndex).key; - m_currentFontAsset.kerningLookupDictionary.TryGetValue((int)keyValue.key, out KerningPair adjustmentPair); - if (adjustmentPair != null) + if (m_currentFontAsset.fontFeatureTable.m_GlyphPairAdjustmentRecordLookupDictionary.TryGetValue(key, out TMP_GlyphPairAdjustmentRecord adjustmentPair)) { - glyphAdjustments += adjustmentPair.secondGlyphAdjustments; - CharacterSpacingAdjustment = adjustmentPair.ignoreSpacingAdjustments ? 0 : CharacterSpacingAdjustment; + glyphAdjustments += adjustmentPair.secondAdjustmentRecord.glyphValueRecord; + characterSpacingAdjustment = (adjustmentPair.featureLookupFlags & FontFeatureLookupFlags.IgnoreSpacingAdjustments) == FontFeatureLookupFlags.IgnoreSpacingAdjustments ? 0 : characterSpacingAdjustment; } } } @@ -2047,7 +2052,7 @@ protected override void GenerateTextMesh() #region Handle Right-to-Left if (m_isRightToLeft) { - m_xAdvance -= ((m_cached_TextElement.glyph.metrics.horizontalAdvance * bold_xAdvance_multiplier + CharacterSpacingAdjustment + m_wordSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); + m_xAdvance -= ((m_cached_TextElement.glyph.metrics.horizontalAdvance * bold_xAdvance_multiplier + characterSpacingAdjustment + m_wordSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance -= m_wordSpacing * currentElementScale; @@ -2157,7 +2162,7 @@ protected override void GenerateTextMesh() if (m_isFXMatrixSet) { // Apply scale matrix when simulating Condensed text. - if (m_FXMatrix.m00 != 1) + if (m_FXMatrix.lossyScale.x != 1) { //top_left = m_FXMatrix.MultiplyPoint3x4(top_left); //bottom_left = m_FXMatrix.MultiplyPoint3x4(bottom_left); @@ -2387,7 +2392,7 @@ protected override void GenerateTextMesh() //m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification; - m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; + m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; m_textInfo.lineInfo[m_lineNumber].baseline = 0 - m_lineOffset; m_textInfo.lineInfo[m_lineNumber].ascender = lineAscender; @@ -2812,7 +2817,7 @@ protected override void GenerateTextMesh() } else if (m_monoSpacing != 0) { - m_xAdvance += (m_monoSpacing - monoAdvance + ((CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta); + m_xAdvance += (m_monoSpacing - monoAdvance + ((characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance += m_wordSpacing * currentElementScale; @@ -2820,9 +2825,9 @@ protected override void GenerateTextMesh() else if (!m_isRightToLeft) { float scaleFXMultiplier = 1; - if (m_isFXMatrixSet) scaleFXMultiplier = m_FXMatrix.m00; + if (m_isFXMatrixSet) scaleFXMultiplier = m_FXMatrix.lossyScale.x; - m_xAdvance += ((m_cached_TextElement.glyph.metrics.horizontalAdvance * scaleFXMultiplier * bold_xAdvance_multiplier + CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); + m_xAdvance += ((m_cached_TextElement.glyph.metrics.horizontalAdvance * scaleFXMultiplier * bold_xAdvance_multiplier + characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset + glyphAdjustments.xAdvance) * currentElementScale + m_cSpacing) * (1 - m_charWidthAdjDelta); if (char.IsWhiteSpace((char)charCode) || charCode == 0x200B) m_xAdvance += m_wordSpacing * currentElementScale; @@ -2895,9 +2900,9 @@ protected override void GenerateTextMesh() m_textInfo.lineInfo[m_lineNumber].alignment = m_lineJustification; if (m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].isVisible) - m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; + m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastVisibleCharacterOfLine].xAdvance - (characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; else - m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastCharacterOfLine].xAdvance - (CharacterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; + m_textInfo.lineInfo[m_lineNumber].maxAdvance = m_textInfo.characterInfo[m_lastCharacterOfLine].xAdvance - (characterSpacingAdjustment + m_currentFontAsset.normalSpacingOffset) * currentElementScale - m_cSpacing; m_textInfo.lineInfo[m_lineNumber].baseline = 0 - m_lineOffset; m_textInfo.lineInfo[m_lineNumber].ascender = lineAscender; @@ -3503,13 +3508,13 @@ protected override void GenerateTextMesh() switch (canvasRenderMode) { case RenderMode.ScreenSpaceOverlay: - xScale *= lossyScale / canvasScaleFactor; + xScale *= Mathf.Abs(lossyScale) / canvasScaleFactor; break; case RenderMode.ScreenSpaceCamera: - xScale *= isCameraAssigned ? lossyScale : 1; + xScale *= isCameraAssigned ? Mathf.Abs(lossyScale) : 1; break; case RenderMode.WorldSpace: - xScale *= lossyScale; + xScale *= Mathf.Abs(lossyScale); break; } @@ -4245,13 +4250,20 @@ protected override Bounds GetCompoundBounds() /// void UpdateSDFScale(float scaleDelta) { + if (scaleDelta == 0 || scaleDelta == float.PositiveInfinity) + { + m_havePropertiesChanged = true; + OnPreRenderCanvas(); + return; + } + for (int materialIndex = 0; materialIndex < m_textInfo.materialCount; materialIndex ++) { TMP_MeshInfo meshInfo = m_textInfo.meshInfo[materialIndex]; for (int i = 0; i < meshInfo.uvs2.Length; i++) { - meshInfo.uvs2[i].y *= scaleDelta; + meshInfo.uvs2[i].y *= Mathf.Abs(scaleDelta); } } diff --git a/package.json b/package.json index 933530c..ff0af5c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "com.unity.textmeshpro", "displayName": "TextMesh Pro", - "version": "1.4.0-preview.1b", + "version": "1.4.0-preview.2a", "unity": "2018.3", "description": "TextMesh Pro is the ultimate text solution for Unity. It's the perfect replacement for Unity's UI Text and the legacy Text Mesh.\n\nPowerful and easy to use, TextMesh Pro uses Advanced Text Rendering techniques along with a set of custom shaders; delivering substantial visual quality improvements while giving users incredible flexibility when it comes to text styling and texturing.\n\nTextMesh Pro provides Improved Control over text formatting and layout with features like character, word, line and paragraph spacing, kerning, justified text, Links, over 30 Rich Text Tags available, support for Multi Font & Sprites, Custom Styles and more.\n\nGreat performance. Since the geometry created by TextMesh Pro uses two triangles per character just like Unity's text components, this improved visual quality and flexibility comes at no additional performance cost.", "keywords": [ @@ -15,6 +15,6 @@ "repository": { "type": "git", "url": "https://gitlab.cds.internal.unity3d.com/upm-packages/text/com.unity.textmeshpro.git", - "revision": "44c2cd5c" + "revision": "f10547e8" } }