Exemple #1
0
 /// <summary>
 /// Writes text from the input parameter to the textholder parameter
 /// with characteristics based on the parameters. Has a typewriter '
 /// effect.
 /// </summary>
 /// <param name="inputText">
 /// The input string to display.
 /// </param>
 /// <param name="textHolder">
 /// The TextMeshProUGUI component to write to.
 /// </param>
 /// <param name="textColour">
 /// The text color to be displayed</param>
 /// <param name="textFont">
 /// The text font to be displayed
 /// </param>
 /// <param name="charDelay">
 /// The time in seconds between the display of each character in the
 /// input string (typewriter delay)
 /// </param>
 /// <param name="delayBeforeNextBlock">
 /// The time in seconds before the next dialogue item is displayed
 /// </param>
 /// <param name="waitForTime">
 /// If true, the dialogue will wait for the delay before displaying the
 /// next dialogue. If false, the dialogue will wait for the next key
 /// pressed.
 /// </param>
 /// <param name="textSize">
 /// The size of the text to display.
 /// </param>
 /// <returns>
 /// IEnumerator that can be placed in a Quoratine to write the text.
 /// </returns>
 protected IEnumerator WriteText(string inputText, TextMeshProUGUI
                                 textHolder, Color textColour, TMPro.TMP_FontAsset textFont,
                                 float charDelay, float delayBeforeNextBlock,
                                 bool waitForTime, float textSize)
 {
     textHolder.font     = textFont;
     textHolder.color    = textColour;
     textHolder.fontSize = textSize;
     for (int i = 0; i < inputText.Length; i++)
     {
         if (SkipWriting && !waitForTime)
         {
             break;
         }
         textHolder.text += inputText[i];
         PlayTypingSound();
         yield return(new WaitForSeconds(charDelay));
     }
     if (SkipWriting)
     {
         textHolder.text = inputText;
     }
     if (waitForTime)
     {
         yield return(new WaitForSeconds(delayBeforeNextBlock));
     }
     Finished = true;
 }
        /// <summary>
        /// Function to add a new material reference and returning its index in the material reference array.
        /// </summary>
        /// <param name="material"></param>
        /// <param name="fontAsset"></param>
        /// <param name="materialReferences"></param>
        /// <param name="materialReferenceIndexLookup"></param>
        /// <returns></returns>
        public static int AddMaterialReference(Material material, TMP_FontAsset fontAsset, MaterialReference[] materialReferences, Dictionary<int, int> materialReferenceIndexLookup)
        {
            int materialID = material.GetInstanceID();
            int index = 0;

            if (materialReferenceIndexLookup.TryGetValue(materialID, out index))
            {
                return index;
            }
            else
            {
                index = materialReferenceIndexLookup.Count;

                // Add new reference index
                materialReferenceIndexLookup[materialID] = index;

                materialReferences[index].index = index;
                materialReferences[index].fontAsset = fontAsset;
                materialReferences[index].spriteAsset = null;
                materialReferences[index].material = material;
                materialReferences[index].isDefaultMaterial = materialID == fontAsset.material.GetInstanceID() ? true : false;
                //materialReferences[index].padding = 0;
                materialReferences[index].referenceCount = 0;

                return index;
            }
        }
        private void LoadFonts()
        {
            TMPro.TMP_FontAsset[] fonts = Resources.FindObjectsOfTypeAll(typeof(TMPro.TMP_FontAsset)) as TMPro.TMP_FontAsset[];

            for (int i = 0; i < fonts.Length; i++)
            {
                TMPro.TMP_FontAsset font = fonts[i];
                fontsDictionary.Add(font.name, font);
            }
        }
 /// <summary>
 /// Constructor for new Material Reference.
 /// </summary>
 /// <param name="index"></param>
 /// <param name="fontAsset"></param>
 /// <param name="spriteAsset"></param>
 /// <param name="material"></param>
 /// <param name="padding"></param>
 public MaterialReference(int index, TMP_FontAsset fontAsset, TMP_SpriteAsset spriteAsset, Material material, float padding)
 {
     this.index = index;
     this.fontAsset = fontAsset;
     this.spriteAsset = spriteAsset;
     this.material = material;
     this.isDefaultMaterial = material.GetInstanceID() == fontAsset.material.GetInstanceID() ? true : false;
     this.padding = padding;
     this.referenceCount = 0;
 }
        private HelpPages LoadHelpPagesForLanguage(Language lang, TMPro.TMP_FontAsset font)
        {
            var fileContents = Resources.Load <TextAsset>(string.Format("Help/{0}", lang.id)).text;
            var pages        = HelpPageParser.Parse(fileContents);

            return(new HelpPages()
            {
                Font = font,
                Pages = pages
            });
        }
        protected virtual void OnValidate()
        {
            //Force pick references on first validate (prevent recalculate every time that unity compiles)
            if (_isFirstValidate)
            {
                _isFirstValidate           = false;
                _previousFont              = m_Font;
                _previousFontTmpPro        = m_FontTMPro;
                _previousImageSetTextAsset = m_ImageSetTextAsset;
            }


            //Validate Name
            if (_previousFontTmpPro != null || _previousFont != null)
            {
                var fontName = _previousFont != null ? _previousFont.name :
#if UNITY_2018_3_OR_NEWER
                               (_previousFontTmpPro != null ? _previousFontTmpPro.faceInfo.familyName :
#else
                               (_previousFontTmpPro != null ? _previousFontTmpPro.fontInfo.Name :
#endif
                                name);
                if (!fontName.EndsWith(VECTOR_FONT_SUFIX))
                {
                    fontName += VECTOR_FONT_SUFIX;
                }
                if (fontName != name)
                {
                    name = fontName;
                    var path = UnityEditor.AssetDatabase.GetAssetPath(this);
                    if (!string.IsNullOrEmpty(path))
                    {
                        UnityEditor.AssetDatabase.RenameAsset(path, name);
                        UnityEditor.AssetDatabase.Refresh();
                    }
                }
            }

            //Try recalculate if invalid
            var v_fontChaged = false;

            if (_previousFont != m_Font || _previousFontTmpPro != m_FontTMPro)
            {
                _previousFont       = m_Font;
                _previousFontTmpPro = m_FontTMPro;
                v_fontChaged        = true;
            }
            if (_previousImageSetTextAsset != m_ImageSetTextAsset || (m_ImageSetTextAsset == null && v_fontChaged))
            {
                _previousImageSetTextAsset = m_ImageSetTextAsset;
                RecreateIconSet();
            }
        }
Exemple #7
0
        /// <summary>

        /// Constructor for new Material Reference.

        /// </summary>

        /// <param name="index"></param>

        /// <param name="fontAsset"></param>

        /// <param name="spriteAsset"></param>

        /// <param name="material"></param>

        /// <param name="padding"></param>

        public MaterialReference(int index, TMP_FontAsset fontAsset, TMP_SpriteAsset spriteAsset, Material material, float padding)

        {
            this.index = index;

            this.fontAsset = fontAsset;

            this.spriteAsset = spriteAsset;

            this.material = material;

            this.isDefaultMaterial = material.GetInstanceID() == fontAsset.material.GetInstanceID() ? true : false;

            this.isFallbackMaterial = false;

            this.fallbackMaterial = null;

            this.padding = padding;

            this.referenceCount = 0;
        }
Exemple #8
0
        private static TMP_FontAsset SearchForGlyphInternal(TMP_FontAsset font, int character, out TMP_Glyph glyph)
        {
            glyph = null;

            if (font == null)
            {
                return(null);
            }

            if (font.characterDictionary.TryGetValue(character, out glyph))
            {
                return(font);
            }
            else if (font.fallbackFontAssets != null && font.fallbackFontAssets.Count > 0)
            {
                for (int i = 0; i < font.fallbackFontAssets.Count && glyph == null; i++)
                {
                    TMP_FontAsset temp = font.fallbackFontAssets[i];
                    int           id   = temp.GetInstanceID();

                    // Skip over the fallback font asset in the event it is null or if already searched.
                    if (temp == null || k_searchedFontAssets.Contains(id))
                    {
                        continue;
                    }

                    // Add to list of font assets already searched.
                    k_searchedFontAssets.Add(id);

                    temp = SearchForGlyphInternal(temp, character, out glyph);

                    if (temp != null)
                    {
                        return(temp);
                    }
                }
            }

            return(null);
        }
Exemple #9
0
        internal static Material GetFallbackMaterial(TMP_FontAsset fontAsset, Material sourceMaterial, int atlasIndex)
        {
            int              sourceMaterialID = sourceMaterial.GetInstanceID();
            Texture          tex   = fontAsset.atlasTextures[atlasIndex];
            int              texID = tex.GetInstanceID();
            long             key   = (long)sourceMaterialID << 32 | (long)(uint)texID;
            FallbackMaterial fallback;

            if (m_fallbackMaterials.TryGetValue(key, out fallback))
            {
                return(fallback.fallbackMaterial);
            }

            // Create new material from the source material and assign relevant atlas texture
            Material fallbackMaterial = new Material(sourceMaterial);

            fallbackMaterial.SetTexture(ShaderUtilities.ID_MainTex, tex);

            fallbackMaterial.hideFlags = HideFlags.HideAndDontSave;

            #if UNITY_EDITOR
            fallbackMaterial.name += " + " + tex.name;
            #endif

            fallback                  = new FallbackMaterial();
            fallback.baseID           = sourceMaterialID;
            fallback.baseMaterial     = fontAsset.material;
            fallback.fallbackID       = key;
            fallback.fallbackMaterial = fallbackMaterial;
            fallback.count            = 0;

            m_fallbackMaterials.Add(key, fallback);
            m_fallbackMaterialLookup.Add(fallbackMaterial.GetInstanceID(), key);

            #if TMP_DEBUG_MODE
            ListFallbackMaterials();
            #endif

            return(fallbackMaterial);
        }
 private static TMP_FontAsset SearchForGlyphInternal(TMP_FontAsset font, int character, out TMP_Glyph glyph)
 {
     glyph = null;
     if (font == null)
     {
         return(null);
     }
     if (font.characterDictionary.TryGetValue(character, out glyph))
     {
         return(font);
     }
     if (font.fallbackFontAssets != null && font.fallbackFontAssets.Count > 0)
     {
         for (int i = 0; i < font.fallbackFontAssets.Count; i++)
         {
             if (glyph != null)
             {
                 break;
             }
             TMP_FontAsset tMP_FontAsset = font.fallbackFontAssets[i];
             if (tMP_FontAsset == null)
             {
                 continue;
             }
             int instanceID = tMP_FontAsset.GetInstanceID();
             if (!k_searchedFontAssets.Contains(instanceID))
             {
                 k_searchedFontAssets.Add(instanceID);
                 tMP_FontAsset = SearchForGlyphInternal(tMP_FontAsset, character, out glyph);
                 if (tMP_FontAsset != null)
                 {
                     return(tMP_FontAsset);
                 }
             }
         }
     }
     return(null);
 }
        private void ResetFontAssetData(TMP_FontAsset font)
        {
            Dictionary <uint, int> charRefDictionary;

            if (!m_FontCharacterLookupDictionary.TryGetValue(font, out charRefDictionary))
            {
                return;
            }

            m_CharTryAddCharacters.Clear();
            foreach (var kv in charRefDictionary)
            {
                m_CharTryAddCharacters.Add((char)kv.Key);
            }

            HashSet <char> nonexistentCharacters;

            if (!m_CharNonexistentCharacters.TryGetValue(font, out nonexistentCharacters))
            {
                nonexistentCharacters = new HashSet <char>();
                m_CharNonexistentCharacters.Add(font, nonexistentCharacters);
            }

            // 重设的话,要把所有用到的文本组件刷一下,不然会有残留影像
            font.ClearFontAssetData();
            m_CharMissingCharacters.Clear();
            bool ret = font.TryAddCharacters(m_CharTryAddCharacters, m_CharMissingCharacters);

            MissingCharactersToNonexistent(font, nonexistentCharacters, charRefDictionary);

            foreach (var kv in m_TextOldCharacterDictionary)
            {
                if (kv.Key)
                {
                    kv.Key.SetVerticesDirty();
                }
            }
        }
Exemple #12
0
        public static void CreateFontAssetVariant()
        {
            Object target = Selection.activeObject;

            // Make sure the selection is a font file
            if (target == null || target.GetType() != typeof(TMP_FontAsset))
            {
                Debug.LogWarning("A Font file must first be selected in order to create a Font Asset.");
                return;
            }

            TMP_FontAsset sourceFontAsset = (TMP_FontAsset)target;

            string sourceFontFilePath = AssetDatabase.GetAssetPath(target);

            string folderPath = Path.GetDirectoryName(sourceFontFilePath);
            string assetName  = Path.GetFileNameWithoutExtension(sourceFontFilePath);

            string newAssetFilePathWithName = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + assetName + " - Variant.asset");

            // Set Texture and Material reference to the source font asset.
            TMP_FontAsset fontAsset = ScriptableObject.Instantiate <TMP_FontAsset>(sourceFontAsset);

            AssetDatabase.CreateAsset(fontAsset, newAssetFilePathWithName);

            fontAsset.atlasPopulationMode = AtlasPopulationMode.Static;

            // Initialize array for the font atlas textures.
            fontAsset.atlasTextures = sourceFontAsset.atlasTextures;
            fontAsset.material      = sourceFontAsset.material;

            // Not sure if this is still necessary in newer versions of Unity.
            EditorUtility.SetDirty(fontAsset);

            AssetDatabase.SaveAssets();
        }
        /// <summary>
        /// Function to check if a certain font asset is contained in the material reference array.
        /// </summary>
        /// <param name="materialReferences"></param>
        /// <param name="fontAsset"></param>
        /// <returns></returns>
        public static bool Contains(MaterialReference[] materialReferences, TMP_FontAsset fontAsset)
        {
            int id = fontAsset.GetInstanceID();

            for (int i = 0; i < materialReferences.Length && materialReferences[i].fontAsset != null; i++)
            {
                if (materialReferences[i].fontAsset.GetInstanceID() == id)
                    return true;
            }

            return false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected TMP_FontAsset GetAlternativeFontAsset()
        {
            bool isItalic = (m_style & FontStyles.Italic) == FontStyles.Italic || (m_fontStyle & FontStyles.Italic) == FontStyles.Italic;

            TMP_FontAsset fontAsset = null;

            int weightIndex = m_fontWeightInternal / 100;

            if (isItalic)
                fontAsset = m_currentFontAsset.fontWeights[weightIndex].italicTypeface;
            else
                fontAsset = m_currentFontAsset.fontWeights[weightIndex].regularTypeface;

            if (fontAsset == null) return m_currentFontAsset;

            m_currentFontAsset = fontAsset;

            return m_currentFontAsset;
        }
Exemple #15
0
        // Event received when font asset properties are changed in Font Inspector
        void ON_FONT_PROPERTY_CHANGED(bool isChanged, TMP_FontAsset font)
        {
            if (font == m_fontAsset)
            {
                //Debug.Log("ON_FONT_PROPERTY_CHANGED event received.");
                m_havePropertiesChanged = true;
                m_hasFontAssetChanged = true;

                SetVerticesDirty();
            }
        }
Exemple #16
0
        /// <summary>
        /// Function to extract all the characters from a font asset.
        /// </summary>
        /// <param name="fontAsset"></param>
        /// <returns></returns>
        public static string GetCharacters(TMP_FontAsset fontAsset)
        {
            string characters = string.Empty;

            for (int i = 0; i < fontAsset.m_glyphInfoList.Count; i++)
            {
                characters += (char)fontAsset.m_glyphInfoList[i].id;
            }

            return characters;
        }
        static void CreateFontAssetFromSelectedObject(Object target)
        {
            Font sourceFont = (Font)target;

            string sourceFontFilePath = AssetDatabase.GetAssetPath(target);

            string folderPath = Path.GetDirectoryName(sourceFontFilePath);
            string assetName = Path.GetFileNameWithoutExtension(sourceFontFilePath);

            string newAssetFilePathWithName = AssetDatabase.GenerateUniqueAssetPath(folderPath + "/" + assetName + " SDF.asset");

            // Initialize FontEngine
            FontEngine.InitializeFontEngine();

            // Load Font Face
            if (FontEngine.LoadFontFace(sourceFont, 90) != FontEngineError.Success)
            {
                Debug.LogWarning("Unable to load font face for [" + sourceFont.name + "]. Make sure \"Include Font Data\" is enabled in the Font Import Settings.", sourceFont);
                return;
            }

            // Create new Font Asset
            TMP_FontAsset fontAsset = ScriptableObject.CreateInstance<TMP_FontAsset>();
            AssetDatabase.CreateAsset(fontAsset, newAssetFilePathWithName);

            fontAsset.version = "1.1.0";

            fontAsset.faceInfo = FontEngine.GetFaceInfo();

            // Set font reference and GUID
            fontAsset.m_SourceFontFileGUID = AssetDatabase.AssetPathToGUID(sourceFontFilePath);
            fontAsset.m_SourceFontFile_EditorRef = sourceFont;
            fontAsset.atlasPopulationMode = AtlasPopulationMode.Dynamic;

            // Default atlas resolution is 1024 x 1024.
            int atlasWidth = fontAsset.atlasWidth = 1024;
            int atlasHeight = fontAsset.atlasHeight = 1024;
            int atlasPadding = fontAsset.atlasPadding = 9;
            fontAsset.atlasRenderMode = GlyphRenderMode.SDFAA;

            // Initialize array for the font atlas textures.
            fontAsset.atlasTextures = new Texture2D[1];

            // Create atlas texture of size zero.
            Texture2D texture = new Texture2D(0, 0, TextureFormat.Alpha8, false);

            texture.name = assetName + " Atlas";
            fontAsset.atlasTextures[0] = texture;
            AssetDatabase.AddObjectToAsset(texture, fontAsset);

            // Add free rectangle of the size of the texture.
            int packingModifier = ((GlyphRasterModes)fontAsset.atlasRenderMode & GlyphRasterModes.RASTER_MODE_BITMAP) == GlyphRasterModes.RASTER_MODE_BITMAP ? 0 : 1;
            fontAsset.freeGlyphRects = new List<GlyphRect>() { new GlyphRect(0, 0, atlasWidth - packingModifier, atlasHeight - packingModifier) };
            fontAsset.usedGlyphRects = new List<GlyphRect>();

            // Create new Material and Add it as Sub-Asset
            Shader default_Shader = Shader.Find("TextMeshPro/Distance Field");
            Material tmp_material = new Material(default_Shader);

            tmp_material.name = texture.name + " Material";
            tmp_material.SetTexture(ShaderUtilities.ID_MainTex, texture);
            tmp_material.SetFloat(ShaderUtilities.ID_TextureWidth, atlasWidth);
            tmp_material.SetFloat(ShaderUtilities.ID_TextureHeight, atlasHeight);

            tmp_material.SetFloat(ShaderUtilities.ID_GradientScale, atlasPadding + packingModifier);

            tmp_material.SetFloat(ShaderUtilities.ID_WeightNormal, fontAsset.normalStyle);
            tmp_material.SetFloat(ShaderUtilities.ID_WeightBold, fontAsset.boldStyle);

            fontAsset.material = tmp_material;

            AssetDatabase.AddObjectToAsset(tmp_material, fontAsset);

            // Add Font Asset Creation Settings
            fontAsset.creationSettings = new FontAssetCreationSettings(fontAsset.m_SourceFontFileGUID, fontAsset.faceInfo.pointSize, 0, atlasPadding, 0, 1024, 1024, 7, string.Empty, (int)GlyphRenderMode.SDFAA);

            // Not sure if this is still necessary in newer versions of Unity.
            EditorUtility.SetDirty(fontAsset);

            AssetDatabase.SaveAssets();
        }
        /// <summary>
        /// Returns the text element (character) for the given unicode value taking into consideration the requested font style and weight.
        /// Function searches the source font asset, its list of font assets assigned as alternative typefaces and potentially its fallbacks.
        /// The font asset out parameter contains a reference to the font asset containing the character.
        /// The typeface type indicates whether the returned font asset is the source font asset, an alternative typeface or fallback font asset.
        /// </summary>
        /// <param name="unicode">The unicode value of the requested character</param>
        /// <param name="sourceFontAsset">The font asset to be searched</param>
        /// <param name="includeFallbacks">Include the fallback font assets in the search</param>
        /// <param name="fontStyle">The font style</param>
        /// <param name="fontWeight">The font weight</param>
        /// <param name="type">Indicates if the OUT font asset is an alternative typeface or fallback font asset</param>
        /// <param name="fontAsset">The font asset that contains the requested character</param>
        /// <returns></returns>
        public static TMP_Character GetCharacterFromFontAsset(uint unicode, TMP_FontAsset sourceFontAsset, bool includeFallbacks, FontStyles fontStyle, FontWeight fontWeight, out bool isAlternativeTypeface, out TMP_FontAsset fontAsset)
        {
            if (includeFallbacks)
            {
                if (k_SearchedFontAssets == null)
                {
                    k_SearchedFontAssets = new List <int>();
                }
                else
                {
                    k_SearchedFontAssets.Clear();
                }
            }

            return(GetCharacterFromFontAsset_Internal(unicode, sourceFontAsset, includeFallbacks, fontStyle, fontWeight, out isAlternativeTypeface, out fontAsset));
        }
Exemple #19
0
 /// <summary>
 ///
 /// </summary>
 /// <param name="fontAsset"></param>
 internal static void RegisterFontAssetForDefinitionRefresh(TMP_FontAsset fontAsset)
 {
     instance.InternalRegisterFontAssetForDefinitionRefresh(fontAsset);
 }
        private void AddMissingCharacters(TMP_FontAsset font)
        {
            font = GetNextDynamicFontAsset(font);
            if (font == null)
            {
                return;
            }

            Dictionary <uint, int> charRefDictionary;

            if (!m_FontCharacterLookupDictionary.TryGetValue(font, out charRefDictionary))
            {
                charRefDictionary = new Dictionary <uint, int>();
                m_FontCharacterLookupDictionary.Add(font, charRefDictionary);
            }

            HashSet <char> nonexistentCharacters;

            if (!m_CharNonexistentCharacters.TryGetValue(font, out nonexistentCharacters))
            {
                nonexistentCharacters = new HashSet <char>();
                m_CharNonexistentCharacters.Add(font, nonexistentCharacters);
            }

            m_CharTryAddCharacters.Clear();
            m_CharMissingCharacters2.Clear();
            foreach (var charMissingCharacter in m_CharMissingCharacters)
            {
                // 如果已经被使用过,则使用计数+1
                int count;
                if (charRefDictionary.TryGetValue((uint)charMissingCharacter, out count))
                {
                    count++;
                    charRefDictionary[charMissingCharacter] = count;
                    continue;
                }

                // 无法生成的字符,不计算
                if (nonexistentCharacters.Contains(charMissingCharacter))
                {
                    m_CharMissingCharacters2.Add(charMissingCharacter);
                    continue;
                }

                count = 1;
                charRefDictionary.Add(charMissingCharacter, count);

                // 优化,如果此字符已经动态生成,就不再放到生成串里
                if (!(font.characterLookupTable != null && font.HasCharacter(charMissingCharacter)))
                {
                    m_CharTryAddCharacters.Add(charMissingCharacter);
                }
            }

            if (m_CharTryAddCharacters.Count > 0 && font.characterLookupTable != null)
            {
                m_CharMissingCharacters.Clear();
                bool ret = font.TryAddCharacters(m_CharTryAddCharacters, m_CharMissingCharacters);
                MissingCharactersToNonexistent(font, nonexistentCharacters, charRefDictionary);

                foreach (var charMissingCharacter in m_CharMissingCharacters)
                {
                    m_CharMissingCharacters2.Add(charMissingCharacter);
                }

                if (!ret)
                {
                    ResetFontAssetData(font);
                }

                m_CharMissingCharacters.Clear();
                foreach (var charMissingCharacter in m_CharMissingCharacters2)
                {
                    m_CharMissingCharacters.Add(charMissingCharacter);
                }
            }

            // 判断下一级回调
            if (m_CharMissingCharacters.Count > 0)
            {
                AddMissingCharacters(font);
            }
        }
        /// <summary>
        /// Internal Function returning the Font Asset corresponding to the provided hash code.
        /// </summary>
        /// <param name="hashCode"></param>
        /// <param name="fontAsset"></param>
        /// <returns></returns>
        private bool TryGetFontAssetInternal(int hashCode, out TMP_FontAsset fontAsset)
        {
            fontAsset = null;

            if (m_FontAssetReferenceLookup.TryGetValue(hashCode, out fontAsset))
            {
                return true;
            }

            return false;
        }
        /// <summary>
        ///  Add new Font Asset reference to dictionary.
        /// </summary>
        /// <param name="fontAsset"></param>
        private void AddFontAssetInternal(TMP_FontAsset fontAsset)
        {
            if (m_FontAssetReferenceLookup.ContainsKey(fontAsset.hashCode)) return;

            // Add reference to the font asset.
            m_FontAssetReferenceLookup.Add(fontAsset.hashCode, fontAsset);

            // Add reference to the font material.
            m_FontMaterialReferenceLookup.Add(fontAsset.materialHashCode, fontAsset.material);
        }
        /// <summary>
        /// Add new material reference and return the index of this new reference in the materialReferences array.
        /// </summary>
        /// <param name="material"></param>
        /// <param name="materialHashCode"></param>
        /// <param name="fontAsset"></param>
        //public int AddMaterial(Material material, int materialHashCode, TMP_FontAsset fontAsset)
        //{
        //    if (!m_MaterialReferenceLookup.ContainsKey(materialHashCode))
        //    {
        //        int index = m_MaterialReferenceLookup.Count;
        //        materialReferences[index].fontAsset = fontAsset;
        //        materialReferences[index].material = material;
        //        materialReferences[index].isDefaultMaterial = material.GetInstanceID() == fontAsset.material.GetInstanceID() ? true : false;
        //        materialReferences[index].index = index;
        //        materialReferences[index].referenceCount = 0;
        //        m_MaterialReferenceLookup[materialHashCode] = index;
        //        // Compute Padding value and store it
        //        // TODO
        //        int fontAssetHashCode = fontAsset.hashCode;
        //        if (!m_FontAssetReferenceLookup.ContainsKey(fontAssetHashCode))
        //            m_FontAssetReferenceLookup.Add(fontAssetHashCode, fontAsset);
        //        m_countInternal += 1;
        //        return index;
        //    }
        //    else
        //    {
        //        return m_MaterialReferenceLookup[materialHashCode];
        //    }
        //}
        /// <summary>
        /// Add new material reference and return the index of this new reference in the materialReferences array.
        /// </summary>
        /// <param name="material"></param>
        /// <param name="materialHashCode"></param>
        /// <param name="spriteAsset"></param>
        /// <returns></returns>
        //public int AddMaterial(Material material, int materialHashCode, TMP_SpriteAsset spriteAsset)
        //{
        //    if (!m_MaterialReferenceLookup.ContainsKey(materialHashCode))
        //    {
        //        int index = m_MaterialReferenceLookup.Count;
        //        materialReferences[index].fontAsset = materialReferences[0].fontAsset;
        //        materialReferences[index].spriteAsset = spriteAsset;
        //        materialReferences[index].material = material;
        //        materialReferences[index].isDefaultMaterial = true;
        //        materialReferences[index].index = index;
        //        materialReferences[index].referenceCount = 0;
        //        m_MaterialReferenceLookup[materialHashCode] = index;
        //        int spriteAssetHashCode =  spriteAsset.hashCode;
        //        if (!m_SpriteAssetReferenceLookup.ContainsKey(spriteAssetHashCode))
        //            m_SpriteAssetReferenceLookup.Add(spriteAssetHashCode, spriteAsset);
        //        m_countInternal += 1;
        //        return index;
        //    }
        //    else
        //    {
        //        return m_MaterialReferenceLookup[materialHashCode];
        //    }
        //}
        /// <summary>
        /// Function to check if the font asset is already referenced.
        /// </summary>
        /// <param name="font"></param>
        /// <returns></returns>
        public bool Contains(TMP_FontAsset font)
        {
            if (m_FontAssetReferenceLookup.ContainsKey(font.hashCode))
                return true;

            return false;
        }
 /// <summary>
 /// Function returning the Font Asset corresponding to the provided hash code.
 /// </summary>
 /// <param name="hashCode"></param>
 /// <param name="fontAsset"></param>
 /// <returns></returns>
 public static bool TryGetFontAsset(int hashCode, out TMP_FontAsset fontAsset)
 {
     return MaterialReferenceManager.instance.TryGetFontAssetInternal(hashCode, out fontAsset);
 }
 /// <summary>
 /// Add new font asset reference to dictionary.
 /// </summary>
 /// <param name="fontAsset"></param>
 public static void AddFontAsset(TMP_FontAsset fontAsset)
 {
     MaterialReferenceManager.instance.AddFontAssetInternal(fontAsset);
 }
        // Event received when font asset properties are changed in Font Inspector
        void ON_FONT_PROPERTY_CHANGED(bool isChanged, TMP_FontAsset font)
        {
            if (MaterialReference.Contains(m_materialReferences, font))
            {
                //Debug.Log("ON_FONT_PROPERTY_CHANGED event received.");
                m_isInputParsingRequired = true;
                m_havePropertiesChanged = true;

                //SetLayoutDirty();
                SetVerticesDirty();
            }
        }
Exemple #27
0
        /// <summary>
        /// Method used to find and cache references to the Underline and Ellipsis characters.
        /// </summary>
        /// <param name=""></param>
        protected void GetSpecialCharacters(TMP_FontAsset fontAsset)
        {
            // Check & Assign Underline Character for use with the Underline tag.
            if (!fontAsset.characterDictionary.TryGetValue(95, out m_cached_Underline_GlyphInfo)) //95
            {
                // Check fallback fonts
                    // TODO
            }

            // Check & Assign Underline Character for use with the Underline tag.
            if (!fontAsset.characterDictionary.TryGetValue(8230, out m_cached_Ellipsis_GlyphInfo)) //95
            {
                // Check fallback fonts
                // TODO
            }
        }
        /// <summary>
        /// Returns the text element (character) for the given unicode value taking into consideration the requested font style and weight.
        /// Function searches the provided list of font assets, the list of font assets assigned as alternative typefaces to them as well as their fallbacks.
        /// The font asset out parameter contains a reference to the font asset containing the character.
        /// The typeface type indicates whether the returned font asset is the source font asset, an alternative typeface or fallback font asset.
        /// </summary>
        /// <param name="unicode">The unicode value of the requested character</param>
        /// <param name="fontAssets">The list of font assets to search</param>
        /// <param name="includeFallbacks">Determines if the fallback of each font assets on the list will be searched</param>
        /// <param name="fontStyle">The font style</param>
        /// <param name="fontWeight">The font weight</param>
        /// <param name="type">Determines if the OUT font asset is an alternative typeface or fallback font asset</param>
        /// <param name="fontAsset">The font asset that contains the requested character</param>
        /// <returns></returns>
        public static TMP_Character GetCharacterFromFontAssets(uint unicode, List <TMP_FontAsset> fontAssets, bool includeFallbacks, FontStyles fontStyle, FontWeight fontWeight, out bool isAlternativeTypeface, out TMP_FontAsset fontAsset)
        {
            isAlternativeTypeface = false;

            // Make sure font asset list is valid
            if (fontAssets == null || fontAssets.Count == 0)
            {
                fontAsset = null;
                return(null);
            }

            if (includeFallbacks)
            {
                if (k_SearchedFontAssets == null)
                {
                    k_SearchedFontAssets = new List <int>();
                }
                else
                {
                    k_SearchedFontAssets.Clear();
                }
            }

            int fontAssetCount = fontAssets.Count;

            for (int i = 0; i < fontAssetCount; i++)
            {
                if (fontAssets[i] == null)
                {
                    continue;
                }

                TMP_Character characterData = GetCharacterFromFontAsset_Internal(unicode, fontAssets[i], includeFallbacks, fontStyle, fontWeight, out isAlternativeTypeface, out fontAsset);

                if (characterData != null)
                {
                    return(characterData);
                }
            }

            fontAsset = null;

            return(null);
        }
        /// <summary>
        /// Restore the State of various variables used in the mesh creation loop.
        /// </summary>
        /// <param name="state"></param>
        /// <returns></returns>
        protected int RestoreWordWrappingState(ref WordWrapState state)
        {
            int index = state.previous_WordBreak;

            // Multi Font & Material support related
            m_currentFontAsset = state.currentFontAsset;
            m_currentSpriteAsset = state.currentSpriteAsset;
            m_currentMaterial = state.currentMaterial;
            m_currentMaterialIndex = state.currentMaterialIndex;

            m_characterCount = state.total_CharacterCount + 1;
            m_visibleCharacterCount = state.visible_CharacterCount;
            m_visibleSpriteCount = state.visible_SpriteCount;
            m_textInfo.linkCount = state.visible_LinkCount;

            m_firstCharacterOfLine = state.firstCharacterIndex;
            m_firstVisibleCharacterOfLine = state.firstVisibleCharacterIndex;
            m_lastVisibleCharacterOfLine = state.lastVisibleCharIndex;

            m_style = state.fontStyle;
            m_fontScale = state.fontScale;
            m_fontScaleMultiplier = state.fontScaleMultiplier;
            //m_maxFontScale = state.maxFontScale;
            m_currentFontSize = state.currentFontSize;

            m_xAdvance = state.xAdvance;
            m_maxAscender = state.maxAscender;
            m_maxDescender = state.maxDescender;
            m_maxLineAscender = state.maxLineAscender;
            m_maxLineDescender = state.maxLineDescender;
            m_startOfLineAscender = state.previousLineAscender;
            m_preferredWidth = state.preferredWidth;
            m_preferredHeight = state.preferredHeight;
            m_meshExtents = state.meshExtents;

            m_lineNumber = state.lineNumber;
            m_lineOffset = state.lineOffset;
            m_baselineOffset = state.baselineOffset;

            //m_lineJustification = state.alignment;
            m_htmlColor = state.vertexColor;
            tag_NoParsing = state.tagNoParsing;

            // XML Tag Stack
            m_colorStack = state.colorStack;
            m_sizeStack = state.sizeStack;
            m_fontWeightStack = state.fontWeightStack;
            m_styleStack = state.styleStack;
            m_materialReferenceStack = state.materialReferenceStack;

            if (m_lineNumber < m_textInfo.lineInfo.Length)
                m_textInfo.lineInfo[m_lineNumber] = state.lineInfo;

            return index;
        }
        /// <summary>
        /// Internal function returning the text element character for the given unicode value taking into consideration the font style and weight.
        /// Function searches the source font asset, list of font assets assigned as alternative typefaces and list of fallback font assets.
        /// </summary>
        private static TMP_Character GetCharacterFromFontAsset_Internal(uint unicode, TMP_FontAsset sourceFontAsset, bool includeFallbacks, FontStyles fontStyle, FontWeight fontWeight, out bool isAlternativeTypeface, out TMP_FontAsset fontAsset)
        {
            fontAsset             = null;
            isAlternativeTypeface = false;
            TMP_Character characterData = null;

            #region FONT WEIGHT AND FONT STYLE HANDLING
            // Determine if a font weight or style is used. If so check if an alternative typeface is assigned for the given weight and / or style.
            bool isItalic = (fontStyle & FontStyles.Italic) == FontStyles.Italic;

            if (isItalic || fontWeight != FontWeight.Regular)
            {
                // Get reference to the font weight pairs of the given font asset.
                TMP_FontWeightPair[] fontWeights = sourceFontAsset.fontWeightTable;

                int fontWeightIndex = 4;
                switch (fontWeight)
                {
                case FontWeight.Thin:
                    fontWeightIndex = 1;
                    break;

                case FontWeight.ExtraLight:
                    fontWeightIndex = 2;
                    break;

                case FontWeight.Light:
                    fontWeightIndex = 3;
                    break;

                case FontWeight.Regular:
                    fontWeightIndex = 4;
                    break;

                case FontWeight.Medium:
                    fontWeightIndex = 5;
                    break;

                case FontWeight.SemiBold:
                    fontWeightIndex = 6;
                    break;

                case FontWeight.Bold:
                    fontWeightIndex = 7;
                    break;

                case FontWeight.Heavy:
                    fontWeightIndex = 8;
                    break;

                case FontWeight.Black:
                    fontWeightIndex = 9;
                    break;
                }

                fontAsset = isItalic ? fontWeights[fontWeightIndex].italicTypeface : fontWeights[fontWeightIndex].regularTypeface;

                if (fontAsset != null)
                {
                    if (fontAsset.characterLookupTable.TryGetValue(unicode, out characterData))
                    {
                        isAlternativeTypeface = true;

                        return(characterData);
                    }
                    else if (fontAsset.atlasPopulationMode == AtlasPopulationMode.Dynamic)
                    {
                        if (fontAsset.TryAddCharacterInternal(unicode, out characterData))
                        {
                            isAlternativeTypeface = true;

                            return(characterData);
                        }

                        // Check if the source font file contains the requested character.
                        //if (TryGetCharacterFromFontFile(unicode, fontAsset, out characterData))
                        //{
                        //    isAlternativeTypeface = true;

                        //    return characterData;
                        //}

                        // If we find the requested character, we add it to the font asset character table
                        // and return its character data.
                        // We also add this character to the list of characters we will need to add to the font atlas.
                        // We assume the font atlas has room otherwise this font asset should not be marked as dynamic.
                        // Alternatively, we could also add multiple pages of font atlas textures (feature consideration).
                    }

                    // At this point, we were not able to find the requested character in the alternative typeface
                    // so we check the source font asset and its potential fallbacks.
                }
            }
            #endregion

            // Search the source font asset for the requested character.
            if (sourceFontAsset.characterLookupTable.TryGetValue(unicode, out characterData))
            {
                // We were able to locate the requested character in the given font asset.
                fontAsset = sourceFontAsset;

                return(characterData);
            }
            else if (sourceFontAsset.atlasPopulationMode == AtlasPopulationMode.Dynamic)
            {
                if (sourceFontAsset.TryAddCharacterInternal(unicode, out characterData))
                {
                    fontAsset = sourceFontAsset;

                    return(characterData);
                }

                //// Check if the source font file contains the requested character.
                //if (TryGetCharacterFromFontFile(unicode, sourceFontAsset, out characterData))
                //{
                //    fontAsset = sourceFontAsset;

                //    //fontAsset.AddCharacterToRasterList(unicode);

                //    return characterData;
                //}

                // If we find the requested character, we add it to the font asset character table
                // and return its character data.
                // We also add this character to the list of characters we will need to add to the font atlas.
                // We assume the font atlas has room otherwise this font asset should not be marked as dynamic.
                // Alternatively, we could also add multiple pages of font atlas textures (feature consideration)
            }

            // Search fallback font assets if we still don't have a valid character and include fallback is set to true.
            if (characterData == null && includeFallbacks && sourceFontAsset.fallbackFontAssetTable != null)
            {
                // Get reference to the list of fallback font assets.
                List <TMP_FontAsset> fallbackFontAssets = sourceFontAsset.fallbackFontAssetTable;
                int fallbackCount = fallbackFontAssets.Count;

                if (fallbackFontAssets != null && fallbackCount > 0)
                {
                    for (int i = 0; i < fallbackCount && characterData == null; i++)
                    {
                        TMP_FontAsset temp = fallbackFontAssets[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);

                        characterData = GetCharacterFromFontAsset_Internal(unicode, temp, includeFallbacks, fontStyle, fontWeight, out isAlternativeTypeface, out fontAsset);

                        if (characterData != null)
                        {
                            return(characterData);
                        }
                    }
                }
            }

            return(null);
        }
        static void ScanProjectFile(AssetFileRecord fileRecord)
        {
            if (m_CancelScanProcess)
            {
                return;
            }

            // Read the asset data file
            string assetDataFile;
            bool   hasDataFileChanged = false;

            try
            {
                assetDataFile = File.ReadAllText(m_ProjectPath + "/" + fileRecord.assetFilePath);
            }
            catch
            {
                // Continue to the next asset if we can't read the current one.
                return;
            }

            // Check if asset file references any text components.
            if (assetDataFile.Contains(k_TextMeshProScriptID) || assetDataFile.Contains(k_TextMeshProUGUIScriptID))
            {
                float characterSpacingValue    = 0;
                float newCharacterSpacingValue = 0;
                float wordSpacingValue         = 0;
                float newWordSpacingValue      = 0;
                float lineSpacingValue         = 0;
                float newLineSpacingValue      = 0;
                float paragraphSpacingValue    = 0;
                float newParagraphSpacingValue = 0;

                float fontSize          = 0;
                float samplingPointSize = 0;
                float faceScale         = 1;

                List <string> lines = assetDataFile.Split('\n').ToList();
                int           serializedVersionInsertionIndex = 0;

                int readingFlag = 0;

                // Read through each lines of the asset file
                for (int i = 0; i < lines.Count; i++)
                {
                    string line = lines[i];

                    // Track potential line index to insert serializedVersion property
                    if (line.Contains("MonoBehaviour:"))
                    {
                        serializedVersionInsertionIndex = i + 1;
                        continue;
                    }

                    // Read until we find the line that contains a reference to a text component
                    if (readingFlag == 0 && (line.Contains(k_TextMeshProScriptID) || line.Contains(k_TextMeshProUGUIScriptID)))
                    {
                        // Check if spacing values for this component have already been converted
                        if (lines[serializedVersionInsertionIndex].Contains("  m_SerializedVersion: 1"))
                        {
                            readingFlag = 0;
                            continue;
                        }

                        lines.Insert(serializedVersionInsertionIndex, "  m_SerializedVersion: 1");
                        readingFlag = 1;
                        continue;
                    }

                    // Keep reading until we find the font asset property field.
                    if (readingFlag == 1)
                    {
                        // Check for font asset property
                        if (line.Contains(k_FontAssetProperty))
                        {
                            int guidIndex = line.IndexOf("guid: ", StringComparison.InvariantCulture);
                            if (guidIndex != -1)
                            {
                                string        guid      = line.Substring(guidIndex + 6, 32);
                                TMP_FontAsset fontAsset = AssetDatabase.LoadAssetAtPath <TMP_FontAsset>(AssetDatabase.GUIDToAssetPath(guid));
                                if (fontAsset != null)
                                {
                                    samplingPointSize = fontAsset.faceInfo.pointSize;
                                    faceScale         = fontAsset.faceInfo.scale;
                                }
                            }

                            readingFlag = 2;
                            continue;
                        }
                    }

                    // Read font size property
                    if (readingFlag == 2)
                    {
                        if (line.Contains(k_FontSizeProperty))
                        {
                            fontSize    = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture);
                            readingFlag = 3;
                            continue;
                        }
                    }

                    // Check for the spacing properties that need to be converted
                    if (readingFlag == 3)
                    {
                        // Read character spacing
                        if (line.Contains(k_CharacterSpacingProperty))
                        {
                            characterSpacingValue = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture);
                            if (characterSpacingValue != 0)
                            {
                                // Convert character spacing value.
                                newCharacterSpacingValue = characterSpacingValue * faceScale / (samplingPointSize * 0.01f);
                                lines[i] = lines[i].Replace(k_CharacterSpacingProperty + characterSpacingValue, k_CharacterSpacingProperty + newCharacterSpacingValue);

                                hasDataFileChanged = true;
                            }
                            continue;
                        }

                        // Read word spacing
                        if (line.Contains(k_WordSpacingProperty))
                        {
                            // Get the character spacing value
                            wordSpacingValue = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture);
                            if (wordSpacingValue != 0)
                            {
                                // Convert character spacing value.
                                newWordSpacingValue = wordSpacingValue * faceScale / (samplingPointSize * 0.01f);
                                lines[i]            = lines[i].Replace(k_WordSpacingProperty + wordSpacingValue, k_WordSpacingProperty + newWordSpacingValue);

                                hasDataFileChanged = true;
                            }
                            continue;
                        }

                        // Read line spacing
                        if (line.Contains(k_LineSpacingProperty))
                        {
                            // Get the value of line spacing value
                            lineSpacingValue = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture);
                            if (lineSpacingValue != 0)
                            {
                                // Convert line spacing value.
                                newLineSpacingValue = lineSpacingValue / (fontSize * 0.01f) * fontSize / samplingPointSize * faceScale;
                                lines[i]            = lines[i].Replace(k_LineSpacingProperty + lineSpacingValue, k_LineSpacingProperty + newLineSpacingValue);

                                hasDataFileChanged = true;
                            }
                            continue;
                        }

                        // Read paragraph spacing
                        if (line.Contains(k_ParagraphSpacingProperty))
                        {
                            // Get the value of line spacing value
                            paragraphSpacingValue = float.Parse(line.Split(':')[1], NumberStyles.Float, CultureInfo.InvariantCulture);
                            if (paragraphSpacingValue != 0)
                            {
                                // Convert line spacing value.
                                newParagraphSpacingValue = paragraphSpacingValue / (fontSize * 0.01f) * fontSize / samplingPointSize * faceScale;
                                lines[i] = lines[i].Replace(k_ParagraphSpacingProperty + paragraphSpacingValue, k_ParagraphSpacingProperty + newParagraphSpacingValue);

                                hasDataFileChanged = true;
                            }

                            readingFlag = 4;
                            continue;
                        }
                    }

                    // Done reading text component serialized data.
                    if (readingFlag == 4 && line.Contains("---"))
                    {
                        readingFlag = 0;

                        string characterSpacingFormat = $"{(characterSpacingValue == 0 ? "                    " : $"{characterSpacingValue,10:F}{newCharacterSpacingValue,10:F}")}";
                        string wordSpacingFormat      = $"{(wordSpacingValue == 0 ? "                    " : $"{wordSpacingValue,10:F}{newWordSpacingValue,10:F}")}";
                        string lineSpacingFormat      = $"{(lineSpacingValue == 0 ? "                    " : $"{lineSpacingValue,10:F}{newLineSpacingValue,10:F}")}";
                        string paragraphSpacingFormat = $"{(paragraphSpacingValue == 0 ? "                    " : $"{paragraphSpacingValue,10:F}{newParagraphSpacingValue,10:F}")}";

                        if (characterSpacingValue != 0 || lineSpacingValue != 0)
                        {
                            m_ProjectScanResults += $"{fileRecord.assetFilePath,-100}" + characterSpacingFormat + wordSpacingFormat + lineSpacingFormat + paragraphSpacingFormat + "\n";
                        }

                        // Update asset data file
                        assetDataFile = string.Join("\n", lines);

                        newCharacterSpacingValue = 0;
                        newWordSpacingValue      = 0;
                        newLineSpacingValue      = 0;
                        newParagraphSpacingValue = 0;
                    }
                }
            }

            // Check if asset file is a font asset
            // if (assetDataFile.Contains(k_FontAssetScriptID))
            // {
            //     float samplingPointSize;
            //     float normalSpacing;
            //     float newNormalSpacing;
            //     float boldSpacing;
            //     float newBoldSpacing;
            // }

            if (hasDataFileChanged)
            {
                AssetModificationRecord modifiedAsset;
                modifiedAsset.assetFilePath = fileRecord.assetFilePath;
                modifiedAsset.assetDataFile = assetDataFile;

                m_ModifiedAssetList.Add(modifiedAsset);
            }
        }
Exemple #32
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="hashcode"></param>
        /// <param name="fontAsset"></param>
        /// <returns></returns>
        public static bool TryGetFontAsset(int hashcode, out TMP_FontAsset fontAsset)
        {
            fontAsset = null;

            return(s_FontAssetReferenceLookup.TryGetValue(hashcode, out fontAsset));
        }
 /// <summary>
 /// Function returning the Font Asset corresponding to the provided hash code.
 /// </summary>
 /// <param name="hashCode"></param>
 /// <param name="fontAsset"></param>
 /// <returns></returns>
 public static bool TryGetFontAsset(int hashCode, out TMP_FontAsset fontAsset)
 {
     return(MaterialReferenceManager.instance.TryGetFontAssetInternal(hashCode, out fontAsset));
 }
Exemple #34
0
        /// <summary>
        /// Function which returns an array that contains all the characters from a font asset.
        /// </summary>
        /// <param name="fontAsset"></param>
        /// <returns></returns>
        public static int[] GetCharactersArray(TMP_FontAsset fontAsset)
        {
            int[] characters = new int[fontAsset.m_glyphInfoList.Count];

            for (int i = 0; i < fontAsset.m_glyphInfoList.Count; i++)
            {
                characters[i] = fontAsset.m_glyphInfoList[i].id;
            }

            return characters;
        }
Exemple #35
0
    static void ParseFnt(string filename)
    {
        var txt = File.ReadAllText(filename);

        var common = Regex.Matches(txt, "^common lineHeight=([0-9]+) base=([0-9]+) scaleW=([0-9]+) scaleH=([0-9]+)", RegexOptions.Multiline)
                     .OfType <Match>()
                     .Select(m => m.Groups.OfType <Group>().Select(g => g.Value).Skip(1).Select(x => int.Parse(x)).ToArray())
                     .First();

        var page = Regex.Matches(txt, "^page id=0 file=\"([^\"]+)\"", RegexOptions.Multiline)
                   .OfType <Match>()
                   .Select(m => m.Groups[1].Value)
                   .First();

        // Create and set the material
        var      atlas            = AssetDatabase.LoadAssetAtPath <Texture2D>(BuildFilenameInSamePath(filename, page));
        var      materialFilename = BuildFilenameWithExtension(BuildFilenameInSamePath(filename, page), "mat");
        Material material         = AssetDatabase.LoadAssetAtPath <Material>(materialFilename);
        bool     matWasCreated    = false;

        if (material == null)
        {
            var shader = AssetDatabase.LoadAssetAtPath <Shader>("Assets/TextMesh Pro/Resources/Shaders/TMP_Sprite.shader");
            material      = new Material(shader);
            matWasCreated = true;
        }
        material.SetTexture("_MainTex", atlas);

        if (matWasCreated)
        {
            AssetDatabase.CreateAsset(material, materialFilename);
        }
        else
        {
            AssetDatabase.SaveAssets();
        }

        var  fntFilename   = BuildFilenameWithExtension(filename, "asset");
        bool fntWasCreated = false;
        var  fnt           = AssetDatabase.LoadAssetAtPath <TMPro.TMP_FontAsset>(fntFilename);

        if (fnt == null)
        {
            fnt           = new TMPro.TMP_FontAsset();
            fntWasCreated = true;
        }

        // Create the atlas asset
        fnt.atlas    = atlas;
        fnt.material = AssetDatabase.LoadAssetAtPath <Material>(materialFilename);

        // Build the face and glyphs
        fnt.AddFaceInfo(new TMPro.FaceInfo()
        {
            AtlasWidth     = fnt.atlas.width,
            AtlasHeight    = fnt.atlas.height,
            Baseline       = common[1],
            Ascender       = common[3],
            Descender      = 0,
            CharacterCount = 42,
            LineHeight     = common[0],
            Name           = Path.GetFileNameWithoutExtension(page),
            Scale          = 1,
            PointSize      = 24,
            Padding        = 4
        });
        fnt.AddGlyphInfo(
            Regex.Matches(txt, "^char id=([0-9]+) x=([0-9]+) y=([0-9]+) width=([0-9]+) height=([0-9]+) xoffset=([0-9]+) yoffset=([0-9]+) xadvance=([0-9]+) page=([0-9]+) chnl=([0-9]+)", RegexOptions.Multiline)
            .OfType <Match>()
            .Select(m => m.Groups.OfType <Group>().Select(g => g.Value).Skip(1).Select(x => int.Parse(x)).ToArray())
            .Select(i => new TMPro.TMP_Glyph()
        {
            id       = i[0],
            x        = i[1],
            y        = i[2],
            width    = i[3],
            height   = i[4],
            xOffset  = i[5],
            yOffset  = i[6],
            xAdvance = i[7],
            scale    = 1
        }).ToArray()
            );

        if (fntWasCreated)
        {
            AssetDatabase.CreateAsset(fnt, fntFilename);
        }
        else
        {
            AssetDatabase.SaveAssets();
        }
    }
        /// <summary>
        /// Method to calculate the preferred width and height of the text object.
        /// </summary>
        /// <returns></returns>
        protected virtual Vector2 CalculatePreferredValues(float defaultFontSize, Vector2 marginSize)
        {
            //Debug.Log("*** CalculatePreferredValues() ***"); // ***** Frame: " + Time.frameCount);

            ////Profiler.BeginSample("TMP Generate Text - Phase I");

            // Early exit if no font asset was assigned. This should not be needed since Arial SDF will be assigned by default.
            if (m_fontAsset == null || m_fontAsset.characterDictionary == null)
            {
                Debug.LogWarning("Can't Generate Mesh! No Font Asset has been assigned to Object ID: " + this.GetInstanceID());

                return Vector2.zero;
            }

            // Early exit if we don't have any Text to generate.
            if (m_char_buffer == null || m_char_buffer.Length == 0 || m_char_buffer[0] == (char)0)
            {
                return Vector2.zero;
            }

            m_currentFontAsset = m_fontAsset;
            m_currentMaterial = m_sharedMaterial;
            m_currentMaterialIndex = 0;
            m_materialReferenceStack.SetDefault(new MaterialReference(0, m_currentFontAsset, null, m_currentMaterial, m_padding));

            // Total character count is computed when the text is parsed.
            int totalCharacterCount = m_totalCharacterCount; // m_VisibleCharacters.Count;

            if (m_internalCharacterInfo == null || totalCharacterCount > m_internalCharacterInfo.Length)
            {
                m_internalCharacterInfo = new TMP_CharacterInfo[totalCharacterCount > 1024 ? totalCharacterCount + 256 : Mathf.NextPowerOfTwo(totalCharacterCount)];
            }

            // Calculate the scale of the font based on selected font size and sampling point size.
            m_fontScale = (defaultFontSize / m_currentFontAsset.fontInfo.PointSize * (m_isOrthographic ? 1 : 0.1f));
            m_fontScaleMultiplier = 1;

            // baseScale is calculated based on the font asset assigned to the text object.
            float baseScale = (defaultFontSize / m_fontAsset.fontInfo.PointSize * m_fontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
            float currentElementScale = m_fontScale;

            m_currentFontSize = defaultFontSize;
            m_sizeStack.SetDefault(m_currentFontSize);

            int charCode = 0; // Holds the character code of the currently being processed character.

            m_style = m_fontStyle; // Set the default style.

            float bold_xAdvance_multiplier = 1; // Used to increase spacing between character when style is bold.

            m_baselineOffset = 0; // Used by subscript characters.

            m_styleStack.Clear();

            m_lineOffset = 0; // Amount of space between lines (font line spacing + m_linespacing).
            m_lineHeight = 0;
            float lineGap = m_currentFontAsset.fontInfo.LineHeight - (m_currentFontAsset.fontInfo.Ascender - m_currentFontAsset.fontInfo.Descender);

            m_cSpacing = 0; // Amount of space added between characters as a result of the use of the <cspace> tag.
            m_monoSpacing = 0;
            float lineOffsetDelta = 0;
            m_xAdvance = 0; // Used to track the position of each character.
            float maxXAdvance = 0; // Used to determine Preferred Width.

            tag_LineIndent = 0; // Used for indentation of text.
            tag_Indent = 0;
            m_indentStack.SetDefault(0);
            tag_NoParsing = false;
            //m_isIgnoringAlignment = false;

            m_characterCount = 0; // Total characters in the char[]

            // Tracking of line information
            m_firstCharacterOfLine = 0;
            m_maxLineAscender = -Mathf.Infinity;
            m_maxLineDescender = Mathf.Infinity;
            m_lineNumber = 0;

            float marginWidth = marginSize.x;
            //float marginHeight = marginSize.y;
            m_marginLeft = 0;
            m_marginRight = 0;
            m_width = -1;

            // Used by Unity's Auto Layout system.
            float renderedWidth = 0;
            float renderedHeight = 0;

            // Tracking of the highest Ascender
            m_maxAscender = 0;
            m_maxDescender = 0;

            // Initialize struct to track states of word wrapping
            bool isFirstWord = true;
            bool isLastBreakingChar = false;
            WordWrapState savedLineState = new WordWrapState();
            SaveWordWrappingState(ref savedLineState, 0, 0);
            WordWrapState savedWordWrapState = new WordWrapState();
            int wrappingIndex = 0;

            //int loopCountA = 0;

            int endTagIndex = 0;
            // Parse through Character buffer to read HTML tags and begin creating mesh.
            for (int i = 0; m_char_buffer[i] != 0; i++)
            {
                charCode = m_char_buffer[i];
                m_textElementType = TMP_TextElementType.Character;

                m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;
                m_currentFontAsset = m_materialReferences[m_currentMaterialIndex].fontAsset;

                int prev_MaterialIndex = m_currentMaterialIndex;

                // Parse Rich Text Tag
                #region Parse Rich Text Tag
                if (m_isRichText && charCode == 60)  // '<'
                {
                    m_isParsingText = true;

                    // Check if Tag is valid. If valid, skip to the end of the validated tag.
                    if (ValidateHtmlTag(m_char_buffer, i + 1, out endTagIndex))
                    {
                        i = endTagIndex;

                        // Continue to next character or handle the sprite element
                        if (m_textElementType == TMP_TextElementType.Character)
                            continue;
                    }
                }
                #endregion End Parse Rich Text Tag

                m_isParsingText = false;

                // Handle Font Styles like LowerCase, UpperCase and SmallCaps.
                #region Handling of LowerCase, UpperCase and SmallCaps Font Styles

                float smallCapsMultiplier = 1.0f;

                if (m_textElementType == TMP_TextElementType.Character)
                {
                    if ((m_style & FontStyles.UpperCase) == FontStyles.UpperCase)
                    {
                        // If this character is lowercase, switch to uppercase.
                        if (char.IsLower((char)charCode))
                            charCode = char.ToUpper((char)charCode);

                    }
                    else if ((m_style & FontStyles.LowerCase) == FontStyles.LowerCase)
                    {
                        // If this character is uppercase, switch to lowercase.
                        if (char.IsUpper((char)charCode))
                            charCode = char.ToLower((char)charCode);
                    }
                    else if ((m_fontStyle & FontStyles.SmallCaps) == FontStyles.SmallCaps || (m_style & FontStyles.SmallCaps) == FontStyles.SmallCaps)
                    {
                        if (char.IsLower((char)charCode))
                        {
                            smallCapsMultiplier = 0.8f;
                            charCode = char.ToUpper((char)charCode);
                        }
                    }
                }
                #endregion

                // Look up Character Data from Dictionary and cache it.
                #region Look up Character Data
                if (m_textElementType == TMP_TextElementType.Sprite)
                {
                    TMP_Sprite sprite = m_currentSpriteAsset.spriteInfoList[m_spriteIndex];
                    if (sprite == null) continue;

                    // Sprites are assigned in the E000 Private Area + sprite Index
                    charCode = 57344 + m_spriteIndex;

                    m_cached_TextElement = sprite;

                    // Adjust the offset relative to the pivot point.
                    //sprite.xOffset += sprite.pivot.x;
                    //sprite.yOffset += sprite.pivot.y;

                    currentElementScale = m_fontAsset.fontInfo.Ascender / sprite.height * sprite.scale * baseScale;

                    m_internalCharacterInfo[m_characterCount].elementType = TMP_TextElementType.Sprite;

                    m_currentMaterialIndex = prev_MaterialIndex;
                }
                else if (m_textElementType == TMP_TextElementType.Character)
                {
                    m_cached_TextElement = m_textInfo.characterInfo[m_characterCount].textElement;
                    m_currentFontAsset = m_textInfo.characterInfo[m_characterCount].fontAsset;

                    m_currentMaterialIndex = m_textInfo.characterInfo[m_characterCount].materialReferenceIndex;

                    // Re-calculate font scale as the font asset may have changed.
                    m_fontScale = m_currentFontSize * smallCapsMultiplier / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f);

                    currentElementScale = m_fontScale * m_fontScaleMultiplier;

                    m_internalCharacterInfo[m_characterCount].elementType = TMP_TextElementType.Character;

                    //padding = m_currentMaterialIndex == 0 ? m_padding : m_subTextObjects[m_currentMaterialIndex].padding;
                }
                #endregion

                // Store some of the text object's information
                m_internalCharacterInfo[m_characterCount].character = (char)charCode;

                // Handle Kerning if Enabled.
                #region Handle Kerning
                if (m_enableKerning && m_characterCount >= 1)
                {
                    int prev_charCode = m_internalCharacterInfo[m_characterCount - 1].character;
                    KerningPairKey keyValue = new KerningPairKey(prev_charCode, charCode);

                    KerningPair pair;

                    m_currentFontAsset.kerningDictionary.TryGetValue(keyValue.key, out pair);
                    if (pair != null)
                    {
                        m_xAdvance += pair.XadvanceOffset * currentElementScale;
                    }
                }
                #endregion

                // Handle Mono Spacing
                #region Handle Mono Spacing
                float monoAdvance = 0;
                if (m_monoSpacing != 0)
                {
                    monoAdvance = (m_monoSpacing / 2 - (m_cached_TextElement.width / 2 + m_cached_TextElement.xOffset) * currentElementScale);
                    m_xAdvance += monoAdvance;
                }
                #endregion

                // Set Padding based on selected font style
                #region Handle Style Padding
                if ((m_style & FontStyles.Bold) == FontStyles.Bold || (m_fontStyle & FontStyles.Bold) == FontStyles.Bold) // Checks for any combination of Bold Style.
                {
                    //style_padding = m_currentFontAsset.boldStyle * 2;
                    bold_xAdvance_multiplier = 1 + m_currentFontAsset.boldSpacing * 0.01f;
                }
                else
                {
                    //style_padding = m_currentFontAsset.normalStyle * 2;
                    bold_xAdvance_multiplier = 1.0f;
                }
                #endregion Handle Style Padding

                //m_internalTextInfo.characterInfo[m_characterCount].scale = currentElementScale;
                //m_internalTextInfo.characterInfo[m_characterCount].origin = m_xAdvance;
                m_internalCharacterInfo[m_characterCount].baseLine = 0 - m_lineOffset + m_baselineOffset;

                // Compute and save text element Ascender and maximum line Ascender.
                float elementAscender = m_currentFontAsset.fontInfo.Ascender * (m_textElementType == TMP_TextElementType.Character ? currentElementScale : baseScale) + m_baselineOffset;
                /* float elementAscenderII = */
                m_internalCharacterInfo[m_characterCount].ascender = elementAscender - m_lineOffset;
                m_maxLineAscender = elementAscender > m_maxLineAscender ? elementAscender : m_maxLineAscender;

                // Compute and save text element Descender and maximum line Descender.
                float elementDescender = m_currentFontAsset.fontInfo.Descender * (m_textElementType == TMP_TextElementType.Character ? currentElementScale : baseScale) + m_baselineOffset;
                float elementDescenderII = m_internalCharacterInfo[m_characterCount].descender = elementDescender - m_lineOffset;
                m_maxLineDescender = elementDescender < m_maxLineDescender ? elementDescender : m_maxLineDescender;

                // Adjust maxLineAscender and maxLineDescender if style is superscript or subscript
                if ((m_style & FontStyles.Subscript) == FontStyles.Subscript || (m_style & FontStyles.Superscript) == FontStyles.Superscript)
                {
                    float baseAscender = (elementAscender - m_baselineOffset) / m_currentFontAsset.fontInfo.SubSize;
                    elementAscender = m_maxLineAscender;
                    m_maxLineAscender = baseAscender > m_maxLineAscender ? baseAscender : m_maxLineAscender;

                    float baseDescender = (elementDescender - m_baselineOffset) / m_currentFontAsset.fontInfo.SubSize;
                    elementDescender = m_maxLineDescender;
                    m_maxLineDescender = baseDescender < m_maxLineDescender ? baseDescender : m_maxLineDescender;
                }

                if (m_lineNumber == 0) m_maxAscender = m_maxAscender > elementAscender ? m_maxAscender : elementAscender;
                //if (m_lineOffset == 0) pageAscender = pageAscender > elementAscender ? pageAscender : elementAscender;

                // Setup Mesh for visible text elements. ie. not a SPACE / LINEFEED / CARRIAGE RETURN.
                #region Handle Visible Characters
                if (charCode == 9 || !char.IsWhiteSpace((char)charCode) || m_textElementType == TMP_TextElementType.Sprite)
                {
                    //m_internalTextInfo.characterInfo[m_characterCount].isVisible = true;

                    // Check if Character exceeds the width of the Text Container
                    #region Handle Line Breaking, Text Auto-Sizing and Horizontal Overflow
                    float width = m_width != -1 ? Mathf.Min(marginWidth + 0.0001f - m_marginLeft - m_marginRight, m_width) : marginWidth + 0.0001f - m_marginLeft - m_marginRight;

                    //m_internalTextInfo.lineInfo[m_lineNumber].width = width;
                    //m_internalTextInfo.lineInfo[m_lineNumber].marginLeft = m_marginLeft;

                    if (m_xAdvance + m_cached_TextElement.xAdvance * currentElementScale > width)
                    {
                        // Word Wrapping
                        #region Handle Word Wrapping
                        if (enableWordWrapping && m_characterCount != m_firstCharacterOfLine)
                        {
                            // Check if word wrapping is still possible
                            #region Line Breaking Check
                            if (wrappingIndex == savedWordWrapState.previous_WordBreak || isFirstWord)
                            {
                                // Word wrapping is no longer possible, now breaking up individual words.
                                if (m_isCharacterWrappingEnabled == false)
                                {
                                    m_isCharacterWrappingEnabled = true;
                                }
                                else
                                    isLastBreakingChar = true;

                                //m_recursiveCount += 1;
                                //if (m_recursiveCount > 20)
                                //{
                                    //Debug.Log("Recursive count exceeded!");
                                    //continue;
                                //}
                            }
                            #endregion

                            // Restore to previously stored state of last valid (space character or linefeed)
                            i = RestoreWordWrappingState(ref savedWordWrapState);
                            wrappingIndex = i;  // Used to detect when line length can no longer be reduced.

                            // Check if Line Spacing of previous line needs to be adjusted.
                            if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == 0)
                            {
                                //Debug.Log("(1) Adjusting Line Spacing on line #" + m_lineNumber);
                                float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
                                AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
                                m_lineOffset += offsetDelta;
                                savedWordWrapState.lineOffset = m_lineOffset;
                                savedWordWrapState.previousLineAscender = m_maxLineAscender;

                                // TODO - Add check for character exceeding vertical bounds
                            }
                            //m_isNewPage = false;

                            // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
                            float lineAscender = m_maxLineAscender - m_lineOffset;
                            float lineDescender = m_maxLineDescender - m_lineOffset;

                            // Update maxDescender and maxVisibleDescender
                            m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;

                            m_firstCharacterOfLine = m_characterCount; // Store first character of the next line.

                            // Compute Preferred Width & Height
                            renderedWidth += m_xAdvance;
                            if (m_enableWordWrapping)
                                renderedHeight = m_maxAscender - m_maxDescender;
                            else
                                renderedHeight = Mathf.Max(renderedHeight, lineAscender - lineDescender);

                            // Store the state of the line before starting on the new line.
                            SaveWordWrappingState(ref savedLineState, i, m_characterCount - 1);

                            m_lineNumber += 1;
                            //isStartOfNewLine = true;

                            // Check to make sure Array is large enough to hold a new line.
                            //if (m_lineNumber >= m_internalTextInfo.lineInfo.Length)
                            //    ResizeLineExtents(m_lineNumber);

                            // Apply Line Spacing based on scale of the last character of the line.
                            if (m_lineHeight == 0)
                            {
                                float ascender = m_internalCharacterInfo[m_characterCount].ascender - m_internalCharacterInfo[m_characterCount].baseLine;
                                lineOffsetDelta = 0 - m_maxLineDescender + ascender + (lineGap + m_lineSpacing + m_lineSpacingDelta) * baseScale;
                                m_lineOffset += lineOffsetDelta;

                                m_startOfLineAscender = ascender;
                            }
                            else
                                m_lineOffset += m_lineHeight + m_lineSpacing * baseScale;

                            m_maxLineAscender = -Mathf.Infinity;
                            m_maxLineDescender = Mathf.Infinity;

                            m_xAdvance = 0 + tag_Indent;

                            continue;
                        }
                        #endregion End Word Wrapping
                    }
                    #endregion End Check for Characters Exceeding Width of Text Container

                }
                #endregion Handle Visible Characters

                // Check if Line Spacing of previous line needs to be adjusted.
                #region Adjust Line Spacing
                if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == 0 && !m_isNewPage)
                {
                    //Debug.Log("Inline - Adjusting Line Spacing on line #" + m_lineNumber);
                    //float gap = 0; // Compute gap.

                    float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
                    AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
                    elementDescenderII -= offsetDelta;
                    m_lineOffset += offsetDelta;

                    m_startOfLineAscender += offsetDelta;
                    savedWordWrapState.lineOffset = m_lineOffset;
                    savedWordWrapState.previousLineAscender = m_startOfLineAscender;
                }
                #endregion

                // Handle xAdvance & Tabulation Stops. Tab stops at every 25% of Font Size.
                #region XAdvance, Tabulation & Stops
                if (charCode == 9)
                {
                    m_xAdvance += m_currentFontAsset.fontInfo.TabWidth * currentElementScale;
                }
                else if (m_monoSpacing != 0)
                    m_xAdvance += (m_monoSpacing - monoAdvance + ((m_characterSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale) + m_cSpacing);
                else
                {
                    m_xAdvance += ((m_cached_TextElement.xAdvance * bold_xAdvance_multiplier + m_characterSpacing + m_currentFontAsset.normalSpacingOffset) * currentElementScale + m_cSpacing);
                }

                // Store xAdvance information
                //m_internalTextInfo.characterInfo[m_characterCount].xAdvance = m_xAdvance;

                #endregion Tabulation & Stops

                // Handle Carriage Return
                #region Carriage Return
                if (charCode == 13)
                {
                    maxXAdvance = Mathf.Max(maxXAdvance, renderedWidth + m_xAdvance);
                    renderedWidth = 0;
                    m_xAdvance = 0 + tag_Indent;
                }
                #endregion Carriage Return

                // Handle Line Spacing Adjustments + Word Wrapping & special case for last line.
                #region Check for Line Feed and Last Character
                if (charCode == 10 || m_characterCount == totalCharacterCount - 1)
                {
                    // Check if Line Spacing of previous line needs to be adjusted.
                    if (m_lineNumber > 0 && !TMP_Math.Approximately(m_maxLineAscender, m_startOfLineAscender) && m_lineHeight == 0)
                    {
                        //Debug.Log("(2) Adjusting Line Spacing on line #" + m_lineNumber);
                        float offsetDelta = m_maxLineAscender - m_startOfLineAscender;
                        AdjustLineOffset(m_firstCharacterOfLine, m_characterCount, offsetDelta);
                        elementDescenderII -= offsetDelta;
                        m_lineOffset += offsetDelta;
                    }

                    // Calculate lineAscender & make sure if last character is superscript or subscript that we check that as well.
                    //float lineAscender = m_maxLineAscender - m_lineOffset;
                    float lineDescender = m_maxLineDescender - m_lineOffset;

                    // Update maxDescender and maxVisibleDescender
                    m_maxDescender = m_maxDescender < lineDescender ? m_maxDescender : lineDescender;

                    m_firstCharacterOfLine = m_characterCount + 1;

                    // Store PreferredWidth paying attention to linefeed and last character of text.
                    if (charCode == 10 && m_characterCount != totalCharacterCount - 1)
                    {
                        maxXAdvance = Mathf.Max(maxXAdvance, renderedWidth + m_xAdvance);
                        renderedWidth = 0;
                    }
                    else
                        renderedWidth = Mathf.Max(maxXAdvance, renderedWidth + m_xAdvance);

                    renderedHeight = m_maxAscender - m_maxDescender;

                    // Add new line if not last lines or character.
                    if (charCode == 10)
                    {
                        // Store the state of the line before starting on the new line.
                        SaveWordWrappingState(ref savedLineState, i, m_characterCount);
                        // Store the state of the last Character before the new line.
                        SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount);

                        m_lineNumber += 1;

                        // Apply Line Spacing
                        if (m_lineHeight == 0)
                        {
                            lineOffsetDelta = 0 - m_maxLineDescender + elementAscender + (lineGap + m_lineSpacing + m_paragraphSpacing + m_lineSpacingDelta) * baseScale;
                            m_lineOffset += lineOffsetDelta;
                        }
                        else
                            m_lineOffset += m_lineHeight + (m_lineSpacing + m_paragraphSpacing) * baseScale;

                        m_maxLineAscender = -Mathf.Infinity;
                        m_maxLineDescender = Mathf.Infinity;
                        m_startOfLineAscender = elementAscender;

                        m_xAdvance = 0 + tag_LineIndent + tag_Indent;
                    }
                }
                #endregion Check for Linefeed or Last Character

                // Save State of Mesh Creation for handling of Word Wrapping
                #region Save Word Wrapping State
                if (m_enableWordWrapping || m_overflowMode == TextOverflowModes.Truncate || m_overflowMode == TextOverflowModes.Ellipsis)
                {
                    if ((charCode == 9 || charCode == 32) && !m_isNonBreakingSpace)
                    {
                        // We store the state of numerous variables for the most recent Space, LineFeed or Carriage Return to enable them to be restored
                        // for Word Wrapping.
                        SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount);
                        m_isCharacterWrappingEnabled = false;
                        isFirstWord = false;
                    }
                    else if (charCode > 0x2e80 && charCode < 0x9fff)
                    {
                        if (m_currentFontAsset.lineBreakingInfo.leadingCharacters.ContainsKey(charCode) == false &&
                           (m_characterCount < totalCharacterCount - 1 &&
                            m_currentFontAsset.lineBreakingInfo.followingCharacters.ContainsKey(m_internalCharacterInfo[m_characterCount + 1].character) == false))
                        {
                            SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount);
                            m_isCharacterWrappingEnabled = false;
                            isFirstWord = false;

                        }
                    }
                    else if ((isFirstWord || m_isCharacterWrappingEnabled == true || isLastBreakingChar))
                        SaveWordWrappingState(ref savedWordWrapState, i, m_characterCount);
                }
                #endregion Save Word Wrapping State

                m_characterCount += 1;
            }

            m_isCharacterWrappingEnabled = false;

            // Adjust Preferred Width and Height to account for Margins.
            renderedWidth += m_margin.x > 0 ? m_margin.x : 0;
            renderedWidth += m_margin.z > 0 ? m_margin.z : 0;

            renderedHeight += m_margin.y > 0 ? m_margin.y : 0;
            renderedHeight += m_margin.w > 0 ? m_margin.w : 0;

            ////Profiler.EndSample();

            return new Vector2(renderedWidth, renderedHeight);
        }
Exemple #37
0
 public bool Contains(TMP_FontAsset font)
 {
     return(this.m_FontAssetReferenceLookup.ContainsKey(font.hashCode));
 }
        /// <summary>
        /// Method used to find and cache references to the Underline and Ellipsis characters.
        /// </summary>
        /// <param name=""></param>
        protected void GetSpecialCharacters(TMP_FontAsset fontAsset)
        {
            // Check & Assign Underline Character for use with the Underline tag.
            if (!fontAsset.characterDictionary.TryGetValue(95, out m_cached_Underline_GlyphInfo)) //95
            {
                // Check fallback fonts
                    // TODO

                if (m_settings == null && !m_settings.warningsDisabled)
                    Debug.LogWarning("Underscore character wasn't found in the current Font Asset. No characters assigned for Underline.", this);
            }

            // Check & Assign Underline Character for use with the Underline tag.
            if (!fontAsset.characterDictionary.TryGetValue(8230, out m_cached_Ellipsis_GlyphInfo)) //95
            {
                // Check fallback fonts
                // TODO

                if (m_settings == null && !m_settings.warningsDisabled)
                    Debug.LogWarning("Ellipsis character wasn't found in the current Font Asset. No characters assigned for Underline.", this);
            }
        }
Exemple #39
0
 private bool TryGetFontAssetInternal(int hashCode, out TMP_FontAsset fontAsset)
 {
     fontAsset = null;
     return(this.m_FontAssetReferenceLookup.TryGetValue(hashCode, out fontAsset));
 }
        /// <summary>
        /// Function to identify and validate the rich tag. Returns the position of the > if the tag was valid.
        /// </summary>
        /// <param name="chars"></param>
        /// <param name="startIndex"></param>
        /// <param name="endIndex"></param>
        /// <returns></returns>
        protected bool ValidateHtmlTag(int[] chars, int startIndex, out int endIndex)
        {
            int tagCharCount = 0;
            byte attributeFlag = 0;

            TagUnits tagUnits = TagUnits.Pixels;
            TagType tagType = TagType.None;

            int attributeIndex = 0;
            m_xmlAttribute[attributeIndex].nameHashCode = 0;
            m_xmlAttribute[attributeIndex].valueType = TagType.None;
            m_xmlAttribute[attributeIndex].valueHashCode = 0;
            m_xmlAttribute[attributeIndex].valueStartIndex = 0;
            m_xmlAttribute[attributeIndex].valueLength = 0;
            m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;

            endIndex = startIndex;
            bool isTagSet = false;
            bool isValidHtmlTag = false;

            for (int i = startIndex; i < chars.Length && chars[i] != 0 && tagCharCount < m_htmlTag.Length && chars[i] != 60; i++)
            {
                if (chars[i] == 62) // ASCII Code of End HTML tag '>'
                {
                    isValidHtmlTag = true;
                    endIndex = i;
                    m_htmlTag[tagCharCount] = (char)0;
                    break;
                }

                m_htmlTag[tagCharCount] = (char)chars[i];
                tagCharCount += 1;

                if (attributeFlag == 1)
                {
                    if (m_xmlAttribute[attributeIndex].valueStartIndex == 0)
                    {
                        // Check for attribute type
                        if (chars[i] == 43 || chars[i] == 45 || char.IsDigit((char)chars[i]))
                        {
                            tagType = TagType.NumericalValue;
                            m_xmlAttribute[attributeIndex].valueType = TagType.NumericalValue;
                            m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
                            m_xmlAttribute[attributeIndex].valueLength += 1;
                        }
                        else if (chars[i] == 35)
                        {
                            tagType = TagType.ColorValue;
                            m_xmlAttribute[attributeIndex].valueType = TagType.ColorValue;
                            m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
                            m_xmlAttribute[attributeIndex].valueLength += 1;
                        }
                        else if (chars[i] != 34)
                        {
                            tagType = TagType.StringValue;
                            m_xmlAttribute[attributeIndex].valueType = TagType.StringValue;
                            m_xmlAttribute[attributeIndex].valueStartIndex = tagCharCount - 1;
                            m_xmlAttribute[attributeIndex].valueHashCode = (m_xmlAttribute[attributeIndex].valueHashCode << 5) + m_xmlAttribute[attributeIndex].valueHashCode ^ chars[i];
                            m_xmlAttribute[attributeIndex].valueLength += 1;
                        }
                    }
                    else
                    {
                        if (tagType == TagType.NumericalValue)
                        {
                            if (chars[i] == 46) // '.' Decimal Point Index
                                m_xmlAttribute[attributeIndex].valueDecimalIndex = tagCharCount - 1;

                            // Check for termination of numerical value.
                            if (chars[i] == 112 || chars[i] == 101 || chars[i] == 37 || chars[i] == 32)
                            {
                                attributeFlag = 2;
                                tagType = TagType.None;
                                attributeIndex += 1;
                                m_xmlAttribute[attributeIndex].nameHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueType = TagType.None;
                                m_xmlAttribute[attributeIndex].valueHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueStartIndex = 0;
                                m_xmlAttribute[attributeIndex].valueLength = 0;
                                m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;

                                if (chars[i] == 101)
                                    tagUnits = TagUnits.FontUnits;
                                else if (chars[i] == 37)
                                    tagUnits = TagUnits.Percentage;
                            }
                            else if (attributeFlag != 2)
                            {
                                m_xmlAttribute[attributeIndex].valueLength += 1;
                            }
                        }
                        else if (tagType == TagType.ColorValue)
                        {
                            if (chars[i] != 32)
                            {
                                m_xmlAttribute[attributeIndex].valueLength += 1;
                            }
                            else
                            {
                                attributeFlag = 2;
                                tagType = TagType.None;
                                attributeIndex += 1;
                                m_xmlAttribute[attributeIndex].nameHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueType = TagType.None;
                                m_xmlAttribute[attributeIndex].valueHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueStartIndex = 0;
                                m_xmlAttribute[attributeIndex].valueLength = 0;
                                m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;
                            }
                        }
                        else if (tagType == TagType.StringValue)
                        {
                            // Compute HashCode value for the named tag.
                            if (chars[i] != 34)
                            {
                                m_xmlAttribute[attributeIndex].valueHashCode = (m_xmlAttribute[attributeIndex].valueHashCode << 5) + m_xmlAttribute[attributeIndex].valueHashCode ^ chars[i];
                                m_xmlAttribute[attributeIndex].valueLength += 1;
                            }
                            else
                            {
                                //m_xmlAttribute[attributeIndex].valueHashCode = -1;
                                attributeFlag = 2;
                                tagType = TagType.None;
                                attributeIndex += 1;
                                m_xmlAttribute[attributeIndex].nameHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueType = TagType.None;
                                m_xmlAttribute[attributeIndex].valueHashCode = 0;
                                m_xmlAttribute[attributeIndex].valueStartIndex = 0;
                                m_xmlAttribute[attributeIndex].valueLength = 0;
                                m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;
                            }
                        }
                    }
                }

                if (chars[i] == 61) // '='
                    attributeFlag = 1;

                // Compute HashCode for the name of the attribute
                if (attributeFlag == 0 && chars[i] == 32)
                {
                    if (isTagSet) return false;

                    isTagSet = true;
                    attributeFlag = 2;

                    tagType = TagType.None;
                    attributeIndex += 1;
                    m_xmlAttribute[attributeIndex].nameHashCode = 0;
                    m_xmlAttribute[attributeIndex].valueType = TagType.None;
                    m_xmlAttribute[attributeIndex].valueHashCode = 0;
                    m_xmlAttribute[attributeIndex].valueStartIndex = 0;
                    m_xmlAttribute[attributeIndex].valueLength = 0;
                    m_xmlAttribute[attributeIndex].valueDecimalIndex = 0;
                }

                if (attributeFlag == 0)
                    m_xmlAttribute[attributeIndex].nameHashCode = (m_xmlAttribute[attributeIndex].nameHashCode << 3) - m_xmlAttribute[attributeIndex].nameHashCode + chars[i];

                if (attributeFlag == 2 && chars[i] == 32)
                    attributeFlag = 0;

            }

            if (!isValidHtmlTag)
            {
                return false;
            }

            //Debug.Log("Tag is [" + m_htmlTag.ArrayToString() + "].  Tag HashCode: " + m_xmlAttribute[0].nameHashCode + "  Tag Value HashCode: " + m_xmlAttribute[0].valueHashCode + "  Attribute 1 HashCode: " + m_xmlAttribute[1].nameHashCode + " Value HashCode: " + m_xmlAttribute[1].valueHashCode);
            //for (int i = 0; i < attributeIndex + 1; i++)
            //    Debug.Log("Tag [" + i + "] with HashCode: " + m_xmlAttribute[i].nameHashCode + " has value of [" + new string(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength) + "] Numerical Value: " + ConvertToFloat(m_htmlTag, m_xmlAttribute[i].valueStartIndex, m_xmlAttribute[i].valueLength, m_xmlAttribute[i].valueDecimalIndex));

            // Special handling of the NoParsing tag
            if (tag_NoParsing && m_xmlAttribute[0].nameHashCode != 53822163)
                return false;
            else if (m_xmlAttribute[0].nameHashCode == 53822163)
            {
                tag_NoParsing = false;
                return true;
            }

            // Color <#FF00FF>
            if (m_htmlTag[0] == 35 && tagCharCount == 7) // if Tag begins with # and contains 7 characters.
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack.Add(m_htmlColor);
                return true;
            }
            // Color <#FF00FF00> with alpha
            else if (m_htmlTag[0] == 35 && tagCharCount == 9) // if Tag begins with # and contains 9 characters.
            {
                m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                m_colorStack.Add(m_htmlColor);
                return true;
            }
            else
            {
                float value = 0;

                switch (m_xmlAttribute[0].nameHashCode)
                {
                    case 98: // <b>
                        m_style |= FontStyles.Bold;
                        m_fontWeightInternal = 700;
                        m_fontWeightStack.Add(700);
                        return true;
                    case 427: // </b>
                        if ((m_fontStyle & FontStyles.Bold) != FontStyles.Bold)
                        {
                            m_style &= ~FontStyles.Bold;
                            m_fontWeightInternal = m_fontWeightStack.Remove();
                        }
                        return true;
                    case 105: // <i>
                        m_style |= FontStyles.Italic;
                        return true;
                    case 434: // </i>
                        m_style &= ~FontStyles.Italic;
                        return true;
                    case 115: // <s>
                        m_style |= FontStyles.Strikethrough;
                        return true;
                    case 444: // </s>
                        if ((m_fontStyle & FontStyles.Strikethrough) != FontStyles.Strikethrough)
                            m_style &= ~FontStyles.Strikethrough;
                        return true;
                    case 117: // <u>
                        m_style |= FontStyles.Underline;
                        return true;
                    case 446: // </u>
                        if ((m_fontStyle & FontStyles.Underline) != FontStyles.Underline)
                            m_style &= ~FontStyles.Underline;
                        return true;

                    case 6552: // <sub>
                        m_fontScaleMultiplier = m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
                        m_baselineOffset = m_currentFontAsset.fontInfo.SubscriptOffset * m_fontScale * m_fontScaleMultiplier;
                        m_style |= FontStyles.Subscript;
                        return true;
                    case 22673: // </sub>
                        if ((m_style & FontStyles.Subscript) == FontStyles.Subscript)
                        {
                            // Check to make sure we are not also using Superscript
                            if ((m_style & FontStyles.Superscript) == FontStyles.Superscript)
                            {
                                m_fontScaleMultiplier = m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
                                m_baselineOffset = m_currentFontAsset.fontInfo.SuperscriptOffset * m_fontScale * m_fontScaleMultiplier;
                            }
                            else
                            {
                                m_baselineOffset = 0;
                                m_fontScaleMultiplier = 1;
                            }

                            m_style &= ~FontStyles.Subscript;
                        }
                        return true;
                    case 6566: // <sup>
                        m_fontScaleMultiplier = m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
                        m_baselineOffset = m_currentFontAsset.fontInfo.SuperscriptOffset * m_fontScale * m_fontScaleMultiplier;
                        m_style |= FontStyles.Superscript;
                        return true;
                    case 22687: // </sup>
                        if ((m_style & FontStyles.Superscript) == FontStyles.Superscript)
                        {
                            // Check to make sure we are not also using Superscript
                            if ((m_style & FontStyles.Subscript) == FontStyles.Subscript)
                            {
                                m_fontScaleMultiplier = m_currentFontAsset.fontInfo.SubSize > 0 ? m_currentFontAsset.fontInfo.SubSize : 1;
                                m_baselineOffset = m_currentFontAsset.fontInfo.SubscriptOffset * m_fontScale * m_fontScaleMultiplier;
                            }
                            else
                            {
                                m_baselineOffset = 0;
                                m_fontScaleMultiplier = 1;
                            }

                            m_style &= ~FontStyles.Superscript;
                        }
                        return true;
                    case -330774850: // <font-weight>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        if ((m_fontStyle & FontStyles.Bold) == FontStyles.Bold)
                        {
                            // Nothing happens since Bold is forced on the text.
                            //m_fontWeight = 700;
                            return true;
                        }

                        // Remove bold style
                        m_style &= ~FontStyles.Bold;

                        switch ((int)value)
                        {
                            case 100:
                                m_fontWeightInternal = 100;
                                break;
                            case 200:
                                m_fontWeightInternal = 200;
                                break;
                            case 300:
                                m_fontWeightInternal = 300;
                                break;
                            case 400:
                                m_fontWeightInternal = 400;

                                break;
                            case 500:
                                m_fontWeightInternal = 500;
                                break;
                            case 600:
                                m_fontWeightInternal = 600;
                                break;
                            case 700:
                                m_fontWeightInternal = 700;
                                m_style |= FontStyles.Bold;
                                break;
                            case 800:
                                m_fontWeightInternal = 800;
                                break;
                            case 900:
                                m_fontWeightInternal = 900;
                                break;
                        }

                        m_fontWeightStack.Add(m_fontWeightInternal);

                        return true;
                    case -1885698441: // </font-weight>
                        m_fontWeightInternal = m_fontWeightStack.Remove();
                        return true;
                    case 6380: // <pos=000.00px> <pos=0em> <pos=50%>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_xAdvance = value;
                                //m_isIgnoringAlignment = true;
                                return true;
                            case TagUnits.FontUnits:
                                m_xAdvance = value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                //m_isIgnoringAlignment = true;
                                return true;
                            case TagUnits.Percentage:
                                m_xAdvance = m_marginWidth * value / 100;
                                //m_isIgnoringAlignment = true;
                                return true;
                        }
                        return false;
                    case 22501: // </pos>
                        m_isIgnoringAlignment = false;
                        return true;
                    case 16034505: // <voffset>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_baselineOffset = value;
                                return true;
                            case TagUnits.FontUnits:
                                m_baselineOffset = value * m_fontScale * m_fontAsset.fontInfo.Ascender;
                                return true;
                            case TagUnits.Percentage:
                                //m_baselineOffset = m_marginHeight * val / 100;
                                return false;
                        }
                        return false;
                    case 54741026: // </voffset>
                        m_baselineOffset = 0;
                        return true;
                    case 43991: // <page>
                        // This tag only works when Overflow - Page mode is used.
                        if (m_overflowMode == TextOverflowModes.Page)
                        {
                            m_xAdvance = 0 + tag_LineIndent + tag_Indent;
                            //m_textInfo.lineInfo[m_lineNumber].marginLeft = m_xAdvance;
                            m_lineOffset = 0;
                            m_pageNumber += 1;
                            m_isNewPage = true;
                        }
                        return true;

                    case 43969: // <nobr>
                        m_isNonBreakingSpace = true;
                        return true;
                    case 156816: // </nobr>
                        m_isNonBreakingSpace = false;
                        return true;
                    case 45545: // <size=>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                if (m_htmlTag[5] == 43) // <size=+00>
                                {
                                    m_currentFontSize = m_fontSize + value;
                                    m_sizeStack.Add(m_currentFontSize);
                                    m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                    return true;
                                }
                                else if (m_htmlTag[5] == 45) // <size=-00>
                                {
                                    m_currentFontSize = m_fontSize + value;
                                    m_sizeStack.Add(m_currentFontSize);
                                    m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                    return true;
                                }
                                else // <size=00.0>
                                {
                                    m_currentFontSize = value;
                                    m_sizeStack.Add(m_currentFontSize);
                                    m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                    return true;
                                }
                            case TagUnits.FontUnits:
                                m_currentFontSize = m_fontSize * value;
                                m_sizeStack.Add(m_currentFontSize);
                                m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                return true;
                            case TagUnits.Percentage:
                                m_currentFontSize = m_fontSize * value / 100;
                                m_sizeStack.Add(m_currentFontSize);
                                m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                                return true;
                        }
                        return false;
                    case 158392: // </size>
                        m_currentFontSize = m_sizeStack.Remove();
                        m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                        return true;
                    case 41311: // <font=xx>
                        //Debug.Log("Font name: \"" + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength) + "\"   HashCode: " + m_xmlAttribute[0].valueHashCode + "   Material Name: \"" + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength) + "\"   Hashcode: " + m_xmlAttribute[1].valueHashCode);

                        int fontHashCode = m_xmlAttribute[0].valueHashCode;
                        int materialAttributeHashCode = m_xmlAttribute[1].nameHashCode;
                        int materialHashCode = m_xmlAttribute[1].valueHashCode;

                        // Special handling for <font=default> or <font=Default>
                        if (fontHashCode == 764638571 || fontHashCode == 523367755)
                        {
                            m_currentFontAsset = m_materialReferences[0].fontAsset;
                            m_currentMaterial = m_materialReferences[0].material;
                            m_currentMaterialIndex = 0;
                            //Debug.Log("<font=Default> assigning Font Asset [" + m_currentFontAsset.name + "] with Material [" + m_currentMaterial.name + "].");

                            m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));

                            m_materialReferenceStack.Add(m_materialReferences[0]);

                            return true;
                        }

                        TMP_FontAsset tempFont;
                        Material tempMaterial;

                        // HANDLE NEW FONT ASSET
                        if (MaterialReferenceManager.TryGetFontAsset(fontHashCode, out tempFont))
                        {
                            //if (tempFont != m_currentFontAsset)
                            //{
                            //    //Debug.Log("Assigning Font Asset: " + tempFont.name);
                            //    m_currentFontAsset = tempFont;
                            //    m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));
                            //}
                        }
                        else
                        {
                            // Load Font Asset
                            tempFont = Resources.Load<TMP_FontAsset>("Fonts & Materials/" + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength));

                            if (tempFont == null)
                                return false;

                            // Add new reference to the font asset as well as default material to the MaterialReferenceManager
                            MaterialReferenceManager.AddFontAsset(tempFont);
                        }

                        // HANDLE NEW MATERIAL
                        if (materialAttributeHashCode == 0 && materialHashCode == 0)
                        {
                            // No material specified then use default font asset material.
                            m_currentMaterial = tempFont.material;

                            m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);

                            m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
                        }
                        else if (materialAttributeHashCode == 103415287) // using material attribute
                        {
                            if (MaterialReferenceManager.TryGetMaterial(materialHashCode, out tempMaterial))
                            {
                                m_currentMaterial = tempMaterial;

                                m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);

                                m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
                            }
                            else
                            {
                                // Load new material
                                tempMaterial = Resources.Load<Material>("Fonts & Materials/" + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength));

                                if (tempMaterial == null)
                                    return false;

                                // Add new reference to this material in the MaterialReferenceManager
                                MaterialReferenceManager.AddFontMaterial(materialHashCode, tempMaterial);

                                m_currentMaterial = tempMaterial;

                                m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentMaterial, tempFont, m_materialReferences, m_materialReferenceIndexLookup);

                                m_materialReferenceStack.Add(m_materialReferences[m_currentMaterialIndex]);
                            }
                        }
                        else
                            return false;

                        m_currentFontAsset = tempFont;
                        m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));

                        return true;
                    case 154158: // </font>
                        MaterialReference materialReference = m_materialReferenceStack.Remove();

                        m_currentFontAsset = materialReference.fontAsset;
                        m_currentMaterial = materialReference.material;
                        m_currentMaterialIndex = materialReference.index;

                        m_fontScale = (m_currentFontSize / m_currentFontAsset.fontInfo.PointSize * m_currentFontAsset.fontInfo.Scale * (m_isOrthographic ? 1 : 0.1f));

                        return true;
                    case 320078: // <space=000.00>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_xAdvance += value;
                                return true;
                            case TagUnits.FontUnits:
                                m_xAdvance += value * m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                return true;
                            case TagUnits.Percentage:
                                // Not applicable
                                return false;
                        }
                        return false;
                    case 276254: // <alpha=#FF>
                        if (m_xmlAttribute[0].valueLength != 3) return false;

                        m_htmlColor.a = (byte)(HexToInt(m_htmlTag[7]) * 16 + HexToInt(m_htmlTag[8]));
                        return true;

                    case 1750458: // <a name=" ">
                        return false;
                    case 426: // </a>
                        return true;
                    case 43066: // <link="name">
                        if (m_isParsingText)
                        {
                            tag_LinkInfo.textComponent = this;
                            tag_LinkInfo.hashCode = m_xmlAttribute[0].valueHashCode;
                            tag_LinkInfo.linkTextfirstCharacterIndex = m_characterCount;

                            tag_LinkInfo.linkIdFirstCharacterIndex = startIndex + m_xmlAttribute[0].valueStartIndex;
                            tag_LinkInfo.linkIdLength = m_xmlAttribute[0].valueLength;

                        }
                        return true;
                    case 155913: // </link>
                        if (m_isParsingText)
                        {
                            tag_LinkInfo.linkTextLength = m_characterCount - tag_LinkInfo.linkTextfirstCharacterIndex;

                            int size = m_textInfo.linkInfo.Length;

                            if (m_textInfo.linkCount + 1 > size)
                                TMP_TextInfo.Resize(ref m_textInfo.linkInfo, size + 1);

                            m_textInfo.linkInfo[m_textInfo.linkCount] = tag_LinkInfo;

                            m_textInfo.linkCount += 1;

                        }
                        return true;
                    case 275917: // <align=>
                        switch (m_xmlAttribute[0].valueHashCode)
                        {
                            case 3774683: // <align=left>
                                m_lineJustification = TextAlignmentOptions.Left;
                                return true;
                            case 136703040: // <align=right>
                                m_lineJustification = TextAlignmentOptions.Right;
                                return true;
                            case -458210101: // <align=center>
                                m_lineJustification = TextAlignmentOptions.Center;
                                return true;
                            case -523808257: // <align=justified>
                                m_lineJustification = TextAlignmentOptions.Justified;
                                return true;
                        }
                        return false;
                    case 1065846: // </align>
                        m_lineJustification = m_textAlignment;
                        return true;
                    case 327550: // <width=xx>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_width = value;
                                break;
                            case TagUnits.FontUnits:
                                return false;
                            //break;
                            case TagUnits.Percentage:
                                m_width = m_marginWidth * value / 100;
                                break;
                        }
                        return true;
                    case 1117479: // </width>
                        m_width = -1;
                        return true;
                    case 322689: // <style="name">
                        TMP_Style style = TMP_StyleSheet.Instance.GetStyle(m_xmlAttribute[0].valueHashCode);

                        if (style == null) return false;

                        m_styleStack.Add(style.hashCode);

                        //// Parse Style Macro
                        for (int i = 0; i < style.styleOpeningTagArray.Length; i++)
                        {
                            if (style.styleOpeningTagArray[i] == 60)
                                ValidateHtmlTag(style.styleOpeningTagArray, i + 1, out i);
                        }
                        return true;
                    case 1112618: // </style>
                        style = TMP_StyleSheet.Instance.GetStyle(m_xmlAttribute[0].valueHashCode);

                        if (style == null)
                        {
                            // Get style from the Style Stack
                            int styleHashCode = m_styleStack.Remove();
                            style = TMP_StyleSheet.Instance.GetStyle(styleHashCode);
                        }

                        if (style == null) return false;
                        //// Parse Style Macro
                        for (int i = 0; i < style.styleClosingTagArray.Length; i++)
                        {
                            if (style.styleClosingTagArray[i] == 60)
                                ValidateHtmlTag(style.styleClosingTagArray, i + 1, out i);
                        }
                        return true;
                    case 281955: // <color=#FF00FF> or <color=#FF00FF00>
                        // <color=#FF00FF> 3 Hex pairs
                        if (m_htmlTag[6] == 35 && tagCharCount == 13)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack.Add(m_htmlColor);
                            return true;
                        }
                        // <color=#FF00FF00> 4 Hex pairs
                        else if (m_htmlTag[6] == 35 && tagCharCount == 15)
                        {
                            m_htmlColor = HexCharsToColor(m_htmlTag, tagCharCount);
                            m_colorStack.Add(m_htmlColor);
                            return true;
                        }

                        // <color=name>
                        switch (m_xmlAttribute[0].valueHashCode)
                        {
                            case 125395: // <color=red>
                                m_htmlColor = Color.red;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 3573310: // <color=blue>
                                m_htmlColor = Color.blue;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 117905991: // <color=black>
                                m_htmlColor = Color.black;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 121463835: // <color=green>
                                m_htmlColor = Color.green;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 140357351: // <color=white>
                                m_htmlColor = Color.white;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 26556144: // <color=orange>
                                m_htmlColor = new Color32(255, 128, 0, 255);
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case -36881330: // <color=purple>
                                m_htmlColor = new Color32(160, 32, 240, 255);
                                m_colorStack.Add(m_htmlColor);
                                return true;
                            case 554054276: // <color=yellow>
                                m_htmlColor = Color.yellow;
                                m_colorStack.Add(m_htmlColor);
                                return true;
                        }
                        return false;
                    case 1983971: // <cspace=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_cSpacing = value;
                                break;
                            case TagUnits.FontUnits:
                                m_cSpacing = value;
                                m_cSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                return false;
                        }
                        return true;
                    case 7513474: // </cspace>
                        m_cSpacing = 0;
                        return true;
                    case 2152041: // <mspace=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                m_monoSpacing = value;
                                break;
                            case TagUnits.FontUnits:
                                m_monoSpacing = value;
                                m_monoSpacing *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                return false;
                        }
                        return true;
                    case 7681544: // </mspace>
                        m_monoSpacing = 0;
                        return true;
                    case 280416: // <class="name">
                        return false;
                    case 1071884: // </color>
                        m_htmlColor = m_colorStack.Remove();
                        return true;
                    case 2068980: // <indent=10px> <indent=10em> <indent=50%>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                tag_Indent = value;
                                break;
                            case TagUnits.FontUnits:
                                tag_Indent = value;
                                tag_Indent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                tag_Indent = m_marginWidth * value / 100;
                                break;
                        }
                        m_indentStack.Add(tag_Indent);

                        m_xAdvance = tag_Indent;
                        return true;
                    case 7598483: // </indent>
                        tag_Indent = m_indentStack.Remove();
                        //m_xAdvance = tag_Indent;
                        return true;
                    case 1109386397: // <line-indent>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                tag_LineIndent = value;
                                break;
                            case TagUnits.FontUnits:
                                tag_LineIndent = value;
                                tag_LineIndent *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                tag_LineIndent = m_marginWidth * value / 100;
                                break;
                        }

                        m_xAdvance += tag_LineIndent;
                        return true;
                    case -445537194: // </line-indent>
                        tag_LineIndent = 0;
                        return true;
                    case 2246877: // <sprite=x>
                        int spriteAssetHashCode = m_xmlAttribute[0].valueHashCode;
                        TMP_SpriteAsset tempSpriteAsset;

                        // CHECK TAG FORMAT
                        if (m_xmlAttribute[0].valueType == TagType.None || m_xmlAttribute[0].valueType == TagType.NumericalValue)
                        {
                            // No Sprite Asset specified
                            if (m_defaultSpriteAsset == null)
                            {
                                // Load TMP Settings
                                if (m_settings == null) m_settings = TMP_Settings.LoadDefaultSettings();

                                if (m_settings != null && m_settings.spriteAsset != null)
                                    m_defaultSpriteAsset = m_settings.spriteAsset;
                                else
                                    m_defaultSpriteAsset = Resources.Load<TMP_SpriteAsset>("Sprite Assets/Default Sprite Asset");

                            }

                            m_currentSpriteAsset = m_defaultSpriteAsset;

                            // No valid sprite asset available
                            if (m_currentSpriteAsset == null)
                                return false;
                        }
                        else
                        {
                            // A Sprite Asset has been specified
                            if (MaterialReferenceManager.TryGetSpriteAsset(spriteAssetHashCode, out tempSpriteAsset))
                            {
                                m_currentSpriteAsset = tempSpriteAsset;
                            }
                            else
                            {
                                // Load Sprite Asset
                                if (tempSpriteAsset == null)
                                {
                                    tempSpriteAsset = Resources.Load<TMP_SpriteAsset>("Sprites/" + new string(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength));
                                }

                                if (tempSpriteAsset == null)
                                    return false;

                                //Debug.Log("Loading & assigning new Sprite Asset: " + tempSpriteAsset.name);
                                MaterialReferenceManager.AddSpriteAsset(spriteAssetHashCode, tempSpriteAsset);
                                m_currentSpriteAsset = tempSpriteAsset;
                            }
                        }

                        if (m_xmlAttribute[0].valueType == TagType.NumericalValue)
                        {
                            int index = (int)ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                            if (index == -9999) return false;

                            m_spriteIndex = index;
                        }
                        else if (m_xmlAttribute[1].nameHashCode == 43347) // <sprite name="">
                        {
                            //Debug.Log("Name attribute [" + new string(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength) + "].");

                            int index = m_currentSpriteAsset.GetSpriteIndex(m_xmlAttribute[1].valueHashCode);
                            if (index == -1) return false;

                            m_spriteIndex = index;

                        }
                        else if (m_xmlAttribute[1].nameHashCode == 295562) // <sprite index=xx>
                        {
                            int index = (int)ConvertToFloat(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength, m_xmlAttribute[1].valueDecimalIndex);
                            if (index == -9999) return false;

                            m_spriteIndex = index;

                            // Check to make sure sprite index is valid
                            if (m_spriteIndex > m_currentSpriteAsset.spriteInfoList.Count - 1) return false;
                        }
                        else
                        {
                            return false;
                        }

                        // Material HashCode for the Sprite Asset is the Sprite Asset Hash Code
                        m_currentMaterialIndex = MaterialReference.AddMaterialReference(m_currentSpriteAsset.material, m_currentSpriteAsset, m_materialReferences, m_materialReferenceIndexLookup);

                        //m_materialReferenceStack.Add(m_materialReferenceManager.materialReferences[m_currentMaterialIndex]);

                        m_spriteColor = s_colorWhite;
                        m_tintSprite = false;

                        // Handle Tint Attribute
                        if (m_xmlAttribute[1].nameHashCode == 45819)
                            m_tintSprite = ConvertToFloat(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength, m_xmlAttribute[1].valueDecimalIndex) != 0;
                        else if (m_xmlAttribute[2].nameHashCode == 45819)
                            m_tintSprite = ConvertToFloat(m_htmlTag, m_xmlAttribute[2].valueStartIndex, m_xmlAttribute[2].valueLength, m_xmlAttribute[2].valueDecimalIndex) != 0;

                        // Handle Color Attribute
                        if (m_xmlAttribute[1].nameHashCode == 281955)
                            m_spriteColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[1].valueStartIndex, m_xmlAttribute[1].valueLength);
                        else if (m_xmlAttribute[2].nameHashCode == 281955)
                            m_spriteColor = HexCharsToColor(m_htmlTag, m_xmlAttribute[2].valueStartIndex, m_xmlAttribute[2].valueLength);

                        m_xmlAttribute[1].nameHashCode = 0;
                        m_xmlAttribute[2].nameHashCode = 0;

                        m_textElementType = TMP_TextElementType.Sprite;
                        return true;
                    case 730022849: // <lowercase>
                        m_style |= FontStyles.LowerCase;
                        return true;
                    case -1668324918: // </lowercase>
                        m_style &= ~FontStyles.LowerCase;
                        return true;
                    case 13526026: // <allcaps>
                    case 781906058: // <uppercase>
                        m_style |= FontStyles.UpperCase;
                        return true;
                    case 52232547: // </allcaps>
                    case -1616441709: // </uppercase>
                        m_style &= ~FontStyles.UpperCase;
                        return true;
                    case 766244328: // <smallcaps>
                        m_style |= FontStyles.SmallCaps;
                        return true;
                    case -1632103439: // </smallcaps>
                        m_style &= ~FontStyles.SmallCaps;
                        return true;
                    case 2109854: // <margin=00.0> <margin=00em> <margin=50%>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginLeft = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
                                break;
                        }
                        m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
                        m_marginRight = m_marginLeft;
                        return true;
                    case 7639357: // </margin>
                        m_marginLeft = 0;
                        m_marginRight = 0;
                        return true;
                    case 1100728678: // <margin-left=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginLeft = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginLeft *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginLeft = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginLeft / 100;
                                break;
                        }
                        m_marginLeft = m_marginLeft >= 0 ? m_marginLeft : 0;
                        return true;
                    case -884817987: // <margin-right=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex); // px
                        if (value == -9999 || value == 0) return false;

                        m_marginRight = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                // Default behavior
                                break;
                            case TagUnits.FontUnits:
                                m_marginRight *= m_fontScale * m_fontAsset.fontInfo.TabWidth / m_fontAsset.tabSize;
                                break;
                            case TagUnits.Percentage:
                                m_marginRight = (m_marginWidth - (m_width != -1 ? m_width : 0)) * m_marginRight / 100;
                                break;
                        }
                        m_marginRight = m_marginRight >= 0 ? m_marginRight : 0;
                        return true;
                    case 1109349752: // <line-height=xx.x>
                        value = ConvertToFloat(m_htmlTag, m_xmlAttribute[0].valueStartIndex, m_xmlAttribute[0].valueLength, m_xmlAttribute[0].valueDecimalIndex);
                        if (value == -9999 || value == 0) return false;

                        m_lineHeight = value;
                        switch (tagUnits)
                        {
                            case TagUnits.Pixels:
                                //m_lineHeight *= m_isOrthographic ? 1 : 0.1f;
                                break;
                            case TagUnits.FontUnits:
                                m_lineHeight *= m_fontAsset.fontInfo.LineHeight * m_fontScale;
                                break;
                            case TagUnits.Percentage:
                                m_lineHeight = m_fontAsset.fontInfo.LineHeight * m_lineHeight / 100 * m_fontScale;
                                break;
                        }
                        return true;
                    case -445573839: // </line-height>
                        m_lineHeight = 0;
                        return true;
                    case 15115642: // <noparse>
                        tag_NoParsing = true;
                        return true;
                    case 1913798: // <action>
                        // TODO
                        return false;
                    case 7443301: // </action>
                        // TODO
                        return false;
                }
            }
            return false;
        }
Exemple #41
0
 public static bool TryGetFontAsset(int hashCode, out TMP_FontAsset fontAsset)
 {
     return(instance.TryGetFontAssetInternal(hashCode, out fontAsset));
 }
 public static void ON_FONT_PROPERTY_CHANGED(bool isChanged, TMP_FontAsset font)
 {
     FONT_PROPERTY_EVENT.Call(isChanged, font);
 }
Exemple #43
0
 public static void AddFontAsset(TMP_FontAsset fontAsset)
 {
     instance.AddFontAssetInternal(fontAsset);
 }
 /// <summary>
 /// Add new font asset reference to dictionary.
 /// </summary>
 /// <param name="fontAsset"></param>
 public static void AddFontAsset(TMP_FontAsset fontAsset)
 {
     MaterialReferenceManager.instance.AddFontAssetInternal(fontAsset);
 }
 public static void ON_FONT_PROPERTY_CHANGED(bool isChanged, TMP_FontAsset font)
 {
     FONT_PROPERTY_EVENT.Call(isChanged, font);
 }