using UnityEngine; using UnityEngine.Serialization; using UnityEngine.TextCore; using UnityEngine.TextCore.LowLevel; using System; using System.Collections; using System.Collections.Generic; using System.Linq; namespace TMPro { /// /// Class that contains the basic information about the font. /// [Serializable] public class FaceInfo_Legacy { public string Name; public float PointSize; public float Scale; public int CharacterCount; public float LineHeight; public float Baseline; public float Ascender; public float CapHeight; public float Descender; public float CenterLine; public float SuperscriptOffset; public float SubscriptOffset; public float SubSize; public float Underline; public float UnderlineThickness; public float strikethrough; public float strikethroughThickness; public float TabWidth; public float Padding; public float AtlasWidth; public float AtlasHeight; } // Class which contains the Glyph Info / Character definition for each character contained in the font asset. [Serializable] public class TMP_Glyph : TMP_TextElement_Legacy { /// /// Function to create a deep copy of a GlyphInfo. /// /// /// public static TMP_Glyph Clone(TMP_Glyph source) { TMP_Glyph copy = new TMP_Glyph(); copy.id = source.id; copy.x = source.x; copy.y = source.y; copy.width = source.width; copy.height = source.height; copy.xOffset = source.xOffset; copy.yOffset = source.yOffset; copy.xAdvance = source.xAdvance; copy.scale = source.scale; return copy; } } // Structure which holds the font creation settings [Serializable] public struct FontAssetCreationSettings { public string sourceFontFileName; public string sourceFontFileGUID; public int faceIndex; public int pointSizeSamplingMode; public int pointSize; public int padding; public int paddingMode; public int packingMode; public int atlasWidth; public int atlasHeight; public int characterSetSelectionMode; public string characterSequence; public string referencedFontAssetGUID; public string referencedTextAssetGUID; public int fontStyle; public float fontStyleModifier; public int renderMode; public bool includeFontFeatures; internal FontAssetCreationSettings(string sourceFontFileGUID, int pointSize, int pointSizeSamplingMode, int padding, int packingMode, int atlasWidth, int atlasHeight, int characterSelectionMode, string characterSet, int renderMode) { this.sourceFontFileName = string.Empty; this.sourceFontFileGUID = sourceFontFileGUID; this.faceIndex = 0; this.pointSize = pointSize; this.pointSizeSamplingMode = pointSizeSamplingMode; this.padding = padding; this.paddingMode = 2; this.packingMode = packingMode; this.atlasWidth = atlasWidth; this.atlasHeight = atlasHeight; this.characterSequence = characterSet; this.characterSetSelectionMode = characterSelectionMode; this.renderMode = renderMode; this.referencedFontAssetGUID = string.Empty; this.referencedTextAssetGUID = string.Empty; this.fontStyle = 0; this.fontStyleModifier = 0; this.includeFontFeatures = false; } } /// /// Contains the font assets for the regular and italic styles associated with a given font weight. /// [Serializable] public struct TMP_FontWeightPair { public TMP_FontAsset regularTypeface; public TMP_FontAsset italicTypeface; } public struct KerningPairKey { public uint ascii_Left; public uint ascii_Right; public uint key; public KerningPairKey(uint ascii_left, uint ascii_right) { ascii_Left = ascii_left; ascii_Right = ascii_right; key = (ascii_right << 16) + ascii_left; } } /// /// Positional adjustments of a glyph /// [Serializable] public struct GlyphValueRecord_Legacy { public float xPlacement; public float yPlacement; public float xAdvance; public float yAdvance; internal GlyphValueRecord_Legacy(UnityEngine.TextCore.LowLevel.GlyphValueRecord valueRecord) { this.xPlacement = valueRecord.xPlacement; this.yPlacement = valueRecord.yPlacement; this.xAdvance = valueRecord.xAdvance; this.yAdvance = valueRecord.yAdvance; } public static GlyphValueRecord_Legacy operator +(GlyphValueRecord_Legacy a, GlyphValueRecord_Legacy b) { GlyphValueRecord_Legacy c; c.xPlacement = a.xPlacement + b.xPlacement; c.yPlacement = a.yPlacement + b.yPlacement; c.xAdvance = a.xAdvance + b.xAdvance; c.yAdvance = a.yAdvance + b.yAdvance; return c; } } [Serializable] public class KerningPair { /// /// The first glyph part of a kerning pair. /// public uint firstGlyph { get { return m_FirstGlyph; } set { m_FirstGlyph = value; } } [FormerlySerializedAs("AscII_Left")] [SerializeField] private uint m_FirstGlyph; /// /// The positional adjustment of the first glyph. /// public GlyphValueRecord_Legacy firstGlyphAdjustments { get { return m_FirstGlyphAdjustments; } } [SerializeField] private GlyphValueRecord_Legacy m_FirstGlyphAdjustments; /// /// The second glyph part of a kerning pair. /// public uint secondGlyph { get { return m_SecondGlyph; } set { m_SecondGlyph = value; } } [FormerlySerializedAs("AscII_Right")] [SerializeField] private uint m_SecondGlyph; /// /// The positional adjustment of the second glyph. /// public GlyphValueRecord_Legacy secondGlyphAdjustments { get { return m_SecondGlyphAdjustments; } } [SerializeField] 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 spacing. /// public bool ignoreSpacingAdjustments { get { return m_IgnoreSpacingAdjustments; } } [SerializeField] private bool m_IgnoreSpacingAdjustments = false; public KerningPair() { m_FirstGlyph = 0; m_FirstGlyphAdjustments = new GlyphValueRecord_Legacy(); m_SecondGlyph = 0; m_SecondGlyphAdjustments = new GlyphValueRecord_Legacy(); } public KerningPair(uint left, uint right, float offset) { firstGlyph = left; m_SecondGlyph = right; xOffset = offset; } public KerningPair(uint firstGlyph, GlyphValueRecord_Legacy firstGlyphAdjustments, uint secondGlyph, GlyphValueRecord_Legacy secondGlyphAdjustments) { m_FirstGlyph = firstGlyph; m_FirstGlyphAdjustments = firstGlyphAdjustments; m_SecondGlyph = secondGlyph; m_SecondGlyphAdjustments = secondGlyphAdjustments; } internal void ConvertLegacyKerningData() { m_FirstGlyphAdjustments.xAdvance = xOffset; //xOffset = 0; } } [Serializable] public class KerningTable { public List kerningPairs; public KerningTable() { kerningPairs = new List(); } public void AddKerningPair() { if (kerningPairs.Count == 0) { kerningPairs.Add(new KerningPair(0, 0, 0)); } else { uint left = kerningPairs.Last().firstGlyph; uint right = kerningPairs.Last().secondGlyph; float xoffset = kerningPairs.Last().xOffset; kerningPairs.Add(new KerningPair(left, right, xoffset)); } } /// /// Add Kerning Pair /// /// First glyph /// Second glyph /// xAdvance value /// public int AddKerningPair(uint first, uint second, float offset) { int index = kerningPairs.FindIndex(item => item.firstGlyph == first && item.secondGlyph == second); if (index == -1) { kerningPairs.Add(new KerningPair(first, second, offset)); return 0; } // Return -1 if Kerning Pair already exists. return -1; } /// /// Add Glyph pair adjustment record /// /// The first glyph /// Adjustment record for the first glyph /// The second glyph /// Adjustment record for the second glyph /// public int AddGlyphPairAdjustmentRecord(uint first, GlyphValueRecord_Legacy firstAdjustments, uint second, GlyphValueRecord_Legacy secondAdjustments) { int index = kerningPairs.FindIndex(item => item.firstGlyph == first && item.secondGlyph == second); if (index == -1) { kerningPairs.Add(new KerningPair(first, firstAdjustments, second, secondAdjustments)); return 0; } // Return -1 if Kerning Pair already exists. return -1; } public void RemoveKerningPair(int left, int right) { int index = kerningPairs.FindIndex(item => item.firstGlyph == left && item.secondGlyph == right); if (index != -1) kerningPairs.RemoveAt(index); } public void RemoveKerningPair(int index) { kerningPairs.RemoveAt(index); } public void SortKerningPairs() { // Sort List of Kerning Info if (kerningPairs.Count > 0) kerningPairs = kerningPairs.OrderBy(s => s.firstGlyph).ThenBy(s => s.secondGlyph).ToList(); } } public static class TMP_FontUtilities { private static List k_searchedFontAssets; /// /// Search through the given font and its fallbacks for the specified character. /// /// The font asset to search for the given character. /// The character to find. /// out parameter containing the glyph for the specified character (if found). /// public static TMP_FontAsset SearchForCharacter(TMP_FontAsset font, uint unicode, out TMP_Character character) { if (k_searchedFontAssets == null) k_searchedFontAssets = new List(); k_searchedFontAssets.Clear(); return SearchForCharacterInternal(font, unicode, out character); } /// /// Search through the given list of fonts and their possible fallbacks for the specified character. /// /// /// /// /// public static TMP_FontAsset SearchForCharacter(List fonts, uint unicode, out TMP_Character character) { return SearchForCharacterInternal(fonts, unicode, out character); } private static TMP_FontAsset SearchForCharacterInternal(TMP_FontAsset font, uint unicode, out TMP_Character character) { character = null; if (font == null) return null; if (font.characterLookupTable.TryGetValue(unicode, out character)) { if (character.textAsset != null) return font; // Remove character from lookup table font.characterLookupTable.Remove(unicode); } if (font.fallbackFontAssetTable != null && font.fallbackFontAssetTable.Count > 0) { for (int i = 0; i < font.fallbackFontAssetTable.Count && character == null; i++) { TMP_FontAsset temp = font.fallbackFontAssetTable[i]; if (temp == null) continue; int id = temp.GetInstanceID(); // Skip over the fallback font asset in the event it is null or if already searched. if (k_searchedFontAssets.Contains(id)) continue; // Add to list of font assets already searched. k_searchedFontAssets.Add(id); temp = SearchForCharacterInternal(temp, unicode, out character); if (temp != null) return temp; } } return null; } private static TMP_FontAsset SearchForCharacterInternal(List fonts, uint unicode, out TMP_Character character) { character = null; if (fonts != null && fonts.Count > 0) { for (int i = 0; i < fonts.Count; i++) { TMP_FontAsset fontAsset = SearchForCharacterInternal(fonts[i], unicode, out character); if (fontAsset != null) return fontAsset; } } return null; } } }